Skip to content

Commit c8fac05

Browse files
committed
don't add frames to old classes
1 parent e745dd3 commit c8fac05

File tree

1 file changed

+151
-136
lines changed

1 file changed

+151
-136
lines changed

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

Lines changed: 151 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
1414
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
1515
import io.opentelemetry.javaagent.extension.instrumentation.internal.AsmApi;
16+
import net.bytebuddy.ClassFileVersion;
1617
import net.bytebuddy.asm.AsmVisitorWrapper;
1718
import net.bytebuddy.description.field.FieldDescription;
1819
import net.bytebuddy.description.field.FieldList;
@@ -72,6 +73,7 @@ public ClassVisitor wrap(
7273

7374
private static class ClassLoaderClassVisitor extends ClassVisitor implements Opcodes {
7475
private String internalClassName;
76+
private boolean frames;
7577

7678
ClassLoaderClassVisitor(ClassVisitor classVisitor) {
7779
super(AsmApi.VERSION, classVisitor);
@@ -87,160 +89,173 @@ public void visit(
8789
String[] interfaces) {
8890
super.visit(version, access, name, signature, superName, interfaces);
8991
internalClassName = name;
92+
frames = ClassFileVersion.ofMinorMajor(version).isAtLeast(ClassFileVersion.JAVA_V6);
9093
}
9194

9295
@Override
9396
public MethodVisitor visitMethod(
9497
int access, String name, String descriptor, String signature, String[] exceptions) {
9598
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
96-
if ("loadClass".equals(name)
97-
&& ("(Ljava/lang/String;)Ljava/lang/Class;".equals(descriptor)
98-
|| "(Ljava/lang/String;Z)Ljava/lang/Class;".equals(descriptor))) {
99-
100-
int argumentCount = Type.getArgumentTypes(descriptor).length;
101-
return new MethodVisitor(api, mv) {
102-
@Override
103-
public void visitCode() {
104-
super.visitCode();
105-
106-
// inserts the following at the start of the loadClass method:
107-
/*
108-
InjectedClassHelper.HelperClassInfo helperClassInfo = InjectedClassHelper.getHelperClassInfo(this, name);
109-
if (helperClassInfo != null) {
110-
Class<?> clazz = findLoadedClass(name);
111-
if (clazz != null) {
112-
return clazz;
113-
}
114-
try {
115-
byte[] bytes = helperClassInfo.getClassBytes();
116-
return defineClass(name, bytes, 0, bytes.length, helperClassInfo.getProtectionDomain());
117-
} catch (LinkageError error) {
118-
clazz = findLoadedClass(name);
119-
if (clazz != null) {
120-
return clazz;
121-
}
122-
throw error;
123-
}
124-
}
125-
*/
126-
127-
Label startTry = new Label();
128-
Label endTry = new Label();
129-
Label handler = new Label();
130-
mv.visitTryCatchBlock(startTry, endTry, handler, "java/lang/LinkageError");
131-
// InjectedClassHelper.HelperClassInfo helperClassInfo =
132-
// InjectedClassHelper.getHelperClassInfo(this, name);
133-
mv.visitVarInsn(ALOAD, 0);
134-
mv.visitVarInsn(ALOAD, 1);
135-
mv.visitMethodInsn(
136-
INVOKESTATIC,
137-
Type.getInternalName(InjectedClassHelper.class),
138-
"getHelperClassInfo",
139-
"(Ljava/lang/ClassLoader;Ljava/lang/String;)"
140-
+ Type.getDescriptor(HelperClassInfo.class),
141-
false);
142-
mv.visitVarInsn(ASTORE, argumentCount + 1); // store helperClassInfo
143-
mv.visitVarInsn(ALOAD, argumentCount + 1);
144-
Label notHelperClass = new Label();
145-
mv.visitJumpInsn(IFNULL, notHelperClass);
146-
147-
// getHelperClassInfo returned non-null
148-
// Class<?> clazz = findLoadedClass(name);
149-
mv.visitVarInsn(ALOAD, 0);
150-
mv.visitVarInsn(ALOAD, 1);
151-
mv.visitMethodInsn(
152-
INVOKEVIRTUAL,
153-
internalClassName,
154-
"findLoadedClass",
155-
"(Ljava/lang/String;)Ljava/lang/Class;",
156-
false);
157-
mv.visitVarInsn(ASTORE, argumentCount + 2); // store clazz
158-
mv.visitVarInsn(ALOAD, argumentCount + 2);
159-
mv.visitJumpInsn(IFNULL, startTry);
160-
161-
// findLoadedClass returned non-null
162-
// return clazz
163-
mv.visitVarInsn(ALOAD, argumentCount + 2);
164-
mv.visitInsn(ARETURN);
165-
166-
mv.visitLabel(startTry);
99+
boolean loadClassMethod =
100+
"loadClass".equals(name)
101+
&& ("(Ljava/lang/String;)Ljava/lang/Class;".equals(descriptor)
102+
|| "(Ljava/lang/String;Z)Ljava/lang/Class;".equals(descriptor));
103+
if (!loadClassMethod) {
104+
return mv;
105+
}
106+
107+
int argumentCount = Type.getArgumentTypes(descriptor).length;
108+
return new MethodVisitor(api, mv) {
109+
@Override
110+
public void visitCode() {
111+
super.visitCode();
112+
113+
// inserts the following at the start of the loadClass method:
114+
/*
115+
InjectedClassHelper.HelperClassInfo helperClassInfo = InjectedClassHelper.getHelperClassInfo(this, name);
116+
if (helperClassInfo != null) {
117+
Class<?> clazz = findLoadedClass(name);
118+
if (clazz != null) {
119+
return clazz;
120+
}
121+
try {
122+
byte[] bytes = helperClassInfo.getClassBytes();
123+
return defineClass(name, bytes, 0, bytes.length, helperClassInfo.getProtectionDomain());
124+
} catch (LinkageError error) {
125+
clazz = findLoadedClass(name);
126+
if (clazz != null) {
127+
return clazz;
128+
}
129+
throw error;
130+
}
131+
}
132+
*/
133+
134+
Label startTry = new Label();
135+
Label endTry = new Label();
136+
Label handler = new Label();
137+
mv.visitTryCatchBlock(startTry, endTry, handler, "java/lang/LinkageError");
138+
// InjectedClassHelper.HelperClassInfo helperClassInfo = InjectedClassHelper
139+
// .getHelperClassInfo(this, name);
140+
mv.visitVarInsn(ALOAD, 0);
141+
mv.visitVarInsn(ALOAD, 1);
142+
mv.visitMethodInsn(
143+
INVOKESTATIC,
144+
Type.getInternalName(InjectedClassHelper.class),
145+
"getHelperClassInfo",
146+
"(Ljava/lang/ClassLoader;Ljava/lang/String;)"
147+
+ Type.getDescriptor(HelperClassInfo.class),
148+
false);
149+
mv.visitVarInsn(ASTORE, argumentCount + 1); // store helperClassInfo
150+
mv.visitVarInsn(ALOAD, argumentCount + 1);
151+
Label notHelperClass = new Label();
152+
mv.visitJumpInsn(IFNULL, notHelperClass);
153+
154+
// getHelperClassInfo returned non-null
155+
// Class<?> clazz = findLoadedClass(name);
156+
mv.visitVarInsn(ALOAD, 0);
157+
mv.visitVarInsn(ALOAD, 1);
158+
mv.visitMethodInsn(
159+
INVOKEVIRTUAL,
160+
internalClassName,
161+
"findLoadedClass",
162+
"(Ljava/lang/String;)Ljava/lang/Class;",
163+
false);
164+
mv.visitVarInsn(ASTORE, argumentCount + 2); // store clazz
165+
mv.visitVarInsn(ALOAD, argumentCount + 2);
166+
mv.visitJumpInsn(IFNULL, startTry);
167+
168+
// findLoadedClass returned non-null
169+
// return clazz
170+
mv.visitVarInsn(ALOAD, argumentCount + 2);
171+
mv.visitInsn(ARETURN);
172+
173+
mv.visitLabel(startTry);
174+
if (frames) {
167175
mv.visitFrame(
168176
Opcodes.F_APPEND,
169177
2,
170178
new Object[] {Type.getInternalName(HelperClassInfo.class), "java/lang/Class"},
171179
0,
172180
null);
173-
// byte[] bytes = helperClassInfo.getClassBytes();
174-
mv.visitVarInsn(ALOAD, argumentCount + 1);
175-
mv.visitMethodInsn(
176-
INVOKEINTERFACE,
177-
Type.getInternalName(HelperClassInfo.class),
178-
"getClassBytes",
179-
"()[B",
180-
true);
181-
mv.visitVarInsn(ASTORE, argumentCount + 3); // store bytes
182-
183-
// return defineClass(name, bytes, 0, bytes.length,
184-
// helperClassInfo.getProtectionDomain());
185-
mv.visitVarInsn(ALOAD, 0);
186-
mv.visitVarInsn(ALOAD, 1);
187-
mv.visitVarInsn(ALOAD, argumentCount + 3);
188-
mv.visitInsn(ICONST_0);
189-
mv.visitVarInsn(ALOAD, argumentCount + 3);
190-
mv.visitInsn(ARRAYLENGTH);
191-
mv.visitVarInsn(ALOAD, argumentCount + 1);
192-
mv.visitMethodInsn(
193-
INVOKEINTERFACE,
194-
Type.getInternalName(HelperClassInfo.class),
195-
"getProtectionDomain",
196-
"()Ljava/security/ProtectionDomain;",
197-
true);
198-
mv.visitMethodInsn(
199-
INVOKEVIRTUAL,
200-
internalClassName,
201-
"defineClass",
202-
"(Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;",
203-
false);
204-
mv.visitLabel(endTry);
205-
mv.visitInsn(ARETURN);
206-
207-
mv.visitLabel(handler);
181+
}
182+
// byte[] bytes = helperClassInfo.getClassBytes();
183+
mv.visitVarInsn(ALOAD, argumentCount + 1);
184+
mv.visitMethodInsn(
185+
INVOKEINTERFACE,
186+
Type.getInternalName(HelperClassInfo.class),
187+
"getClassBytes",
188+
"()[B",
189+
true);
190+
mv.visitVarInsn(ASTORE, argumentCount + 3); // store bytes
191+
192+
// return defineClass(name, bytes, 0, bytes.length,
193+
// helperClassInfo.getProtectionDomain());
194+
mv.visitVarInsn(ALOAD, 0);
195+
mv.visitVarInsn(ALOAD, 1);
196+
mv.visitVarInsn(ALOAD, argumentCount + 3);
197+
mv.visitInsn(ICONST_0);
198+
mv.visitVarInsn(ALOAD, argumentCount + 3);
199+
mv.visitInsn(ARRAYLENGTH);
200+
mv.visitVarInsn(ALOAD, argumentCount + 1);
201+
mv.visitMethodInsn(
202+
INVOKEINTERFACE,
203+
Type.getInternalName(HelperClassInfo.class),
204+
"getProtectionDomain",
205+
"()Ljava/security/ProtectionDomain;",
206+
true);
207+
mv.visitMethodInsn(
208+
INVOKEVIRTUAL,
209+
internalClassName,
210+
"defineClass",
211+
"(Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;",
212+
false);
213+
mv.visitLabel(endTry);
214+
mv.visitInsn(ARETURN);
215+
216+
mv.visitLabel(handler);
217+
if (frames) {
208218
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/LinkageError"});
209-
mv.visitVarInsn(ASTORE, argumentCount + 3); // store LinkageError
210-
// clazz = findLoadedClass(name);
211-
mv.visitVarInsn(ALOAD, 0);
212-
mv.visitVarInsn(ALOAD, 1);
213-
mv.visitMethodInsn(
214-
INVOKEVIRTUAL,
215-
internalClassName,
216-
"findLoadedClass",
217-
"(Ljava/lang/String;)Ljava/lang/Class;",
218-
false);
219-
mv.visitVarInsn(ASTORE, argumentCount + 2); // score clazz
220-
mv.visitVarInsn(ALOAD, argumentCount + 2);
221-
Label throwError = new Label();
222-
mv.visitJumpInsn(IFNULL, throwError);
223-
// return clazz
224-
mv.visitVarInsn(ALOAD, argumentCount + 2);
225-
mv.visitInsn(ARETURN);
226-
mv.visitLabel(throwError);
219+
}
220+
mv.visitVarInsn(ASTORE, argumentCount + 3); // store LinkageError
221+
// clazz = findLoadedClass(name);
222+
mv.visitVarInsn(ALOAD, 0);
223+
mv.visitVarInsn(ALOAD, 1);
224+
mv.visitMethodInsn(
225+
INVOKEVIRTUAL,
226+
internalClassName,
227+
"findLoadedClass",
228+
"(Ljava/lang/String;)Ljava/lang/Class;",
229+
false);
230+
mv.visitVarInsn(ASTORE, argumentCount + 2); // score clazz
231+
mv.visitVarInsn(ALOAD, argumentCount + 2);
232+
Label throwError = new Label();
233+
mv.visitJumpInsn(IFNULL, throwError);
234+
// return clazz
235+
mv.visitVarInsn(ALOAD, argumentCount + 2);
236+
mv.visitInsn(ARETURN);
237+
mv.visitLabel(throwError);
238+
if (frames) {
227239
mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {"java/lang/LinkageError"}, 0, null);
228-
// throw error
229-
mv.visitVarInsn(ALOAD, argumentCount + 3);
230-
mv.visitInsn(ATHROW);
240+
}
241+
// throw error
242+
mv.visitVarInsn(ALOAD, argumentCount + 3);
243+
mv.visitInsn(ATHROW);
231244

232-
mv.visitLabel(notHelperClass);
245+
mv.visitLabel(notHelperClass);
246+
if (frames) {
233247
mv.visitFrame(Opcodes.F_CHOP, 3, null, 0, null);
248+
// ensure there aren't two frames at the same location
249+
mv.visitInsn(NOP);
234250
}
251+
}
235252

236-
@Override
237-
public void visitMaxs(int maxStack, int maxLocals) {
238-
// minimally we have argumentCount parameters + this + 3 locals added by us
239-
super.visitMaxs(maxStack, Math.max(maxLocals, argumentCount + 1 + 3));
240-
}
241-
};
242-
}
243-
return mv;
253+
@Override
254+
public void visitMaxs(int maxStack, int maxLocals) {
255+
// minimally we have argumentCount parameters + this + 3 locals added by us
256+
super.visitMaxs(maxStack, Math.max(maxLocals, argumentCount + 1 + 3));
257+
}
258+
};
244259
}
245260
}
246261
}

0 commit comments

Comments
 (0)