how to debug an internal error?

自古美人都是妖i 提交于 2019-12-12 19:30:39

问题


So I have a class Foo that should eventually adjust and reload classes. It has a method for that, too:

private void redefineClass(String classname, byte[] bytecode) {
    ClassFileLocator cfl = ClassFileLocator.Simple.of(classname,bytecode);

    Class clazz;
    try{
        clazz = Class.forName(classname);
    }catch(ClassNotFoundException e){
        throw new RuntimeException(e);
    }

    Debug._print("REDEFINING %s",clazz.getName());

    new ByteBuddy()
            .redefine(clazz,cfl)
            .make()
            .load(clazz.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent())
            ;
}

To test it, I simply load the classes from .class files to byte[] (using ASM)

private byte[] getBytecode(String classname){
    try {
        Path p = Paths.get(LayoutConstants.SRC_DIR).resolve(classname.replace(".","/") + ".class");
        File f = p.toFile();
        InputStream is = new FileInputStream(f);
        ClassReader cr = new ClassReader(is);
        ClassWriter cw = new ClassWriter(cr,0);
        cr.accept(cw,0);
        return cw.toByteArray();
    }catch(IOException e){
        throw new RuntimeException(e);
    }
}

and pass it on to redefineClass above. Seems to work for quite a few classes ... not for all, though:

REDEFINING parc.util.Vector$1
Exception in thread "Thread-0" java.lang.InternalError: Enclosing method not found
    at java.lang.Class.getEnclosingMethod(Class.java:952)
    at sun.reflect.generics.scope.ClassScope.computeEnclosingScope(ClassScope.java:50)
    at sun.reflect.generics.scope.AbstractScope.getEnclosingScope(AbstractScope.java:74)
    at sun.reflect.generics.scope.AbstractScope.lookup(AbstractScope.java:90)
    at sun.reflect.generics.factory.CoreReflectionFactory.findTypeVariable(CoreReflectionFactory.java:110)
    at sun.reflect.generics.visitor.Reifier.visitTypeVariableSignature(Reifier.java:165)
    at sun.reflect.generics.tree.TypeVariableSignature.accept(TypeVariableSignature.java:43)
    at sun.reflect.generics.visitor.Reifier.reifyTypeArguments(Reifier.java:68)
    at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:138)
    at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49)
    at sun.reflect.generics.repository.ClassRepository.getSuperInterfaces(ClassRepository.java:100)
    at java.lang.Class.getGenericInterfaces(Class.java:814)
    at net.bytebuddy.description.type.TypeList$Generic$OfLoadedInterfaceTypes$TypeProjection.resolve(TypeList.java:722)
    at net.bytebuddy.description.type.TypeDescription$Generic$LazyProjection.accept(TypeDescription.java:5308)
    at net.bytebuddy.description.type.TypeList$Generic$AbstractBase.accept(TypeList.java:249)
    at net.bytebuddy.dynamic.scaffold.InstrumentedType$Factory$Default$1.represent(InstrumentedType.java:221)
    at net.bytebuddy.ByteBuddy.redefine(ByteBuddy.java:698)
    at net.bytebuddy.ByteBuddy.redefine(ByteBuddy.java:676)
    at parc.Foo.redefineClass(Foo.java:137)

disassembling Vector$1 gives me class Vector$1 implements java/util/Enumeration, so that indicates it's this class:

/**
 * Returns an enumeration of the components of this vector. The
 * returned {@code Enumeration} object will generate all items in
 * this vector. The first item generated is the item at index {@code 0},
 * then the item at index {@code 1}, and so on.
 *
 * @return  an enumeration of the components of this vector
 * @see     Iterator
 */
public Enumeration<E> elements() {
    return new Enumeration<E>() {
        int count = 0;

        public boolean hasMoreElements() {
            return count < elementCount;
        }

        public E nextElement() {
            synchronized (Vector.this) {
                if (count < elementCount) {
                    return elementData(count++);
                }
            }
            throw new NoSuchElementException("Vector Enumeration");
        }
    };
}

except I still have no idea what to do with that information.

For some reason the instrumented code that was saved to file can be loaded and used but can't be REloaded.

How do I find out why?

EDIT: I should mention that the project I'm working on requires Java 7.


回答1:


I tested several Java versions and could not find any problems with Class.getEnclosingMethod and Class.getGenericInterfaces for a local class implementing a generic interface, like in the Vector.elements()/Enumeration<E> case. Perhaps, the problems arise, because the class file has already been manipulated.

But it seems that whatever the ByteBuddy frontend is doing under the hood involving Class.getGenericInterfaces is just overkill for your use case, as you have the intended result byte code already.

I suggest going one level down and use

ClassReloadingStrategy s = ClassReloadingStrategy.fromInstalledAgent();
s.load(clazz.getClassLoader(),
    Collections.singletonMap(new TypeDescription.ForLoadedType(clazz), bytecode));

to skip these operations and just activate your byte code.

When the class loading strategy is based on ClassReloadingStrategy.Strategy.REDEFINITION you can also use

ClassReloadingStrategy s = ClassReloadingStrategy.fromInstalledAgent();
s.reset(ClassFileLocator.Simple.of(classname, bytecode), clazz);

as it will use the bytecode retrieved through the ClassFileLocator as base.




回答2:


Looking at the byte-buddy code, I assume that ClassReloadingStrategy.fromInstalledAgent() will return a ClassReloadingStrategy configured with Strategy.REDEFINITION, which does not support anonymous classes. Use Strategy.RETRANSFORMATION instead.

ClassReloadingStrategy strat = new ClassReloadingStrategy(
   (Instrumentation) ClassLoader.getSystemClassLoader()
                    .loadClass("net.bytebuddy.agent.Installer")
                    .getMethod("getInstrumentation")
                    .invoke(null), 
   Strategy.RETRANSFORMATION);

You may consider writing a bug report, the default behavior does not match the comment which says that the default is Strategy.RETRANSFORMATION.



来源:https://stackoverflow.com/questions/48869694/how-to-debug-an-internal-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!