0

I am new to instrumentation. I need to add a static variable and maybe a static method later on in one of bootstrap classes, java.lang.String. I tried both Javassist and ASM but both report error,

> Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(Unknown Sou
rce)
        at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(Unknown So
urce)

Caused by: java.lang.UnsupportedOperationException: class redefinition failed: a
ttempted to change the schema (add/remove fields)
        at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)

        at sun.instrument.InstrumentationImpl.retransformClasses(Unknown Source)

here is my transform method and ASM code,

        public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                                ProtectionDomain domain, byte[] classfileBuffer) 

      {

        if (className.startsWith("java/lang/String")) {
            try {
                classfileBuffer = modifyField(classfileBuffer);
            } catch (Exception e) {
                e.printStackTrace();
            }
        return classfileBuffer
    }

public static byte[] modifyField(byte[] origClassData) throws Exception {
    ClassReader cr = new ClassReader(origClassData);
    final ClassWriter cw = new ClassWriter(cr, ASM5);
    // add the static final fields
    cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "bVal","Z", null, new Boolean("false")).visitEnd();
    // wrap the ClassWriter with a ClassVisitor that adds the static block to
    // initialize the above fields
    ClassVisitor cv = new CustomVisitor(ASM5, cw);
    // feed the original class to the wrapped ClassVisitor
    cr.accept(cv, 0);
    // produce the modified class
    byte[] newClassData = cw.toByteArray();
    return newClassData;
}

I have also turned TRUE on both Can-Redefine-Classes and Can-Retransform-Classes.

Thanks for your help

Sams2018
  • 1
  • 1

2 Answers2

0

The JVM does not allow the addition of fields or any other change in the class file format, just as the exception indicates. There are special builds of the OpenJDK such as the dynamic code evolution JVM that allow this, but most JVM do not support this.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • Thanks, Rafael. is there a way to intercept or wrapper this Java system class ? – Sams2018 Nov 04 '18 at 03:32
  • You can change the byte code of any none-native method what should allow you to do most things. – Rafael Winterhalter Nov 04 '18 at 16:28
  • My intention is to listen to any change on a String object or invoke methods defined in Class string. Instrumentation of the String class seems most straight. Appreciate if you can point to the right direction on how to achieve this and share any sample if available without exception above – Sams2018 Nov 04 '18 at 18:19
  • Then you can instrument the byte code. If you need to add a field, define a new class within the bootstrap class loader and manage the state within this class. You cannot add new fields to `String`. – Rafael Winterhalter Nov 05 '18 at 07:59
  • @Sams2018 what do you mean with “change on a String object”? String objects are immutable. – Holger Nov 07 '18 at 09:12
0

I had the same problem sometime ago. I can point you to my question that may help you.

It looks like with Javassist you can modify the body of a native method, but cannot add methods or fields. Take a look at this qustion: Java agent cannot transform all the classes in my project

rakwaht
  • 3,666
  • 3
  • 28
  • 45