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 40481fbe98..e27ac7dc6b 100644 --- a/src/main/java/org/apache/bcel/verifier/structurals/InstConstraintVisitor.java +++ b/src/main/java/org/apache/bcel/verifier/structurals/InstConstraintVisitor.java @@ -404,7 +404,10 @@ public void visitCALOAD(final CALOAD o) { final Type index = stack().peek(0); indexOfInt(o, index); - arrayrefOfArrayType(o, arrayref); + if (arrayrefOfArrayType(o, arrayref) && !((ArrayType) arrayref).getElementType().equals(Type.CHAR)) { + constraintViolated(o, "The 'arrayref' does not refer to an array with elements of type char but to an array of type " + + ((ArrayType) arrayref).getElementType() + "."); + } } /** diff --git a/src/test/java/org/apache/bcel/verifier/VerifierArrayAccessTest.java b/src/test/java/org/apache/bcel/verifier/VerifierArrayAccessTest.java index 3f96b04e6f..0cebe1319c 100644 --- a/src/test/java/org/apache/bcel/verifier/VerifierArrayAccessTest.java +++ b/src/test/java/org/apache/bcel/verifier/VerifierArrayAccessTest.java @@ -32,6 +32,7 @@ import org.apache.bcel.verifier.tests.TestArrayAccess04ShortCreator; import org.apache.bcel.verifier.tests.TestArrayAccess04UnknownCreator; import org.apache.bcel.verifier.tests.TestArrayAccess05Creator; +import org.apache.bcel.verifier.tests.TestArrayAccess06Creator; import org.junit.jupiter.api.Test; class VerifierArrayAccessTest extends AbstractVerifierTest { @@ -54,6 +55,8 @@ void testInvalidArrayAccess() throws IOException, ClassNotFoundException { assertThrowsExactly(IllegalArgumentException.class, testArrayAccess04UnknownCreator::create, "Invalid type "); new TestArrayAccess05Creator().create(); assertVerifyRejected("TestArrayAccess05", "Verification of iaload applied to a multidimensional int[][] must fail."); + new TestArrayAccess06Creator().create(); + assertVerifyRejected("TestArrayAccess06", "Verification of caload applied to an int[] must fail."); } @Test diff --git a/src/test/java/org/apache/bcel/verifier/tests/TestArrayAccess06Creator.java b/src/test/java/org/apache/bcel/verifier/tests/TestArrayAccess06Creator.java new file mode 100644 index 0000000000..587535b411 --- /dev/null +++ b/src/test/java/org/apache/bcel/verifier/tests/TestArrayAccess06Creator.java @@ -0,0 +1,91 @@ +/* + * 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 caload} to an {@code int[]} reference. The {@code caload} instruction requires a + * {@code char[]}, so applying it to an array with a different component type is illegal and structural verification must + * reject it. + */ +public class TestArrayAccess06Creator extends TestCreator { + private final InstructionFactory factory; + private final ConstantPoolGen cp; + private final ClassGen cg; + + public TestArrayAccess06Creator() { + cg = new ClassGen(TEST_PACKAGE + ".TestArrayAccess06", "java.lang.Object", "TestArrayAccess06.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[] {}, "", TEST_PACKAGE + ".TestArrayAccess06", il, cp); + il.append(InstructionFactory.createLoad(Type.OBJECT, 0)); + il.append(factory.createInvoke("java.lang.Object", "", 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 + ".TestArrayAccess06", il, cp); + + il.append(new PUSH(cp, 1)); + il.append(factory.createNewArray(Type.INT, (short) 1)); // int[] + il.append(new PUSH(cp, 0)); + il.append(InstructionConst.CALOAD); // caload 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(); + } +}