3 Replies Latest reply: Apr 27, 2012 5:42 AM by Andrew Dinn RSS

Accessing a variable scoped to a switch case block, within an action expression

jaikiran pai Master

Assuming I have code which looks like:

 

public void doSomething() {
       .....
      switch(onsomething) {
               case 1:
                    int someVar = ....;
                    fooBar(); // assume this is line 10
                    break;
               default:
                    break;
     }  
}

 

Assuming the line number for fooBar() invocation is 10 and I want to check the value of someVar, I've got this rule:

RULE test
CLASS someClass
METHOD doSomething
AT LINE 10
IF TRUE
DO

System.out.println("Value is = " +  $someVar);

ENDRULE

 

This rule keeps failing with a message along the lines of "unsatisfiable local variable binding $someVar checking method doSomething". My guess is that it has to do with the fact that the someVar is scoped within the swith case block and isn't visible outside of it. But since I am trying to insert this rule at LINE 10 where this variable is infact visible, shouldn't this rule pass? Or is there some different way to write this rule?

 

Am using 2.0.1 version by the way.

  • 1. Re: Accessing a variable scoped to a switch case block, within an action expression
    Andrew Dinn Master

    Hi Jaikiran

    jaikiran pai wrote:

     

     

    This rule keeps failing with a message along the lines of "unsatisfiable local variable binding $someVar checking method doSomething". My guess is that it has to do with the fact that the someVar is scoped within the swith case block and isn't visible outside of it. But since I am trying to insert this rule at LINE 10 where this variable is infact visible, shouldn't this rule pass? Or is there some different way to write this rule?

     

    Hmm, I may to investigate this one too. Byteman uses the localvar debug info installed by javac to identify in-scope variables. So, if there is an bytecode range where the debugger thinks the variable is in scope then byteman also ought to think the variable is in scope. So, I'll ask the obvious question first: are you sure you compiled this class with the relevant debug options to include both line numbers and local var tables (obviously '-g' is enough).

     

    Assuming the answer is yes then the immediate thing to do is to disassemble the class using javap -c (-private) -verbose and see which bytecodes are included in the scope of line 10 and whether the local var is visible in that scope. n.b. with location AT LINE 10 the injection point is just before the first bytecode labelled with line number = 10 -- except of course for constructors where injection can sometimes be delayed until after a super or indirect this constructor has been called.

     

    One thing to note is that in the byetcode variables go out of scope once they are no longer referenced. I say this because it raises an issue with the (possibly artificial) example you provided

     

    switch(onsomething) {
      case 1:
        int someVar = ....;
        fooBar(); // assume this is line 10
        break;

     

    variable somevar is  actually out of scope at line 10. I know in theory Java says the variable is available from the declaration point onwards but of course, that is a moot point if subsequent code does not reference it. javac  can (and will) choose to limit the localvars extent to the bytecode section where it is live and in use. In practice, with this example javac would limit the scope of someVar up to (but not to overlap) the call to foobar. Now a scope also starts immediately after the related local var slot is written. As a consequence the start and end bytecode offsets for the scope are the same for this example and hence the scope has an extent of length zero.

  • 2. Re: Accessing a variable scoped to a switch case block, within an action expression
    jaikiran pai Master

    Andrew, sorry about the late reply. I've been delaying on replying to this thread, hoping to get to the bottom of this issue. But other priority tasks aren't letting that happen. FWIW, I haven't been able to reproduce this against a simple class/method. However, I keep seeing this against a specific class/method that belongs to jboss-remoting project. So I'll have to spend a bit more time to see what's going on there. I'll come back to this soon.

     

     

    Andrew Dinn wrote:

     

     

    One thing to note is that in the byetcode variables go out of scope once they are no longer referenced. I say this because it raises an issue with the (possibly artificial) example you provided

     

    switch(onsomething) {
      case 1:
        int someVar = ....;
        fooBar(); // assume this is line 10
        break;

     

    variable somevar is  actually out of scope at line 10. I know in theory Java says the variable is available from the declaration point onwards but of course, that is a moot point if subsequent code does not reference it. javac  can (and will) choose to limit the localvars extent to the bytecode section where it is live and in use. In practice, with this example javac would limit the scope of someVar up to (but not to overlap) the call to foobar. Now a scope also starts immediately after the related local var slot is written. As a consequence the start and end bytecode offsets for the scope are the same for this example and hence the scope has an extent of length zero.

    Yes, the code I posted was artificial and the real code actually references that variable in the subsequent line(s). But thank you for explaining what javac does in cases like in the above (artificial) code. I had a feeling that javac would be smart enough to do such a thing, but I wasn't ever sure about it. Thanks for confirming it.

  • 3. Re: Accessing a variable scoped to a switch case block, within an action expression
    Andrew Dinn Master

    Hi Jaikiran,

    jaikiran pai wrote:

     

    Andrew, sorry about the late reply. I've been delaying on replying to this thread, hoping to get to the bottom of this issue. But other priority tasks aren't letting that happen. FWIW, I haven't been able to reproduce this against a simple class/method. However, I keep seeing this against a specific class/method that belongs to jboss-remoting project. So I'll have to spend a bit more time to see what's going on there. I'll come back to this soon.

     

    No apology needed. I have been feeling guilty myself about not trying to reproduce this -- I am very busy on JVM work at present.

     

    Can you point me at the offending bytecode and the relevant injection point. I could at least decompile it and see what the local var table says.

     

    Also, if you can either run bmcheck yourself and see if the injection fails or advise me of which jars I need to provide in order to be able to check the rule using bmcheck then we can see if we get an inject failure at check time. That should make it very easy to debug the injection problem.

     

    n.b. bmcheck needs enough jars in the classpath to resolve references when it loads the target class. Often the jar containing the target class is enough but sometimes it needs extra jars to resolve classes imported from other packages. You make these available on the command line using -cp

     

      bmcheck -cp jar1 . . . -cp jarN path/to/myscript.btm