Skip to content

Commit 3ff2409

Browse files
committed
Replace use of ByteBuddy's ClassInjector when redefining modules to add reads
1 parent 43a25a6 commit 3ff2409

File tree

2 files changed

+74
-34
lines changed

2 files changed

+74
-34
lines changed

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/HelperInjector.java

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
package datadog.trace.agent.tooling;
22

33
import static datadog.trace.bootstrap.AgentClassLoading.INJECTING_HELPERS;
4+
import static java.util.Arrays.asList;
45

56
import datadog.trace.bootstrap.instrumentation.api.EagerHelper;
7+
import datadog.trace.util.JDK9ModuleAccess;
68
import java.io.IOException;
79
import java.lang.ref.WeakReference;
10+
import java.lang.reflect.AnnotatedElement;
811
import java.security.CodeSource;
912
import java.security.ProtectionDomain;
10-
import java.util.Arrays;
1113
import java.util.Collections;
14+
import java.util.HashSet;
1215
import java.util.LinkedHashMap;
1316
import java.util.LinkedHashSet;
1417
import java.util.List;
@@ -20,7 +23,6 @@
2023
import net.bytebuddy.dynamic.ClassFileLocator;
2124
import net.bytebuddy.dynamic.DynamicType;
2225
import net.bytebuddy.dynamic.loading.ClassInjector;
23-
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
2426
import net.bytebuddy.utility.JavaModule;
2527
import org.slf4j.Logger;
2628
import org.slf4j.LoggerFactory;
@@ -40,9 +42,9 @@ public class HelperInjector implements Instrumenter.TransformingAdvice {
4042
private final Map<String, byte[]> dynamicTypeMap = new LinkedHashMap<>();
4143

4244
private final Map<ClassLoader, Boolean> injectedClassLoaders =
43-
Collections.synchronizedMap(new WeakHashMap<ClassLoader, Boolean>());
45+
Collections.synchronizedMap(new WeakHashMap<>());
4446

45-
private final List<WeakReference<Object>> helperModules = new CopyOnWriteArrayList<>();
47+
private final List<WeakReference<AnnotatedElement>> helperModules = new CopyOnWriteArrayList<>();
4648

4749
/**
4850
* Construct HelperInjector.
@@ -71,7 +73,7 @@ public HelperInjector(
7173
this.requestingName = requestingName;
7274
this.adviceShader = adviceShader;
7375

74-
this.helperClassNames = new LinkedHashSet<>(Arrays.asList(helperClassNames));
76+
this.helperClassNames = new LinkedHashSet<>(asList(helperClassNames));
7577
}
7678

7779
public HelperInjector(
@@ -132,12 +134,10 @@ public DynamicType.Builder<?> transform(
132134
final Map<String, byte[]> classnameToBytes = getHelperMap();
133135
final Map<String, Class<?>> classes = injectClassLoader(classLoader, classnameToBytes);
134136

135-
// All datadog helper classes are in the unnamed module
136-
// And there's exactly one unnamed module per classloader
137-
// Use the module of the first class for convenience
137+
// all datadog helper classes are in the unnamed module
138+
// and there's exactly one unnamed module per classloader
138139
if (JavaModule.isSupported()) {
139-
final JavaModule javaModule = JavaModule.ofType(classes.values().iterator().next());
140-
helperModules.add(new WeakReference<>(javaModule.unwrap()));
140+
helperModules.add(new WeakReference<>(JDK9ModuleAccess.getUnnamedModule(classLoader)));
141141
}
142142

143143
// forcibly initialize any eager helpers
@@ -177,43 +177,42 @@ private Map<String, Class<?>> injectClassLoader(
177177
final ClassLoader classLoader, final Map<String, byte[]> classnameToBytes) {
178178
INJECTING_HELPERS.begin();
179179
try {
180-
ProtectionDomain protectionDomain = createProtectionDomain(classLoader);
181-
return new ClassInjector.UsingReflection(classLoader, protectionDomain)
182-
.injectRaw(classnameToBytes);
180+
if (useAgentCodeSource) {
181+
ProtectionDomain protectionDomain = createProtectionDomain(classLoader);
182+
return new ClassInjector.UsingReflection(classLoader, protectionDomain)
183+
.injectRaw(classnameToBytes);
184+
} else {
185+
return new ClassInjector.UsingReflection(classLoader).injectRaw(classnameToBytes);
186+
}
183187
} finally {
184188
INJECTING_HELPERS.end();
185189
}
186190
}
187191

188192
private ProtectionDomain createProtectionDomain(final ClassLoader classLoader) {
189-
if (useAgentCodeSource) {
190-
CodeSource codeSource = HelperInjector.class.getProtectionDomain().getCodeSource();
191-
return new ProtectionDomain(codeSource, null, classLoader, null);
192-
} else {
193-
return ClassLoadingStrategy.NO_PROTECTION_DOMAIN;
194-
}
193+
CodeSource codeSource = HelperInjector.class.getProtectionDomain().getCodeSource();
194+
return new ProtectionDomain(codeSource, null, classLoader, null);
195195
}
196196

197197
private void ensureModuleCanReadHelperModules(final JavaModule target) {
198198
if (JavaModule.isSupported() && target != JavaModule.UNSUPPORTED && target.isNamed()) {
199-
for (final WeakReference<Object> helperModuleReference : helperModules) {
200-
final Object realModule = helperModuleReference.get();
201-
if (realModule != null) {
202-
final JavaModule helperModule = JavaModule.of(realModule);
203-
204-
if (!target.canRead(helperModule)) {
205-
log.debug("Adding module read from {} to {}", target, helperModule);
206-
ClassInjector.UsingInstrumentation.redefineModule(
207-
Utils.getInstrumentation(),
208-
target,
209-
Collections.singleton(helperModule),
210-
Collections.<String, Set<JavaModule>>emptyMap(),
211-
Collections.<String, Set<JavaModule>>emptyMap(),
212-
Collections.<Class<?>>emptySet(),
213-
Collections.<Class<?>, List<Class<?>>>emptyMap());
199+
AnnotatedElement targetModule = (AnnotatedElement) target.unwrap();
200+
Set<AnnotatedElement> extraReads = null;
201+
for (final WeakReference<AnnotatedElement> helperModuleReference : helperModules) {
202+
final AnnotatedElement helperModule = helperModuleReference.get();
203+
if (helperModule != null) {
204+
if (!JDK9ModuleAccess.canRead(targetModule, helperModule)) {
205+
if (extraReads == null) {
206+
extraReads = new HashSet<>();
207+
}
208+
extraReads.add(helperModule);
214209
}
215210
}
216211
}
212+
if (extraReads != null) {
213+
log.debug("Adding module reads from {} to {}", targetModule, extraReads);
214+
JDK9ModuleAccess.addModuleReads(Utils.getInstrumentation(), targetModule, extraReads);
215+
}
217216
}
218217
}
219218
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package datadog.trace.util;
2+
3+
import static java.util.Collections.emptyMap;
4+
import static java.util.Collections.emptySet;
5+
6+
import java.lang.instrument.Instrumentation;
7+
import java.lang.reflect.AnnotatedElement;
8+
import java.util.Set;
9+
import javax.annotation.Nullable;
10+
11+
/** Use standard API to work with JPMS modules on Java9+. */
12+
@SuppressWarnings("Since15")
13+
public final class JDK9ModuleAccess {
14+
15+
/** Retrieves a class-loader's unnamed module. */
16+
public static @Nullable AnnotatedElement getUnnamedModule(ClassLoader cl) {
17+
try {
18+
return cl.getUnnamedModule();
19+
} catch (Throwable e) {
20+
return null; // not available
21+
}
22+
}
23+
24+
/** Returns {@code true} if the first module can read the second module. */
25+
public static boolean canRead(AnnotatedElement module, AnnotatedElement anotherModule) {
26+
return ((java.lang.Module) module).canRead((java.lang.Module) anotherModule);
27+
}
28+
29+
/** Adds extra module reads to the given module. */
30+
@SuppressWarnings({"rawtypes", "unchecked"})
31+
public static void addModuleReads(
32+
Instrumentation inst, AnnotatedElement module, Set<AnnotatedElement> extraReads) {
33+
inst.redefineModule(
34+
(java.lang.Module) module,
35+
(Set) extraReads,
36+
emptyMap(),
37+
emptyMap(),
38+
emptySet(),
39+
emptyMap());
40+
}
41+
}

0 commit comments

Comments
 (0)