Skip to content

Commit 03da778

Browse files
authored
Reduce unsafe usages (#14855)
1 parent d13ea9c commit 03da778

File tree

26 files changed

+277
-97
lines changed

26 files changed

+277
-97
lines changed

instrumentation/executors/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/executors/ThreadPoolExecutorTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
import io.opentelemetry.api.baggage.Baggage;
1212
import io.opentelemetry.context.Scope;
13-
import io.opentelemetry.javaagent.bootstrap.VirtualFieldInstalledMarker;
13+
import io.opentelemetry.javaagent.bootstrap.field.VirtualFieldInstalledMarker;
1414
import java.util.concurrent.CountDownLatch;
1515
import java.util.concurrent.FutureTask;
1616
import java.util.concurrent.LinkedBlockingQueue;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
plugins {
2+
id("otel.java-conventions")
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.internal.classloader.stub;
7+
8+
import java.security.ProtectionDomain;
9+
10+
/**
11+
* A placeholder for java.lang.ClassLoader to allow compilation of advice classes that invoke
12+
* protected methods of ClassLoader (like defineClass and findLoadedClass). During the build we'll
13+
* use shadow plugin to replace reference to this class with the real java.lang.ClassLoader.
14+
*/
15+
@SuppressWarnings("JavaLangClash")
16+
public abstract class ClassLoader {
17+
public abstract Class<?> findLoadedClass(String name);
18+
19+
public abstract Class<?> defineClass(
20+
String name, byte[] b, int off, int len, ProtectionDomain protectionDomain);
21+
}

instrumentation/internal/internal-class-loader/javaagent-integration-tests/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ dependencies {
66
compileOnly("org.apache.commons:commons-lang3:3.12.0")
77
testImplementation("org.apache.commons:commons-lang3:3.12.0")
88

9-
testInstrumentation(project(":instrumentation:internal:internal-class-loader:javaagent"))
9+
testInstrumentation(project(":instrumentation:internal:internal-class-loader:javaagent", configuration = "shaded"))
1010
}

instrumentation/internal/internal-class-loader/javaagent/build.gradle.kts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
2+
13
plugins {
24
id("otel.javaagent-instrumentation")
35
}
46

57
dependencies {
68
compileOnly(project(":javaagent-bootstrap"))
79
compileOnly(project(":javaagent-tooling"))
10+
compileOnly(project(":instrumentation:internal:internal-class-loader:compile-stub"))
811

912
testImplementation(project(":javaagent-bootstrap"))
1013

@@ -21,3 +24,32 @@ dependencies {
2124
testImplementation("org.eclipse.platform:org.eclipse.osgi:3.13.200")
2225
testImplementation("org.apache.felix:org.apache.felix.framework:6.0.2")
2326
}
27+
28+
val shadedJar by tasks.registering(ShadowJar::class) {
29+
from(zipTree(tasks.jar.get().archiveFile))
30+
archiveClassifier.set("shaded")
31+
}
32+
33+
tasks {
34+
withType(ShadowJar::class) {
35+
relocate("io.opentelemetry.javaagent.instrumentation.internal.classloader.stub", "java.lang")
36+
}
37+
38+
assemble {
39+
dependsOn(shadedJar)
40+
}
41+
}
42+
43+
// Create a consumable configuration for the shaded jar. We can't use the "shadow" configuration
44+
// because that is taken by the agent-testing.jar
45+
configurations {
46+
consumable("shaded") {
47+
attributes {
48+
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named("shaded"))
49+
}
50+
}
51+
}
52+
53+
artifacts {
54+
add("shaded", shadedJar)
55+
}

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,37 @@ public void transform(TypeTransformer transformer) {
5757
@SuppressWarnings("unused")
5858
public static class LoadClassAdvice {
5959

60+
// Class loader stub is shaded back to the real class loader class. It is used to call protected
61+
// method from the advice that the compiler won't let us call directly. During runtime it is
62+
// fine since this code is inlined into subclasses of ClassLoader that can call protected
63+
// methods.
6064
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
6165
public static Class<?> onEnter(
62-
@Advice.This ClassLoader classLoader, @Advice.Argument(0) String name) {
63-
return InjectedClassHelper.loadHelperClass(classLoader, name);
66+
@Advice.This java.lang.ClassLoader classLoader,
67+
@Advice.This
68+
io.opentelemetry.javaagent.instrumentation.internal.classloader.stub.ClassLoader
69+
classLoaderStub,
70+
@Advice.Argument(0) String name) {
71+
InjectedClassHelper.HelperClassInfo helperClassInfo =
72+
InjectedClassHelper.getHelperClassInfo(classLoader, name);
73+
if (helperClassInfo != null) {
74+
Class<?> clazz = classLoaderStub.findLoadedClass(name);
75+
if (clazz != null) {
76+
return clazz;
77+
}
78+
try {
79+
byte[] bytes = helperClassInfo.getClassBytes();
80+
return classLoaderStub.defineClass(
81+
name, bytes, 0, bytes.length, helperClassInfo.getProtectionDomain());
82+
} catch (LinkageError error) {
83+
clazz = classLoaderStub.findLoadedClass(name);
84+
if (clazz != null) {
85+
return clazz;
86+
}
87+
throw error;
88+
}
89+
}
90+
return null;
6491
}
6592

6693
@AssignReturned.ToReturned

instrumentation/internal/internal-lambda/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/internal/lambda/LambdaInstrumentationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import static org.assertj.core.api.Assertions.assertThat;
99

10-
import io.opentelemetry.javaagent.bootstrap.VirtualFieldInstalledMarker;
10+
import io.opentelemetry.javaagent.bootstrap.field.VirtualFieldInstalledMarker;
1111
import org.junit.jupiter.api.Test;
1212

1313
class LambdaInstrumentationTest {

instrumentation/internal/internal-reflection/javaagent-integration-tests/src/test/java/ReflectionTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
import instrumentation.TestHelperClass;
99
import io.opentelemetry.javaagent.bootstrap.InstrumentationProxy;
10-
import io.opentelemetry.javaagent.bootstrap.VirtualFieldAccessorMarker;
11-
import io.opentelemetry.javaagent.bootstrap.VirtualFieldInstalledMarker;
10+
import io.opentelemetry.javaagent.bootstrap.field.VirtualFieldAccessorMarker;
11+
import io.opentelemetry.javaagent.bootstrap.field.VirtualFieldInstalledMarker;
1212
import java.io.ObjectStreamClass;
1313
import java.io.Serializable;
1414
import java.lang.reflect.Field;

instrumentation/internal/internal-reflection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/reflection/ReflectionHelper.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
package io.opentelemetry.javaagent.instrumentation.internal.reflection;
77

88
import io.opentelemetry.javaagent.bootstrap.InstrumentationProxy;
9-
import io.opentelemetry.javaagent.bootstrap.VirtualFieldAccessorMarker;
10-
import io.opentelemetry.javaagent.bootstrap.VirtualFieldDetector;
11-
import io.opentelemetry.javaagent.bootstrap.VirtualFieldInstalledMarker;
9+
import io.opentelemetry.javaagent.bootstrap.field.VirtualFieldAccessorMarker;
10+
import io.opentelemetry.javaagent.bootstrap.field.VirtualFieldDetector;
11+
import io.opentelemetry.javaagent.bootstrap.field.VirtualFieldInstalledMarker;
1212
import java.lang.reflect.Field;
1313
import java.lang.reflect.Method;
1414
import java.util.ArrayList;

javaagent-bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/InjectedClassHelper.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
package io.opentelemetry.javaagent.bootstrap;
77

8+
import java.security.ProtectionDomain;
89
import java.util.function.BiFunction;
910
import java.util.function.BiPredicate;
1011
import java.util.function.Function;
@@ -37,21 +38,27 @@ public static boolean isHelperClass(ClassLoader classLoader, String className) {
3738
return helperClassDetector.test(classLoader, className);
3839
}
3940

40-
private static volatile BiFunction<ClassLoader, String, Class<?>> helperClassLoader;
41+
private static volatile BiFunction<ClassLoader, String, HelperClassInfo> helperClassInfo;
4142

42-
public static void internalSetHelperClassLoader(
43-
BiFunction<ClassLoader, String, Class<?>> helperClassLoader) {
44-
if (InjectedClassHelper.helperClassLoader != null) {
43+
public static void internalSetHelperClassInfo(
44+
BiFunction<ClassLoader, String, HelperClassInfo> helperClassInfo) {
45+
if (InjectedClassHelper.helperClassInfo != null) {
4546
// Only possible by misuse of this API, just ignore.
4647
return;
4748
}
48-
InjectedClassHelper.helperClassLoader = helperClassLoader;
49+
InjectedClassHelper.helperClassInfo = helperClassInfo;
4950
}
5051

51-
public static Class<?> loadHelperClass(ClassLoader classLoader, String className) {
52-
if (helperClassLoader == null) {
52+
public static HelperClassInfo getHelperClassInfo(ClassLoader classLoader, String className) {
53+
if (helperClassInfo == null) {
5354
return null;
5455
}
55-
return helperClassLoader.apply(classLoader, className);
56+
return helperClassInfo.apply(classLoader, className);
57+
}
58+
59+
public interface HelperClassInfo {
60+
byte[] getClassBytes();
61+
62+
ProtectionDomain getProtectionDomain();
5663
}
5764
}

0 commit comments

Comments
 (0)