raphw/byte-buddy

Please help me check this issue. I use the inherited LaunchedURLClassLoader method in agentLauncher to load my lib package, and then inject the shared class into Bootstrap ClassLoader.

biuifuture opened this issue · 7 comments

Caused by: java.lang.ClassNotFoundException: net.bytebuddy.matcher.MethodParameterTypeMatcher
at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at com.xx.xx.xagent.loader.thirdlib.org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
at com.xx.xx.xagent.loader.AgentClassLoader.loadClass(AgentClassLoader.java:33)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)

【xagent】: 13:19:54.592 ERROR [com.xx.xx.xagent.agent.AgentListener] - transformer com.xx.xx.xagent.plugins.methodgather.BeanTest error
java.lang.NoClassDefFoundError: net/bytebuddy/matcher/MethodParameterTypeMatcher
at net.bytebuddy.matcher.ElementMatchers.hasGenericType(ElementMatchers.java:246)
at net.bytebuddy.matcher.ElementMatchers.hasType(ElementMatchers.java:235)
at net.bytebuddy.dynamic.scaffold.MethodRegistry$Default.prepare(MethodRegistry.java:476)
at net.bytebuddy.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder.toTypeWriter(RedefinitionDynamicTypeBuilder.java:203)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$UsingTypeWriter.make(DynamicType.java:4062)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:12529)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:12464)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access$1800(AgentBuilder.java:12173)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:12873)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:12811)
at java.security.AccessController.doPrivileged(Native Method)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doPrivileged(AgentBuilder.java)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:12373)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:473)
at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at com.xx.xx.xagent.plugins.methodgather.MethodGatherPluginTest.main(MethodGatherPluginTest.java:7)
Caused by: java.lang.ClassNotFoundException: net.bytebuddy.matcher.MethodParameterTypeMatcher
at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at com.xx.xx.xagent.loader.thirdlib.org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
at com.xx.xx.xagent.loader.AgentClassLoader.loadClass(AgentClassLoader.java:33)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
... 28 more

@Advice.OnMethodEnter
public static ContextInfo onEnter(@Advice.This Object self,
@Advice.Origin("#t") String className,
@Advice.Origin("#m") String method,
@Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] args) {
ContextInfo contextInfo = new ContextInfo();
Dispatcher.getAction("xxAction").onEnter(self,className,method,args,contextInfo);
return contextInfo;
}

@Advice.OnMethodExit(onThrowable = Throwable.class)
public static void onExit(@Advice.Enter ContextInfo contextInfo,
                          @Advice.This Object self,
                          @Advice.Origin("#t") String className,
                          @Advice.Origin("#m") String method,
                          @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] args,
                          @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object retValue,
                          @Advice.Thrown Throwable throwable) {
    Dispatcher.getAction("xxAction").onExit(self,className, method, args, retValue, throwable, contextInfo);
}

Is Byte Buddy on the class path from before? If so, you might have a version clash since the version used might differ from the version you are using.

【xagent】: 20:06:14.845 ERROR [com.xx.xx.xagent.agent.AgentListener] - transformer com.xx.xx.xagent.plugins.methodgather.BeanTest with classLoader sun.misc.Launcher$AppClassLoader@18b4aac2 error
java.lang.VerifyError: (class: net/bytebuddy/dynamic/scaffold/TypeWriter$Default$ForInlining$WithFullProcessing, method: writeTo signature: (Lnet/bytebuddy/jar/asm/ClassVisitor;Lnet/bytebuddy/dynamic/scaffold/TypeInitializer;Lnet/bytebuddy/dynamic/scaffold/TypeWriter$Default$ForInlining$ContextRegistry;II)Lnet/bytebuddy/jar/asm/ClassVisitor;) Incompatible argument to function

There is only one version(1.14.18) of bytebuddy in the agent

Another error was reported in the listener:

【xagent】: 20:13:44.334 ERROR [com.xx.xx.xagent.agent.AgentListener] - transformer java.util.IdentityHashMap$KeyIterator with classLoader null error
java.lang.LinkageError: loader constraint violation: when resolving method "net.bytebuddy.pool.TypePool$Default$GenericTypeExtractor$IncompleteToken$ForInnerClass.<init>(Ljava/lang/String;Lnet/bytebuddy/pool/TypePool$Default$GenericTypeExtractor$IncompleteToken;)V" the class loader (instance of com/jdh/xfyl/xagent/loader/AgentClassLoader) of the current class, net/bytebuddy/pool/TypePool$Default$GenericTypeExtractor, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for the method's defining class, net/bytebuddy/pool/TypePool$Default$GenericTypeExtractor$IncompleteToken$ForInnerClass, have different Class objects for the type net/bytebuddy/pool/TypePool$Default$GenericTypeExtractor$IncompleteToken used in the signature
	at net.bytebuddy.pool.TypePool$Default$GenericTypeExtractor.visitInnerClassType(TypePool.java:1878)

This is how it is configured in my agentBuilder

AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, module, protectionDomain) -> {
                addUserClassLoader(agentClassLoader,classLoader);
                return builder.visit(
                        Advice.to(transformerDefinition.getAgentAdvice().getClass()).on(transformerDefinition.getMethodMather())
                );
            };
            new AgentBuilder.Default()
                    .with(new AgentListener())
                    .with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
                    .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
                    .with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.with(AgentBuilder.LocationStrategy.ForClassLoader.STRONG.withFallbackTo(ClassFileLocator.ForClassLoader.ofBootLoader()))
                    .ignore(ElementMatchers.isSynthetic())
                    .or(ElementMatchers.nameStartsWith("sun."))
                    .or(ElementMatchers.nameStartsWith("com.sun."))
                    .or(ElementMatchers.nameStartsWith("brave."))
                    .or(ElementMatchers.nameStartsWith("zipkin2."))
                    .or(ElementMatchers.nameStartsWith("com.fasterxml"))
                    .or(ElementMatchers.nameStartsWith("org.apache.logging"))
                    .or(ElementMatchers.nameStartsWith("kotlin."))
                    .or(ElementMatchers.nameStartsWith("javax."))
                    .or(ElementMatchers.nameStartsWith("net.bytebuddy."))
                    .or(ElementMatchers.nameStartsWith("com\\.sun\\.proxy\\.\\$Proxy.+"))
                    .or(ElementMatchers.nameStartsWith("java\\.lang\\.invoke\\.BoundMethodHandle\\$Species_L.+"))
                    .or(ElementMatchers.nameStartsWith("org.junit."))
                    .or(ElementMatchers.nameStartsWith("junit."))
                    .or(ElementMatchers.nameStartsWith("java.util."))
                    .or(ElementMatchers.nameStartsWith("com.intellij."))
                    .type(transformerDefinition.getClassMather())
                    .transform(transformer)
                    .installOn(instrumentation);

I seem to have found the root cause. In the agent's premise, I used LaunchedURLClassLoader to load bytebuddy, but I don't know why it was loaded by AppClassLoader。

public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception {
        JarFileArchive archive = new JarFileArchive(getArchiveFileContains());
        URL[] urls = nestArchiveUrls(archive);
        ClassLoader agentClassLoader = new AgentClassLoader(urls);
        loadAgent(agentClassLoader,() -> {
            agentClassLoader.loadClass(AGENT_CLASS)
                    .getDeclaredMethod(AGENT_METHOD, String.class, Instrumentation.class)
                    .invoke(null, agentArgs, instrumentation);
            return null;
        });
    }

This is the jar directory structure I built

image