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 2aef1be6 use array element type not basic type for primitive array
access (#520)
2aef1be6 is described below
commit 2aef1be6546ed79cae003dfc0eefd864c211be80
Author: Naveed Khan <[email protected]>
AuthorDate: Sun Jul 12 02:03:01 2026 +0000
use array element type not basic type for primitive array access (#520)
getBasicType() drops the dimension count, so iaload on int[][] passed
structural verification even though its component type is a reference; the ten
primitive *aload/*astore constraints in InstConstraintVisitor now use
getElementType() like the reference and byte/char siblings.
---
.../structurals/InstConstraintVisitor.java | 20 ++---
.../bcel/verifier/VerifierArrayAccessTest.java | 3 +
.../verifier/tests/TestArrayAccess05Creator.java | 92 ++++++++++++++++++++++
3 files changed, 105 insertions(+), 10 deletions(-)
diff --git
a/src/main/java/org/apache/bcel/verifier/structurals/InstConstraintVisitor.java
b/src/main/java/org/apache/bcel/verifier/structurals/InstConstraintVisitor.java
index 34c7f19a..40481fbe 100644
---
a/src/main/java/org/apache/bcel/verifier/structurals/InstConstraintVisitor.java
+++
b/src/main/java/org/apache/bcel/verifier/structurals/InstConstraintVisitor.java
@@ -518,7 +518,7 @@ public class InstConstraintVisitor extends EmptyVisitor {
if (!(stack().peek(1) instanceof ArrayType)) {
constraintViolated(o, "Stack next-to-top must be of type double[]
but is '" + stack().peek(1) + "'.");
}
- final Type t = ((ArrayType) stack().peek(1)).getBasicType();
+ final Type t = ((ArrayType) stack().peek(1)).getElementType();
if (t != Type.DOUBLE) {
constraintViolated(o, "Stack next-to-top must be of type double[]
but is '" + stack().peek(1) + "'.");
}
@@ -539,7 +539,7 @@ public class InstConstraintVisitor extends EmptyVisitor {
if (!(stack().peek(2) instanceof ArrayType)) {
constraintViolated(o, "Stack next-to-next-to-top must be of type
double[] but is '" + stack().peek(2) + "'.");
}
- final Type t = ((ArrayType) stack().peek(2)).getBasicType();
+ final Type t = ((ArrayType) stack().peek(2)).getElementType();
if (t != Type.DOUBLE) {
constraintViolated(o, "Stack next-to-next-to-top must be of type
double[] but is '" + stack().peek(2) + "'.");
}
@@ -825,7 +825,7 @@ public class InstConstraintVisitor extends EmptyVisitor {
if (!(stack().peek(1) instanceof ArrayType)) {
constraintViolated(o, "Stack next-to-top must be of type float[]
but is '" + stack().peek(1) + "'.");
}
- final Type t = ((ArrayType) stack().peek(1)).getBasicType();
+ final Type t = ((ArrayType) stack().peek(1)).getElementType();
if (t != Type.FLOAT) {
constraintViolated(o, "Stack next-to-top must be of type float[]
but is '" + stack().peek(1) + "'.");
}
@@ -846,7 +846,7 @@ public class InstConstraintVisitor extends EmptyVisitor {
if (!(stack().peek(2) instanceof ArrayType)) {
constraintViolated(o, "Stack next-to-next-to-top must be of type
float[] but is '" + stack().peek(2) + "'.");
}
- final Type t = ((ArrayType) stack().peek(2)).getBasicType();
+ final Type t = ((ArrayType) stack().peek(2)).getElementType();
if (t != Type.FLOAT) {
constraintViolated(o, "Stack next-to-next-to-top must be of type
float[] but is '" + stack().peek(2) + "'.");
}
@@ -1199,7 +1199,7 @@ public class InstConstraintVisitor extends EmptyVisitor {
if (!(stack().peek(1) instanceof ArrayType)) {
constraintViolated(o, "Stack next-to-top must be of type int[] but
is '" + stack().peek(1) + "'.");
}
- final Type t = ((ArrayType) stack().peek(1)).getBasicType();
+ final Type t = ((ArrayType) stack().peek(1)).getElementType();
if (t != Type.INT) {
constraintViolated(o, "Stack next-to-top must be of type int[] but
is '" + stack().peek(1) + "'.");
}
@@ -1233,7 +1233,7 @@ public class InstConstraintVisitor extends EmptyVisitor {
if (!(stack().peek(2) instanceof ArrayType)) {
constraintViolated(o, "Stack next-to-next-to-top must be of type
int[] but is '" + stack().peek(2) + "'.");
}
- final Type t = ((ArrayType) stack().peek(2)).getBasicType();
+ final Type t = ((ArrayType) stack().peek(2)).getElementType();
if (t != Type.INT) {
constraintViolated(o, "Stack next-to-next-to-top must be of type
int[] but is '" + stack().peek(2) + "'.");
}
@@ -1970,7 +1970,7 @@ public class InstConstraintVisitor extends EmptyVisitor {
if (!(stack().peek(1) instanceof ArrayType)) {
constraintViolated(o, "Stack next-to-top must be of type long[]
but is '" + stack().peek(1) + "'.");
}
- final Type t = ((ArrayType) stack().peek(1)).getBasicType();
+ final Type t = ((ArrayType) stack().peek(1)).getElementType();
if (t != Type.LONG) {
constraintViolated(o, "Stack next-to-top must be of type long[]
but is '" + stack().peek(1) + "'.");
}
@@ -2004,7 +2004,7 @@ public class InstConstraintVisitor extends EmptyVisitor {
if (!(stack().peek(2) instanceof ArrayType)) {
constraintViolated(o, "Stack next-to-next-to-top must be of type
long[] but is '" + stack().peek(2) + "'.");
}
- final Type t = ((ArrayType) stack().peek(2)).getBasicType();
+ final Type t = ((ArrayType) stack().peek(2)).getElementType();
if (t != Type.LONG) {
constraintViolated(o, "Stack next-to-next-to-top must be of type
long[] but is '" + stack().peek(2) + "'.");
}
@@ -2552,7 +2552,7 @@ public class InstConstraintVisitor extends EmptyVisitor {
if (!(stack().peek(1) instanceof ArrayType)) {
constraintViolated(o, "Stack next-to-top must be of type short[]
but is '" + stack().peek(1) + "'.");
}
- final Type t = ((ArrayType) stack().peek(1)).getBasicType();
+ final Type t = ((ArrayType) stack().peek(1)).getElementType();
if (t != Type.SHORT) {
constraintViolated(o, "Stack next-to-top must be of type short[]
but is '" + stack().peek(1) + "'.");
}
@@ -2573,7 +2573,7 @@ public class InstConstraintVisitor extends EmptyVisitor {
if (!(stack().peek(2) instanceof ArrayType)) {
constraintViolated(o, "Stack next-to-next-to-top must be of type
short[] but is '" + stack().peek(2) + "'.");
}
- final Type t = ((ArrayType) stack().peek(2)).getBasicType();
+ final Type t = ((ArrayType) stack().peek(2)).getElementType();
if (t != Type.SHORT) {
constraintViolated(o, "Stack next-to-next-to-top must be of type
short[] but is '" + stack().peek(2) + "'.");
}
diff --git
a/src/test/java/org/apache/bcel/verifier/VerifierArrayAccessTest.java
b/src/test/java/org/apache/bcel/verifier/VerifierArrayAccessTest.java
index d44bc9d9..3f96b04e 100644
--- a/src/test/java/org/apache/bcel/verifier/VerifierArrayAccessTest.java
+++ b/src/test/java/org/apache/bcel/verifier/VerifierArrayAccessTest.java
@@ -31,6 +31,7 @@ import
org.apache.bcel.verifier.tests.TestArrayAccess04IntCreator;
import org.apache.bcel.verifier.tests.TestArrayAccess04LongCreator;
import org.apache.bcel.verifier.tests.TestArrayAccess04ShortCreator;
import org.apache.bcel.verifier.tests.TestArrayAccess04UnknownCreator;
+import org.apache.bcel.verifier.tests.TestArrayAccess05Creator;
import org.junit.jupiter.api.Test;
class VerifierArrayAccessTest extends AbstractVerifierTest {
@@ -51,6 +52,8 @@ class VerifierArrayAccessTest extends AbstractVerifierTest {
assertVerifyRejected("TestArrayAccess04Short", "Verification of an
arraystore instruction of a short on an array of references must fail.");
final TestArrayAccess04UnknownCreator testArrayAccess04UnknownCreator
= new TestArrayAccess04UnknownCreator();
assertThrowsExactly(IllegalArgumentException.class,
testArrayAccess04UnknownCreator::create, "Invalid type <unknown object>");
+ new TestArrayAccess05Creator().create();
+ assertVerifyRejected("TestArrayAccess05", "Verification of iaload
applied to a multidimensional int[][] must fail.");
}
@Test
diff --git
a/src/test/java/org/apache/bcel/verifier/tests/TestArrayAccess05Creator.java
b/src/test/java/org/apache/bcel/verifier/tests/TestArrayAccess05Creator.java
new file mode 100644
index 00000000..bd01b83f
--- /dev/null
+++ b/src/test/java/org/apache/bcel/verifier/tests/TestArrayAccess05Creator.java
@@ -0,0 +1,92 @@
+/*
+ * 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.verifier.tests;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.bcel.Const;
+import org.apache.bcel.generic.ClassGen;
+import org.apache.bcel.generic.ConstantPoolGen;
+import org.apache.bcel.generic.InstructionConst;
+import org.apache.bcel.generic.InstructionFactory;
+import org.apache.bcel.generic.InstructionHandle;
+import org.apache.bcel.generic.InstructionList;
+import org.apache.bcel.generic.MethodGen;
+import org.apache.bcel.generic.PUSH;
+import org.apache.bcel.generic.Type;
+
+/**
+ * Emits a method that applies {@code iaload} directly to an {@code int[][]}
reference, that is, without first indexing
+ * into the outer dimension. The component type of {@code int[][]} is {@code
int[]} (a reference), so {@code iaload} is
+ * illegal and structural verification must reject it.
+ */
+public class TestArrayAccess05Creator extends TestCreator {
+ private final InstructionFactory factory;
+ private final ConstantPoolGen cp;
+ private final ClassGen cg;
+
+ public TestArrayAccess05Creator() {
+ cg = new ClassGen(TEST_PACKAGE + ".TestArrayAccess05",
"java.lang.Object", "TestArrayAccess05.java", Const.ACC_PUBLIC |
Const.ACC_SUPER,
+ new String[] {});
+ cp = cg.getConstantPool();
+ factory = new InstructionFactory(cg, cp);
+ }
+
+ @Override
+ public void create(final OutputStream out) throws IOException {
+ createMethod_0();
+ createMethod_1();
+ cg.getJavaClass().dump(out);
+ }
+
+ private void createMethod_0() {
+ final InstructionList il = new InstructionList();
+ final MethodGen method = new MethodGen(Const.ACC_PUBLIC, Type.VOID,
Type.NO_ARGS, new String[] {}, "<init>", TEST_PACKAGE + ".TestArrayAccess05",
il, cp);
+ il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
+ il.append(factory.createInvoke("java.lang.Object", "<init>",
Type.VOID, Type.NO_ARGS, Const.INVOKESPECIAL));
+ il.append(InstructionFactory.createReturn(Type.VOID));
+ method.setMaxStack();
+ method.setMaxLocals();
+ cg.addMethod(method.getMethod());
+ il.dispose();
+ }
+
+ private void createMethod_1() {
+ final InstructionList il = new InstructionList();
+ final MethodGen method = new MethodGen(Const.ACC_PUBLIC |
Const.ACC_STATIC, Type.VOID, Type.NO_ARGS, new String[] {}, "test",
+ TEST_PACKAGE + ".TestArrayAccess05", il, cp);
+
+ il.append(new PUSH(cp, 1));
+ il.append(new PUSH(cp, 1));
+ il.append(factory.createNewArray(Type.INT, (short) 2)); // int[][]
+ il.append(new PUSH(cp, 0));
+ il.append(InstructionConst.IALOAD); // iaload on int[][] is illegal
+ il.append(InstructionConst.POP);
+ final InstructionHandle ihReturn =
il.append(InstructionFactory.createReturn(Type.VOID));
+ assertNotNull(ihReturn);
+ method.setMaxStack();
+ method.setMaxLocals();
+ cg.addMethod(method.getMethod());
+ il.dispose();
+ }
+}