java - 使用Javassist修改代码生成java.lang.VerifyError : Expecting to find integer on stack

标签 java bytecode javassist bytecode-manipulation

我使用 javassist 重写了一个名为 compile 的方法(该方法采用 String 数组作为参数):我创建了一个新方法,其签名为 compile 方法(它是原始方法的副本),将实际的 compile 方法重命名为 compile$Impl 并添加了对 Mine 类的一些调用。

复制是这样完成的:

CtMethod interceptMethod = CtNewMethod.copy(method, methodName, ctClass, null);

javassist重写的代码:

try { 
  com.company.CustomClass.instance().preintercept(this);
  boolean result = compile$impl($$);
  result = com.company.CustomClass.instance().dointercept(result, new Object[] { this , $1 });
  return result;
 } finally { 
    com.company.CustomClass.instance().postintercept(this);
 }

代码被写入一个名为 body 的 StringBuffer 变量中,后面的变量的内容被写入新的 compile 方法的主体中,如下所示:

        interceptMethod.setBody(body.toString());
        ctClass.addMethod(interceptMethod);

我的com.company.CustomClass具有由新的compile方法调用的方法:

   public Object dointercept(boolean retval, Object.. args) {
        return (Boolean)returned;
    }

public static synchronized CustomClass instance() {
    // _instance is already instanciated when this method is called
    return _instance;
}

public void preintercept(Object arg) {
 // some stuff before
}

public void postintercept(Object arg) {
 // some stuff after

}

执行代码时,我收到一个验证错误:

java.lang.VerifyError: (class: org/eclipse/jdt/internal/compiler/batch/Main, method: compile signature: ([Ljava/lang/String;)Z) Expecting to find integer on stack

我已将修改后的类的字节码写入磁盘,以尝试找出问题。以下是我从新的 compile 方法中获得的结果:

   public boolean compile(java.lang.String[] arg0) {
        try {
            0 invokestatic 2130;      /* com.company.CustomClass.instance() */
            3 aload_0;
            4 invokevirtual 2134;     /* void preintercept(java.lang.Object arg0) */
            7 aload_0;
            8 aload_1;
            9 invokevirtual 2136;     /* boolean compile$impl(java.lang.String[] arg0) */
            12 istore_2;
            13 invokestatic 2130;     /* com.company.CustomClass.instance() */
            16 iload_2;
            17 iconst_2;
            18 anewarray 4;           /* new java.lang.Object[] */
            21 dup;
            22 iconst_0;
            23 aload_0;
            24 aastore;
            25 dup;
            26 iconst_1;
            27 aload_1;
            28 aastore;
            29 invokevirtual 2140;    /* java.lang.Object dointercept(boolean arg0, java.lang.Object[] arg1) */
            32 istore_2;
            33 iload_2;
            34 istore_3;
            35 goto 17;
            38 iload_3;
            39 ireturn;
        }
        finally {                 /* covers bytes 0 to 40 */
            40 astore 4;
            42 invokestatic 2130;     /* com.company.CustomClass.instance() */
            45 aload_0;
            46 invokevirtual 2143;    /* void postintercept(java.lang.Object arg0) */
            49 aload 4;
            51 athrow;
            52 invokestatic 2130;     /* com.company.CustomClass.instance() */
            55 aload_0;
            56 invokevirtual 2143;    /* void postintercept(java.lang.Object arg0) */
            59 goto -21;
        }
    }

当我对类的字节码进行类型分析时,错误出现在第 32 行 istore_2 指令处。分析如下:

Type based analysis: compile([Ljava/lang/String;)Z
Offset  Bytecode        Stack before              Stack after               
----------------------------------------------------------------------------
0       invokestatic    <empty>                   L                         
3       aload_0         L                         L, L                      
4       invokevirtual   L, L                      <empty>                   
7       aload_0         <empty>                   L                         
8       aload_1         L                         L, L                      
9       invokevirtual   L, L                      I                         
12      istore_2        I                         <empty>                   
13      invokestatic    <empty>                   L                         
16      iload_2         L                         L, I                      
17      iconst_2        L, I                      L, I, I                   
18      anewarray       L, I, I                   L, I, L                   
21      dup             L, I, L                   L, I, L, L                
22      iconst_0        L, I, L, L                L, I, L, L, I             
23      aload_0         L, I, L, L, I             L, I, L, L, I, L          
24      aastore         L, I, L, L, I, L          L, I, L                   
25      dup             L, I, L                   L, I, L, L                
26      iconst_1        L, I, L, L                L, I, L, L, I             
27      aload_1         L, I, L, L, I             L, I, L, L, I, L          
28      aastore         L, I, L, L, I, L          L, I, L                   
29      invokevirtual   L, I, L                   L                         
32      istore_2        L                         <empty>                   
                        Error: Expecting to find I on stack, type on stack L. 

33      iload_2         <empty>                   I                         
34      istore_3        I                         <empty>                   
35      goto            <empty>                   <empty>                   
38      iload_3         <empty>                   I                         
39      ireturn         I                         <empty>                   
40      astore          L                         <empty>                   
42      invokestatic    <empty>                   L                         
45      aload_0         L                         L, L                      
46      invokevirtual   L, L                      <empty>                   
49      aload           <empty>                   L                         
51      athrow          L                         L                         
52      invokestatic    <empty>                   L                         
55      aload_0         L                         L, L                      
56      invokevirtual   L, L                      <empty>                   
59      goto            <empty>                   <empty>                   
----------------------------------------------------------------------------

但我不明白为什么存储 int 会出现问题,因为我知道 我没有使用任何整数(我确信遗漏了一些东西)。

谢谢

最佳答案

这是因为 doIntercept 返回一个 Boolean Object,并且它被存储为指向对象的指针(即 L 出现在 29)。然后,它尝试将此值存储为原始 boolean 值,即原始整数 I。

如果您使用显式强制转换,或在末尾添加 .booleanValue()

com.company.CustomClass.instance().dointercept(result, new Object[] { this , $1 }).booleanValue();

这可能有用吗?

问题是它没有将对象的“自动拆箱”编译为基元。

https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

关于java - 使用Javassist修改代码生成java.lang.VerifyError : Expecting to find integer on stack,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33676910/

相关文章:

java - java中如何获取数字证书的 key 使用情况

java - 无法在 Android 中解析为整数

java - Java字节码如何应对多平台?

java - 用于字节码检索的解析器 dex 文件

java - 执行后在Java代理中运行代码?帖子主要?

javascript - RESTful 客户端中的 Ajax 请求

Java 8 lambda 表达式字节码一致性

java - 获取 Java 类型的签名作为字符串

java - 使用 javassist 创建类并使其可用

java - 用于检查字符串中重复字符的正则表达式