Sono nuovo ad ASM e desidero qualche aiuto correlato alla trasformazione bytecode.Aggiunta del blocco try/catch in bytecode tramite ASM
Domanda: Vorrei aggiungere il blocco try/catch per l'intero metodo in bytecode tramite ASM e voglio eseguire il metodo senza utilizzare l'opzione java -noverify. Posso aggiungere il blocco try/catch per l'intero metodo, ma quando ho provato ad eseguire il metodo sto ottenendo 'java.lang.VerifyError'. Se utilizzo l'opzione java -noverify, verrà eseguita. Mi aiuti per favore.
Di seguito sono riportati i dettagli.
public class Example {
public static void hello() {
System.out.println("Hello world");
}
}
voglio trasformare il codice di cui sopra, come di seguito l'introduzione di blocchi try/catch, con strumentazione ASM bytecode.
public class Example {
public static void hello() {
try
{
System.out.println("Hello world");
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
seguito code Aggiungi blocco try/catch, ma non riesce a eseguire il codice con l'opzione -noverify fuori java.
public class InstrumentExample {
/**
* Our custom method modifier method visitor class. It delegate all calls to
* the super class. Do our logic of adding try/catch block
*
*/
public static class ModifierMethodWriter extends MethodVisitor {
// methodName to make sure adding try catch block for the specific
// method.
private String methodName;
// below label variables are for adding try/catch blocks in instrumented
// code.
private Label lTryBlockStart;
private Label lTryBlockEnd;
private Label lCatchBlockStart;
private Label lCatchBlockEnd;
/**
* constructor for accepting methodVisitor object and methodName
*
* @param api: the ASM API version implemented by this visitor
* @param mv: MethodVisitor obj
* @param methodName : methodName to make sure adding try catch block for the specific method.
*/
public ModifierMethodWriter(int api, MethodVisitor mv, String methodName) {
super(api, mv);
this.methodName = methodName;
}
// We want to add try/catch block for the entire code in the method
// so adding the try/catch when the method is started visiting the code.
@Override
public void visitCode() {
super.visitCode();
// adding try/catch block only if the method is hello()
if (methodName.equals("hello")) {
lTryBlockStart = new Label();
lTryBlockEnd = new Label();
lCatchBlockStart = new Label();
lCatchBlockEnd = new Label();
// set up try-catch block for RuntimeException
visitTryCatchBlock(lTryBlockStart, lTryBlockEnd,
lCatchBlockStart, "java/lang/Exception");
// started the try block
visitLabel(lTryBlockStart);
}
}
@Override
public void visitMaxs(int maxStack, int maxLocals) {
// closing the try block and opening the catch block if the method
// is hello()
if (methodName.equals("hello")) {
// closing the try block
visitLabel(lTryBlockEnd);
// when here, no exception was thrown, so skip exception handler
visitJumpInsn(GOTO, lCatchBlockEnd);
// exception handler starts here, with RuntimeException stored
// on stack
visitLabel(lCatchBlockStart);
// store the RuntimeException in local variable
visitVarInsn(ASTORE, 2);
// here we could for example do e.printStackTrace()
visitVarInsn(ALOAD, 2); // load it
visitMethodInsn(INVOKEVIRTUAL, "java/lang/Exception",
"printStackTrace", "()V", false);
// exception handler ends here:
visitLabel(lCatchBlockEnd);
}
super.visitMaxs(maxStack, maxLocals);
}
}
/**
* Our class modifier class visitor. It delegate all calls to the super
* class Only makes sure that it returns our MethodVisitor for every method
*
*/
public static class ModifierClassWriter extends ClassVisitor {
private int api;
public ModifierClassWriter(int api, ClassWriter cv) {
super(api, cv);
this.api = api;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature,
exceptions);
// Our custom MethodWriter
ModifierMethodWriter mvw = new ModifierMethodWriter(api, mv, name);
return mvw;
}
}
public static void main(String[] args) throws IOException {
DataOutputStream dout = null;
try {
// loading the class
InputStream in = InstrumentExample.class
.getResourceAsStream("Example.class");
ClassReader classReader = new ClassReader(in);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
// Wrap the ClassWriter with our custom ClassVisitor
ModifierClassWriter mcw = new ModifierClassWriter(ASM4, cw);
ClassVisitor cv = new CheckClassAdapter(mcw);
classReader.accept(cv, 0);
byte[] byteArray = cw.toByteArray();
dout = new DataOutputStream(new FileOutputStream(new File("Example.class")));
dout.write(byteArray);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (dout != null)
dout.close();
}
}
}
Per il debug ho usato CheckClassAdapter e ho avuto sotto problema di verifica.
Message:org.objectweb.asm.tree.analysis.AnalyzerException: Execution can fall off end of the code
at org.objectweb.asm.tree.analysis.Analyzer.findSubroutine(Unknown Source)
at org.objectweb.asm.tree.analysis.Analyzer.findSubroutine(Unknown Source)
at org.objectweb.asm.tree.analysis.Analyzer.analyze(Unknown Source)
at org.objectweb.asm.util.CheckClassAdapter.verify(Unknown Source)
at org.objectweb.asm.util.CheckClassAdapter.verify(Unknown Source)
at com.mfr.instrumentation.selenium.work.InstrumentExample.main(InstrumentExample.java:166)
hello()V
00000 ? : L0
00001 ? : GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
00002 ? : LDC "Hello world"
00003 ? : INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
00004 ? : RETURN
00005 ? : L1
00006 ? : GOTO L2
00007 ? : L3
00008 ? : ASTORE 2
00009 ? : ALOAD 2
00010 ? : INVOKEVIRTUAL java/lang/Exception.printStackTrace()V
00011 ? : L2
TRYCATCHBLOCK L0 L1 L3 java/lang/Exception
Non ho compreso il messaggio di verifica precedente.
Qual è la domanda? – biziclop
Domanda è come posso trasformare il mio codice iniziale con il blocco try/catch sul mio ultimo codice avendo provato/catturare il blocco usando la strumentazione bytecode ASM. –