---
src/changes/changes.xml | 2 +-
.../java/org/apache/bcel/classfile/Attribute.java | 37 ++++++++++++++++++----
.../java/org/apache/bcel/classfile/Unknown.java | 10 +-----
src/main/java/org/apache/bcel/util/Args.java | 28 ++++++++++++++++
4 files changed, 61 insertions(+), 16 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 502b818f..30a26c71 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -98,7 +98,7 @@ The <action> type attribute can be add,update,fix,remove.
<action type="fix" dev="ggregory" due-to="Gary
Gregory">org.apache.bcel.util.ClassPath hashCode() and equals() don't match.</action>
<action type="fix" dev="markt"
due-to="OSS-Fuzz">org.apache.bcel.classfile.StackMapType constructors now throw ClassFormatException on
invalid input.</action>
<action type="add" dev="ggregory" due-to="nbauma109, Gary
Gregory">Code coverage and bug fixes for bcelifier #171.</action>
- <action type="fix" dev="markt" due-to="Mark
Thomas">org.apache.bcel.classfile.Unknown constructors now throw ClassFormatException on invalid length
input.</action>
+ <action type="fix" dev="markt" due-to="Mark Thomas, Gary
Gregory">org.apache.bcel.classfile.Attribute constructors now throw ClassFormatException on invalid length
input.</action>
<!-- UPDATE -->
<action type="update" dev="ggregory" due-to="Gary
Gregory">Bump spotbugs-maven-plugin from 4.7.2.2 to 4.7.3.0 #167.</action>
<action type="update" dev="ggregory"
due-to="Dependabot">Bump jmh.version from 1.35 to 1.36 #170.</action>
diff --git a/src/main/java/org/apache/bcel/classfile/Attribute.java
b/src/main/java/org/apache/bcel/classfile/Attribute.java
index d1d38f40..14a76cc2 100644
--- a/src/main/java/org/apache/bcel/classfile/Attribute.java
+++ b/src/main/java/org/apache/bcel/classfile/Attribute.java
@@ -27,9 +27,17 @@ import org.apache.bcel.Const;
import org.apache.bcel.util.Args;
/**
- * Abstract super class for <em>Attribute</em> objects. Currently the
<em>ConstantValue</em>, <em>SourceFile</em>,
- * <em>Code</em>, <em>Exceptiontable</em>, <em>LineNumberTable</em>,
<em>LocalVariableTable</em>, <em>InnerClasses</em>
- * and <em>Synthetic</em> attributes are supported. The <em>Unknown</em>
attribute stands for non-standard-attributes.
+ * Abstract super class for <em>Attribute</em> objects. Currently the <em>ConstantValue</em>,
<em>SourceFile</em>, <em>Code</em>, <em>Exceptiontable</em>,
+ * <em>LineNumberTable</em>, <em>LocalVariableTable</em>, <em>InnerClasses</em> and
<em>Synthetic</em> attributes are supported. The <em>Unknown</em> attribute
+ * stands for non-standard-attributes.
+ *
+ * <pre>
+ * attribute_info {
+ * u2 attribute_name_index;
+ * u4 attribute_length;
+ * u1 info[attribute_length];
+ * }
+ * </pre>
*
* @see ConstantValue
* @see SourceFile
@@ -238,10 +246,26 @@ public abstract class Attribute implements Cloneable,
Node {
@java.lang.Deprecated
protected ConstantPool constant_pool; // TODO make private (has getter &
setter)
+ /**
+ * Constructs an instance.
+ *
+ * <pre>
+ * attribute_info {
+ * u2 attribute_name_index;
+ * u4 attribute_length;
+ * u1 info[attribute_length];
+ * }
+ * </pre>
+ *
+ * @param tag tag.
+ * @param nameIndex u2 name index.
+ * @param length u4 length.
+ * @param constantPool constant pool.
+ */
protected Attribute(final byte tag, final int nameIndex, final int
length, final ConstantPool constantPool) {
this.tag = tag;
this.name_index = Args.requireU2(nameIndex, 0, constantPool.getLength(),
getClass().getSimpleName() + " name index");
- this.length = length;
+ this.length = Args.requireU4(length, getClass().getSimpleName() + "
attribute length");
this.constant_pool = constantPool;
}
@@ -271,12 +295,13 @@ public abstract class Attribute implements Cloneable, Node {
}
/**
- * @return deep copy of this attribute
+ * @param constantPool constant pool to save.
+ * @return deep copy of this attribute.
*/
public abstract Attribute copy(ConstantPool constantPool);
/**
- * Dump attribute to file stream in binary format.
+ * Dumps attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
diff --git a/src/main/java/org/apache/bcel/classfile/Unknown.java
b/src/main/java/org/apache/bcel/classfile/Unknown.java
index df088430..6f72dc24 100644
--- a/src/main/java/org/apache/bcel/classfile/Unknown.java
+++ b/src/main/java/org/apache/bcel/classfile/Unknown.java
@@ -49,7 +49,7 @@ public final class Unknown extends Attribute {
public Unknown(final int nameIndex, final int length, final byte[] bytes,
final ConstantPool constantPool) {
super(Const.ATTR_UNKNOWN, nameIndex, length, constantPool);
this.bytes = bytes;
- name = constantPool.getConstantUtf8(nameIndex).getBytes();
+ this.name = constantPool.getConstantUtf8(nameIndex).getBytes();
}
/**
@@ -66,14 +66,6 @@ public final class Unknown extends Attribute {
if (length > 0) {
bytes = new byte[length];
input.readFully(bytes);
- } else if (length < 0) {
- // Length is defined in the JVM specification as an unsigned 4 byte
- // integer but is read as a signed integer. This is not an issue as
- // the JRE API consistently uses byte[] or ByteBuffer for classes.
- // Therefore treat any negative number here as a format error.
- throw new ClassFormatException(String.format(
- "Invalid length %,d for Unknown attribute. Must be greater than
or equal to zero and less than %,d",
- length & 0xFFFFFFFFL, Integer.MAX_VALUE));
}
}
diff --git a/src/main/java/org/apache/bcel/util/Args.java b/src/main/java/org/apache/bcel/util/Args.java
index defc071f..642f6508 100644
--- a/src/main/java/org/apache/bcel/util/Args.java
+++ b/src/main/java/org/apache/bcel/util/Args.java
@@ -53,6 +53,20 @@ public class Args {
return require(value, 0, message);
}
+ /**
+ * Requires a u1 value.
+ *
+ * @param value The value to test.
+ * @param message The message prefix
+ * @return The value to test.
+ */
+ public static int requireU1(final int value, final String message) {
+ if (value < 0 || value > Const.MAX_BYTE) {
+ throw new ClassFormatException(String.format("%s [Value out of range (0
- %,d) for type u1: %,d]", message, Const.MAX_BYTE, value));
+ }
+ return value;
+ }
+
/**
* Requires a u2 value of at least {@code min} and not above {@code max}.
*
@@ -97,4 +111,18 @@ public class Args {
public static int requireU2(final int value, final String message) {
return requireU2(value, 0, message);
}
+
+ /**
+ * Requires a u4 value.
+ *
+ * @param value The value to test.
+ * @param message The message prefix
+ * @return The value to test.
+ */
+ public static int requireU4(final int value, final String message) {
+ if (value < 0) {
+ throw new ClassFormatException(String.format("%s [Value out of range (0
- %,d) for type u4: %,d]", message, Integer.MAX_VALUE, value));
+ }
+ return value;
+ }
}