0
使用Javassist 3.20.0.GA,我試圖將代碼注入一個空循環。使用Javassist,如何將代碼添加到空循環?
我試過的一切,我試圖創建修改後的類的新實例,我一直運行到一個java.lang.VerifyError錯誤。
我試圖將問題隔離到無法成功運行的小程序。
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.Bytecode;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.CodeIterator;
import javassist.bytecode.InstructionPrinter;
import javassist.bytecode.MethodInfo;
import javassist.compiler.Javac;
public class EmptyLoopTest {
private void testEmptyLoopModification() throws Exception {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get(EmptyLoopTest.class.getName() + "$EmptyLoopClass");
CtMethod m = cc.getDeclaredMethod("emptyLoopMethod");
printMethod("Before modifications", m);
MethodInfo methodInfo = m.getMethodInfo();
CodeAttribute ca = methodInfo.getCodeAttribute();
CodeIterator ci = ca.iterator();
Javac jv = new Javac(cc);
jv.compileStmnt("System.out.println(\"injected into loop\");");
Bytecode b = jv.getBytecode();
adjustCodeAttributeIfNeeded(b, ca);
ci.insertAt(0, b.get());
printMethod("After modifications", m);
Class c = cc.toClass();
logInfo("Attempting to create instance of modified class");
c.newInstance();
}
private void adjustCodeAttributeIfNeeded(Bytecode b, CodeAttribute ca){
int locals = b.getMaxLocals();
int stack = b.getMaxStack();
if(stack > ca.getMaxStack()) {
ca.setMaxStack(stack);
}
if(locals > ca.getMaxLocals()) {
ca.setMaxLocals(locals);
}
}
private void printMethod(String title, CtMethod m){
logInfo(title);
InstructionPrinter instructionPrinter = new InstructionPrinter(System.out);
instructionPrinter.print(m);
}
private void logInfo(String message){
System.out.println("");
System.out.println("------" + message);
}
public class EmptyLoopClass {
public void emptyLoopMethod() {
for(;;){
}
}
}
public static void main(String[] args) throws Exception {
// have errors written to sysout so all output from this program is in order
System.setErr(System.out);
new EmptyLoopTest().testEmptyLoopModification();
}
}
當我運行這個程序,以下是寫入到控制檯..
------Before modifications
0: goto 0
------After modifications
0: getstatiC#32 = Field java.lang.System.out(Ljava/io/PrintStream;)
3: ldC#34 = "injected into loop"
5: invokevirtual #40 = Method java.io.PrintStream.println((Ljava/lang/String;)V)
8: goto 8
------Attempting to create instance of modified class
Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 8
Exception Details:
Location:
EmptyLoopTest$EmptyLoopClass.emptyLoopMethod()V @8: goto
Reason:
Expected stackmap frame at this location.
Bytecode:
0x0000000: b200 2012 22b6 0028 a700 00
Stackmap Table:
same_frame(@0)
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
at java.lang.Class.getConstructor0(Class.java:3075)
at java.lang.Class.newInstance(Class.java:412)
at EmptyLoopTest.testEmptyLoopModification(EmptyLoopTest.java:35)
at EmptyLoopTest.main(EmptyLoopTest.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Process finished with exit code 1
如果按預期工作一切都被我所期待的修改轉到0,而不是後的GOTO指令當前顯示的內容是goto 8.這就好像調用javassist.bytecode.CodeIterator#insertAt時,StackMapTable沒有適當調整。
任何人都可以發現我在這裏做錯了嗎?
感謝,
埃裏克