Bytecode instrumentation system classes in Java with ASM - java

My javaagent, run via -javagent, instruments classes with callbacks to static methods on one of my classes. This works great, apart from on system classes, e.g. java/lang, java/util, which throw ClassDefNotFounderror at the point when the method is called (with INVOKESTATIC). So it appears they are instrumented, because the method call is attempted, but have an access or visibility issue that my user classes don't have. My callback class and its methods are all public.
I've tried adding my class to the classpath (instead of just loading via -javaagent) but that didn't help. Is there some protection of system classes I need to override?

It sounds like you're explicitly looking for classes to instrument. Why aren't you using java.lang.instrument to intercept classes that are being loaded when the target JVM executes? See this example
Can you paste your code, or the relevant parts?

Related

What is Causing a Java Class to be Loaded?

I am trying to open a Java class file, instrument the bytecode and save the class file before the class is loaded into the JVM. My problem is that a class is being loaded "too soon" into the JVM. The bytecode is instrumented after the class is loaded into the JVM.
-verbose:class prints when each class is loaded but it doesn't tell me what triggered the JVM to load the class. How do I get a call stack which shows the class being loaded?
Putting a breakpoint in the following code, shows the call stack when the class is initialized and not loaded.
static
{
System.out.println("Initialized!");
}
Note: I know I could use a Java agent to do this and guarantee the bytecode is instrumented. But, I choose this route for various reasons.
I opened java.lang.ClassLoader and set a conditional breakpoint in loadClass(String name, boolean resolve). The condition is arg0.endsWith("MyClass") where arg0 is the name parameter. When the breakpoint is triggered, the IDE displays the call stack. Several frames down on the call stack shows me why the class is being loaded.
Note: This condition works in Eclipse IDE and may need a little tweaking in other IDEs.
On the Hotspot JVM, which is what is used with the the Oracle and OpenJDK java distributions, classes are loaded when they are first referenced. Here are the relevant snippets from https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html
The Java Virtual Machine starts up by creating an initial class, which is specified in an implementation-dependent manner, using the bootstrap class loader (§5.3.1). The Java Virtual Machine then links the initial class, initializes it, and invokes the public class method void main(String[]). The invocation of this method drives all further execution. Execution of the Java Virtual Machine instructions constituting the main method may cause linking (and consequently creation) of additional classes and interfaces, as well as invocation of additional methods.
Creation of a class or interface C denoted by the name N consists of the construction in the method area of the Java Virtual Machine (§2.5.4) of an implementation-specific internal representation of C. Class or interface creation is triggered by another class or interface D, which references C through its run-time constant pool. Class or interface creation may also be triggered by D invoking methods in certain Java SE platform class libraries (§2.12) such as reflection.
If you wish to actually perform the bytecode manipulation yourself, and at runtime, then there are at least two models that you may choose to follow
Use something akin to AspectJ's load time weaving, which involves using a separate classloader and an agent to respond to class loading
How JRebel does it, via monitoring known .class files for updated timestamps http://zeroturnaround.com/software/jrebel/learn/faq/
Unless you have a very strong need to do this yourself however, consider using one of the above mentioned tools. Better yet, determine if Java annotations and reflection can solve what you are attempting to do instead.

How to scan for a particular annotation of java classes loaded at runtime as a bytecode?

If a java class loaded at runtime as a bytecode (e.g. via ASM library or other mechanism), is it on a classpath of java? I don't see it.
How to scan all annotations of classes loaded this way, if it's not on the java classpath?
I use google reflections and a custom classloader of a 3-rd party library.
Scanning for classes works as follows:
Reflections reflections = new Reflections(ClasspathHelper.forPackage("com.mypackage",
MyCustomClassLoader),
new SubTypesScanner(), new TypeAnnotationsScanner());
Set<Class<?>> myClasses = reflections.getTypesAnnotatedWith(MyAnnotation.class);
MyAnnotation - is marked as #Retention(RetentionPolicy.RUNTIME).
The above (in a class) is loaded dynamically at runtime by JVM.
As can be seen, behind the scenes, Reflections tries to get all URLs to be scanned using 2 classloaders by default static and context.
Reflection.scan()
Update: I have found an answer Can you find all classes in a package using reflection? saying that "If there are classes that get generated, or delivered remotely, you will not be able to discover those classes." But there is no proof, however.
Can please anybody give more details on this and confirm?
Dynamically instantiating classes at run time does not change the classpath that your JVM is using. What happens is that some ClassLoader class fetches bytecode from somewhere; and makes it "available" to you. But that does in no way change the "search order" for loading classes (and that is basically what the classpath is about: it only tells the JVM where and in which order to look for classes to load).
Meaning: any "loading" of a class results in some object of class java.lang.Class.
If you want to query the structure of any loaded class; you "just" need to get to the corresponding Class object. Class provides methods like getAnnotation(). It also provides methods to retrieve other objects that represent the methods and fields of the specific Class; and those objects can be queried for annotations in similar ways.
Update, regarding the updates in the question: there are situations where you don't have access to the file system where classes are coming from. You can load classes, when you know their name, but you have no way looking into the "place" where these classes live. And that basically breaks your ability to use reflection as intended.
There is no need to "prove" that, it is simply a consequence of the fact that Java allows you to load classes when you know there name, but "hides" the exact content of "where" those classes are coming from.

Is it possible to redefine core JDK classes using instrumentation?

