Skip to content

Commit 43a9df2

Browse files
committed
Force inlining of classloading instrumentations to prevent indy recursions
1 parent 3cfce19 commit 43a9df2

File tree

4 files changed

+105
-79
lines changed

4 files changed

+105
-79
lines changed

instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/BootDelegationInstrumentation.java

Lines changed: 25 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
package io.opentelemetry.javaagent.instrumentation.internal.classloader;
77

88
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass;
9-
import static java.util.logging.Level.WARNING;
109
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
1110
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
1211
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
@@ -17,17 +16,14 @@
1716
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
1817
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
1918

20-
import io.opentelemetry.javaagent.bootstrap.BootstrapPackagePrefixesHolder;
2119
import io.opentelemetry.javaagent.bootstrap.CallDepth;
2220
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
2321
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
24-
import io.opentelemetry.javaagent.tooling.Constants;
25-
import java.lang.invoke.MethodHandle;
26-
import java.lang.invoke.MethodHandles;
27-
import java.lang.invoke.MethodType;
28-
import java.util.List;
29-
import java.util.logging.Logger;
22+
import io.opentelemetry.javaagent.tooling.Utils;
23+
import io.opentelemetry.javaagent.tooling.bytebuddy.ExceptionHandlers;
24+
import net.bytebuddy.agent.builder.AgentBuilder;
3025
import net.bytebuddy.asm.Advice;
26+
import net.bytebuddy.description.method.MethodDescription;
3127
import net.bytebuddy.description.type.TypeDescription;
3228
import net.bytebuddy.matcher.ElementMatcher;
3329

