1

Using ASM 5.0.3 (with Java 1.8.0_65 & Tomcat 8.0.30) , Visiting one of the JSP (date.jsp) Method - _JSP(_jspService) , getting below exception

javax.servlet.ServletException: java.lang.VerifyError: Operand stack overflow
Exception Details:
  Location:
    org/apache/jsp/jsp/dates/date_jsp._jspService(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V @0: aload_1
  Reason:
    Exceeded max stack size.
  Current Frame:
    bci: @0
    flags: { }
    locals: { 'org/apache/jsp/jsp/dates/date_jsp', 'javax/servlet/http/HttpServletRequest', 'javax/servlet/http/HttpServletResponse' }
    stack: { }
  Bytecode: .......................

Note : I am not changing the byte code of the method , Just visiting the methods using MethodVisitor class of ASM 5.0.3.

date.jsp

<html>
<%@ page session="false"%>
    <body>
        <jsp:useBean id='clock' scope='page' class='dates.JspCalendar' type="dates.JspCalendar"/>
    </body>
</html>

Note : If i remove the <jsp:useBean ..../> , JSP Page executing fine & not getting any java.lang.VerifyError

Also attached outline of my code :

public byte[] transform(ClassLoader loader, String className, Class<?> 
                        classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException{ 
            if(!className.equals("org/apache/jsp/jsp/dates/date_jsp")){
                return classfileBuffer;
            }
            ClassReader classReader = null;
            try{
                classReader=new ClassReader(classfileBuffer);
            }
            catch(Throwable exp){
                return classfileBuffer;
            }

        int writerFlag = ClassWriter.COMPUTE_MAXS;
        int accpetFlag = ClassReader.EXPAND_FRAMES;
        int classFileversion = getClassJavaVersion(classReader);
        if(classFileversion > 50){
            writerFlag = ClassWriter.COMPUTE_FRAMES;
            accpetFlag = ClassReader.SKIP_FRAMES;
        }
        ClassWriter classWriter = new ClassWriter(classReader, writerFlag);
        ClassVisitor classVisitor =(ClassVisitor) new MiniJSPClassVisitor(classWriter , className,  classFileversion);
        if(classVisitor!=null){
            try{
                classReader.accept(classVisitor, accpetFlag); 
            }catch(Exception e) {}
            finally{
                classfileBuffer =  classWriter.toByteArray();
            }
        }
        return classfileBuffer;
    }

    private static int getClassJavaVersion(ClassReader classReader) {
        return classReader.readUnsignedShort(6);
    }`

Note : Compiled JSP class version is 51, So ASM uses , ClassWriter.COMPUTE_FRAMES and ClassReader.SKIP_FRAMES

MiniJSPClassVisitor.java

public class MiniJSPClassVisitor extends ClassVisitor {

    private static final String _jspServiceDesc = "(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V";

    public MiniJSPClassVisitor(ClassVisitor classVisitor , String className,  int classFileVersion) {
        super(Opcodes.ASM5 , classVisitor);
    }

    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        MethodVisitor mv;
        mv = super.visitMethod(access, name, desc, signature, exceptions);
        if (mv != null) {
            if ((access & Opcodes.ACC_NATIVE) != 0 || (access & Opcodes.ACC_ABSTRACT) != 0){
                return mv;
            }
            if(name.equals("<clinit>") || name.equals("<init>") || name.equals("init")){
                return mv;
            }
            if(name.equals("_jspService") && desc.equals(_jspServiceDesc)){
                mv = new SimpleMethodVisitor(Opcodes.ASM5 , mv , name);
            }
            return mv;
        }
        return null;
    }
}

SimpleMethodVisitor.java

public class SimpleMethodVisitor extends MethodVisitor {
    private String methodName = null;

    public SimpleMethodVisitor(int api, MethodVisitor mv, String methodName) {
        super(Opcodes.ASM5, mv);
        this.methodName = methodName;
        System.out.println("SimpleMethodVisitor :"+methodName );
    }

I printed the bytecode of the class - org/apache/jsp/jsp/dates/date_jsp with and without visting _jspService method , using TraceClassVisitor

pw = new PrintWriter(homeFolder + File.separator + "date.log");
ClassReader cr = new ClassReader(classfileBuffer);
cr.accept(new TraceClassVisitor(null, new ASMifier(), pw), ClassReader.EXPAND_FRAMES);

Seems that ASM calculates wrong max stack , when visiting the _jspService method - mv.visitMaxs(0, 10) instead of mv.visitMaxs(8, 10)

Attached the screenshot with correct maxstack

enter image description here

Wrong maxstack

enter image description here

For Reference , compiled version of the _jspService method is attached

public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
        throws java.io.IOException, javax.servlet.ServletException {

final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
return;
}

    final javax.servlet.jsp.PageContext pageContext;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;


    try {
      response.setContentType("text/html");
      pageContext = _jspxFactory.getPageContext(this, request, response,
                null, false, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("\r\n");
      out.write("<html>\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("<body>\r\n");
      dates.JspCalendar clock = null;
      clock = (dates.JspCalendar) _jspx_page_context.getAttribute("clock", javax.servlet.jsp.PageContext.PAGE_SCOPE);
      if (clock == null){
        clock = new dates.JspCalendar();
        _jspx_page_context.setAttribute("clock", clock, javax.servlet.jsp.PageContext.PAGE_SCOPE);
      }
      out.write("\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("</body>\r\n");
      out.write("</html>\r\n");
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try {
            if (response.isCommitted()) {
              out.flush();
            } else {
              out.clearBuffer();
            }
          } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
        else throw new ServletException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

How to resolve java.lang.VerifyError, occured when JSP Bean is declared? (or) Need to do anything in the ASM side to overcome this issue?. Thanks in advance

Note:

Same code is working with Java 6 with Tomcat 6

EDIT #1, Holger attached the bytecode of the method _jspService.

{
mv = cw.visitMethod(ACC_PUBLIC, "_jspService", "(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V", null, new String[] { "java/io/IOException", "javax/servlet/ServletException" });
mv.visitCode();
Label l0 = new Label();
Label l1 = new Label();
Label l2 = new Label();
mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable");
Label l3 = new Label();
Label l4 = new Label();
Label l5 = new Label();
mv.visitTryCatchBlock(l3, l4, l5, "java/io/IOException");
Label l6 = new Label();
Label l7 = new Label();
mv.visitTryCatchBlock(l0, l6, l7, null);
Label l8 = new Label();
mv.visitLabel(l8);
mv.visitLineNumber(82, l8);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEINTERFACE, "javax/servlet/http/HttpServletRequest", "getMethod", "()Ljava/lang/String;", true);
mv.visitVarInsn(ASTORE, 3);
Label l9 = new Label();
mv.visitLabel(l9);
mv.visitLineNumber(83, l9);
mv.visitLdcInsn("GET");
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);
Label l10 = new Label();
mv.visitJumpInsn(IFNE, l10);
mv.visitLdcInsn("POST");
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);
mv.visitJumpInsn(IFNE, l10);
mv.visitLdcInsn("HEAD");
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);
mv.visitJumpInsn(IFNE, l10);
mv.visitFieldInsn(GETSTATIC, "javax/servlet/DispatcherType", "ERROR", "Ljavax/servlet/DispatcherType;");
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEINTERFACE, "javax/servlet/http/HttpServletRequest", "getDispatcherType", "()Ljavax/servlet/DispatcherType;", true);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/DispatcherType", "equals", "(Ljava/lang/Object;)Z", false);
mv.visitJumpInsn(IFNE, l10);
Label l11 = new Label();
mv.visitLabel(l11);
mv.visitLineNumber(84, l11);
mv.visitVarInsn(ALOAD, 2);
mv.visitIntInsn(SIPUSH, 405);
mv.visitLdcInsn("JSPs only permit GET POST or HEAD");
mv.visitMethodInsn(INVOKEINTERFACE, "javax/servlet/http/HttpServletResponse", "sendError", "(ILjava/lang/String;)V", true);
Label l12 = new Label();
mv.visitLabel(l12);
mv.visitLineNumber(85, l12);
mv.visitInsn(RETURN);
mv.visitLabel(l10);
mv.visitLineNumber(91, l10);
mv.visitInsn(ACONST_NULL);
mv.visitVarInsn(ASTORE, 5);
Label l13 = new Label();
mv.visitLabel(l13);
mv.visitLineNumber(93, l13);
mv.visitInsn(ACONST_NULL);
mv.visitVarInsn(ASTORE, 6);
Label l14 = new Label();
mv.visitLabel(l14);
mv.visitLineNumber(94, l14);
mv.visitInsn(ACONST_NULL);
mv.visitVarInsn(ASTORE, 7);
mv.visitLabel(l0);
mv.visitLineNumber(98, l0);
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn("text/html");
mv.visitMethodInsn(INVOKEINTERFACE, "javax/servlet/http/HttpServletResponse", "setContentType", "(Ljava/lang/String;)V", true);
Label l15 = new Label();
mv.visitLabel(l15);
mv.visitLineNumber(99, l15);
mv.visitFieldInsn(GETSTATIC, "org/apache/jsp/jsp/dates/date_jsp", "_jspxFactory", "Ljavax/servlet/jsp/JspFactory;");
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
Label l16 = new Label();
mv.visitLabel(l16);
mv.visitLineNumber(100, l16);
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ICONST_0);
mv.visitIntInsn(SIPUSH, 8192);
mv.visitInsn(ICONST_1);
Label l17 = new Label();
mv.visitLabel(l17);
mv.visitLineNumber(99, l17);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspFactory", "getPageContext", "(Ljavax/servlet/Servlet;Ljavax/servlet/ServletRequest;Ljavax/servlet/ServletResponse;Ljava/lang/String;ZIZ)Ljavax/servlet/jsp/PageContext;", false);
mv.visitVarInsn(ASTORE, 4);
Label l18 = new Label();
mv.visitLabel(l18);
mv.visitLineNumber(101, l18);
mv.visitVarInsn(ALOAD, 4);
mv.visitVarInsn(ASTORE, 7);
Label l19 = new Label();
mv.visitLabel(l19);
mv.visitLineNumber(102, l19);
mv.visitVarInsn(ALOAD, 4);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/PageContext", "getServletContext", "()Ljavax/servlet/ServletContext;", false);
mv.visitInsn(POP);
Label l20 = new Label();
mv.visitLabel(l20);
mv.visitLineNumber(103, l20);
mv.visitVarInsn(ALOAD, 4);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/PageContext", "getServletConfig", "()Ljavax/servlet/ServletConfig;", false);
mv.visitInsn(POP);
Label l21 = new Label();
mv.visitLabel(l21);
mv.visitLineNumber(104, l21);
mv.visitVarInsn(ALOAD, 4);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/PageContext", "getOut", "()Ljavax/servlet/jsp/JspWriter;", false);
mv.visitVarInsn(ASTORE, 5);
Label l22 = new Label();
mv.visitLabel(l22);
mv.visitLineNumber(105, l22);
mv.visitVarInsn(ALOAD, 5);
mv.visitVarInsn(ASTORE, 6);
Label l23 = new Label();
mv.visitLabel(l23);
mv.visitLineNumber(107, l23);
mv.visitVarInsn(ALOAD, 5);
mv.visitLdcInsn("<html>\r\n");
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspWriter", "write", "(Ljava/lang/String;)V", false);
Label l24 = new Label();
mv.visitLabel(l24);
mv.visitLineNumber(108, l24);
mv.visitVarInsn(ALOAD, 5);
mv.visitLdcInsn("\r\n");
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspWriter", "write", "(Ljava/lang/String;)V", false);
Label l25 = new Label();
mv.visitLabel(l25);
mv.visitLineNumber(109, l25);
mv.visitVarInsn(ALOAD, 5);
mv.visitLdcInsn("\u0009<body>\r\n");
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspWriter", "write", "(Ljava/lang/String;)V", false);
Label l26 = new Label();
mv.visitLabel(l26);
mv.visitLineNumber(110, l26);
mv.visitVarInsn(ALOAD, 5);
mv.visitLdcInsn("\u0009\u0009");
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspWriter", "write", "(Ljava/lang/String;)V", false);
Label l27 = new Label();
mv.visitLabel(l27);
mv.visitLineNumber(111, l27);
mv.visitInsn(ACONST_NULL);
mv.visitVarInsn(ASTORE, 8);
Label l28 = new Label();
mv.visitLabel(l28);
mv.visitLineNumber(112, l28);
mv.visitVarInsn(ALOAD, 7);
mv.visitLdcInsn("clock");
mv.visitInsn(ICONST_1);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/PageContext", "getAttribute", "(Ljava/lang/String;I)Ljava/lang/Object;", false);
mv.visitTypeInsn(CHECKCAST, "dates/JspCalendar");
mv.visitVarInsn(ASTORE, 8);
Label l29 = new Label();
mv.visitLabel(l29);
mv.visitLineNumber(113, l29);
mv.visitVarInsn(ALOAD, 8);
Label l30 = new Label();
mv.visitJumpInsn(IFNONNULL, l30);
Label l31 = new Label();
mv.visitLabel(l31);
mv.visitLineNumber(114, l31);
mv.visitTypeInsn(NEW, "dates/JspCalendar");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "dates/JspCalendar", "<init>", "()V", false);
mv.visitVarInsn(ASTORE, 8);
Label l32 = new Label();
mv.visitLabel(l32);
mv.visitLineNumber(115, l32);
mv.visitVarInsn(ALOAD, 7);
mv.visitLdcInsn("clock");
mv.visitVarInsn(ALOAD, 8);
mv.visitInsn(ICONST_1);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/PageContext", "setAttribute", "(Ljava/lang/String;Ljava/lang/Object;I)V", false);
mv.visitLabel(l30);
mv.visitLineNumber(117, l30);
mv.visitVarInsn(ALOAD, 5);
mv.visitLdcInsn("\r\n");
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspWriter", "write", "(Ljava/lang/String;)V", false);
Label l33 = new Label();
mv.visitLabel(l33);
mv.visitLineNumber(118, l33);
mv.visitVarInsn(ALOAD, 5);
mv.visitLdcInsn("\u0009</body>\r\n");
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspWriter", "write", "(Ljava/lang/String;)V", false);
Label l34 = new Label();
mv.visitLabel(l34);
mv.visitLineNumber(119, l34);
mv.visitVarInsn(ALOAD, 5);
mv.visitLdcInsn("</html>\r\n");
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspWriter", "write", "(Ljava/lang/String;)V", false);
mv.visitLabel(l1);
mv.visitLineNumber(120, l1);
Label l35 = new Label();
mv.visitJumpInsn(GOTO, l35);
mv.visitLabel(l2);
mv.visitVarInsn(ASTORE, 8);
Label l36 = new Label();
mv.visitLabel(l36);
mv.visitLineNumber(121, l36);
mv.visitVarInsn(ALOAD, 8);
mv.visitTypeInsn(INSTANCEOF, "javax/servlet/jsp/SkipPageException");
mv.visitJumpInsn(IFNE, l6);
Label l37 = new Label();
mv.visitLabel(l37);
mv.visitLineNumber(122, l37);
mv.visitVarInsn(ALOAD, 6);
mv.visitVarInsn(ASTORE, 5);
Label l38 = new Label();
mv.visitLabel(l38);
mv.visitLineNumber(123, l38);
mv.visitVarInsn(ALOAD, 5);
Label l39 = new Label();
mv.visitJumpInsn(IFNULL, l39);
mv.visitVarInsn(ALOAD, 5);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspWriter", "getBufferSize", "()I", false);
mv.visitJumpInsn(IFEQ, l39);
mv.visitLabel(l3);
mv.visitLineNumber(125, l3);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEINTERFACE, "javax/servlet/http/HttpServletResponse", "isCommitted", "()Z", true);
Label l40 = new Label();
mv.visitJumpInsn(IFEQ, l40);
Label l41 = new Label();
mv.visitLabel(l41);
mv.visitLineNumber(126, l41);
mv.visitVarInsn(ALOAD, 5);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspWriter", "flush", "()V", false);
Label l42 = new Label();
mv.visitLabel(l42);
mv.visitLineNumber(127, l42);
mv.visitJumpInsn(GOTO, l39);
mv.visitLabel(l40);
mv.visitLineNumber(128, l40);
mv.visitVarInsn(ALOAD, 5);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspWriter", "clearBuffer", "()V", false);
mv.visitLabel(l4);
mv.visitLineNumber(130, l4);
mv.visitJumpInsn(GOTO, l39);
mv.visitLabel(l5);
mv.visitInsn(POP);
mv.visitLabel(l39);
mv.visitLineNumber(131, l39);
mv.visitVarInsn(ALOAD, 7);
Label l43 = new Label();
mv.visitJumpInsn(IFNULL, l43);
mv.visitVarInsn(ALOAD, 7);
mv.visitVarInsn(ALOAD, 8);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/PageContext", "handlePageException", "(Ljava/lang/Throwable;)V", false);
mv.visitJumpInsn(GOTO, l6);
mv.visitLabel(l43);
mv.visitLineNumber(132, l43);
mv.visitTypeInsn(NEW, "javax/servlet/ServletException");
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, 8);
mv.visitMethodInsn(INVOKESPECIAL, "javax/servlet/ServletException", "<init>", "(Ljava/lang/Throwable;)V", false);
mv.visitInsn(ATHROW);
mv.visitLabel(l6);
mv.visitLineNumber(135, l6);
mv.visitFieldInsn(GETSTATIC, "org/apache/jsp/jsp/dates/date_jsp", "_jspxFactory", "Ljavax/servlet/jsp/JspFactory;");
mv.visitVarInsn(ALOAD, 7);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspFactory", "releasePageContext", "(Ljavax/servlet/jsp/PageContext;)V", false);
Label l44 = new Label();
mv.visitJumpInsn(GOTO, l44);
mv.visitLabel(l7);
mv.visitLineNumber(134, l7);
mv.visitVarInsn(ASTORE, 9);
Label l45 = new Label();
mv.visitLabel(l45);
mv.visitLineNumber(135, l45);
mv.visitFieldInsn(GETSTATIC, "org/apache/jsp/jsp/dates/date_jsp", "_jspxFactory", "Ljavax/servlet/jsp/JspFactory;");
mv.visitVarInsn(ALOAD, 7);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspFactory", "releasePageContext", "(Ljavax/servlet/jsp/PageContext;)V", false);
Label l46 = new Label();
mv.visitLabel(l46);
mv.visitLineNumber(136, l46);
mv.visitVarInsn(ALOAD, 9);
mv.visitInsn(ATHROW);
mv.visitLabel(l35);
mv.visitLineNumber(135, l35);
mv.visitFieldInsn(GETSTATIC, "org/apache/jsp/jsp/dates/date_jsp", "_jspxFactory", "Ljavax/servlet/jsp/JspFactory;");
mv.visitVarInsn(ALOAD, 7);
mv.visitMethodInsn(INVOKEVIRTUAL, "javax/servlet/jsp/JspFactory", "releasePageContext", "(Ljavax/servlet/jsp/PageContext;)V", false);
mv.visitLabel(l44);
mv.visitLineNumber(137, l44);
mv.visitInsn(RETURN);
Label l47 = new Label();
mv.visitLabel(l47);
mv.visitLocalVariable("this", "Lorg/apache/jsp/jsp/dates/date_jsp;", null, l8, l47, 0);
mv.visitLocalVariable("request", "Ljavax/servlet/http/HttpServletRequest;", null, l8, l47, 1);
mv.visitLocalVariable("response", "Ljavax/servlet/http/HttpServletResponse;", null, l8, l47, 2);
mv.visitLocalVariable("_jspx_method", "Ljava/lang/String;", null, l9, l47, 3);
mv.visitLocalVariable("pageContext", "Ljavax/servlet/jsp/PageContext;", null, l18, l1, 4);
mv.visitLocalVariable("out", "Ljavax/servlet/jsp/JspWriter;", null, l13, l47, 5);
mv.visitLocalVariable("_jspx_out", "Ljavax/servlet/jsp/JspWriter;", null, l14, l47, 6);
mv.visitLocalVariable("_jspx_page_context", "Ljavax/servlet/jsp/PageContext;", null, l0, l47, 7);
mv.visitLocalVariable("clock", "Ldates/JspCalendar;", null, l28, l1, 8);
mv.visitLocalVariable("t", "Ljava/lang/Throwable;", null, l36, l6, 8);
mv.visitMaxs(0, 10);
mv.visitEnd();
}
Ramesh Subramanian
  • 944
  • 1
  • 12
  • 28
  • The `SimpleMethodVisitor`’s code is incomplete. Actually *everything* is missing. In contrast, most of the code of the other classes is irrelevant here. – Holger Feb 02 '16 at 10:56
  • Hi Holger, SimpleMethodVisitor contains only constuctor, is it required to override all the methods? I am just visiting the methods, not changing any method body – Ramesh Subramanian Feb 02 '16 at 11:07
  • 1
    That’s hard to believe as local variable numbers are different between the two screenshots and a no-op visitor won’t do that. Besides that, you should stop your habit of catching and ignoring exceptions. – Holger Feb 02 '16 at 11:28
  • Hi Holger, thanks for points. I too not able to believe that local variables are different. Further more, `date.jsp` and `dates.JspCalendar` are default Tomcat examples, not my code. I just removed the lines from the body tag of JSP for specific problem identification. Is the issue happens due to method inline or any other reason? – Ramesh Subramanian Feb 02 '16 at 12:05
  • I just realized that you are using the Instrumentation API and probably comparing the persistent byte code with the byte code received by the transformer. In this case, renumbering of the local variables might be possible, without changing the code’s meaning. But that’s not explaining the stack size issue. If you suspect ASM to calculate it wrong, you should post the entire method’s byte code (please, not as a screenshot) to allow possible reproduction of the problem. – Holger Feb 02 '16 at 19:17
  • Hi Holger, Thanks for your inputs. As you told, local variables are renumbered some time. Also attached the byte code of the entire method (_jspService). – Ramesh Subramanian Feb 03 '16 at 05:31
  • If required, will send you all the sources. Please note that my email id is - os.ramesh@yahoo.com – Ramesh Subramanian Feb 03 '16 at 05:39

1 Answers1

2

I found the solution to resolve such kind of VerifyError with java 1.7 and 1.8

In the transform() method of MyClassFileTransformer , i replaced the line

ClassWriter classWriter = new ClassWriter(classReader, writerFlag); with new line ClassWriter classWriter = new ByteCodeWriter(classReader, loader, writerFlag);

ByteCodeWriter.java

`

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;

public class ByteCodeWriter extends ClassWriter
{
  static final String OBJECT_REPRESENTATION = "java/lang/Object";
  ClassLoader classLoader;

  public ByteCodeWriter(ClassReader classReader, ClassLoader loader, int writerFlag)
  {
    super(classReader, writerFlag);
    this.classLoader = loader;
  }

  protected String getCommonSuperClass(String className1, String className2)
  {
    Class class1;
    Class class2;
    try
    {
      class1 = Class.forName(className1.replace('/', '.'), false, this.classLoader);
      class2 = Class.forName(className2.replace('/', '.'), false, this.classLoader);
    }
    catch (Exception th) {
      throw new RuntimeException(th.getMessage());
    }

    if (class1.isAssignableFrom(class2)) {
      return className1;
    }
    if (class2.isAssignableFrom(class1)) {
      return className2;
    }

    if ((class1.isInterface()) || (class2.isInterface())) {
      return "java/lang/Object";
    }

    do {
      class1 = class1.getSuperclass();
    }
    while (!(class1.isAssignableFrom(class2)));
    return class1.getName().replace('.', '/');
  }
}`

Basically I extend ClassWriter class and override the method getCommonSuperClass

Error while instrumenting class files (asm.ClassWriter.getCommonSuperClass) helped me to resolve the issue.

But i do not know, what is the necessity to override getCommonSuperClass.

Community
  • 1
  • 1
Ramesh Subramanian
  • 944
  • 1
  • 12
  • 28
  • 1
    ASM need this method to properly calculate StackMapFrame table. But in java environment could be a lot of classloaders and ASM could be loaded in different classloader than class which is loading instrumented class. Int that case `Class.forName` which is used here would not find required class. It is up to you to properly handle this method. – Grzesuav Feb 05 '16 at 16:30