Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;

import java.io.IOException;
import java.util.stream.Stream;

import org.apache.bcel.generic.ArrayInstruction;
import org.apache.bcel.generic.InstructionConst;
import org.apache.bcel.generic.Type;
import org.apache.bcel.verifier.tests.TestArrayAccess02Creator;
import org.apache.bcel.verifier.tests.TestArrayAccess03Creator;
import org.apache.bcel.verifier.tests.TestArrayAccess04DoubleCreator;
Expand All @@ -33,10 +37,49 @@
import org.apache.bcel.verifier.tests.TestArrayAccess04UnknownCreator;
import org.apache.bcel.verifier.tests.TestArrayAccess05Creator;
import org.apache.bcel.verifier.tests.TestArrayAccess06Creator;
import org.apache.bcel.verifier.tests.TestArrayAccess07Creator;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

class VerifierArrayAccessTest extends AbstractVerifierTest {

/**
* Array load and store instructions applied to an array whose component type does not match the instruction.
* {@code caload} and {@code iaload} have their own tests, {@link org.apache.bcel.verifier.tests.TestArrayAccess06Creator} and
* {@link org.apache.bcel.verifier.tests.TestArrayAccess05Creator}.
*/
static Stream<Arguments> invalidComponentTypeArrayAccess() {
return Stream.of(
// @formatter:off
Arguments.of(InstructionConst.AALOAD, Type.INT),
Arguments.of(InstructionConst.AASTORE, Type.INT),
Arguments.of(InstructionConst.BALOAD, Type.INT),
Arguments.of(InstructionConst.BASTORE, Type.INT),
Arguments.of(InstructionConst.CASTORE, Type.INT),
Arguments.of(InstructionConst.DALOAD, Type.INT),
Arguments.of(InstructionConst.DASTORE, Type.INT),
Arguments.of(InstructionConst.FALOAD, Type.INT),
Arguments.of(InstructionConst.FASTORE, Type.INT),
Arguments.of(InstructionConst.IASTORE, Type.CHAR),
Arguments.of(InstructionConst.LALOAD, Type.INT),
Arguments.of(InstructionConst.LASTORE, Type.INT),
Arguments.of(InstructionConst.SALOAD, Type.INT),
Arguments.of(InstructionConst.SASTORE, Type.INT));
// @formatter:on
}

@ParameterizedTest
@MethodSource("invalidComponentTypeArrayAccess")
void testInvalidComponentTypeArrayAccess(final ArrayInstruction arrayInstruction, final Type arrayElementType)
throws IOException, ClassNotFoundException {
final TestArrayAccess07Creator creator = new TestArrayAccess07Creator(arrayInstruction, arrayElementType);
creator.create();
assertVerifyRejected(creator.getSimpleClassName(),
"Verification of " + arrayInstruction.getName() + " applied to a " + arrayElementType + "[] must fail.");
}

@Test
void testInvalidArrayAccess() throws IOException, ClassNotFoundException {
new TestArrayAccess03Creator().create();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* 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 java.io.IOException;
import java.io.OutputStream;

import org.apache.bcel.Const;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ArrayInstruction;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionConst;
import org.apache.bcel.generic.InstructionFactory;
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 the given array load or store instruction to an array whose component type does not
* match the instruction, for example {@code castore} on an {@code int[]} or {@code laload} on an {@code int[]}.
* Structural verification must reject every such access.
*/
public class TestArrayAccess07Creator extends TestCreator {
private final InstructionFactory factory;
private final ConstantPoolGen cp;
private final ClassGen cg;
private final ArrayInstruction arrayInstruction;
private final Type arrayElementType;
private final String simpleClassName;

public TestArrayAccess07Creator(final ArrayInstruction arrayInstruction, final Type arrayElementType) {
this.arrayInstruction = arrayInstruction;
this.arrayElementType = arrayElementType;
final String name = arrayInstruction.getName();
simpleClassName = "TestArrayAccess07" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
cg = new ClassGen(TEST_PACKAGE + "." + simpleClassName, "java.lang.Object", simpleClassName + ".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 + "." + simpleClassName, 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 + "." + simpleClassName, il, cp);

il.append(new PUSH(cp, 1));
il.append(factory.createNewArray(arrayElementType, (short) 1));
il.append(new PUSH(cp, 0));
if (arrayInstruction.produceStack(cp) == 0) {
// store: push a value of the type the instruction stores, then access the mismatched array
il.append(storedValue());
il.append(arrayInstruction);
} else {
// load: access the mismatched array, then pop the loaded value
il.append(arrayInstruction);
il.append(arrayInstruction.produceStack(cp) == 2 ? InstructionConst.POP2 : InstructionConst.POP);
}
il.append(InstructionFactory.createReturn(Type.VOID));
method.setMaxStack();
method.setMaxLocals();
cg.addMethod(method.getMethod());
il.dispose();
}

@Override
protected String getClassName() {
return simpleClassName + JavaClass.EXTENSION;
}

public String getSimpleClassName() {
return simpleClassName;
}

private Instruction storedValue() {
switch (arrayInstruction.getOpcode()) {
case Const.AASTORE:
return InstructionConst.ACONST_NULL;
case Const.DASTORE:
return InstructionConst.DCONST_1;
case Const.FASTORE:
return InstructionConst.FCONST_1;
case Const.LASTORE:
return InstructionConst.LCONST_1;
default:
return InstructionConst.ICONST_1;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ private File getClassesFolder() throws IOException {
}
}

private String getClassName() {
protected String getClassName() {
final String name = getClass().getName();
return name.substring(name.lastIndexOf('.') + 1).replace("Creator", JavaClass.EXTENSION);
}
Expand Down
Loading