[
http://jira.jboss.com/jira/browse/JASSIST-53?page=comments#action_12409278 ]
Yanic Inghelbrecht commented on JASSIST-53:
-------------------------------------------
This is invalid because super() is not the first statement.
Actually, I think that this is only a Java language imitation, not a JVM limitation.
I believe the most relevant part of the JVM spec is :
"A valid instruction sequence must not have an uninitialized object on the operand
stack or in a local variable during a backwards branch, or in a local variable in code
protected by an exception handler or a finally clause."
You can find it in the last paragraph of section 4.9.4 in JVM spec, 2nd ed.
Link to section 4.9.4 :
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.htm...
I suspect your argument is not accurate, because when the above example is changed to use
a finally block, the code after replacement becomes
public Client() { try { super(); } finally {} }
for which the verifier does not complain.
In any case, by 'rephrasing' my code as explained in JASSIST-52, I was able to
catch exceptions thrown by the super constructor. So it is possible after all.
For example, when the replacement becomes
"{try {$_=$proceed($$);} catch (Throwable t) {throw t;}}";
the verifier does not complain either.
For me, this is no longer an issue.
Again, thanks for the help.
Best regards,
Yanic
VerifyError (constructor must call super() or this()) through
ConstructorCall#replace when block includes a try/catch block
---------------------------------------------------------------------------------------------------------------------------
Key: JASSIST-53
URL:
http://jira.jboss.com/jira/browse/JASSIST-53
Project: Javassist
Issue Type: Bug
Environment: javassist 3.7.1 (from cvs HEAD), jdk 1.6.0_03 on winXP
Reporter: Yanic Inghelbrecht
Assigned To: Shigeru Chiba
Included is the simplest test case I could find that reproduces the error, it consists of
two classes : Client (to be instrumented) and Main (does the instrumentation).
When run, it produces the following exception trace :
Exception in thread "main" java.lang.VerifyError: (class:
test_verify_error_with_try_catch_in_replace_for_constructor_call/Client, method:
<init> signature: ()V) Constructor must call super() or this()
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
at java.lang.Class.getConstructor0(Unknown Source)
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at
test_verify_error_with_try_catch_in_replace_for_constructor_call.Main.main(Main.java:31)
Also, when the replacement block uses $0 (the constructed object), for example :
String block = "{try {$_=$proceed($$);} catch (Throwable t)
{System.out.println($0);}}";
the error message changes to :
Exception in thread "main" java.lang.VerifyError: (class:
test_verify_error_with_try_catch_in_replace_for_constructor_call/Client, method:
<init> signature: ()V) Register 1 contains wrong type
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
at java.lang.Class.getConstructor0(Unknown Source)
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at
test_verify_error_with_try_catch_in_replace_for_constructor_call.Main.main(Main.java:31)
Again, this is related (for me at least) to JIRA JAVASSIST 51 and 52, since those also
deal with adding a try/catch block using replace in an ExprEditor#edit method.
So far I've reported three issues all related to adding try/catch block with a
replace in ExprEditor#edit :
51 for NewExpr
52 for MethodCall
53 for ConstructorCall
I don't use the other ExprEditor#edit methods (i.e. edit(Handler), edit(FieldAccess),
...), so I don't expect to report any similar issues. However, you may want to check
them to see if they suffer from the same problem.
I hope it's an easy fix for you!
Best regards,
Yanic
-- source for Client.java
package test_verify_error_with_try_catch_in_replace_for_constructor_call;
public class Client {
//
}
-- source for Main.java
package test_verify_error_with_try_catch_in_replace_for_constructor_call;
import java.lang.reflect.Method;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Loader;
import javassist.NotFoundException;
import javassist.Translator;
import javassist.expr.ConstructorCall;
import javassist.expr.ExprEditor;
public class Main {
public static void main(String[] args) throws Exception {
ClassPool pool = new ClassPool(true);
Loader cl = new Loader();
try {
cl.addTranslator(pool, new MyTranslator());
} catch (Exception e) {
e.printStackTrace();
return;
}
// load the Client class
Class
clientClass=cl.loadClass("test_verify_error_with_try_catch_in_replace_for_constructor_call.Client");
// create an instance
Object client=clientClass.newInstance();
}
static public class MyTranslator extends ExprEditor implements Translator {
public void onLoad(ClassPool pool, String classname) throws NotFoundException,
CannotCompileException {
CtClass cc = pool.get(classname);
modify(cc);
}
public void modify(CtClass c) throws CannotCompileException {
for (CtBehavior b : c.getDeclaredBehaviors()) {
b.instrument(this);
}
}
@Override
public void edit(ConstructorCall cc) throws CannotCompileException {
// simple proceed surrounded by a try/catch block
// each block gives a different VerifyError
String block = "{try {$_=$proceed($$);} catch (Throwable t) {}}";
// String block = "{try {$_=$proceed($$);} catch (Throwable t)
{System.out.println($0);}}";
cc.replace(block);
}
public void start(ClassPool pool) throws NotFoundException, CannotCompileException {
// do nothing
}
}
}
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://jira.jboss.com/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira