java.lang.VerifyError:字节码检测后的局部变量类型错误
我插入了一些Java字节码。我想做的是: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.
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
,typeString
。然后它到达a2.clear()
,发现您使用的变量在堆栈映射表中不存在,验证失败。好的,谢谢!我如何将变量添加到堆栈映射表中?我希望visitLocalVariable
能帮我做到这一点…您肯定想使用该标志让ClassWriter
为您做到这一点…