This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-bcel.git
commit 177bbacbc028b3023077ca0b813665c26ed899f4 Author: Gary Gregory <[email protected]> AuthorDate: Mon Jan 12 08:53:55 2026 -0500 Code.Code(int, int, DataInput, ConstantPool) now throws a ClassFormatException if the code array is greater than the JVM specification allows --- src/changes/changes.xml | 1 + src/main/java/org/apache/bcel/classfile/Code.java | 37 ++++++++++++----------- src/main/java/org/apache/bcel/util/Args.java | 19 +++++++++++- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 319ea3bb..2699912c 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -67,6 +67,7 @@ The <action> type attribute can be add,update,fix,remove. <action type="fix" dev="ggregory" due-to="Gary Gregory">Make the build reproducible on the Azul JDK.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">Exception message in Args.requireU4() refers to the wrong data type.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">Exception message in Args.requireU2() refers to the wrong upper range value.</action> + <action type="fix" dev="ggregory" due-to="Gary Gregory">Code.Code(int, int, DataInput, ConstantPool) now throws a ClassFormatException if the code array is greater than the JVM specification allows.</action> <!-- ADD --> <action type="add" dev="ggregory" due-to="Gary Gregory">Add Const.MAJOR_26.</action> <action type="add" dev="ggregory" due-to="Gary Gregory">Add Const.MINOR_26.</action> diff --git a/src/main/java/org/apache/bcel/classfile/Code.java b/src/main/java/org/apache/bcel/classfile/Code.java index 9bad7f84..9b4c02f2 100644 --- a/src/main/java/org/apache/bcel/classfile/Code.java +++ b/src/main/java/org/apache/bcel/classfile/Code.java @@ -80,37 +80,40 @@ public final class Code extends Attribute { } /** - * @param nameIndex Index pointing to the name <em>Code</em> - * @param length Content length in bytes - * @param file Input stream - * @param constantPool Array of constants + * Constructs a Code attribute object from a DataInput. + * + * @param nameIndex Index pointing to the name <em>Code</em>. + * @param length Content length in bytes. + * @param dataInput Data input. + * @param constantPool Array of constants. + * @throws ClassFormatException if the code array read from {@code file} is greater than {@link Const#MAX_CODE_SIZE}. */ - Code(final int nameIndex, final int length, final DataInput file, final ConstantPool constantPool) throws IOException { + Code(final int nameIndex, final int length, final DataInput dataInput, final ConstantPool constantPool) throws IOException { // Initialize with some default values which will be overwritten later - this(nameIndex, length, file.readUnsignedShort(), file.readUnsignedShort(), (byte[]) null, (CodeException[]) null, (Attribute[]) null, constantPool); - final int codeLength = Args.requireU4(file.readInt(), 1, "Code length attribute"); + this(nameIndex, length, dataInput.readUnsignedShort(), dataInput.readUnsignedShort(), (byte[]) null, (CodeException[]) null, (Attribute[]) null, + constantPool); + final int codeLength = Args.requireU4(dataInput.readInt(), 1, Const.MAX_CODE_SIZE, "Code length attribute"); code = new byte[codeLength]; // Read byte code - file.readFully(code); + dataInput.readFully(code); /* - * Read exception table that contains all regions where an exception handler is active, i.e., a try { ... } catch () - * block. + * Read exception table that contains all regions where an exception handler is active, i.e., a try { ... } catch () block. */ - final int exceptionTableLength = file.readUnsignedShort(); + final int exceptionTableLength = dataInput.readUnsignedShort(); exceptionTable = new CodeException[exceptionTableLength]; for (int i = 0; i < exceptionTableLength; i++) { - exceptionTable[i] = new CodeException(file); + exceptionTable[i] = new CodeException(dataInput); } /* * Read all attributes, currently 'LineNumberTable' and 'LocalVariableTable' */ - final int attributesCount = file.readUnsignedShort(); + final int attributesCount = dataInput.readUnsignedShort(); attributes = new Attribute[attributesCount]; for (int i = 0; i < attributesCount; i++) { - attributes[i] = readAttribute(file, constantPool); + attributes[i] = readAttribute(dataInput, constantPool); } /* - * Adjust length, because of setAttributes in this(), s.b. length is incorrect, because it didn't take the internal - * attributes into account yet! Very subtle bug, fixed in 3.1.1. + * Adjust length, because of setAttributes in this(), s.b. length is incorrect, because it didn't take the internal attributes into account yet! Very + * subtle bug, fixed in 3.1.1. */ super.setLength(length); } @@ -141,7 +144,7 @@ public final class Code extends Attribute { /** * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. - * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. + * That is, the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. * * @param v Visitor object */ diff --git a/src/main/java/org/apache/bcel/util/Args.java b/src/main/java/org/apache/bcel/util/Args.java index 37c9756d..57a4300e 100644 --- a/src/main/java/org/apache/bcel/util/Args.java +++ b/src/main/java/org/apache/bcel/util/Args.java @@ -123,10 +123,27 @@ public class Args { * @return The value to test. */ public static int requireU4(final int value, final int min, final String message) { + // Should really be 2^32-1, instead 2^21-1. + return requireU4(value, min, Integer.MAX_VALUE, message); + } + + /** + * Requires a u4 value of at least {@code min} and not above {@code max}. + * + * @param value The value to test. + * @param min The minimum required u4 value. + * @param max The maximum required u4 value. + * @param message The message prefix + * @return The value to test. + * @throws IllegalArgumentException if {@code min < 0} or {@code max > Integer.MAX_VALUE}. + * @throws ClassFormatException if {@code value < min} or {@code value > max}. + * @since 6.12.0 + */ + public static int requireU4(final int value, final int min, final int max, final String message) { if (min < 0) { throw new IllegalArgumentException(String.format("%s programming error: min %,d < 0", message, min)); } - if (value < min) { + if (value < min || value > max) { throw new ClassFormatException( String.format("%s [Value out of range (%,d - %,d) for type u4: %,d]", message, min, Integer.MAX_VALUE, value & 0xFFFFFFFFL)); }
