ReCrash: Making software failures reproducible by preserving object states

ReCrash logoIt is very hard to fix a software failure without being able to reproduce it. However, reproducing a failure is often difficult and time-consuming. This paper proposes a novel technique, ReCrash, that generates multiple unit tests that reproduce a given program failure. During every execution of the target program, ReCrash stores partial copies of method arguments in memory. If the program fails (e.g., crashes), ReCrash uses the saved information to create unit tests reproducing the failure.

We present ReCrashJ, an implementation of ReCrash for Java. ReCrashJ reproduced real crashes from Javac, SVNKit, Eclipsec, and BST. ReCrashJ is efficient, incurring 13%--64% performance overhead. If this overhead is unacceptable, then ReCrashJ has another mode that has negligible overhead until a crash occurs and 0%--1.7% overhead until the crash occurs for a second time, at which point the test cases are generated.

Contents:


Download


Publication


ReCrash HOWTO

This section shows how to use ReCrash.

  1. Sample Java Program
    Suppose we have an example Java program, crash/CrashExample.java:
    package crash;
    
    import java.util.Random;
    
    public class CrashExample {
      public static int abs(Integer i) {
        Integer ret = null;
        if (i < 0) {
          ret = -i;
        } else if (i > 0) {
          ret = i;
        }
        return ret.intValue();
      }
    
      public static void main(String args[]) {
        try {
          CrashExample crash = new CrashExample();
          abs(rand());
          System.out.println("No crash this time");
        } catch(Exception e) {
          e.printStackTrace();
        }
      }
    
      /** Returns a random int between -2 and 2, inclusive. */
      public static int rand() {
        return new Random().nextInt(5)-2;
      }
    
    }
  2. Compile the program.
    javac crash/CrashExample.java
    
    then run it:
    java crash.CrashExample
    
    You may need to run it many times, because it only crashes some of the time.
  3. Optional: Annotate Exception Handler: "reCrash with".equals(e);
    ReCrash automatically captures any uncaught exceptions in the main method, so typically you do not have to change your source code in any way.

    However, if you have your own exception handler (in any method) that prevents the main method from throwing an error, you need to annotate which exceptions ReCrash should try to reproduce. You do so by adding the statement "reCrash with".equals(e); (where e is the exception to reproduce. This does not have any side-effect on your program and does not require any additional jar files to compile or run.

    For example, because the CrashExample program above never throws an exception, you would change it as follows:

        ...
        } catch(Exception e) {
          "reCrash with".equals(e);
          e.printStack();
        }
        ...
    
    Now, compile CrashExample.java as usual.
    javac crash/CrashExample.java
    
    You can also run it to confirm that the program behaves just as before.
    java crash.CrashExample
    
  4. Using ReCrash in the Development Mode
    If you are a developer and want to use ReCrash in your development process, ReCrash provides the javaagent mode. Run your application as usual and add only the -javaagent option with reCrash.jar. For example, to run CrashExample:
        java -javaagent:reCrash.jar crash.CrashExample
  5. Using ReCrash in the Deploying Mode
    If you want to distribute ReCrash enabled (instrumented) class file(s), ReCrash can automatically generate instrumented class file(s) for you. To instrument CrashExample.class:
        java -jar reCrash.jar crash/CrashExample.class trans/crash/CrashExample.class
    To instrument an entire jar file (yourProgram.jar):
        java -jar reCrash.jar yourProgram.jar transformedProgram.jar
    Then users download and run the instrumented CrashExample.class instead of the original one. To run the instrumented class file(s), you need reCrash.jar in your class path. When you distribute the instrumented class files, you need to include reCrash.jar with the instrumented class file(s).

    For example, you could run

        java -jar reCrash.jar crash/CrashExample.class trans/crash/CrashExample.class
        java -cp trans:reCrash.jar crash.CrashExample
    (repeating the last command until it produces test cases).
  6. Reproducing crashes by running generated Test Cases
    If the subject program crashes (any uncaught exception happens or the program reaches the annotated location, "reCrash with".equals(e)) in the ReCrash development or deploying mode, ReCrash will generate test cases. The test cases are printed to standard output, but they are also saved in directory /tmp/generated_tests/, and it is easier for you to run them from there.

    An example generated test case is:

    public class Recrash_reCrash37419_trace_gz extends TestCase {
      public void setUp() throws Exception {
        TraceReader.readTrace("/tmp/reCrash37419.trace.gz");
      }
    
      public void test_crash_CrashExample_abs_1() throws Throwable {
        TraceReader.setMethodTraceItem(1);
        crash.CrashExample thisObject  = (crash.CrashExample) TraceReader.readObject(0);
    
        // load arguments
        Integer arg_1 = 0;
    
        // Method invocation
        thisObject.abs(arg_1);
      }
    }
    To compile and run the generated test cases, you need reCrash.jar and your subject program in your class path, as shown here (you will need to change the number "37419"):
      javac -cp $CLASSPATH:reCrash.jar:. /tmp/generated_tests/Recrash_reCrash37419_trace_gz.java 
      java -cp $CLASSPATH:reCrash.jar:.:/tmp junit.textui.TestRunner generated_tests.Recrash_reCrash37419_trace_gz
    

Limitations

ReCrash cannot reproduce errors in the default package (sometimes called the top-level package). This is due to a change in Java 1.4 that makes it impossible to access the default package from any non-default package. Good Java style discourages the use of the default package.


Contributions

You can contribute to ReCrash by sending bug reports, code patches, and suggestions. Use the public mailing list for ReCrash bug report or suggestions: recrash@googlegroups.com. You can subscribe and view the mail archive at http://groups.google.com/group/recrash.


People


Powered by ASM

Last updated: April 13, 2009