Advanced variables manipulation with Byteman

In this basic tutorial Introduction to Byteman we have learnt how to use Byteman tool to inject some bytecode in your Java classes, without modifying the actual code but by coding some rules files which can be further enhanced by Byteman Helper classes. In this tutorial we will go more in deep in this awesome tool to learn how to vary the application flow by changing a method variable.

So here's a simple Java example class:

public class Test   
{  
  public void action(Pojo test) throws Exception  
  {  
    if (!test.isOk()) {  
      throw new Exception("Error in Test " + test);  
    }  
  }  
}

In this simple class we're checking for the isSuccess method in the action method. In case the isSuccess returns false a new Exception is raised. Hacking the value of the function called in the method is quite simple. Here is a Byteman rule which will prevent the exception to get thrown:

RULE hack rule
CLASS Test  
METHOD action  
AT INVOKE isOk  
IF TRUE  
$test.ok = true  
ENDRULE  

What is worth mentioning is that the rule is injected into the Java code before method isOk is called. If you want to be more precise you could make it clearer by writing

AT INVOKE Test.isOk()

The assignment in the rule action ($test.ok = true ) uses $test to refer to the first parameter of method action by name. This way you can set the value of the Pojo's ok class member to true. By the way, yuo can also refer to it by index using the syntax $1.

The list of location (AT) clauses is restricted to positions in the source code which clearly identify locations in the corresponding bytecode. For example

AT ENTRY
AT EXIT
AT INVOKE calledMethod
AT WRITE fieldName =
AT READ $localVarName
AT LINE nnn

Here's one more example which detects a change in local variable using AFTER WRITE:

RULE Check Variable Write
CLASS Test
METHOD main
AFTER WRITE $y
IF $y==2
DO traceln("y is now set to 2")
ENDRULE

Finally, it's worth mentioning that you can insert more than one expression in a DO clause to make your Rules more complex. The only twist is that you need to separate them using a ';' -- for example:

RULE  
...    
DO traceln("y is now set to 2");
traceStack()  
ENDRULE 

Follow us on Twitter