Я пытаюсь сделать это, перезаписав байт-код класса, используя ASM 4.0, чтобы заменить все методы native с заглушками <<20 > .
Пока у меня есть это:
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 будет перезаписан (в этом случае без изменений) и будет выполнен отлично.
Ясно, что я ничего не делаю правильно, и замена метода native на метод не native не так прост, как отключение модификатора native от метода, но я понятия не имею, где начать. ASM Docs не говорят о работе с методами 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 -stripped, которые вызывают проблему.
Что кажется действительно нечетным, так это то, что трассировка стека составляет всего 16 кадров; Я бы предпочел, чтобы он получил больше StackOverflowError.