[jboss-jira] [JBoss JIRA] Commented: (JASSIST-53) VerifyError (constructor must call super() or this()) through ConstructorCall#replace when block includes a try/catch block

Yanic Inghelbrecht (JIRA) jira-events at lists.jboss.org
Thu Apr 17 04:35:44 EDT 2008


    [ 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.html#9839

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

        



More information about the jboss-jira mailing list