Bytebuddy Java Agent: AgentBuilder affects control flow of a second, unrelated AgentBuilder - java

So I am implementing a Java Agent that installs multiple AgentBuilder, one of them only if an environment variable was defined correctly. The problem I face is that the behavior of a second AgentBuilder changes depending on whether the optional one was installed. To me it seems like installing the optional AgentBuilder affects which methods, that are instrumented by the second unrelated AgentBuilder, get called and how often.
if (EnvVar.isTrue()) {
// These methods are customs so I don't have to rewrite the whole AgentBuilder-chain...
getAgentBuilder1(inst, tempFolder).installOn(inst);
}
getAgentBuilder2(inst, tempFolder).installOn(inst);
The AgentBuilder1 uses the following type matching:
ElementMatchers.isSubTypeOf(InputStream.class)
.and(
ElementMatchers.not(
ElementMatchers.namedOneOf(InflaterInputStream.class.getName())
.or(ElementMatchers.isPrivate())
)
)
and the AgentBuilder2 this one:
ElementMatchers.namedOneOf(Class.class.getName(), ClassLoader.class.getName());
Now the transformer for AgentBuilder1 uses an Advice to print a log message when the read(...)-method of an InputStream was called, and AgentBuilder2 prints a log message when the ClassLoader.getResource(...)-method or the Class.getResource(...)-method was called.
Everything works as expected, apart from the fact that the AgentBuilder2 logs a lot more resources if AgentBuilder1 was installed than if it wasn't installed - while instrumenting the exact same program... It looks like the Class.getResource(...) method is being called much more often if AgentBuilder1 was installed. Any Ideas?

Byte Buddy invokes these methods. If you want to instrument classes that might already be loaded, you would need to use a retransformation strategy. Also, I would recommend to combine these agents in a single builder and only install it once.

Related

Make a Java class visible from any ClassLoader

