This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-bcel.git
The following commit(s) were added to refs/heads/master by this push:
new 9d49870b Validate u1 count bound in INVOKEINTERFACE and MULTIANEWARRAY
(#523)
9d49870b is described below
commit 9d49870b1ebd47f5c14daed4d00f15d7f58d13ad
Author: Naveed Khan <[email protected]>
AuthorDate: Wed Jul 15 21:08:14 2026 +0000
Validate u1 count bound in INVOKEINTERFACE and MULTIANEWARRAY (#523)
* validate u1 count bound in invokeinterface and multianewarray
* split count bounds test into one class per instruction
---
.../org/apache/bcel/generic/INVOKEINTERFACE.java | 4 +-
.../org/apache/bcel/generic/MULTIANEWARRAY.java | 2 +-
.../apache/bcel/generic/INVOKEINTERFACETest.java | 62 ++++++++++++++++++++++
.../apache/bcel/generic/MULTIANEWARRAYTest.java | 29 ++++++++++
4 files changed, 94 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/apache/bcel/generic/INVOKEINTERFACE.java
b/src/main/java/org/apache/bcel/generic/INVOKEINTERFACE.java
index 6657b3a8..1945b1fb 100644
--- a/src/main/java/org/apache/bcel/generic/INVOKEINTERFACE.java
+++ b/src/main/java/org/apache/bcel/generic/INVOKEINTERFACE.java
@@ -55,8 +55,8 @@ public final class INVOKEINTERFACE extends InvokeInstruction {
public INVOKEINTERFACE(final int index, final int nargs) {
super(Const.INVOKEINTERFACE, index);
super.setLength(5);
- if (nargs < 1) {
- throw new ClassGenException("Number of arguments must be > 0 " +
nargs);
+ if (nargs < 1 || nargs > Const.MAX_BYTE) {
+ throw new ClassGenException("Number of arguments out of range (1 -
" + Const.MAX_BYTE + "): " + nargs);
}
this.nargs = nargs;
}
diff --git a/src/main/java/org/apache/bcel/generic/MULTIANEWARRAY.java
b/src/main/java/org/apache/bcel/generic/MULTIANEWARRAY.java
index bdc2f027..2c720c7e 100644
--- a/src/main/java/org/apache/bcel/generic/MULTIANEWARRAY.java
+++ b/src/main/java/org/apache/bcel/generic/MULTIANEWARRAY.java
@@ -50,7 +50,7 @@ public class MULTIANEWARRAY extends CPInstruction implements
LoadClass, Allocati
*/
public MULTIANEWARRAY(final int index, final short dimensions) {
super(org.apache.bcel.Const.MULTIANEWARRAY, index);
- if (dimensions < 1) {
+ if (dimensions < 1 || dimensions > org.apache.bcel.Const.MAX_BYTE) {
throw new ClassGenException("Invalid dimensions value: " +
dimensions);
}
this.dimensions = dimensions;
diff --git a/src/test/java/org/apache/bcel/generic/INVOKEINTERFACETest.java
b/src/test/java/org/apache/bcel/generic/INVOKEINTERFACETest.java
new file mode 100644
index 00000000..5d5ac4cd
--- /dev/null
+++ b/src/test/java/org/apache/bcel/generic/INVOKEINTERFACETest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.bcel.generic;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.apache.bcel.Const;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link INVOKEINTERFACE}.
+ *
+ * @see <a
href="https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-6.html#jvms-6.5.invokeinterface">JVM
INVOKEINTERFACE specification</a>
+ */
+class INVOKEINTERFACETest {
+
+ private static int dumpedCountByte(final INVOKEINTERFACE instruction)
throws IOException {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try (DataOutputStream dos = new DataOutputStream(bos)) {
+ instruction.dump(dos);
+ }
+ // opcode, u2 index, u1 count, u1 zero
+ return bos.toByteArray()[3] & 0xFF;
+ }
+
+ @Test
+ void testCountRoundTrips() throws IOException {
+ assertEquals(Const.MAX_BYTE, dumpedCountByte(new INVOKEINTERFACE(1,
Const.MAX_BYTE)));
+ }
+
+ /**
+ * The {@code count} operand of {@code invokeinterface} is an unsigned
byte (1-255) and {@code dump} writes it with {@code writeByte}, so the
constructor
+ * must reject values above {@link Const#MAX_BYTE} instead of truncating
them.
+ */
+ @Test
+ void testRejectsCountAboveU1() {
+ assertEquals(Const.MAX_BYTE, new INVOKEINTERFACE(1,
Const.MAX_BYTE).getCount());
+ assertThrows(ClassGenException.class, () -> new INVOKEINTERFACE(1,
Const.MAX_BYTE + 1));
+ }
+}
diff --git a/src/test/java/org/apache/bcel/generic/MULTIANEWARRAYTest.java
b/src/test/java/org/apache/bcel/generic/MULTIANEWARRAYTest.java
index 986f241e..dd9ad02d 100644
--- a/src/test/java/org/apache/bcel/generic/MULTIANEWARRAYTest.java
+++ b/src/test/java/org/apache/bcel/generic/MULTIANEWARRAYTest.java
@@ -20,6 +20,11 @@
package org.apache.bcel.generic;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
import org.apache.bcel.Const;
import org.apache.bcel.util.ByteSequence;
@@ -32,6 +37,20 @@ import org.junit.jupiter.api.Test;
*/
class MULTIANEWARRAYTest {
+ private static int dumpedDimensionsByte(final MULTIANEWARRAY instruction)
throws IOException {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try (DataOutputStream dos = new DataOutputStream(bos)) {
+ instruction.dump(dos);
+ }
+ // opcode, u2 index, u1 dimensions
+ return bos.toByteArray()[3] & 0xFF;
+ }
+
+ @Test
+ void testDimensionsRoundTrips() throws IOException {
+ assertEquals(Const.MAX_BYTE, dumpedDimensionsByte(new
MULTIANEWARRAY(1, (short) Const.MAX_BYTE)));
+ }
+
/**
* The {@code dimensions} operand of {@code multianewarray} is an unsigned
byte (1-255), so a value above 127 must not be read as a negative number.
*/
@@ -44,4 +63,14 @@ class MULTIANEWARRAYTest {
assertEquals(200, instruction.getDimensions());
}
}
+
+ /**
+ * The {@code dimensions} operand of {@code multianewarray} is an unsigned
byte (1-255) and {@code dump} writes it with {@code writeByte}, so the
+ * constructor must reject values above {@link Const#MAX_BYTE} instead of
truncating them.
+ */
+ @Test
+ void testRejectsDimensionsAboveU1() {
+ assertEquals(Const.MAX_BYTE, new MULTIANEWARRAY(1, (short)
Const.MAX_BYTE).getDimensions());
+ assertThrows(ClassGenException.class, () -> new MULTIANEWARRAY(1,
(short) (Const.MAX_BYTE + 1)));
+ }
}