byte-buddy: IllegalArgumentException: Can not set static XXX field YYY to XXX

I built a java agent with byte buddy (1.3.10), and it works pretty well for most cases. However I ran into an issue when I attached it to Intellij itself (I want to trace what happens when I use the “Run with Coverage”) and I’m having a hard time isolating the problem.

Here’s what happens:

Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at com.intellij.coverage.CoverageExecutor.<clinit>(CoverageExecutor.java) … 46 more Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at net.bytebuddy.agent.builder.Nexus.initialize(Nexus.java:95) … 51 more Caused by: java.lang.IllegalArgumentException: Can not set static agent.Interceptor field com.intellij.coverage.CoverageExecutor.delegate$1466166956 to agent.Interceptor at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167) at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171) at sun.reflect.UnsafeStaticObjectFieldAccessorImpl.set(UnsafeStaticObjectFieldAccessorImpl.java:79) at java.lang.reflect.Field.set(Field.java:764) at net.bytebuddy.implementation.LoadedTypeInitializer$ForStaticField.onLoad(LoadedTypeInitializer.java:105) at net.bytebuddy.implementation.LoadedTypeInitializer$Compound.onLoad(LoadedTypeInitializer.java:180) at net.bytebuddy.agent.builder.AgentBuilder$InitializationStrategy$SelfInjection$Dispatcher$InjectingInitializer.onLoad(AgentBuilder.java:1542) … 56 more

The code:

new AgentBuilder.Default().type(nameStartsWith("com.intellij.coverage").and(not(nameContains("auxiliary")))).transform(new AgentBuilder.Transformer() {

    public Builder<?> transform(Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader) {

        return builder.method(isDeclaredBy(typeDescription)).intercept(MethodDelegation.to(new Interceptor()));
    }
}).installOn(instrumentation);

As an aside, you’ll notice the filter I’m using on auxiliary classes. I’m probably missing something but I thought I didn’t need to do that any more (see http://stackoverflow.com/a/34946824/3408654).

I’m using an instance to intercept method calls. However the issue is gone if I use a static reference like:

return builder.method(isDeclaredBy(typeDescription)).intercept(MethodDelegation.to(Interceptor.class));

But I would rather not use a static reference.

Note that I tried to attach the agent with instance or static reference to a simple program and both versions worked. The issue only occurs when I attach it to Intellij.

Any ideas? Anything I should do to help figure out the root cause?

Thanks!

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 18 (8 by maintainers)

Most upvoted comments

You’re right. My mistake was that I renamed the packages in the source and therefore I was getting that exception when I was running my tests (where the bootstrap class loader is not used).

I solved it by renaming my packages only when I maven package my agent jar.

This is not too surprising. In order to avoid interference with a program, IntelliJ runs all of its code in a separate class loader. This separate class loader has your application classes accessible but does not load them from the system class loader (i.e. sun.misc.Launcher$AppClassLoader) but from a custom class loader that references the same jar file via a custom URL class loader (com.intellij.util.lang.UrlClassLoader).

A Java class is represented by a tuple in its loaded format that is a class name and a class loader. In this case, the instances are not equal. The instance you create is an instance of the app class loader’s class, when the IntelliJ class is instrumented, it however resolves the class to the one loaded by the IntelliJ class loader. The types are no longer equal and the exception you observe is happening.

One option would be to use a primitive for representing the interceptor type. Neither class loader can avoid loading a class from the bootstrap class loader where types are always shared. (e.g. make your “interceptor”) an instance of java.lang.function.Function.