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)));
+    }
 }

Reply via email to