I want to redefine the bytecode of the StackOverflowError constructor so I have a "hook" for when a stack overflow occurs. All I want to do is insert a single method call to a static method of my choosing at the start of the constructor. Is it possible to do this?
You should be able to do it using one of two ways (unless something changed in the last 1-2 years, in which case I'd love some links to changelogs/docs):
Mentioned in a comment, not very feasible I guess, modify the classes you are interested in, put them in a jar and then use the -bootclasspath option to load them instead of the default ones. As was mentioned before this can have some legal issues (and is a pain to do in general).
You should be able to (or at least you used to be able to) instrument almost all core classes (iirc Class was the only exception I've seen). One of many problems you might have is the fact that many of core classes are being initialized before the agents you provide (or well their premain methods to be exact) are consulted. To overcome this you will have to add Can-Retransform-Classes property to your agent jar and then re-transform the classes you are interested in. Be aware that re-transformation is a bit less powerful and doesn't give you all the options you'd have normally with instrumentation, you can read more about it in the doc.
I am assuming you know how to do instrumentation?
There are several things to consider.
It is possible to redefine java.lang.StackOverflowError. I tried it successfully on 1.7.0_40. isModifiableClass(java.lang.StackOverflowError.class) return true and I successfully redefined it inserting a method invocation into all of its constructors
You should be aware that when you insert a method call into a class via Instrumentation you still have to obey the visibility imposed by the ClassLoader relationships. Since StackOverflowError is loaded by the bootstrap loader it can only invoke methods of classes loaded by the bootstrap loader. You would have to add the target method’s class(es) to the bootstrap loader
This works if the application’s code throws a StackOverflowError manually. However, when a real stackoverflow occurs, the last thing the JVM will do is to invoke additional methods (keep in mind what the error says, the stack is full). Consequently it creates an instance of StackOverflowError without calling its constructor (a JVM can do that). So your instrumentation is pointless in this situation.
As already pointed out by others, a “Pure Java Application” must not rely on modified JRE classes. It is only valid to use Instrumentation as add-on, i.e. development or JVM management tool. You should keep in mind that the fact that Oracle’s JVM 1.7.0_40 supports the redefinition of StackOverflowError does not imply that other versions or other JVMs do as well.

How can I intercept a method call to a library class in Java or Android?

I have a library class that is a singleton and does NOT implement any interface (So I'm assuming I cannot use dynamic proxies). But, I need the same functionality as the dynamic proxy. I need to hijack the call, log some data and pass on the call to the library as is.
Is it possible to do this without having to use AspectJ or Spring AOP? (I'm not sure how to use these frameworks, but I will have to look into it if there is no other way).
You can provide your own implementation of the same class, with the same name and package, and try to put it into classpath first. The calling code with such classpath will pick the intercepting class first, and the intercepting class can call others classes of the actual package to provide its actual functionality.
Best would be to remove the overridden class from the library .jar with archive tool.
You could change the import statements in the classes that call f() so that they see a different class that implements f(). The implementation of that class would do the logging and call the real f().
Still requires some editing, but less than changing every call.
BTW: Depending on the size of the project, you may want to consider making wrappers to that "black box" anyway, if this type of requirement will be ongoing.
Like I started in my comment wrapper all the classes you implement from the external library. Then call the external library from your own classes this way you can log in the function(s) you want. If you use the same function name then you don't have to change what you call you only have to change your import(s). Most IDEs provide mass name replace so it shouldn't be too big of a burden it will be tedious however.

Package and visibility

I'm making an SDK and I'm trying to separate classes to different packages, those classes use some other shared classes. The issue is if I made the shared classes public everyone will be able to see them, not only my classes. What's the right way to make them only accessible by my application?
Example :
Package a
MyClass1
Package b
MyClass2
Package c
public MySharedClass
Because c is public MySharedClass will be able to access it, but the issue is that it will also will be visible to the world, how could I prevent that?
Create a package that is documented as an internal package, not to be used by clients.
There is no way in Java to make a class public only for certain packages: It either is public for everyone or package-private (public only in the declared package).
I think there's a proposal for modules to allow better control in the visibility of classes, but we'll have to wait, at least, for Java 8.
The packages are all "public" in Java, what you can protect is the classes within a package. For limiting the visibility of a class to only a given package, declare it like this (without the public visibility modifier):
class MyClass {
// ...
}
In that way, only the classes in the same package as MyClass will be able to see it.
Non trivial:
The shared classes could be defined by a generally accessible set of interfaces. The actual implementation should be loaded explicitly via a Classloader. After that, simply apply Java Security Management mechanisms to control access to the implementation classes. Anyone can see the interfaces and access to actual implementation will be restricted to your SDK.
(A varient of above is what every web/app server needs to do. How do you think Tomcat prevents you from accessing some other app's "public" classes?)
edit: note above is a runtime mechanism. There are static (post) compile approaches as well. APT for example, could be effective here. Naturally I am not addressing a restructuring of your package (in OP) and only addressing how to secure access to a general approach. But these are a bit 'hacky' -- the runtime mechanism of class loading is canonical and imo strictly more correct.
If the class is shared by classes from two different packages, it could be a good indication that these two classes should be in the same package, along with the shared class, which wouldn't be public and would thus only be usable by classes of the same package.
If it's really not an option, just document the shared class appropriately, to indicate that it's not supposed to be used outside of the SDK internal code, that it's subject to changes in future versions, and make it even clearer by naming the package "internal" or somthing like this.
protected modifier can use,in case of your class will access only in same package. otherwise there is no possibility.

Categories

Resources