使用ASM重写Java本机方法

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (14)

我试图通过使用ASM 4.0重新编写类的字节码来替代所有native使用非native存根的方法。

到目前为止,我有这样的:

class ClassAdapter extends ClassVisitor {

    public ClassAdapter(ClassVisitor cv) {
        super(Opcodes.ASM4, cv);
    }

    @Override
    public MethodVisitor visitMethod(int access, String base, String desc, String signature, String[] exceptions) {
        return cv.visitMethod(access & ~Opcodes.ACC_NATIVE, base, desc, signature, exceptions);
    }

}

这是由执行

private static byte[] instrument(byte[] originalBytes, ClassLoader loader) {
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
    ClassAdapter adapter = new ClassAdapter(cw);

    ClassReader cr = new ClassReader(originalBytes);
    cr.accept(adapter, ClassReader.SKIP_FRAMES);

    return cw.toByteArray();
}

这看起来很简单:我ACC_NATIVE将该方法取消visitMethod()并保留其他所有内容。然而,当我这样做的时候java.lang.Object,它会死于一个

Exception in thread "main" 
Exception: java.lang.StackOverflowError thrown from the UncaughtExceptionHandler in thread "main"

StackOverflow发生在仪表时间,而不是运行时间,我认为这很不寻常。但是,如果我删除了& ~Opcodes.ACC_NATIVE修饰符,则会java.lang.Object被重写(在这种情况下不会改变)并完美地执行。

很显然,我没有做正确的事情,用nativenative方法替换方法并不像删除native方法上的修饰符那么简单,但我不知道从哪里开始。该ASM文档不谈论与工作native方法的。有没有经验与ASM合作的人知道我需要做什么才能让native方法重写起作用?

对不起,那短暂的,无用的信息是e.printStackTrace()给我的,但是e.getStackTrace()我使用我设法得到了一些有用的东西:

java.util.concurrent.ConcurrentHashMap.hash(ConcurrentHashMap.java:332)
java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:1124)
java.util.Collections$SetFromMap.add(Collections.java:3903)
sandbox.classloader.MyClassLoader.instrument(Unknown Source)
sandbox.classloader.MyClassLoader.loadClass(Unknown Source)
java.lang.ClassLoader.defineClass1(Native Method)
java.lang.ClassLoader.defineClass(ClassLoader.java:791)
java.lang.ClassLoader.defineClass(ClassLoader.java:634)
sandbox.classloader.MyClassLoader.findClass(Unknown Source)
sandbox.classloader.MyClassLoader.loadClass(Unknown Source)
sandbox.Tester.main(Unknown Source)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

所以在我看来,这个错误实际上是在执行时发生的(例如,我错误地认为它是在仪表时间)并且是调用的结果hashCode()。正如它发生的那样,hashCode()我(可能错误地)剥离了它的native修饰符的原生方法之一。很明显,它调用native导致问题的解决方法。

提问于
用户回答回答于

扫码关注云+社区