java.lang.VerifyError:字节码检测后的局部变量类型错误

java.lang.VerifyError:字节码检测后的局部变量类型错误,java,bytecode,java-bytecode-asm,Java,Bytecode,Java Bytecode Asm,我插入了一些Java字节码。我想做的是: InstrumentStackElem[] stack; int stackpointer; void foo(){ stackpointer = (stackpointer + 1) % stack.length; InstrumentStackElem localref = stack[stackpointer]; localref.init(); //before each return localref.

我插入了一些Java字节码。我想做的是:

InstrumentStackElem[] stack;
int stackpointer;
void foo(){
    stackpointer = (stackpointer + 1) % stack.length;
    InstrumentStackElem localref = stack[stackpointer];
    localref.init();

    //before each return
    localref.clear();
    stackpointer = (stackpointer -1 +stack.length) % stack.length;
因此,在每个方法的开头,我递增stackpointer并获取对数组元素的本地引用。在每次返回之前,我调用元素上的clear方法并再次减少计数器

当我尝试访问localref.clear()调用的字段时,我总是得到一个java.lang.VerifyError

示例方法:

public static boolean isValidName(final String s) {
        if (!s.matches("[_a-zA-Z][_a-zA-Z0-9]*")) {
            return false;
        }

        if (s.toCharArray()[0] == '_') { // this check should not be -> this is
                                            // a bug
            return false;
        }

        return true;
    }
相应的插装字节码

 public static boolean isValidName(java.lang.String);
    Code:
       0: getstatic     #38                 // Field instrumentation_static_stackpointer:I
       3: iconst_1
       4: iadd
       5: bipush        16
       7: irem
       8: putstatic     #38                 // Field instrumentation_static_stackpointer:I
      11: getstatic     #40                 // Field instrumentation_static_stack:[Lme/instrumentor/InstrumentStackElem;
      14: getstatic     #38                 // Field instrumentation_static_stackpointer:I
      17: aaload
      18: astore_2
      19: aload_2
      20: bipush        -1
      22: ldc           #113                // String isValidName_Ljava_lang_String__Z
      24: invokevirtual #48                 // Method me/instrumentor/InstrumentStackElem.init:(ILjava/lang/String;)V
      27: aload_0
      28: ldc           #115                // String [_a-zA-Z][_a-zA-Z0-9]*
      30: invokevirtual #118                // Method java/lang/String.matches:(Ljava/lang/String;)Z
      33: ifne          56
      36: iconst_0
      37: aload_2
      38: invokevirtual #110                // Method me/instrumentor/InstrumentStackElem.clear:()V
      41: getstatic     #38                 // Field instrumentation_static_stackpointer:I
      44: iconst_1
      45: isub
      46: bipush        16
      48: iadd
      49: bipush        16
      51: irem
      52: putstatic     #38                 // Field instrumentation_static_stackpointer:I
      55: ireturn
      56: aload_0
      57: invokevirtual #122                // Method java/lang/String.toCharArray:()[C
      60: iconst_0
      61: caload
      62: bipush        95
      64: if_icmpne     87
      67: iconst_0
      68: aload_2
      69: invokevirtual #110                // Method me/instrumentor/InstrumentStackElem.clear:()V
      72: getstatic     #38                 // Field instrumentation_static_stackpointer:I
      75: iconst_1
      76: isub
      77: bipush        16
      79: iadd
      80: bipush        16
      82: irem
      83: putstatic     #38                 // Field instrumentation_static_stackpointer:I
      86: ireturn
      87: iconst_1
      88: aload_2
      89: invokevirtual #110                // Method me/instrumentor/InstrumentStackElem.clear:()V
      92: getstatic     #38                 // Field instrumentation_static_stackpointer:I
      95: iconst_1
      96: isub
      97: bipush        16
      99: iadd
     100: bipush        16
     102: irem
     103: putstatic     #38                 // Field instrumentation_static_stackpointer:I
     106: ireturn
这正是引发的错误:

  Unexpected error: Lexer: java.lang.VerifyError: Bad local variable type
Exception Details:
  Location:
    lexer/Lexer.isValidName(Ljava/lang/String;)Z @68: aload_2
  Reason:
    Type top (current frame, locals[2]) is not assignable to reference type
  Current Frame:
    bci: @68
    flags: { }
    locals: { 'java/lang/String' }
    stack: { integer }
  Bytecode:
    0000000: b200 2604 6010 1070 b300 26b2 0028 b200
    0000010: 2632 4d2c 10ff 1271 b600 302a 1273 b600
    0000020: 769a 0017 032c b600 6eb2 0026 0464 1010
    0000030: 6010 1070 b300 26ac 2ab6 007a 0334 105f
    0000040: a000 1703 2cb6 006e b200 2604 6410 1060
    0000050: 1010 70b3 0026 ac04 2cb6 006e b200 2604
    0000060: 6410 1060 1010 70b3 0026 ac            
  Stackmap Table:
    same_frame(@56)
    same_frame(@87)
我使用asm库插入方法,并使用
this.method.visitLocalVariable(“localstackref”,“Lme/instrumentor/InstrumentStackElem;”,null,bl,el,this.stackelementindex);
添加局部变量。
stackelementindex
在本例中为2


有人能帮我吗?

生成的字节码是正确的,除了忘记更新stackmap表

以下是生成字节码的伪代码供参考

instrumentation_static_stackpointer = (instrumentation_static_stackpointer + 1) % 16
a2 = instrumentation_static_stack[instrumentation_static_stackpointer]
a2.init(-1, "isValidName_Ljava_lang_String__Z")
if (!s.matches("[_a-zA-Z][_a-zA-Z0-9]*")) goto L56
a2.clear()
instrumentation_static_stackpointer = (instrumentation_static_stackpointer - 1 + 16) % 16
return 0

L56:
if (s.toCharArray()[0] != 95) goto L87
a2.clear()
instrumentation_static_stackpointer = (instrumentation_static_stackpointer - 1 + 16) % 16
return 0

L87:
instrumentation_static_stackpointer = (instrumentation_static_stackpointer - 1 + 16) % 16
return 1

问题在于,在字节码版本51.0+中(您可能正在使用字节码版本),必须在
StackMapTable
属性中包含字节码变量的类型信息。但是,您没有更新它以包含新变量
a2
的类型。只有在任何时候都有一个跳转或跳转目标。因此,当它到达L56时,它查阅表以查看传入的类型是什么,表中说唯一的变量是
s
,type
String
。然后它到达
a2.clear()
,发现您使用的变量在堆栈映射表中不存在,验证失败。

好的,谢谢!我如何将变量添加到
堆栈映射表中?我希望
visitLocalVariable
能帮我做到这一点…您肯定想使用该标志让
ClassWriter
为您做到这一点…