m0skit0
m0skit0

Reputation: 25873

Inconsistent stack height 0 != 1

I'm modifying a Java class bytecode through an hexadecimal editor, and I want to force a method to always return true.

  1. Replaced all its bytecode with nops to keep the size intact (original size is 1890).
  2. Execute a pop to restore the stack height since it receives an argument.
  3. Return true with iconst_1 followed by ireturn.
public static boolean test(java.lang.String);
        descriptor: (Ljava/lang/String;)Z
        flags: ACC_PUBLIC, ACC_STATIC
        Code:
          stack=5, locals=12, args_size=1
             0: nop
             1: nop
             2: nop
             3: nop
             4: nop
             [...]
          1886: nop
          1887: nop
          1888: pop
          1889: iconst_1
          1890: ireturn

But when executing it, I'm getting the following error

java.lang.VerifyError: (class: com/example/test/TestBytecode, method: test signature: (Ljava/lang/String;)Z) Inconsistent stack height 0 != 1

NOTE: with or without pop the result is exactly the same.

Upvotes: 5

Views: 4756

Answers (3)

morgano
morgano

Reputation: 17422

If you are using Java 7 or later, probably the JVM is validating your bytecode with the stack map frames. (Check this question/answer for an explanation of the stack map frames)

If you are using Java 7, try using -XX:-UseSplitVerifier in the command line when you run your class.

If you are using java 8, then you will also have modify the stack map frames; doing so is not trivial, so I better recommend you to use a bytecode manipulation library like javassist.

UPDATE

Based on the comment of @Holger, he is right. However as far as I've seen you are filling unwanted op codes with NOPs rather than removing them.

As you probably already know, the machine instructions are located in an attribute called code; this attribute can have "sub-attributes" (attributes of code itself). One of these is the attribute StackMapTable, which is an "array" (a table) of "stack maps".

Replacing this attribute with zeros won't be enough, you'll have to:

  • set the number of entries of that table (the stack map table) to zero
  • delete the only entry on that table (and offset the following attributes and other fields)

still want to do it by hand? :-)

Upvotes: 1

Siguza
Siguza

Reputation: 23870

pop pops a value from the stack, but the string that is passed as argument is in "local variable" 0.
You should be able to safely omit that pop.

Also, you should be able to leave out all nops, and instead just replace instruction 0 with iconst_1, instruction 1 with ireturn, and leave the entire rest of the method unchanged.
This way you'd be doing less work and probably even increasing performance.

Upvotes: 2

Clashsoft
Clashsoft

Reputation: 11882

The pop is unnecessary, since the arguments are not on the stack at first. They are only pushed onto the stack when using *load instructions as if they were local variables, which can happen at any time.

Upvotes: 4

Related Questions