I'm using a Java Agent (Agent.class) to transform a method in a program (Program.class) in a way that includes a call to the Agent class.
public Program.getMultiplier()F:
ALOAD 1
ALOAD 2
FDIV
+ INVOKESTATIC Agent.getCustomMultiplier(F)F
FRETURN
I've inspected the class loaders and their parents of both Agent and Program classes, and their hierarchy looks like this:
Agent.class: AppClassLoader <- PlatformClassLoader <- null
Program.class: URLClassLoader <- PlatformClassLoader <- null
When the Program executes the added INVOKESTATIC instruction, it throws a ClassNotFoundException -- it cannot find the Agent class as it was loaded by a different class loader.
As a temporary solution, I've tried forcing AppClassLoader to become a parent of URLClassLoader with reflection, which works in older Java versions but has been removed since Java 12.
Is there a more reliable way to make sure my Agent class is visible from any class loader?
You can add classes to the bootstrap class loader using appendToBootstrapClassLoaderSearch. This makes the classes of the specified jar file available to all classes whose defining class loader follows the standard delegation pattern.
But this requires the classes to be packaged in a jar file. When you specify the Agent’s own jar file, you have to be aware that classes loaded through the bootstrap loader are distinct from the classes loaded through the app loader, even when they originate from the same jar file. Further, the classes loaded by the bootstrap loader must not have dependencies to classes loaded by by other class loaders.
If your getCustomMultiplier method is supposed to interact with the running Agent, you have to separate the agent and the class containing this method.
Have your Agent listen to the creation of new ClassLoaders and then attach instances of them to the new ClassLoaders.
This way you preserve your "Agent listens to ClassLoader" interface, even if it now extends beyond the one platform class loader you expected the Agent to listen to.
You may be able to do something specific that works for URLClassLoader, but not all classes are loaded by an instance of URLClassLoader. Any OSGi project won't, most web servers also use their own classloaders in order to support hot reload, etc.
As far as I know there's no way to just casually update some 'global parent of all classloaders' or inject one; there's no such parent, and even if there was, a classloader is free to ignore its parent entirely.
Therefore the general answer is: No, you can't do that.
But, let's get our hacking hats on!
You're an agent already. One of the things you get to do as agent is to 'witness' classes as they are being loaded. Just invoke .addTransformer on the instance of Instrumentation you get in your agentmain and register one.
When you notice the Program class being loaded, do the following:
Take the bytecode and toss it through ASM, BCEL, Bytecode Buddy, or any other java 'class file reader/transformer' framework.
Also open up a class from within your agent's code (I wouldn't use Agent itself, I'd make a class called ProgramAddonMethods or whatnot as a container - everything inside is for the program to use / for your agent to 'inject' into that program.
Add every static member in ProgramAddonMethods directly to Program. As you do so, modify the typename on all accesses (both INVOKESTATIC and the read/write field opcodes) where the etypename is ProgramAddonMethods and make it the fully qualified name of the targeted class instead.
inject the INVOKESTATIC as you already do, but, rewrite it so that it's going to its own class, as you just copied all the static methods and fields over there.
Then return the bytecode of that modified class from your transformer.
This 100% guarantees you cannot possibly run into any module or classpath boundary issues and it will work with any classloader abstraction, guaranteed, but there are some caveats:
Just don't attempt to futz with instance anything. Make it all static methods and fields. You can make fake instance fields using an IdentityHashMap if you must (e.g. a static IdentityHashMap<Foo, String> names; is effectively identical to adding private String name; to the Foo class.. except it's a bit slower of course; presumably as you're already in a mess o reflection that's acceptable here).
Your code has to be 'dependency free'. It cannot rely on anything else, no libraries other than java.*, not even a helper class. This idea quickly runs out of steam if the job you're injecting becomes complicated. If you must, make a classloader for your own agent jar using the appropriate 'thread-safely initialize it only once' guards, and have that load in a bundle that does have the benefit of allowing dependencies.
This is all highly complicated stuff but you appear to have already worked out how to inject INVOKESTATIC calls, so, I think you know how to do this.
This is precisely what lombok does to 'patch' some methods in eclipse to ensure that things like save actions, auto-formatting, and syntax highlighting don't break - lombok injects knowledge of generated notes where appropriate and does it in this exact manner because eclipse uses a classloader platform called Equinox which makes any other solution problematic. You can look at it for inspiration or guidelines, though it's not particularly well documented. You're looking in particular at:
The lombok.eclipse.agent package in the eclipseAgent source root.
The lombok.patcher project which is lombok's only actual dependency, in particular the lombok.patcher.PatchScript.transplantMethod method.
Note that the next method may also interest you: lombok.patcher's 'insert' doesn't move the method - it injects the body of the method directly in there (it 'inlines'). This requires some serious finagling of the stack and is only advised for extremely simple one-liner-esque methods, and probably is excessive and unneccessary firepower for this problem.
DISCLAIMER: I wrote most of that.

How can i use redefineClasses() method in javaagents

I have been using premain() with addTransformer(). Since, it gives javassist.ClassNotFound exceptions for certain classes when i run the agent with a server, i thought to try the agentMain() with redefineClasses(). I went through many links, but so far i am unable to find a piece of code that gives me clear idea on how to set up a simple java agent using these two methods. Some help would be really appreciated.
Can we use redefineClasses() with premain()? (When we use redefineClasses() do we still need the transform method?)
I am trying to instrument set of methods of set of classes, where i know the fully qualified name of those classes as com.test.Foo. I wanted to instrument them without going through the entire set of classes loaded onto JVM. I have been reading those documents back and forth, but still i am unable to get a clear idea on how to use that redefineClasses method?
You can call redefineClasses from anywhere, also from a premain method which is nothing but an extension to a normal Java program run by the same JVM process previous to a main method.
A trivial example for running a redefinition is:
instrumentation.redefineClasses(new ClassDefinition(Foo.class, new byte[] {...}));
This way, Foo is set to be represented by the byte array that must contain a valid class file for Foo where all signatures of fields and methods are the same as by the loaded Foo.class. You can use a tool like ASM for instrumenting the class.
If you really only want to instrument Foo, then this might just be the way to go instead of using a ClassFileTransformer.

