From 17f25ec382ea9ddcaac04cd6df89484539ead4ea Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 18 Oct 2026 08:41:38 -0400 Subject: [PATCH] ```text Update ECJ versions and generate the SWAP fixture with BCEL Default ecj.version to 3.46.100. Add property-only Maven profiles selecting 3.33.0 on Java 11 and below and 3.26.0 on Java 8 and below, with the Java 8 profile taking precedence when both activate. Replace Java 1.4 compilation in VerifierMainTest with BCEL-generated bytecode containing a SWAP instruction. Current ECJ releases reject the old source level, leaving the expected class file missing. Remove the unused SWAP.java fixture. Run the verifier subprocess with the current Java runtime and prepend the temporary fixture directory to its classpath. Retain assertions for successful verification and exactly one SWAP instruction, and dispose of instruction lists after use. --- pom.xml | 25 ++++++++- src/test/java/org/apache/bcel/data/SWAP.java | 39 ------------- .../bcel/verifier/VerifierMainTest.java | 55 ++++++++++++++----- 3 files changed, 64 insertions(+), 55 deletions(-) delete mode 100644 src/test/java/org/apache/bcel/data/SWAP.java diff --git a/pom.xml b/pom.xml index ac1ac5e958..dc0f823229 100644 --- a/pom.xml +++ b/pom.xml @@ -59,9 +59,7 @@ 12314220 5.19.1 false - - - 3.26.0 + 3.46.100 true @@ -497,6 +495,27 @@ + + ecj-java-11-down + + (,12) + + + + 3.33.0 + + + + + ecj-java-8-down + + (,1.9) + + + + 3.26.0 + + spdx-java-11 diff --git a/src/test/java/org/apache/bcel/data/SWAP.java b/src/test/java/org/apache/bcel/data/SWAP.java deleted file mode 100644 index cb0ac82a73..0000000000 --- a/src/test/java/org/apache/bcel/data/SWAP.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.data; - -import java.lang.reflect.Constructor; - -/* - * A test for SWAP instruction. - * To be compiled with Eclipse Compiler (ecj) with source/target 1.4. - * This is a requirement for SWAP instruction to be generated. - * If compiled with javac source/target 1.1+ or ecj source/target 1.5+, no SWAP instruction is generated. - */ -public class SWAP { - public static Constructor getTestConstructor(final Class theClass) throws NoSuchMethodException { - final Class[] args = { String.class }; - try { - return theClass.getConstructor(args); - } catch (final NoSuchMethodException e) { - } - return theClass.getConstructor(new Class[0]); - } -} diff --git a/src/test/java/org/apache/bcel/verifier/VerifierMainTest.java b/src/test/java/org/apache/bcel/verifier/VerifierMainTest.java index e6f490b61d..a2938ad38b 100644 --- a/src/test/java/org/apache/bcel/verifier/VerifierMainTest.java +++ b/src/test/java/org/apache/bcel/verifier/VerifierMainTest.java @@ -22,24 +22,29 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.BufferedInputStream; +import java.io.File; import java.io.InputStream; -import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import org.apache.bcel.AbstractTest; +import org.apache.bcel.Const; import org.apache.bcel.classfile.ClassParser; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Method; +import org.apache.bcel.generic.ClassGen; import org.apache.bcel.generic.EmptyVisitor; +import org.apache.bcel.generic.ILOAD; +import org.apache.bcel.generic.InstructionConst; import org.apache.bcel.generic.InstructionHandle; import org.apache.bcel.generic.InstructionList; +import org.apache.bcel.generic.MethodGen; import org.apache.bcel.generic.SWAP; +import org.apache.bcel.generic.Type; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemProperties; -import org.eclipse.jdt.internal.compiler.batch.Main; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -50,16 +55,36 @@ class VerifierMainTest extends AbstractTest { @Test void testSWAP() throws Exception { - final String[] argv = { "src/test/java/org/apache/bcel/data/SWAP.java", "-g", "-source", "1.4", "-target", "1.4", "-d", tempDir.toString() }; - new Main(new PrintWriter(System.out), new PrintWriter(System.err), false/*systemExit*/, null/*options*/, null/*progress*/).compile(argv); + final String className = "org.apache.bcel.data.SWAP"; + final Path classFile = tempDir.resolve("org/apache/bcel/data/SWAP.class"); + final ClassGen classGen = new ClassGen(className, "java.lang.Object", "SWAP.java", Const.ACC_PUBLIC | Const.ACC_SUPER, null); + classGen.setMajor(Const.MAJOR_1_4); + classGen.setMinor(Const.MINOR_1_4); + classGen.addEmptyConstructor(Const.ACC_PUBLIC); + final InstructionList instructions = new InstructionList(); + try { + instructions.append(new ILOAD(0)); + instructions.append(new ILOAD(1)); + instructions.append(InstructionConst.SWAP); + instructions.append(InstructionConst.ISUB); + instructions.append(InstructionConst.IRETURN); + final MethodGen methodGen = new MethodGen(Const.ACC_PUBLIC | Const.ACC_STATIC, Type.INT, new Type[] { Type.INT, Type.INT }, + new String[] { "first", "second" }, "swap", className, instructions, classGen.getConstantPool()); + methodGen.setMaxStack(); + methodGen.setMaxLocals(); + classGen.addMethod(methodGen.getMethod()); + } finally { + instructions.dispose(); + } + classGen.getJavaClass().dump(classFile.toFile()); final String javaAgent = getJavaAgent(); final List args = new ArrayList<>(); - args.add("java"); + args.add(SystemProperties.getJavaHome() + File.separator + "bin" + File.separator + "java"); if (javaAgent != null) { args.add(javaAgent.replace("jacoco.exec", "jacoco_org.apache.bcel.data.SWAP.exec")); } args.add("-cp"); - args.add(SystemProperties.getJavaClassPath()); + args.add(tempDir + File.pathSeparator + SystemProperties.getJavaClassPath()); args.add("org.apache.bcel.verifier.Verifier"); args.add("org/apache/bcel/data/SWAP.class"); final ProcessBuilder pb = new ProcessBuilder(args); @@ -76,7 +101,7 @@ void testSWAP() throws Exception { assertEquals(0, StringUtils.countMatches(output, "VERIFIED_REJECTED"), output); assertEquals(6, StringUtils.countMatches(output, "VERIFIED_OK"), output); } - // Class has passed the JustIce verifier, but now we need to ensure that the SWAP instruction is in the compiled class. + // Class has passed the JustIce verifier, but now we need to ensure that the SWAP instruction is in the generated class. final List swapInstructionsList = new ArrayList<>(); final EmptyVisitor swapCollector = new EmptyVisitor() { @Override @@ -85,14 +110,18 @@ public void visitSWAP(final SWAP obj) { super.visitSWAP(obj); } }; - try (InputStream in = Files.newInputStream(tempDir.resolve("org/apache/bcel/data/SWAP.class"))) { + try (InputStream in = Files.newInputStream(classFile)) { final ClassParser classParser = new ClassParser(in, "SWAP.class"); final JavaClass javaClass = classParser.parse(); - final Method method = javaClass.getMethod(org.apache.bcel.data.SWAP.class.getMethod("getTestConstructor", Class.class)); - final byte[] code = method.getCode().getCode(); - final InstructionList instructionList = new InstructionList(code); - for (final InstructionHandle instructionHandle : instructionList) { - instructionHandle.accept(swapCollector); + for (final Method method : javaClass.getMethods()) { + final InstructionList instructionList = new InstructionList(method.getCode().getCode()); + try { + for (final InstructionHandle instructionHandle : instructionList) { + instructionHandle.accept(swapCollector); + } + } finally { + instructionList.dispose(); + } } } assertEquals(1, swapInstructionsList.size());