4

today I just tried to play a little bit around with the opcodes in compiled java class file. After inserting

iinc 1,1

the java virtual machine responds with:

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.

This is my example source code:

public class Test {

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

The opcode for an increment is 0x84 + 2 bytes for operands. There's only one section in the resulting class file, which contains 0x84:

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

So I would translate this as:

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

corresponding to my i++; i++; i++;

I then tried to append just 840101 to increment the variable once more, but that didn't work and resulted in the ClassFormatError.

Is there anything like a checksum for the class file? I looked up the format of a classfile in http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html but could not find anything which points out to some kind of bytes_of_classfile or something. I also don't understand why the error is "Truncated Class File", because I did append something :-)

I know its not a good idea to edit class files directly, but I'm just interested on the VM internals here.

Kara
  • 6,115
  • 16
  • 50
  • 57
echox
  • 9,726
  • 6
  • 33
  • 51
  • 4
    RE: "I know its not a good idea to...", There are a lot of things that are a bad idea to do in production code, but are great ways to learn. This sounds like one of them. :) – Bill the Lizard May 11 '10 at 14:21

3 Answers3

5

(Disclaimer: I didn't disassemble your example.)

If you look at the structure of the class format, you'll see that method_info contains in its attributes Code_attributes (4.7.3), which in turn specify among others the code_length.

Because of your editing, you first violate the declared length, and second of course any subsequent data after the method you modified would now be at different offsets.

Volker Stolz
  • 7,274
  • 1
  • 32
  • 50
2

I'd recommend using a bytecode manipulation library like asm, CGLIB or javassist Compare the before and after, and then you'll know how to do this for yourself.

As for your current problem - make sure the rest of the file remains the same.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • Like I wrote: "I know its not a good idea to edit class files directly, but I'm just interested on the VM internals here." Anyway thank you for your recommendations. – echox May 11 '10 at 14:19
  • I didn't know this implies that you don't want to use a bytecode manipulation tool - it is also a sort of direct manipulation :) – Bozho May 11 '10 at 14:20
  • Right ;-) Maybe I could do the manipulation with a framework and then check the diff of the resulting class files, but this wouldn't explain the vm mechanism to me, which throws the error. :-) – echox May 11 '10 at 14:23
  • @echox: I think doing it via the tools would be a **great** help, even if it's not what you want to do, because the before/after comparison would be very interesting. – Joachim Sauer May 11 '10 at 14:55
  • @echox I am pretty sure that understanding the file format for a class file won't give you any insight into the VM's intenals. This is a virtual environment and a lot of translation/compiling occurs to turn a class into what the VM does with it. – Peter Lawrey May 22 '10 at 07:29
  • The only expection I can think of, is that the byte code instructions encoding limits the size of a method to 64K bytes long, which is a problem for generated code. – Peter Lawrey May 22 '10 at 07:30
  • @Peter I have learned a great deal about the JVM buy experimenting with Class file. The Class file format is directly tied with the JVM's operations. That;s why they are both described in the jvms – H-H May 22 '10 at 10:57
1

You should be careful that a Class file should respect a large number of structural constraints (you can read about them there), and your edit did violate one of them (you should've updated the code length attributes).

For quick editing of class file with a nice GUI, I recommend jbe. Otherwise, you can use a bytecode manipulation library to programmatically modify class files. I have been using BCEL, but other libraries do exist.

H-H
  • 4,431
  • 6
  • 33
  • 41