Перезапись собственных Java-методов с использованием ASM - программирование
Подтвердить что ты не робот

Перезапись собственных Java-методов с использованием ASM

Я пытаюсь сделать это, перезаписав байт-код класса, используя 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.

4b9b3361

Ответ 1

  • Это не так просто заменить собственный код заглушками, но он не так уж далеко от него

  • Если вы посмотрите ClassVisitor # visitMethod (int access, String name, String desc, String signature, String [] exceptions) вы увидите, что он возвращает MethodVisitor

  • MethodVisitor, который вы теперь должны использовать. Если вы хотите сделать абстрактные заглушки, вы должны добавить хотя бы вызов methodVisitor.visitEnd()

  • Если вы хотите сделать пустые заглушки, вам нужно добавить visitCode, а также при необходимости вернуть значение