Редактирование файла .class напрямую, игра с кодами операций

сегодня я просто попытался немного поиграться с кодами операций в скомпилированном файле класса java. После вставки

iinc 1,1

виртуальная машина java отвечает:

Exception in thread "main" java.lang.ClassFormatError: Truncated class file
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
        at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
Could not find the main class: Test.  Program will exit.

Это мой пример исходного кода:

public class Test {

    public static void main(String[] args) {
        int i = 5;
        i++;
        i++;
        i++;
        System.out.println("Number: " + i + "\n");
    }
}

Код операции для приращения - 0x84 + 2 байта для операндов. В результирующем файле класса есть только один раздел, содержащий 0x84:

[..] 8401 0184 0101 8401 01[..]

Я бы перевел это так:

iinc 1,1
iinc 1,1
iinc 1,1

соответствует моему i ++; i ++; i ++;

Затем я попытался добавить только 840101, чтобы еще раз увеличить переменную, но это не сработало и привело к ошибке ClassFormatError.

Есть ли что-нибудь вроде контрольной суммы для файла класса? Я просмотрел формат файла класса в http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html, но не смог найти ничего, что указывает на какой-то файл bytes_of_classfile или что-то в этом роде. Я также не понимаю, почему это ошибка "Truncated Class File", потому что я кое-что добавил :-)

Я знаю, что редактировать файлы классов напрямую - не лучшая идея, но меня здесь интересует только внутреннее устройство ВМ.


person echox    schedule 11.05.2010    source источник
comment
RE: Я знаю, что это плохая идея ... Есть много вещей, которые плохая идея делать в производственном коде, но это отличный способ научиться. Это похоже на один из них. :)   -  person Bill the Lizard    schedule 11.05.2010


Ответы (3)


(Отказ от ответственности: я не разбирал ваш пример.)

Если вы посмотрите на структуру формата класса, вы увидите, что method_info содержит в своих атрибутах Code_attributes (4.7.3), которые, в свою очередь, определяют среди прочего code_length.

Из-за вашего редактирования вы сначала нарушаете заявленную длину, а во-вторых, конечно, любые последующие данные после измененного вами метода теперь будут с другими смещениями.

person Volker Stolz    schedule 11.05.2010

Я бы рекомендовал использовать библиотеку для работы с байт-кодом, например asm, CGLIB или javassist Сравните предыдущий и после, и тогда вы будете знать, как это сделать для себя.

Что касается вашей текущей проблемы - убедитесь, что остальная часть файла не изменилась.

person Bozho    schedule 11.05.2010
comment
Как я уже писал: я знаю, что редактировать файлы классов напрямую - не лучшая идея, но меня здесь интересует только внутреннее устройство виртуальной машины. В любом случае спасибо за ваши рекомендации. - person echox; 11.05.2010
comment
Я не знал, что это означает, что вы не хотите использовать инструмент для манипулирования байт-кодом - это тоже своего рода прямая манипуляция :) - person Bozho; 11.05.2010
comment
Верно ;-) Возможно, я мог бы проделать манипуляции с фреймворком, а затем проверить разницу полученных файлов классов, но это не объяснило бы мне механизм vm, который вызывает ошибку. :-) - person echox; 11.05.2010
comment
@echox: Я думаю, что выполнение этого с помощью инструментов было бы отличным подспорьем, даже если это не то, что вы хотите сделать, потому что сравнение до / после было бы очень интересно. - person Joachim Sauer; 11.05.2010
comment
@echox Я почти уверен, что понимание формата файла для файла класса не даст вам никакого представления о внутреннем устройстве виртуальной машины. Это виртуальная среда, и для превращения класса в то, что с ним делает виртуальная машина, происходит много трансляций / компиляций. - person Peter Lawrey; 22.05.2010
comment
Единственное, что я могу придумать, это то, что кодирование инструкций байтового кода ограничивает размер метода до 64 Кбайт, что является проблемой для сгенерированного кода. - person Peter Lawrey; 22.05.2010
comment
@Peter Я много узнал о покупке JVM, экспериментируя с файлом класса. Формат файла класса напрямую связан с операциями JVM. Вот почему они оба описаны в jvms - person H-H; 22.05.2010

Вы должны быть осторожны, чтобы файл класса учитывал большое количество структурных ограничений (вы можете прочитать о них there), и ваше изменение нарушило один из них (вам следовало обновить атрибуты длины кода).

Для быстрого редактирования файла класса с красивым графическим интерфейсом я рекомендую jbe. В противном случае вы можете использовать библиотеку манипуляций с байт-кодом для программного изменения файлов классов. Я использовал BCEL, но существуют и другие библиотеки.

person H-H    schedule 22.05.2010