This is an automated email from the ASF dual-hosted git repository.
ggregory 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 5cd030ea Add a sanity check in JavaClassTest
5cd030ea is described below
commit 5cd030ea7ac483fc2977318d770f78fe9974f341
Author: Gary Gregory <[email protected]>
AuthorDate: Mon Jan 19 06:54:46 2026 -0500
Add a sanity check in JavaClassTest
Extract some constants
---
.../org/apache/bcel/classfile/JavaClassTest.java | 68 ++++++++++++++++------
1 file changed, 50 insertions(+), 18 deletions(-)
diff --git a/src/test/java/org/apache/bcel/classfile/JavaClassTest.java
b/src/test/java/org/apache/bcel/classfile/JavaClassTest.java
index b1faaa22..ff76cba5 100644
--- a/src/test/java/org/apache/bcel/classfile/JavaClassTest.java
+++ b/src/test/java/org/apache/bcel/classfile/JavaClassTest.java
@@ -26,7 +26,9 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
import org.apache.bcel.Const;
import org.apache.bcel.Repository;
@@ -37,6 +39,7 @@ import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.Type;
import org.apache.bcel.util.ClassPath;
import org.apache.bcel.util.SyntheticRepository;
+import org.apache.commons.lang3.SystemProperties;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@@ -48,8 +51,11 @@ import org.junit.jupiter.params.provider.MethodSource;
*/
class JavaClassTest {
- private static final String CLASS_NAME = "TargetClass";
+ private static final String INTERFACE_NAME_A = "InterfaceA";
+
+ private static final String INTERFACE_NAME_B = "InterfaceB";
+ private static final String CLASS_NAME = "TargetClass";
// Doesn't compile due to cyclic inheritance
// private interface InterfaceA extends InterfaceB {
// }
@@ -60,14 +66,20 @@ class JavaClassTest {
@TempDir
static Path tempDir;
+ static Path tempClassFile;
+
+ static Path tempIntefaceAFile;
+
+ static Path tempIntefaceBFile;
+
@BeforeAll
static void beforeAll() throws Exception {
// Create InterfaceA that extends InterfaceB (will create cycle)
- writeInterfaceA();
+ tempIntefaceAFile = writeInterfaceA();
// Create InterfaceB that extends InterfaceA (completes the cycle)
- writeInterfaceB();
+ tempIntefaceBFile = writeInterfaceB();
// Create a class that implements InterfaceA
- writeTargetClass();
+ tempClassFile = writeTargetClass();
// Cycle: InterfaceA -> InterfaceB -> InterfaceA -> ...
}
@@ -90,23 +102,27 @@ class JavaClassTest {
return baos.toByteArray();
}
- private static void writeInterfaceA() throws Exception {
+ private static Path writeInterfaceA() throws Exception {
// Create InterfaceA that extends InterfaceB
- final ClassGen cg = new ClassGen("InterfaceA", "java.lang.Object",
"InterfaceA.java", Const.ACC_PUBLIC | Const.ACC_INTERFACE | Const.ACC_ABSTRACT,
- new String[] { "InterfaceB" });
- cg.getJavaClass().dump(tempDir.resolve("InterfaceA.class").toString());
+ final ClassGen classGen = new ClassGen(INTERFACE_NAME_A,
"java.lang.Object", INTERFACE_NAME_A + ".java",
+ Const.ACC_PUBLIC | Const.ACC_INTERFACE | Const.ACC_ABSTRACT,
new String[] { INTERFACE_NAME_B });
+ final Path path = tempDir.resolve(INTERFACE_NAME_A + ".class");
+ classGen.getJavaClass().dump(path.toString());
+ return path;
}
- private static void writeInterfaceB() throws Exception {
+ private static Path writeInterfaceB() throws Exception {
// Create InterfaceB that extends InterfaceA
- final ClassGen cg = new ClassGen("InterfaceB", "java.lang.Object",
"InterfaceB.java", Const.ACC_PUBLIC | Const.ACC_INTERFACE | Const.ACC_ABSTRACT,
- new String[] { "InterfaceA" });
- cg.getJavaClass().dump(tempDir.resolve("InterfaceB.class").toString());
+ final ClassGen classGen = new ClassGen(INTERFACE_NAME_B,
"java.lang.Object", INTERFACE_NAME_B + ".java",
+ Const.ACC_PUBLIC | Const.ACC_INTERFACE | Const.ACC_ABSTRACT,
new String[] { INTERFACE_NAME_A });
+ final Path path = tempDir.resolve(INTERFACE_NAME_B + ".class");
+ classGen.getJavaClass().dump(path.toString());
+ return path;
}
- private static void writeTargetClass() throws Exception {
+ private static Path writeTargetClass() throws Exception {
// Create a class that implements InterfaceA
- final ClassGen cg = new ClassGen(CLASS_NAME, "java.lang.Object",
"VulnerableClass.java", Const.ACC_PUBLIC, new String[] { "InterfaceA" });
+ final ClassGen cg = new ClassGen(CLASS_NAME, "java.lang.Object",
CLASS_NAME + ".java", Const.ACC_PUBLIC, new String[] { INTERFACE_NAME_A });
// Add default constructor
final InstructionList il = new InstructionList();
final MethodGen constructor = new MethodGen(Const.ACC_PUBLIC,
Type.VOID, Type.NO_ARGS, new String[] {}, "<init>", CLASS_NAME, il,
cg.getConstantPool());
@@ -119,7 +135,9 @@ class JavaClassTest {
cg.addMethod(constructor.getMethod());
il.dispose();
// Create the class file
- cg.getJavaClass().dump(tempDir.resolve(CLASS_NAME +
".class").toString());
+ final Path path = tempDir.resolve(CLASS_NAME + ".class");
+ cg.getJavaClass().dump(path.toString());
+ return path;
}
private Field findFieldDoesNotExist(final Class<?> clazz) throws
ClassNotFoundException {
@@ -149,11 +167,26 @@ class JavaClassTest {
}
@Test
- void testFindFieldCustomInterface1() throws ClassNotFoundException {
+ void testFindFieldCustomInterface1() throws IOException,
ClassNotFoundException {
// Set up repository to load classes from the malicious_classes
directory
- final String classPath = tempDir.toString() +
System.getProperty("path.separator") + System.getProperty("java.class.path");
+ final String classPath = tempDir.toString() +
SystemProperties.getPathSeparator() + SystemProperties.getJavaClassPath();
Repository.setRepository(SyntheticRepository.getInstance(new
ClassPath(classPath)));
assertThrows(ClassFormatException.class, () ->
Repository.lookupClass(CLASS_NAME).findField("nonExistentField", Type.INT));
+ // sanity check
+ final Path targetDir = Paths.get("target/test-classes");
+ final Path targetClassFile = targetDir.resolve(CLASS_NAME + ".class");
+ final Path targetInterfaceA = targetDir.resolve(INTERFACE_NAME_A +
".class");
+ final Path targetInterfaceB = targetDir.resolve(INTERFACE_NAME_B +
".class");
+ try {
+ Files.copy(tempClassFile, targetClassFile);
+ Files.copy(tempIntefaceAFile, targetInterfaceA);
+ Files.copy(tempIntefaceBFile, targetInterfaceB);
+ assertThrows(ClassCircularityError.class, () ->
Class.forName(CLASS_NAME));
+ } finally {
+ Files.delete(targetClassFile);
+ Files.delete(targetInterfaceA);
+ Files.delete(targetInterfaceB);
+ }
}
@Test
@@ -195,5 +228,4 @@ class JavaClassTest {
void testGetSuperClassesAll(final Class<?> clazz) throws
ClassNotFoundException {
assertNotNull(Repository.lookupClass(clazz.getName()).getSuperClasses());
}
-
}