@@ -53,48 +49,24 @@ public ElementMatcher<TypeDescription> typeMatcher() {
5349

5450
@Override
5551
public void transform(TypeTransformer transformer) {
56-
transformer.applyAdviceToMethod(
57-
isMethod()
58-
.and(named("loadClass"))
59-
.and(
60-
takesArguments(1)
61-
.and(takesArgument(0, String.class))
62-
.or(
63-
takesArguments(2)
64-
.and(takesArgument(0, String.class))
65-
.and(takesArgument(1, boolean.class))))
66-
.and(isPublic().or(isProtected()))
67-
.and(not(isStatic())),
68-
BootDelegationInstrumentation.class.getName() + "$LoadClassAdvice");
69-
}
70-
71-
public static class Holder {
72-
73-
public static final List<String> bootstrapPackagesPrefixes = findBootstrapPackagePrefixes();
74-
75-
/**
76-
* We have to make sure that {@link BootstrapPackagePrefixesHolder} is loaded from bootstrap
77-
* class loader. After that we can use in {@link LoadClassAdvice}.
78-
*/
79-
private static List<String> findBootstrapPackagePrefixes() {
80-
try {
81-
Class<?> holderClass =
82-
Class.forName(
83-
"io.opentelemetry.javaagent.bootstrap.BootstrapPackagePrefixesHolder", true, null);
84-
MethodHandle methodHandle =
85-
MethodHandles.publicLookup()
86-
.findStatic(
87-
holderClass, "getBoostrapPackagePrefixes", MethodType.methodType(List.class));
88-
//noinspection unchecked
89-
return (List<String>) methodHandle.invokeExact();
90-
} catch (Throwable e) {
91-
Logger.getLogger(Holder.class.getName())
92-
.log(WARNING, "Unable to load bootstrap package prefixes from the bootstrap CL", e);
93-
return Constants.BOOTSTRAP_PACKAGE_PREFIXES;
94-
}
95-
}
52+
ElementMatcher.Junction<MethodDescription> methodMatcher = isMethod()
53+
.and(named("loadClass"))
54+
.and(
55+
takesArguments(1)
56+
.and(takesArgument(0, String.class))
57+
.or(
58+
takesArguments(2)
59+
.and(takesArgument(0, String.class))
60+
.and(takesArgument(1, boolean.class))))
61+
.and(isPublic().or(isProtected()))
62+
.and(not(isStatic()));
9663

97-
private Holder() {}
64+
transformer.applyTransformer(
65+
new AgentBuilder.Transformer.ForAdvice()
66+
.include(Utils.getBootstrapProxy(), Utils.getAgentClassLoader())
67+
.withExceptionHandler(ExceptionHandlers.defaultExceptionHandler())
68+
.advice(methodMatcher, BootDelegationInstrumentation.class.getName() + "$LoadClassAdvice")
69+
);
9870
}
9971

10072
@SuppressWarnings("unused")
@@ -113,7 +85,7 @@ public static Class<?> onEnter(@Advice.Argument(0) String name) {
11385
}
11486

11587
try {
116-
for (String prefix : Holder.bootstrapPackagesPrefixes) {
88+
for (String prefix : BootstrapPackagesHelper.bootstrapPackagesPrefixes) {
11789
if (name.startsWith(prefix)) {
11890
try {
11991
return Class.forName(name, false, null);
@@ -134,13 +106,11 @@ public static Class<?> onEnter(@Advice.Argument(0) String name) {
134106
}
135107

136108
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
137-
@Advice.AssignReturned.ToReturned
138-
public static Class<?> onExit(
139-
@Advice.Return Class<?> result, @Advice.Enter Class<?> resultFromBootstrapLoader) {
109+
public static void onExit(
110+
@Advice.Return(readOnly = false) Class<?> result, @Advice.Enter Class<?> resultFromBootstrapLoader) {
140111
if (resultFromBootstrapLoader != null) {
141-
return resultFromBootstrapLoader;
112+
result = resultFromBootstrapLoader;
142113
}
143-
return result;
144114
}
145115
}
146116
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package io.opentelemetry.javaagent.instrumentation.internal.classloader;
2+
3+
import io.opentelemetry.javaagent.bootstrap.BootstrapPackagePrefixesHolder;
4+
import io.opentelemetry.javaagent.tooling.Constants;
5+
6+
import java.lang.invoke.MethodHandle;
7+
import java.lang.invoke.MethodHandles;
8+
import java.lang.invoke.MethodType;
9+
import java.util.List;
10+
import java.util.logging.Logger;
11+
12+
import static java.util.logging.Level.WARNING;
13+
14+
public class BootstrapPackagesHelper {
15+
16+
public static final List<String> bootstrapPackagesPrefixes = findBootstrapPackagePrefixes();
17+
18+
/**
19+
* We have to make sure that {@link BootstrapPackagePrefixesHolder} is loaded from bootstrap class
20+
* loader. After that we can use in {@link BootDelegationInstrumentation.LoadClassAdvice}.
21+
*/
22+
private static List<String> findBootstrapPackagePrefixes() {
23+
try {
24+
Class<?> holderClass =
25+
Class.forName(
26+
"io.opentelemetry.javaagent.bootstrap.BootstrapPackagePrefixesHolder", true, null);
27+
MethodHandle methodHandle =
28+
MethodHandles.publicLookup()
29+
.findStatic(
30+
holderClass, "getBoostrapPackagePrefixes", MethodType.methodType(List.class));
31+
//noinspection unchecked
32+
return (List<String>) methodHandle.invokeExact();
33+
} catch (Throwable e) {
34+
Logger.getLogger(BootstrapPackagesHelper.class.getName())
35+
.log(WARNING, "Unable to load bootstrap package prefixes from the bootstrap CL", e);
36+
return Constants.BOOTSTRAP_PACKAGE_PREFIXES;
37+
}
38+
}
39+
40+
private BootstrapPackagesHelper() {}
41+
}

instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/ClassLoaderInstrumentationModule.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@
1010
import com.google.auto.service.AutoService;
1111
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
1212
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
13+
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
1314
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
15+
import java.util.Arrays;
1416
import java.util.List;
1517

1618
@AutoService(InstrumentationModule.class)
17-
public class ClassLoaderInstrumentationModule extends InstrumentationModule {
19+
public class ClassLoaderInstrumentationModule extends InstrumentationModule implements
20+
ExperimentalInstrumentationModule {
1821
public ClassLoaderInstrumentationModule() {
1922
super("internal-class-loader");
2023
}
@@ -26,10 +29,15 @@ public boolean defaultEnabled(ConfigProperties config) {
2629
}
2730

2831
@Override
29-
public boolean isHelperClass(String className) {
30-
// TODO: this can be removed when we drop inlined-advice support
31-
// The advices can directly access this class in the AgentClassLoader with invokedynamic Advice
32-
return className.equals("io.opentelemetry.javaagent.tooling.Constants");
32+
public List<String> getAdditionalHelperClassNames() {
33+
return Arrays.asList(
34+
"io.opentelemetry.javaagent.instrumentation.internal.classloader.BootstrapPackagesHelper",
35+
"io.opentelemetry.javaagent.tooling.Constants");
36+
}
37+
38+
@Override
39+
public List<String> injectedClassNames() {
40+
return getAdditionalHelperClassNames();
3341
}
3442

3543
@Override
@@ -38,6 +46,7 @@ public List<TypeInstrumentation> typeInstrumentations() {
3846
new BootDelegationInstrumentation(),
3947
new LoadInjectedClassInstrumentation(),
4048
new ResourceInjectionInstrumentation(),
41-
new DefineClassInstrumentation());
49+
new DefineClassInstrumentation()
50+
);
4251
}
4352
}

instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/LoadInjectedClassInstrumentation.java

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
import io.opentelemetry.javaagent.bootstrap.InjectedClassHelper;
1919
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
2020
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
21+
import io.opentelemetry.javaagent.tooling.Utils;
22+
import io.opentelemetry.javaagent.tooling.bytebuddy.ExceptionHandlers;
23+
import net.bytebuddy.agent.builder.AgentBuilder;
2124
import net.bytebuddy.asm.Advice;
25+
import net.bytebuddy.description.method.MethodDescription;
2226
import net.bytebuddy.description.type.TypeDescription;
2327
import net.bytebuddy.matcher.ElementMatcher;
2428

@@ -35,19 +39,23 @@ public ElementMatcher<TypeDescription> typeMatcher() {
3539

3640
@Override
3741
public void transform(TypeTransformer transformer) {
38-
transformer.applyAdviceToMethod(
39-
isMethod()
40-
.and(named("loadClass"))
41-
.and(
42-
takesArguments(1)
43-
.and(takesArgument(0, String.class))
44-
.or(
45-
takesArguments(2)
46-
.and(takesArgument(0, String.class))
47-
.and(takesArgument(1, boolean.class))))
48-
.and(isPublic().or(isProtected()))
49-
.and(not(isStatic())),
50-
LoadInjectedClassInstrumentation.class.getName() + "$LoadClassAdvice");
42+
ElementMatcher.Junction<MethodDescription> methodMatcher = isMethod()
43+
.and(named("loadClass"))
44+
.and(
45+
takesArguments(1)
46+
.and(takesArgument(0, String.class))
47+
.or(
48+
takesArguments(2)
49+
.and(takesArgument(0, String.class))
50+
.and(takesArgument(1, boolean.class))))
51+
.and(isPublic().or(isProtected()))
52+
.and(not(isStatic()));
53+
transformer.applyTransformer(
54+
new AgentBuilder.Transformer.ForAdvice()
55+
.include(Utils.getBootstrapProxy(), Utils.getAgentClassLoader())
56+
.withExceptionHandler(ExceptionHandlers.defaultExceptionHandler())
57+
.advice(methodMatcher, LoadInjectedClassInstrumentation.class.getName() + "$LoadClassAdvice")
58+
);
5159
}
5260

5361
@SuppressWarnings("unused")
@@ -65,13 +73,11 @@ public static Class<?> onEnter(
6573
}
6674

6775
@Advice.OnMethodExit(onThrowable = Throwable.class)
68-
@Advice.AssignReturned.ToReturned
69-
public static Class<?> onExit(
70-
@Advice.Return Class<?> result, @Advice.Enter Class<?> loadedClass) {
76+
public static void onExit(
77+
@Advice.Return(readOnly = false) Class<?> result, @Advice.Enter Class<?> loadedClass) {
7178
if (loadedClass != null) {
72-
return loadedClass;
79+
result = loadedClass;
7380
}
74-
return result;
7581
}
7682
}
7783
}

0 commit comments

Comments
 (0)