Fix class loading instrumentation

This commit is contained in:
Trask Stalnaker 2020-02-27 17:32:01 -08:00
parent 55276148b9
commit 0984ac2a61
1 changed files with 20 additions and 13 deletions

View File

@ -71,32 +71,39 @@ public final class ClassloadingInstrumentation extends Instrumenter.Default {
public static class LoadClassAdvice { public static class LoadClassAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static Class<?> onEnter( public static Class<?> onEnter(@Advice.Argument(0) final String name) {
@Advice.Argument(0) final String name, @Advice.Local("_callDepth") int callDepth) { // need to use call depth here to prevent re-entry from call to Class.forName() below
callDepth = CallDepthThreadLocalMap.incrementCallDepth(ClassLoader.class); // because on some JVMs (e.g. IBM's, though IBM bootstrap loader is explicitly excluded above)
// Class.forName() ends up calling loadClass() on the bootstrap loader which would then come
// back to this instrumentation over and over, causing a StackOverflowError
final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(ClassLoader.class);
if (callDepth > 0) { if (callDepth > 0) {
return null; return null;
} }
for (final String prefix : Constants.BOOTSTRAP_PACKAGE_PREFIXES) { try {
if (name.startsWith(prefix)) { for (final String prefix : Constants.BOOTSTRAP_PACKAGE_PREFIXES) {
try { if (name.startsWith(prefix)) {
return Class.forName(name, false, null); try {
} catch (final ClassNotFoundException e) { return Class.forName(name, false, null);
} catch (final ClassNotFoundException e) {
}
} }
} }
} finally {
// need to reset it right away, not waiting until onExit()
// otherwise it will prevent this instrumentation from being applied when loadClass()
// ends up calling a ClassFileTransformer which ends up calling loadClass() further down the
// stack on one of our bootstrap packages (since the call depth check would then suppress
// the nested loadClass instrumentation)
CallDepthThreadLocalMap.reset(ClassLoader.class);
} }
return null; return null;
} }
@Advice.OnMethodExit(onThrowable = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class)
public static void onExit( public static void onExit(
@Advice.Local("_callDepth") final int callDepth,
@Advice.Return(readOnly = false) Class<?> result, @Advice.Return(readOnly = false) Class<?> result,
@Advice.Enter final Class<?> resultFromBootstrapLoader) { @Advice.Enter final Class<?> resultFromBootstrapLoader) {
if (callDepth > 0) {
return;
}
CallDepthThreadLocalMap.reset(ClassLoader.class);
if (resultFromBootstrapLoader != null) { if (resultFromBootstrapLoader != null) {
result = resultFromBootstrapLoader; result = resultFromBootstrapLoader;
} }