[jboss-jira] [JBoss JIRA] (JASSIST-241) VerifyError: Expecting a stackmap frame - Switch case statement Java 7
Patson Luk (JIRA)
issues at jboss.org
Thu Jan 15 21:08:49 EST 2015
[ https://issues.jboss.org/browse/JASSIST-241?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13033009#comment-13033009 ]
Patson Luk commented on JASSIST-241:
------------------------------------
Dig a bit deeper into the code, it appears that below is the cause of the exception : (excuse me if any of below reasoning is incorrect as I am not too familiar with the libray)
# "insertAfter" on method replaces return statement with "goto" that jumps to the injected code
# In order to replace the RETURN op with GOTO, it needs to allocate a bigger block as GOTO take more byte, it attempts to insert gap of size 2 (not a wide goto) (CtBehavior.insertGoto)
# During the gap insertion, CodeIterator checks the byte alignment of the method, if there's TABLESWITCH (my case) or LOOKUPSWITCH, it will throws AlignmentException as the require the gapLength to be multiple of 4
# To insert a gap of multiple of 4, The end result will be a GOTO followed with 2 NOOP
# Now in the class MapMaker, it attempts to build the stackmap
# It builds a list of BasicBlock, the sequence would be (at the entrance of MapMaker.toStackMap)
#* The IfNotNull (branch instruction block)
#* The GOTO block (if o is null, used to be a return but now replaced by GOTO because of code injection)
#* The 2 NOOPS block (dead code - inserted by the GAP ) with incoming=1 (after the fixDeadcode)
#* The target "branch-to" block of ifNotNull with incoming = 1 (as IfNotNull jumps to this)
# Now in MapMaker.isTarget logic, it checks whether the block is a "branch target". To my understanding if incoming > 1, that means it should be a branch target (makes sense), if it's zero then it should NOT be a branch trarget (also makes sense), if it's 1, then it checks if the previous block has stop == true (ends with an unconditional jump), this logic makes sense MOST of the case as if the previous block is unconditional jump and this block still has incoming == 1, that means someone else branches to this block (*Just my assumption/understanding, could be wrong!*) This however, creates problem if a branch target is preceded by a piece of dead code which has stop == false
So my thought is that can we flag if a block is a dead code? It seems like javassist already has the logic to find out dead code block (fixDeadCode) and BasicBlock.makeBlocks. And in the logic of MapMaker.isTarget, if the previous block is dead code and if the "incoming" of current block == 1, that means this current block is a valid branch target as dead code does not increment the following block.
Hopefully i capture the problem correctly, apologize if i have made any false assumptions!
> VerifyError: Expecting a stackmap frame - Switch case statement Java 7
> ----------------------------------------------------------------------
>
> Key: JASSIST-241
> URL: https://issues.jboss.org/browse/JASSIST-241
> Project: Javassist
> Issue Type: Bug
> Affects Versions: 3.19.0-GA
> Environment: jdk7
> Reporter: Patson Luk
> Assignee: Shigeru Chiba
>
> This could be a duplicate of issue 215 and 205.
> Tested it on the master (3.19.0-GA) with java 7. Running the below class
> {code}
> import java.util.Random;
> import javassist.ClassPool;
> import javassist.CtClass;
> import javassist.CtMethod;
> public class TestDriver {
> public static void main(String[] args) throws Exception {
> ClassPool pool = ClassPool.getDefault();
> CtClass cc = pool.get("TestClass");
>
> CtMethod testMethod = cc.getMethod("test", "(Ljava/lang/Object;)V");
> testMethod.insertAfter("System.out.println(\"inserted!\");");
> cc.toClass();
> //invoke it
> TestClass.test(new Object());
> }
> }
> class TestClass {
> public static void test(Object o) {
> //part 1
> if (o == null) {
> return;
> }
> //part 2
> int oper = new Random().nextInt();
> switch (oper) {
> case 1:
> break;
> }
> }
> }
> {code}
>
> Triggers error message as below:
> {quote}
> Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 9 in method TestClass.test(Ljava/lang/Object;)V at offset 1
> at TestDriver.main(TestDriver.java:19)
> {quote}
> *Please take note that:*
> # This is observed on Java 7. When the same code is run on Java 6, it is fine
> # Both the "part 1" - return statement (commented in the code above) and "part 2" - switch/case statement have to be there to trigger the error. If either of those are commented out, then the code runs fine
--
This message was sent by Atlassian JIRA
(v6.3.11#6341)
More information about the jboss-jira
mailing list