How do I overcome the “VerifyError:Expecting a sta

2020-03-27 05:02发布

问题:

I am using ASM 5.0.3 bytecode modification library with Tomcat 8 and JDK 8.

My intention is to inject bytecode successfully into all the classes. However, I encountered the following error:

java.lang.VerifyError: Expecting a stackmap frame at branch target 18
Exception Details:
  Location:
    com/sun/crypto/provider/SunJCE.getInstance()Lcom/sun/crypto/provider/SunJCE; @0: getstatic
  Reason:
    Expected stackmap frame at this location.
  Bytecode:
    0x0000000: b200 0bc7 000b bb00 3659 b700 0cb0 b200
    0x0000010: 0bb0 bf                                
  Exception Handler Table:
    bci [0, 18] => handler: 18
  Stackmap Table:
    append_frame(@14,Integer)

            at java.lang.Class.getDeclaredConstructors0(Native Method)
            at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
            at java.lang.Class.getConstructor0(Unknown Source)
            at java.lang.Class.newInstance(Unknown Source)
            at sun.security.jca.ProviderConfig$2.run(Unknown Source)
            at sun.security.jca.ProviderConfig$2.run(Unknown Source)
           ......Some more uninteresting lines in the stack trace.......
            at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
            at java.lang.reflect.Method.invoke(Unknown Source)
            at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:310)
            at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:484)

The key parts of the code that I used in order to call ASM's methods are as follows:

ClassWriter classWriter = new  ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);

classReader.accept(myClassVisitor, ClassReader.EXPAND_FRAMES);

The above code works perfectly well with bytecode modification of a JDK 6 application. The error shows up only for JDK 7 and JDK 8 applications.

Various blog posts and stackoverflow posts point to using the -XX:-UseSplitVerifier or the -noverify flags. However this seems like a short-term workaround especially given that the -XX:-UseSplitVerifier flag is deprecated in JDK 8. I would like to achieve a permanent solution rather than rely on a flag that would eventually be unsupported in future Java releases.

Thank you in advance.

Edit: In reference to Adam's kind suggestion of using COMPUTE_FRAMES instead of COMPUTE_MAXS, this link ASM - java.lang.VerifyError: Operand stack overflow Exception summarizes the errors so far with COMPUTE_FRAMES. Currently, I am unable to progress on JDK 7/8 with either of COMPUTE_MAXS or COMPUTE_FRAMES.

回答1:

Use the ClassWriter#COMPUTE_FRAMES flag for the stack map frames to be recomputed. The bytecode verifier uses typechecker (stack map) from JDK 7 on, so that's why your code works on JDK 6.

Note that (from COMPUTE_FRAMES JavaDoc):

computeFrames implies computeMaxs



回答2:

I fixed the issue, after extending ClassWriter class and override the method getCommonSuperClass.

Please check this ASM 5.0.3 With Java 1.8 incorrect maxStack with Java.lang.VerifyError: Operand stack overflow