0
votes

I am performing instrumentation on all classes in the class path. This includes the JDK classes as well.

Instrumentation code works very well if I instrument my class (HelloWorld for example). Other than that, I receive the below ugly error.

java.lang.NoClassDefFoundError - klass: 'java/lang/NoClassDefFoundError'

A fatal error has been detected by the Java Runtime Environment:

Internal Error (exceptions.cpp:427), pid=35008, tid=0x00007f8db6892700 fatal error: ExceptionMark destructor expects no pending exceptions

JRE version: Java(TM) SE Runtime Environment (8.0_171-b11) (build 1.8.0_171-b11) Java VM: Java HotSpot(TM) 64-Bit Server VM (25.171-b11 mixed mode linux-amd64 compressed oops) Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again

An error report file with more information is saved as: /home/user/yield_instrumentation/hs_err_pid35008.log

If you would like to submit a bug report, please visit: http://bugreport.java.com/bugreport/crash.jsp ./run_agent.sh: line 1: 35008 Aborted java -javaagent:yield_point.jar HelloWorld

The error log files contains the following:

--------------- T H R E A D ---------------

Current thread (0x00007f578c00b000): JavaThread "main" [_thread_in_vm, id=34854, stack(0x00007f5794434000,0x00007f5794535000)]

Stack: [0x00007f5794434000,0x00007f5794535000], sp=0x00007f5794533a00, free space=1022k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) V [libjvm.so+0xacfffa] VMError::report_and_die()+0x2ba V [libjvm.so+0x500189] report_fatal(char const*, int, char const*)+0x59 V [libjvm.so+0x582bd0] ExceptionMark::~ExceptionMark()+0xb0 V [libjvm.so+0xa7cea6] Threads::create_vm(JavaVMInitArgs*, bool*)+0x396 V [libjvm.so+0x6d6e44] JNI_CreateJavaVM+0x74 C [libjli.so+0x797e] JavaMain+0x9e C [libpthread.so.0+0x7494] start_thread+0xc4

--------------- P R O C E S S ---------------

Java Threads: ( => current thread ) 0x00007f578c4de000 JavaThread "C1 CompilerThread14" daemon [_thread_blocked, id=34901, stack(0x00007f574b6f7000,0x00007f574b7f8000)] 0x00007f578c4dc000 JavaThread "C1 CompilerThread13" daemon [_thread_blocked, id=34900, stack(0x00007f574b7f8000,0x00007f574b8f9000)] 0x00007f578c4da000 JavaThread "C1 CompilerThread12" daemon [_thread_blocked, id=34899, stack(0x00007f574b8f9000,0x00007f574b9fa000)] "hs_err_pid34853.log" 1609L, 80820C

Below is my instrumentation Code

public byte[] transform(ClassLoader loader, String className,
        Class classBeingRedefined, ProtectionDomain protectionDomain,
        byte[] classfileBuffer) throws IllegalClassFormatException {

    byte[] byteCode = classfileBuffer;

    try {
        ClassPool classPool = ClassPool.getDefault();
            CtClass ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
        CtClass greeting_ct = classPool.get("whatever.GreetingFactory");

        /*if(!ctClass.getSimpleName().equalsIgnoreCase("HelloWorld")) {
            return byteCode; 
        }*/

        //The below returns all methods including constructors
        CtBehavior[] all_methods =  ctClass.getDeclaredBehaviors();
        for (CtBehavior method : all_methods) {
            MethodInfo methodInfo = method.getMethodInfo();
            CodeAttribute code = methodInfo.getCodeAttribute();
            CodeIterator instruction_iterator = code.iterator();                    
            int instruction_loc=0;          
            Bytecode invoke_hi = new Bytecode(methodInfo.getConstPool());
            invoke_hi.addInvokestatic(greeting_ct,"hello", void_non());
            int pos = instruction_iterator.insertEx(invoke_hi.get());
            instruction_iterator.insert(code.getExceptionTable(), pos);             
        }

    ctClass.detatch(); //Without or without this statement ... result is the same
    return ctClass.toBytecode();    
    } catch (Throwable ex) {
        ex.printStackTrace();
    }

    return byteCode;
}

    public static String void_non() {
     String desc = Descriptor.ofMethod(CtClass.voidType, null);
     return desc;
}
1
Can you share your instrumentation code? - draganstankovic
I modified my question to include the code .... - T-Student-105

1 Answers

0
votes

Here is little bit detailed answer to the question. It is related to class loaders. In Java, there multiple class loader including the following:

  1. The boot class loader that loads all of the JDK related classes. It has certain paths to look for such the path to rt.jar.

  2. Classpath class loader that loads everything in the class path.

Classes are resolved at run-time when needed. The code I am injecting contains references to other code outside of the JDK (that is loaded by the boot class loader). At runtime, JDK will ask the boot class loader to load classes, which of course does not have them. They are loaded by the classpath class loader.

To solve this, Java allows to add additional paths to be loaded by the default class loader.

java -Xbootclasspath/p:javassist.jar:whatever.jar