-
1. Re: How to print out exception in a method?
adinn Sep 27, 2019 6:16 AM (in response to leiyu)Hi Lei Yu,
Let's just use Java syntax formatting so we can read your code a bit better
public void myMethod(PrintWriter out) { ConcurrentMap<string, string=""> applicationMap = new ConcurrentHashMap<string, string="">(); // The FileWriter constructor throws IOException, which must be caught. System.out.println("SecondServlet.myMethod: just in"); // PrintWriter out = null; int start = 0; try { out = new PrintWriter(new FileWriter("OutFile.txt")); System.out.println("args[" + Integer.toString(start) ); for (int i = 0; i < SIZE; i++) { // The get(int) method throws IndexOutOfBoundsException, which must be caught. out.println("Value at: " + i + " = " + list.get(11)); } } catch (IOException ce) { applicationMap.put("error", "test1"); ce.printStackTrace(); } catch (IndexOutOfBoundsException ie) { System.out.println("SecondServlet.myMethod idenxoutofbound"); applicationMap.put("error", "test2"); System.out.println("SecondServlet.myMethod "+ applicationMap.get("error")); // ie.printStackTrace(); } finally { out.close(); } System.out.println("SecondServlet.myMethod >>>> done"); }
There are a few things missing from the code that need adding so we can test this. list appears to be a field of the owning class and SIZE appears to be a final constant.
Also, you there are a few things wrong with the program. You pass out as an argument then shadow it with a local variable out in the try block. So, the method argument is not needed. However, when you delete it you find that the call to close in the finally block does nto compile because out is undefined. That's because the local variable out goes out of scope when you leave the try block. You need to declare it outside the block and intiialize it inside. You also need to fix the finally code so it does not call close if out == null.
Here is a slightly modified version which fixes these problems and can be compiled and run:
import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; import java.util.List; import java.util.LinkedList; public class MyTest { private List list; public final static int SIZE = 3; public MyTest() { list = new LinkedList(); list.add("one"); list.add("two"); list.add("three"); } public void myMethod() { ConcurrentMap<string, string=""> applicationMap = new ConcurrentHashMap<string, string="">(); // The FileWriter constructor throws IOException, which must be caught. System.out.println("SecondServlet.myMethod: just in"); int start = 0; PrintWriter out = null; try { out = new PrintWriter(new FileWriter("OutFile.txt")); System.out.println("args[" + Integer.toString(start) ); for (int i = 0; i < SIZE; i++) { // The get(int) method throws IndexOutOfBoundsException, which must be caught. out.println("Value at: " + i + " = " + list.get(11)); } } catch (IOException ce) { applicationMap.put("error", "test1"); ce.printStackTrace(); } catch (IndexOutOfBoundsException ie) { System.out.println("SecondServlet.myMethod indexoutofbound"); applicationMap.put("error", "test2"); System.out.println("SecondServlet.myMethod "+ applicationMap.get("error")); // ie.printStackTrace(); } finally { if (out != null) { out.close(); } } System.out.println("SecondServlet.myMethod >>>> done"); } public static void main(String[] args) { MyTest myTest = new MyTest(); myTest.myMethod(); } }
So, just to check it works as expected here is a normal run[adinn@localhost byteman]$ javac -g MyTest.java [adinn@localhost byteman]$ java MyTest SecondServlet.myMethod: just in args[0 SecondServlet.myMethod indexoutofbound SecondServlet.myMethod test2 SecondServlet.myMethod >>>> done [adinn@localhost byteman]$
Notice that I passed -g to javac. That's because you want to refer to local variable ie in your rule. You need to ensure javac adds symbols to the bytecode for class MyTest if you want to be able to refer to them in rules.
Now, lets look at the rule you provided (n.b. I have changed the class name to refer to class MyTest)
RULE myMethod Exception 1 CLASS MyTest METHOD myMethod AT CALL applicationMap.put IF TRUE DO traceln("********>IndexOutOfBoundsException " + $ie) ENDRULE
The first thing to do is to run script bmcheck to see if the rule works ok
$ bmcheck.sh -cp . mytest.btm Checking rule myMethod Exception 1 against class MyTest WARNING : Problem type checking rule "myMethod Exception 1" loaded from mytest.btm line 5 against method myMethod() void org.jboss.byteman.rule.exception.TypeWarningException: no matching injection point for method myMethod() void WARNING : Problem type checking rule "myMethod Exception 1" loaded from mytest.btm line 5 org.jboss.byteman.rule.exception.TypeWarningException: failed to find any matching trigger method in class MyTest TestScript: 2 total warnings 2 type warnings [adinn@localhost byteman]$
So, Byteman tried to inject the rule into the right clas sand method but could not find an injection location that matches. That's easy to explain. The AT CALL location says that the call is to method called applicationMap.put. That doesn't actually name a method. applicationMap is the name of a variable of type ConcurrentMap. So, if you want to name the method that is being called you need to refer to it as ConcurrentMap.put. Ok, so let's fix that
RULE myMethod Exception 1 CLASS MyTest METHOD myMethod AT CALL ConcurrentMap.put IF TRUE DO traceln("********>IndexOutOfBoundsException " + $ie) ENDRULE
and run bmcheck again
[adinn@localhost byteman]$ bmcheck -cp . mytest.btm Checking rule myMethod Exception 1 against class MyTest WARNING : Problem type checking rule "myMethod Exception 1" loaded from mytest.btm line 5 against method myMethod() void org.jboss.byteman.rule.exception.TypeWarningException: invalid local variable binding $ie for method myMethod() void WARNING : Problem type checking rule "myMethod Exception 1" loaded from mytest.btm line 5 org.jboss.byteman.rule.exception.TypeWarningException: failed to find any matching trigger method in class MyTest TestScript: 2 total warnings 2 type warnings [adinn@localhost byteman]$
So, now Byteman has foudn a place to inject and rejected it because local variable ie is not in scope at that point. This is because it has foudn the first call to ConcurrentMap.put in the first catch block and, yes, ie is not in scope at that call. The full syntax for AT CALL isAT CALL method [count=1]
where method identifies the method being called and count identifies which call you want if more than one cal appears in the body of the methodl. The default count is 1. You can specify ALL to inject at every call or a positive number N to inject at the Nth call. So, what you want is to inject at the 2nd call:RULE myMethod Exception 1 CLASS MyTest METHOD myMethod AT CALL ConcurrentMap.put 2 IF TRUE DO traceln("********>IndexOutOfBoundsException " + $ie) ENDRULE
If we try again with that rule it bmcheck shoudl be happy
[adinn@localhost byteman]$ bmcheck -cp . mytest.btm Checking rule myMethod Exception 1 against class MyTest Parsed rule "myMethod Exception 1" for class MyTest Type checked rule "myMethod Exception 1" TestScript: no errors [adinn@localhost byteman]$
Ok, so now let's run it:
[adinn@localhost byteman]$ bmjava -l mytest.btm MyTest SecondServlet.myMethod: just in args[0 SecondServlet.myMethod indexoutofbound ********>IndexOutOfBoundsException java.lang.IndexOutOfBoundsException: Index: 11, Size: 3 SecondServlet.myMethod test2 SecondServlet.myMethod >>>> done [adinn@localhost byteman]$
I hope that helps you to get started ijecting rules into your application. Let me know if you need more help getting your ruels to run.
regards,
Andrew Dinn
-
2. Re: How to print out exception in a method?
leiyu Sep 27, 2019 7:11 AM (in response to adinn)Hi Andrew,
Thanks a lot for the detailed explanation, it is clear to me now. Sorry about my test program, I have not done any coding for years. My real aim was to create a byteman rule for the class FactoryFinder at line 630
mojarra/FactoryFinder.java at ac33eac70d458d97c3a7ba7f8ea504e16f23a930 · jboss/mojarra · GitHub
and line 637, but as we cannot reproduce the exception, I created a test program. So for my test program, there are two exceptions, how do you use the rule to capture either IOException and IndexOutOfBoundsException, here both have AT CALL ConcurrentMap.put 2, is there a way to check which exception it is? I would like to distinguishing which exceptions the application has encountered, but the local variable for both exceptions are different.
I would also like to know:
* For a static method that returns Object, what would be $0?
* Is it possible to use bmcheck.sh when the application is deployed to JBoss? I have used -cp to add classpath, but it was still complaining missing libs.
Thanks a lot
Lei
-
3. Re: How to print out exception in a method?
leiyu Sep 27, 2019 7:31 AM (in response to leiyu)Hi Andrew,
I have figured out below
So for my test program, there are two exceptions, how do you use the rule to capture either IOException and IndexOutOfBoundsException, here both have AT CALL ConcurrentMap.put 2, is there a way to check which exception it is? I would like to distinguishing which exceptions the application has encountered, but the local variable for both exceptions are different.
The rules below works for catching both exceptions
RULE myMethod Exception 1
CLASS com.larinia.app.SecondServlet
METHOD myMethod
AT CALL ConcurrentMap.put 1
IF TRUE
DO
traceln("********> IOException" + $ce);
ENDRULE
RULE myMethod Exception 2
CLASS com.larinia.app.SecondServlet
METHOD myMethod
AT CALL ConcurrentMap.put 2
IF TRUE
DO
traceln("********> IndexOutOfBoundexception" + $ie);
ENDRULE
I am still not sure about the answers for my other two questions, if you can help would be great.
BTW, the FactoryFinder is not compile with -g flag, would that effect the result of byteman? I didn't use AT LINE before of that.
Kind Regards
Lei
-
4. Re: How to print out exception in a method?
adinn Sep 27, 2019 10:33 AM (in response to leiyu)1 of 1 people found this helpfulHi Lei Yu,
* For a static method that returns Object, what would be $0?
* Is it possible to use bmcheck.sh when the application is deployed to JBoss? I have used -cp to add classpath, but it was still complaining missing libs.
$0 cannot be used in a rule injected into a static method. $0 can only be used in an instance method to refer to this.
bmcheck is an offline checker. When you have several jars you have to provide multiple -cp arguments like this:
$ bmcheck -cp AppClass.jar -cp LibClasses.jar -cpo LibClasses2.jar myscript.btm
You won't need to provide every jar that you app uses. bmcheck has to be able to load the classes or interfaces mentioned in the CLASS clauses of your rules. So, assume your rules mention classes C1 and C2 and interface I1 Obviously, you need to provide the jars that include class files for C1, C2 and I1. You will also need to include jars that contain classes that are directly referenced from C1, C2 and I1. So, if C1 imports C3 or has a field of type I2 and C3 or I2 are in a library jar then will need to add the librray jar on the command using -cp.
BTW, the FactoryFinder is not compile with -g flag, would that effect the result of byteman? I didn't use AT LINE before of that.
When you inject into a class that has not been compiled with -g you cannot use line numbers to specify the location for rule injection (that may explain why your AT LINE rule failed). Also, you cannot employ local variable names (like ce in the FactoryFinder code you refer to) or parameter variable names (like the ClassLoader parameter cl). You can still refer to parameter cl by index. Since it is the first parameter you would refer to it as $1. Byteman knows that this parameter is of type ClassLoader. You can also refer to $0 (the FactoryManagerCache instance that is handling the getApplicationFactoryManager) and you can refer to field applicationMap using $0.applicationMap. Unfortunately, without -g compilation there is no way for a Byteman rule to access the value of local variables.
regards,
Andrew Dinn
-
5. Re: How to print out exception in a method?
leiyu Sep 27, 2019 12:08 PM (in response to adinn)Hi Andrew,
Thanks a lot for your help. It's much clearer to me now.
I will try out the bmcheck script with relevant jars. My mistake before was setting JBOSS_HOME as the classpath.
Thanks again.
Lei