GetPropertyAction vs System.getProperty in obtaining system variables

I have been using quite a lot of
System.getProperty("property")
in order to obtain environmental information. However, it seems to me that Sun prefers the following :
(String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("property"));
The strange thing is that this code involves a cast and as a result should be slightly slower than the
System.getProperty
implementation, that only uses a security manager and then instantly fetches the property from the instance variable props. My question is why did Sun chose to use the second method to obtain most environmental variables in their code internally, while
System.getProperty
seems like the faster way to go?
Both methods have a different meaning, and thus the right one has to be used depending on what the current code needs to do.
The code System.getProperty("property") says "Give me the value of the property, if the current security context allows me to read it."
The code that uses doPrivileged says "Give me the value of the property, if the current class (where this line of code is in) is allowed to read it."
The difference comes into play, when the protection domain of the current class is different from the currently active security context.
For example, consider a framework which executes the code of a plugin, which is untrusted. So the framework uses a SecurityManager to restrict the actions of the untrusted plugin code. But of course the plugin may call some methods of the framework, and suppose that one of these methods needs to read a property. Now as the method is called from untrusted restricted code, it is itself restricted and thus reading the property would fail. But of course the framework trusts itself and wants itself to be able to read that property, even in the case that somewhere in the call stack is untrusted code. That's when you need to use doPrivileged. It basically says "no matter what is up there in the call stack, I am a piece of framework code, and I am allowed to do whatever the framework code is allowed to do". So reading the property using the second method succeeds.
Of course one needs to be careful when using doPrivileged in order to not let the (untrusted) calling code do to much. If, for example, the framework code offers the following method to the plugin:
public String getProp(String key) {
return (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction(key));
}
this would completely invalidate the policy that the untrusted code is not allowed to read system properties, because it can just use your method.
So use this method only when you know it is safe to do it, and only when you need it (which is, when you want your code to be able to do more than some other code should be able to do directly). Inside a normal application (which usually runs with no SecurityManager or the same security context for all code), there is no difference and the first method should be used.
I would recommend to stick with System.getProperty() since sun.security.action.GetPropertyAction seems to be proprietary to SUN and will not work on all Java VM implementations. Even the compiler warns you about it as:
warning: sun.security.action.GetPropertyAction is Sun proprietary API and may be removed in a future release
To understand what it actually means see this answer.
The reason to use a class like sun.security.action.GetPropertyAction is to avoid loading several, basically identical classes.
If you wrote:
(String) java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<java.lang.String>() {
String run() {
System.getProperty("property");
}
}
);
Each time you wanted to get a system property, you would load a new class for each getProperty call. Each class takes system resources and lives as long as the containing ClassLoader (forever for the bootclassloader).
Check out the javap output for more details:
javap -c -v -p sun.security.action.GetPropertyAction

Do I have any method to override System Properties in Java?

