Skip to content

Commit b8a6ca9

Browse files
print exceptions ocurring from within classfile transformer to stdout
1 parent f14062a commit b8a6ca9

File tree

2 files changed

+56
-69
lines changed

2 files changed

+56
-69
lines changed

luceedebug/src/main/java/luceedebug/Agent.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,12 @@ public static void premain(String argString, Instrumentation inst) throws Throwa
233233
//
234234
System.setProperty("org.osgi.framework.bootdelegation", "com.sun.jdi,com.sun.jdi.connect,com.sun.jdi.event,com.sun.jdi.request,luceedebug,luceedebug_shadow.*");
235235

236+
// touch System.out before agent is loaded, otherwise trying to print from within the agent during jvm initialization phase
237+
// can trigger stackoverflows. And note that System.out.println("") doesn't seem to work, as if printing the empty string
238+
// early returns, and skips whatever classloading we need to do.
239+
// TODO: clarify the exact failure case we are attempting to workaround here.
240+
System.out.println("[luceedebug] version " + Constants.version);
241+
236242
try (var jarFile = new JarFile(parsedArgs.jarPath)) {
237243
inst.appendToSystemClassLoaderSearch(jarFile);
238244
var classInjections = jarFile
@@ -258,14 +264,12 @@ public static void premain(String argString, Instrumentation inst) throws Throwa
258264
final var config = new Config(Config.checkIfFileSystemIsCaseSensitive(parsedArgs.jarPath));
259265
final var transformer = new LuceeTransformer(classInjections, parsedArgs.jdwpHost, parsedArgs.jdwpPort, parsedArgs.debugHost, parsedArgs.debugPort, config);
260266
inst.addTransformer(transformer);
261-
transformer.makeSystemOutPrintlnSafeForUseInTransformer();
262267
}
263268
catch (Throwable e) {
264269
e.printStackTrace();
265270
System.exit(1);
266271
}
267272

268-
System.out.println("[luceedebug] version " + Constants.version);
269273
System.out.println("[luceedebug] agent premain complete");
270274
}
271275
}

luceedebug/src/main/java/luceedebug/LuceeTransformer.java

