Reputation: 25873
I'm modifying a Java class bytecode through an hexadecimal editor, and I want to force a method to always return true.
pop
to restore the stack height since it receives an argument.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
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:
still want to do it by hand? :-)
Upvotes: 1
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 nop
s, 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
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