I am getting a practical issue and the issue can be dascribed as follows.
We are developing a component (Say a plugin) to do some task when an event is triggered within an external CMS using the API provided by them. They have provided some jar libraries, So what we are doing is implementing an Interface provided by them. Then an internal method is called when an event is triggered. (The CMS is creating only one instance of class when the first event triggers, then it just executes the method with each event trigger)
The function can be summarized as follows,
import com.external.ProvidedInterface;
public class MonitorProgram implements ProvidedInterface{
public void process(){
//This method is called when an event is triggered in CMS
}
}
Within our class we are using "javax.net.ssl.HttpsURLConnection" (JAVA 1.5). But HttpsURLConnection migrated to javax.net.ssl from com.sun.net.ssl for 1.4. But it seems the CMS I am referring to (We dont know their implementation actually) uses something like this
System.setProperty("java.protocol.handler.pkgs","com.sun.net.ssl.internal.www.protocol");
leading to a ClassCastException in our code.
I think my question is clear. In our case we cant set VM parameters,
-Djava.protocol.handler.pkgs=
Also we cant set it back using,
System.setProperty("")
because the VM instance is same for CMS and our program.
What can I do for get this problem resolved? And idea or experiences?
This is not clear for me.
Do you want to overwrite a system property?
You can do this.
Overwrite the System.property before calling the external library method and when the method returns you can set the old System.property back
final String propertyName = "Property";
String oldProperty = System.getProperty(propertyName);
System.setProperty(propertyName,"NEW_VALUE");
monitorProgram.process();
System.setProperty(propertyName,oldProperty);
Or do you want to prevent, that the called process overwrites the system.property?
And why you can not set the system property by hand?
I don't think you are going to have much success getting two pieces of code to use different properties.
In your own code however, you can define your own URLStreamHandlerFactory. Doing this will allow you to create a javax.net.ssl.HttpsURLConnection from a URL. While protocol handlers aren't the easiest thing to figure out, I think you can get them to do the job.
See http://java.sun.com/developer/onlineTraining/protocolhandlers/
Find the offending class in the stack trace
Use jad or a similar tool to decompile it.
Fix the name of the property
Compile the resulting file and either replace the .class file in the CMS's jar or put it into a place which is earlier in the classpath.
Use ant to automate this process (well, the compile and build of the JAR; not the decompiling)
When it works, make sure you save everything (original file, changed file, build file) somewhere so you can easily do it again.
While this may sound like a ridiculous or dangerous way to fix the issue, it will work. Especially since your CMS provider doesn't seem to develop his product actively.

Remove uses of certain Java classes at compile time

I am looking for a way to remove all uses of a particular class, including the class itself, at compile time. Basically a form of pre-processing, but I'd like to do it without having to surround all the instances with #ifdebug ... #endif.
Is there any ant-based tool out there that can do this? If not, can anyone point me in the right direction for how to write such a tool? (not a minor undertaking I know, but if its the only option...)
The situation is I have a helper class for debugging function calls. This is instantiated at the beginning of a function and a call is made at the end. This is a JavaME application so I'm nervous about the overhead this is adding to performance. I already have a release and debug build that have pre-processor directives using ProGuard, so I would like to exclude the use of this helper class from the release build. It doesn't appear this can be done with ProGuard.
"This is instantiated at the beginning of a function and a call is made at the end. "
If this is all over your code maybe you need to look at AOP.
or a state design pattern for the helper class, in test mode it does one thing but in prod it does another(like nothing)
Do you know that this debug code will make the JavaME app slow? You could also try creating a way to conditionally call these debug methods.
A few more ideas ... I've never written a JavaME app, but I assume there is way to run/test with running on the actual device. Given this way of running/testing, perhaps you can use Eclipse/Netbeans to debug your code and use proper breakpoints instead of programmatically tracing method calls. No harm to compiled code in this case. Also consider using AspectJ to trace method calls, this can be conditionally done after code is compiled since AspectJ alters bytecode directly (not sure how this plays with JavaME). Lastly, I've heard of people using the standard GNU C/C++ preprocessor on Java. I have no idea if it works, google will help you.
Not exactly what you want but...
You could separate your code to modules (core and debug, in your case), then make sure modules call each other via reflection: use an interface available in core, create a wrapper class in core that will hide object instantiation via reflection detail/
Then, on production, just omit the debug code and have the wrapper "do nothing" if the instantiation fail / when you set a specific flag.
This way your debug classes won't make it into production and you won't have to "statically link" to them so your core production code won't care.
Of course, this is only possible if your debug code has no side effects visible to core code, but it seems that's your case (from your problem description).
Is it possible to just create the class once, on application startup, instead of creating an instance for each method? Your debug class could then look like this:
public class Debug // maybe make this a *gasp* singleton?
{
public static void start(); // called at start of method
public static void end(); // called at end, probably should be in a finally block
public static void setDebugMode(boolean debugOn); // turn off for production mode
}
Set debug mode to "true" in testing but "false" in production. When debug mode is off, none of the methods do anything (except check the state of debug mode, of course).
You don't avoid the overhead of the function call, and you do need to check the state of that boolean, but you do get to avoid jumping through hoops trying to avoid load the class at all.
This will need more work if you have a multithreaded application, too.

Categories

Resources