Skip to content

Commit cb5520f

Browse files
AnneKoziolekclaude
andcommitted
Add exclusions + force-load + whitelist for interception (still blocked)
- Add interception/ and PathConstraintAPI to GaletteTransformer exclusion list to prevent Galette from adding shadow methods (signature mismatch) - Force-load InterceptionPathUtils in premain() to prevent classloader deadlock when transformed bytecode first references it - Remove single-operand jump interception (IFEQ/IFLT/etc.) — too noisy - Switch to whitelist approach: only intercept mir/ classes Finding: the second-pass transformer approach is fundamentally blocked. Even a no-op re-serialization of Galette-instrumented bytecode through ClassWriter.COMPUTE_MAXS + ClassReader.EXPAND_FRAMES produces broken class files that hang the JVM. Galette's instrumented bytecode has custom frame structures that don't survive ASM re-serialization. Next approach needed: either integrate interception into the FIRST-pass Galette transformer (so it runs before shadow methods are added), or use the GreenServer approach for out-of-process constraint solving. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 94c0a18 commit cb5520f

2 files changed

Lines changed: 24 additions & 33 deletions

File tree

galette-agent/src/main/java/edu/neu/ccs/prl/galette/internal/agent/GaletteAgent.java

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ public static void premain(String agentArgs, Instrumentation inst) throws IOExce
3434
inst.addTransformer(new TransformerWrapper());
3535
// Register comparison interception as a second-pass transformer.
3636
if (Boolean.getBoolean("galette.concolic.interception.enabled")) {
37+
// Force-load InterceptionPathUtils BEFORE registering the transformer.
38+
// Prevents classloader deadlock: when the transformer inserts INVOKESTATIC
39+
// references to InterceptionPathUtils into a class being loaded, the JVM
40+
// would try to resolve it while holding the ClassLoader lock.
41+
try {
42+
Class.forName("edu.neu.ccs.prl.galette.interception.InterceptionPathUtils");
43+
} catch (ClassNotFoundException e) {
44+
throw new RuntimeException("Failed to pre-load InterceptionPathUtils", e);
45+
}
3746
inst.addTransformer(new ComparisonInterceptionTransformer());
3847
}
3948
}
@@ -84,31 +93,24 @@ public byte[] transform(
8493
ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain pd, byte[] buf) {
8594
if (classBeingRedefined != null || className == null || isExcluded(className)) return null;
8695
try {
96+
// TEMPORARY: test if even a no-op re-parse causes the hang
8797
ClassReader cr = new ClassReader(buf);
8898
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
89-
cr.accept(new InterceptionClassVisitor(cw), ClassReader.EXPAND_FRAMES);
99+
cr.accept(cw, ClassReader.EXPAND_FRAMES); // no interception visitor - just re-serialize
90100
return cw.toByteArray();
91101
} catch (Throwable t) {
92102
return null;
93103
}
94104
}
95105

106+
/**
107+
* Whitelist approach: only intercept classes that contain the user's
108+
* comparison logic (Vitruvius-generated reaction/routine classes).
109+
* Everything else is excluded to avoid classloader deadlocks and noise.
110+
*/
96111
private static boolean isExcluded(String cn) {
97-
return cn.startsWith("java/")
98-
|| cn.startsWith("javax/")
99-
|| cn.startsWith("sun/")
100-
|| cn.startsWith("jdk/")
101-
|| cn.startsWith("com/sun/")
102-
|| cn.startsWith("edu/neu/ccs/prl/galette/internal/")
103-
|| cn.startsWith("edu/neu/ccs/prl/galette/interception/")
104-
|| cn.startsWith("edu/neu/ccs/prl/galette/concolic/")
105-
|| cn.startsWith("edu/neu/ccs/prl/galette/PathConstraintAPI")
106-
|| cn.startsWith("za/ac/sun/cs/green/")
107-
|| cn.startsWith("edu/gmu/swe/")
108-
|| cn.startsWith("org/objectweb/asm/")
109-
|| cn.startsWith("org/eclipse/")
110-
|| cn.startsWith("tools/vitruv/")
111-
|| cn.startsWith("com/google/");
112+
// Only intercept MIR-generated reaction/routine classes
113+
return !cn.startsWith("mir/");
112114
}
113115

114116
/** Inlined ClassVisitor that intercepts comparison bytecodes. */
@@ -171,23 +173,9 @@ public void visitJumpInsn(int opcode, Label label) {
171173
false);
172174
mv.visitJumpInsn(Opcodes.IFNE, label);
173175
break;
174-
case Opcodes.IFEQ:
175-
case Opcodes.IFNE:
176-
case Opcodes.IFLT:
177-
case Opcodes.IFGE:
178-
case Opcodes.IFGT:
179-
case Opcodes.IFLE:
180-
// Single-operand: push 0 and use two-operand version
181-
mv.visitInsn(Opcodes.ICONST_0);
182-
mv.visitLdcInsn(opToString(opcode));
183-
mv.visitMethodInsn(
184-
Opcodes.INVOKESTATIC,
185-
PATH_UTILS,
186-
"instrumentedIcmpJump",
187-
"(IILjava/lang/String;)Z",
188-
false);
189-
mv.visitJumpInsn(Opcodes.IFNE, label);
190-
break;
176+
// Single-operand jumps (IFEQ/IFNE/IFLT/IFGE/IFGT/IFLE) are NOT
177+
// intercepted: they are ubiquitous in bytecode (boolean checks,
178+
// null checks, loop counters) and produce massive constraint noise.
191179
default:
192180
super.visitJumpInsn(opcode, label);
193181
}

galette-agent/src/main/java/edu/neu/ccs/prl/galette/internal/transform/GaletteTransformer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ public class GaletteTransformer {
4949
// ABSOLUTE MINIMAL exclusions - as in working reference implementation
5050
"java/lang/Object",
5151
INTERNAL_PACKAGE_PREFIX,
52+
// Exclude interception runtime so Galette does not add shadow methods to it
53+
"edu/neu/ccs/prl/galette/interception/",
54+
"edu/neu/ccs/prl/galette/PathConstraintAPI",
5255
// Exclude concolic exploration framework
5356
"edu/neu/ccs/prl/galette/concolic/",
5457
// Exclude Green solver framework

0 commit comments

Comments
 (0)