Lines changed: 50 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -31,30 +31,6 @@ static public class ClassInjection {
3131
*/
3232
private ClassInjection[] pendingCoreLoaderClassInjections;
3333

34-
/**
35-
* this print stuff is debug related;
36-
* If you want to println at some arbitrary time very soon after initializing the transformer and registering it with the JVM,
37-
* it's possible that the classes responsible for System.out.println are being loaded when _we_ say System.out.println,
38-
* which results in cryptic ClassCircularityErrors and eventually assertion failures from JVM native code.
39-
*/
40-
private boolean systemOutPrintlnLoaded = false;
41-
private ArrayList<String> pendingPrintln = new ArrayList<>();
42-
private void println(String s) {
43-
if (!systemOutPrintlnLoaded) {
44-
pendingPrintln.add(s);
45-
}
46-
else {
47-
System.out.println(s);
48-
}
49-
}
50-
public void makeSystemOutPrintlnSafeForUseInTransformer() {
51-
System.out.print("");
52-
systemOutPrintlnLoaded = true;
53-
for (var s : pendingPrintln) {
54-
println(s);
55-
}
56-
}
57-
5834
public LuceeTransformer(
5935
ClassInjection[] injections,
6036
String jdwpHost,
@@ -78,63 +54,70 @@ public byte[] transform(ClassLoader loader,
7854
ProtectionDomain protectionDomain,
7955
byte[] classfileBuffer
8056
) throws IllegalClassFormatException {
81-
var classReader = new ClassReader(classfileBuffer);
82-
String superClass = classReader.getSuperName();
57+
try {
58+
var classReader = new ClassReader(classfileBuffer);
59+
String superClass = classReader.getSuperName();
8360

84-
if (className.equals("lucee/runtime/type/scope/ClosureScope")) {
85-
return instrumentClosureScope(classfileBuffer);
86-
}
87-
else if (className.equals("lucee/runtime/ComponentImpl")) {
88-
if (loader == null) {
89-
throw new RuntimeException("instrumention ComponentImpl but core loader not seen yet");
61+
if (className.equals("lucee/runtime/type/scope/ClosureScope")) {
62+
return instrumentClosureScope(classfileBuffer);
9063
}
91-
return instrumentComponentImpl(classfileBuffer, loader);
92-
}
93-
else if (className.equals("lucee/runtime/PageContextImpl")) {
94-
GlobalIDebugManagerHolder.luceeCoreLoader = loader;
95-
96-
try {
97-
Method m = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
98-
m.setAccessible(true);
99-
100-
for (var injection : pendingCoreLoaderClassInjections) {
101-
// warn: reflection ... when does that become unsupported?
102-
m.invoke(GlobalIDebugManagerHolder.luceeCoreLoader, injection.name, injection.bytes, 0, injection.bytes.length);
64+
else if (className.equals("lucee/runtime/ComponentImpl")) {
65+
if (loader == null) {
66+
throw new RuntimeException("instrumention ComponentImpl but core loader not seen yet");
10367
}
104-
105-
pendingCoreLoaderClassInjections = null;
68+
return instrumentComponentImpl(classfileBuffer, loader);
69+
}
70+
else if (className.equals("lucee/runtime/PageContextImpl")) {
71+
GlobalIDebugManagerHolder.luceeCoreLoader = loader;
10672

10773
try {
108-
final var klass = GlobalIDebugManagerHolder.luceeCoreLoader.loadClass("luceedebug.coreinject.DebugManager");
109-
GlobalIDebugManagerHolder.debugManager = (IDebugManager)klass.getConstructor().newInstance();
110-
111-
System.out.println("[luceedebug] Loaded " + GlobalIDebugManagerHolder.debugManager + " with ClassLoader '" + GlobalIDebugManagerHolder.debugManager.getClass().getClassLoader() + "'");
112-
GlobalIDebugManagerHolder.debugManager.spawnWorker(config, jdwpHost, jdwpPort, debugHost, debugPort);
74+
Method m = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
75+
m.setAccessible(true);
76+
77+
for (var injection : pendingCoreLoaderClassInjections) {
78+
// warn: reflection ... when does that become unsupported?
79+
m.invoke(GlobalIDebugManagerHolder.luceeCoreLoader, injection.name, injection.bytes, 0, injection.bytes.length);
80+
}
81+
82+
pendingCoreLoaderClassInjections = null;
83+
84+
try {
85+
final var klass = GlobalIDebugManagerHolder.luceeCoreLoader.loadClass("luceedebug.coreinject.DebugManager");
86+
GlobalIDebugManagerHolder.debugManager = (IDebugManager)klass.getConstructor().newInstance();
87+
88+
System.out.println("[luceedebug] Loaded " + GlobalIDebugManagerHolder.debugManager + " with ClassLoader '" + GlobalIDebugManagerHolder.debugManager.getClass().getClassLoader() + "'");
89+
GlobalIDebugManagerHolder.debugManager.spawnWorker(config, jdwpHost, jdwpPort, debugHost, debugPort);
90+
}
91+
catch (Throwable e) {
92+
e.printStackTrace();
93+
System.exit(1);
94+
}
95+
96+
return classfileBuffer;
11397
}
11498
catch (Throwable e) {
11599
e.printStackTrace();
116100
System.exit(1);
101+
return null;
117102
}
118-
119-
return classfileBuffer;
120103
}
121-
catch (Throwable e) {
122-
e.printStackTrace();
123-
System.exit(1);
124-
return null;
104+
else if (superClass.equals("lucee/runtime/ComponentPageImpl") || superClass.equals("lucee/runtime/PageImpl")) {
105+
// System.out.println("[luceedebug] Instrumenting " + className);
106+
if (GlobalIDebugManagerHolder.luceeCoreLoader == null) {
107+
System.out.println("Got class " + className + " before receiving PageContextImpl, debugging will fail.");
108+
System.exit(1);
109+
}
110+
111+
return instrumentCfmOrCfc(classfileBuffer, classReader, className);
125112
}
126-
}
127-
else if (superClass.equals("lucee/runtime/ComponentPageImpl") || superClass.equals("lucee/runtime/PageImpl")) {
128-
// System.out.println("[luceedebug] Instrumenting " + className);
129-
if (GlobalIDebugManagerHolder.luceeCoreLoader == null) {
130-
System.out.println("Got class " + className + " before receiving PageContextImpl, debugging will fail.");
131-
System.exit(1);
113+
else {
114+
return classfileBuffer;
132115
}
133-
134-
return instrumentCfmOrCfc(classfileBuffer, classReader, className);
135116
}
136-
else {
137-
return classfileBuffer;
117+
catch (Throwable e) {
118+
e.printStackTrace();
119+
System.exit(1);
120+
return null;
138121
}
139122
}
140123

0 commit comments

Comments
 (0)