ASM 5.0.3 With Java 1.8 incorrect maxStack with Java.lang.VerifyError: Operand stack overflow
ASM 5.0.3 With Java 1.8 incorrect maxStack with Java.lang.VerifyError: Operand stack overflow
使用 ASM 5.0.3(使用 Java 1.8.0_65 & Tomcat 8.0.30),访问 JSP (date.jsp ) 方法 - _JSP(_jspService) ,低于异常
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: .......................
注意:我没有更改方法的字节码,只是访问使用 ASM 5.0.3 的 MethodVisitor class 的方法。
date.jsp
<html>
<%@ page session="false"%>
<body>
<jsp:useBean id='clock' scope='page' class='dates.JspCalendar' type="dates.JspCalendar"/>
</body>
</html>
注意:
如果我删除 <jsp:useBean ..../>
, JSP 页面执行正常并且没有得到任何 java.lang.VerifyError
另附上我的代码大纲:
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);
}`
注意:编译的JSPclass版本是51,所以ASM使用,ClassWriter.COMPUTE_FRAMES
和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 );
}
我使用 TraceClassVisitor
在有和没有访问 _jspService
方法的情况下打印了 class - org/apache/jsp/jsp/dates/date_jsp
的字节码
pw = new PrintWriter(homeFolder + File.separator + "date.log");
ClassReader cr = new ClassReader(classfileBuffer);
cr.accept(new TraceClassVisitor(null, new ASMifier(), pw), ClassReader.EXPAND_FRAMES);
似乎 ASM 在访问 _jspService 方法时计算了错误的最大堆栈 - mv.visitMaxs(0, 10)
而不是 mv.visitMaxs(8, 10)
附上正确最大堆栈的屏幕截图
错误的最大筹码
作为参考,附上 _jspService 方法的编译版本
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);
}
}
}
如何解决声明 JSP Bean 时发生的 java.lang.VerifyError?
(要么)
需要在 ASM 方面做些什么来克服这个问题?提前致谢
注:
相同的代码适用于 Java 6 和 Tomcat 6
编辑 #1,Holger 附加了方法 _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();
}
我找到了使用 java 1.7 和 1.8
解决此类 VerifyError 的解决方案
在 MyClassFileTransformer
的 transform()
方法中,我替换了行
ClassWriter classWriter = new ClassWriter(classReader, writerFlag);
换行
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('.', '/');
}
}`
基本上我扩展 ClassWriter
class 并覆盖方法 getCommonSuperClass
Error while instrumenting class files (asm.ClassWriter.getCommonSuperClass) 帮我解决了这个问题。
但我不知道,有什么必要覆盖getCommonSuperClass
。
使用 ASM 5.0.3(使用 Java 1.8.0_65 & Tomcat 8.0.30),访问 JSP (date.jsp ) 方法 - _JSP(_jspService) ,低于异常
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: .......................
注意:我没有更改方法的字节码,只是访问使用 ASM 5.0.3 的 MethodVisitor class 的方法。
date.jsp
<html>
<%@ page session="false"%>
<body>
<jsp:useBean id='clock' scope='page' class='dates.JspCalendar' type="dates.JspCalendar"/>
</body>
</html>
注意:
如果我删除 <jsp:useBean ..../>
, JSP 页面执行正常并且没有得到任何 java.lang.VerifyError
另附上我的代码大纲:
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);
}`
注意:编译的JSPclass版本是51,所以ASM使用,ClassWriter.COMPUTE_FRAMES
和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 );
}
我使用 TraceClassVisitor
在有和没有访问_jspService
方法的情况下打印了 class - org/apache/jsp/jsp/dates/date_jsp
的字节码
pw = new PrintWriter(homeFolder + File.separator + "date.log");
ClassReader cr = new ClassReader(classfileBuffer);
cr.accept(new TraceClassVisitor(null, new ASMifier(), pw), ClassReader.EXPAND_FRAMES);
似乎 ASM 在访问 _jspService 方法时计算了错误的最大堆栈 - mv.visitMaxs(0, 10)
而不是 mv.visitMaxs(8, 10)
附上正确最大堆栈的屏幕截图
错误的最大筹码
作为参考,附上 _jspService 方法的编译版本
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);
}
}
}
如何解决声明 JSP Bean 时发生的 java.lang.VerifyError? (要么) 需要在 ASM 方面做些什么来克服这个问题?提前致谢
注:
相同的代码适用于 Java 6 和 Tomcat 6
编辑 #1,Holger 附加了方法 _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();
}
我找到了使用 java 1.7 和 1.8
解决此类 VerifyError 的解决方案在 MyClassFileTransformer
的 transform()
方法中,我替换了行
ClassWriter classWriter = new ClassWriter(classReader, writerFlag);
换行
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('.', '/');
}
}`
基本上我扩展 ClassWriter
class 并覆盖方法 getCommonSuperClass
Error while instrumenting class files (asm.ClassWriter.getCommonSuperClass) 帮我解决了这个问题。
但我不知道,有什么必要覆盖getCommonSuperClass
。