jsr:使用javassist插入后字节码中存在错误
我尝试使用带有“insertAfter()”的javassist在方法之后添加代码。 但运行代码时报告了错误:jsr:使用javassist插入后字节码中存在错误,java,javassist,bytecode-manipulation,Java,Javassist,Bytecode Manipulation,我尝试使用带有“insertAfter()”的javassist在方法之后添加代码。 但运行代码时报告了错误: try { CtClass ctClass = ClassPool.getDefault().get(className.replace('/', '.')); CtMethod ctMethod = ctClass.getDeclaredMethod("display1"); ctMethod.insertBef
try {
CtClass ctClass = ClassPool.getDefault().get(className.replace('/', '.'));
CtMethod ctMethod = ctClass.getDeclaredMethod("display1");
ctMethod.insertBefore(
"name=\"我是name!这次用javassist了哦!\";" +
"value=\"我是value!\";" +
"System.out.println(\"我是加进去的哦,哈哈:\" + name);"
);
ctMethod.insertAfter("System.out.println(value);");
return ctClass.toBytecode();
} catch (Exception e) {
e.printStackTrace();
}
运行后,报告了错误:
线程“main”java.lang.VerifyError中出现异常:错误指令:a8
例外情况详情:
地点:
com/atlassian/api/examples/ForASMTestClass.display1()V @62: jsr
原因:
Error exists in the bytecode
字节码:
0x0000000: 2a12 28b5 0026 2a12 2cb5 002a b200 2ebb
0x0000010: 0030 59b7 0032 1234 b600 382a b400 3ab6
0x0000020: 003c b600 40b6 0042 b200 122a b400 18b6
0x0000030: 001a b200 122a b400 20b6 001a 014d a800
0x0000040: 04b1 4cb2 0044 2ab4 0046 b600 48a9 01
at transformer.modifycode.InstrumentationMain.main(InstrumentationMain.java:7)
加载类:java/lang/VerifyError
使用javap获取字节码:
public void display1();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=4, locals=4, args_size=1
0: aload_0
1: ldc #43 // String xx
3: putfield #41 // Field name:Ljava/lang/String;
6: getstatic #18 // Field java/lang/System.out:Ljava/io/PrintStream;
9: aload_0
10: getfield #24 // Field name:Ljava/lang/String;
13: invokevirtual #26 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
16: getstatic #18 // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_0
20: getfield #32 // Field value:Ljava/lang/String;
23: invokevirtual #26 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
26: goto 42
29: astore_1
30: getstatic #18 // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_0
34: getfield #32 // Field value:Ljava/lang/String;
37: invokevirtual #26 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: aload_1
41: athrow
42: getstatic #18 // Field java/lang/System.out:Ljava/io/PrintStream;
45: aload_0
46: getfield #32 // Field value:Ljava/lang/String;
49: invokevirtual #26 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
52: aconst_null
53: astore_3
54: jsr 58
57: return
58: astore_2
59: getstatic #45 // Field java/lang/System.out:Ljava/io/PrintStream;
62: aload_0
63: getfield #47 // Field value:Ljava/lang/String;
66: invokevirtual #49 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
69: ret 2
Exception table:
from to target type
6 29 29 any
LineNumberTable:
line 11: 6
line 12: 16
line 13: 26
line 14: 30
line 15: 40
line 14: 42
line 16: 52
LocalVariableTable:
Start Length Slot Name Signature
0 58 0 this Lcom/test/swing/ForASMTestClass;
StackMapTable: number_of_entries = 2
frame_type = 87 /* same_locals_1_stack_item */
stack = [ class java/lang/Throwable ]
frame_type = 12 /* same */
目前,我可以使用ASM在方法之后添加代码,但效率不高,因为很多字节码都需要手动编写。在javap命令输出中,如果您还提供类文件头(可以使用-v实现),它将显示类的主要版本,这将非常有用 根据您提供的信息,我打赌该类的主要版本是51(java 7)或52(java 8),因为在这种情况下不支持jrs操作码 如您所知(感谢@Holger提供直接链接。在第一次编辑中,我使用了a,因为我没有找到直接引用): 如果类文件版本号为51.0或更高,则jsr操作码或jsr_w操作码都不会出现在代码数组中 这可以解释为什么会出现验证错误 如果我不得不猜测为什么会出现该操作码,我会说您使用的是一个较旧的javassist版本,它仍然使用JSR操作码实现insertAfterMethod(finally语句使用了该操作码),如果您使用最新的javassist版本,它可能会得到修复 我知道这个答案更多的是基于一种猜测,即在实际的“确凿证据”中,可能并不准确。如果问题不是我所描述的,请编辑您的答案以添加更多信息,例如:
- 类的标题信息,包括次要版本和主要版本
- javap输出在javassist操作之前
- javassist版本
- 运行代码的当前JVM(品牌和版本)
code
具有StackMapTable
属性。html网页链接是:“如果类文件版本号为51.0或更高,那么jsr操作码或jsr_w操作码都不会出现在代码数组中”@Holger:谢谢,在这种基于(大)猜测的回答中,很高兴看到其他人同意我的观点。关于StackMapTable,Java1.6中引入了它以加快字节码验证。所以op仍然可能运行JVM 1.6,其中jsr应该是一个有效的操作码,而这只是javassist注入造成的混乱。@Holger:还感谢您在规范中提供的HTML链接!我将更新答案只有版本50,其中定义了StackMapTable
属性,但没有立即禁止jsr
指令。请注意,StackMapTable
无效,因为在子例程注入之后,它应该有三个条目,而不是两个条目。但是对于v50类文件,如果StackMapTable
验证失败,那么验证器将故障切换到旧文件。因此,版本号很可能高于50,特别是当消息明确表示它根本不喜欢jsr
时。@Holger:分析得很好,我没有注意到这一点!谢谢你提供更多的信息