Reputation: 41
I have been trying to use a Java agent to apply a bytecode transformation with ASM.
I implemented an Agent with the premain
method adding a transformer to the Instrumentation.
I added the "Premain-Class" line in the .jar manifest
Premain-Class: <MyAgentPath>
Then I tried to run the application with the agent.
There I have a problem : my transformer modifies some method calls, so if not all involved classes are modified too, it cannot work. And there are some classes which are not modified, like "org.apache.commons.math3.util.FastMath". Of course then, I got the error :
java.lang.NoSuchMethodError: org.apache.commons.math3.util.FastMath.floor<new_descriptor>
I checked a lot of posts saying it could be the bootstrap loader which does not know the path to this class so I tried to add it using different ways :
Adding the "Boot-Class-Path" line to the manifest :
Boot-Class-Path: <...>/commons-math3<...>.jar
Using the method "appendToBootstrapClassLoaderSearch(JarFile)"
inst.appendToBootstrapClassLoaderSearch("<...>/commons-math3<...>.jar");
Using the JVM argument "-Xbootclasspath/a:"
-Xbootclasspath/a:<...>/commons-math3<...>.jar
None of this changed anything.
I also used the Instrumentation class method getAllLoadedClasses()
to see which ones were loaded, and all classes involved in the application process where loaded, including FastMath.
for(Class<?> clazz : MyAgent.getInstInstance().getAllLoadedClasses()){
buffWrite.write(clazz.getName());
As the class "FastMath" gave an error and as the Bootstrap Loader should have its path, I tried adding some method calls to methods from other classes in the same package. It appears the problem does not show for every class of the package.
For example: MathUtils
is transformed and a call to the modified method checkFinite(D)V
-> checkFinite<new_descriptor>
.
So I guess the problem has nothing to do with the paths given to the bootstrap loader.
If you have some ideas about what is happening, I would be glad to hear about it!
Upvotes: 4
Views: 1275
Reputation: 44042
A NoSuchMethodError
is most likely not caused by not adding something to the bootstrap class loader. The only chance that this could be a problem would be if there were suddenly two such jars available where one was instrumented and the other was not.
If you call change a method checkFinite(D)V
to become another method checkFinite<new_descriptor>
, then you need to make sure that any class using FastMath.floor
updates the descriptor to this method. This means that you need to walk through every method of every class looking for visitMethodIns
calls of ASM. It seems like you are missing some. Since you are changing the layout of the FastMath
class, you must instrument it while loading it for the first time and you cannot redefine it.
The Java internal classes do not know of FastMath
as this is a third-party dependency. Therefore, it should be possible to instrument any call from your agent. It seems to me like you are loading FastMath
prematurely.
Upvotes: 2