ReCrash: Making software failures reproducible by preserving object states

It 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 (Version 0.3, Released on July 8, 2008)


Publication


ReCrash HOWTO

This section shows how to use ReCrash. (Use 'ant' first to compile the source code)

  1. Sample Java Program
    Suppose we have an example Java program, CrashExample.java:
    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[]) {
        CrashExample crash = new CrashExample();
        try {
          abs(rand());
        } catch(Exception e) {
          e.printStack();
        }
      }
    
      /** Returns a random int between -10 and 10, inclusive. */
      public static int rand() {
        return new Random().nextInt(21)-10;
      }
    
    }
  2. Annotate Exception Handler: "reCrash with".equals(e);
    ReCrash automatically captures any uncaught exceptions. However, if you have your own exception handler, you need to annotate which exceptions should be considered as crashes. For example, if you consider the exception in the main (in the previous example) as a crash, you need to add "reCrash with".equals(e); code in the location. Make sure the 'e' is the exception you want ReCrash to capture. ReCrash automatically detects the annotation and adds a method monitoring module.

    This does not have any side-effect of your program and does not require any additional jar files. The annotated source code will look like:

    public class CrashExample {
    
      [...]
    
      public static void main(String args[]) {
        try {
          CrashExample crash = new CrashExample();
          abs(rand());
        } catch(Exception e) {
          "reCrash with".equals(e);
           e.printStack();
        }
      }
    
      [...]
    
    }
  3. Compile CrashExample.java as usual.
    After annotating the exception locations, just compile the source as usual. You don't need any additional jar files to compile your source code.
  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 you application as usual and add only the -javaagent option with reCrash.jar. For example, to run the CrashExample.class:
        java -javaagent:reCrash.jar 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 the CrashExample.class:
        java -jar reCrash.jar CrashExample.class trans/CrashExample.class
    To instrument a 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. To distribute the instrumented class files, you need to include reCrash.jar with the instrumented class file(s).
  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 such as:
    public class Recrash51901 extends TestCase {
      public void setUp() throws Exception {
        TraceReader.readTrace("/tmp/reCrash51901.trace.gz");
      }
    
      public void test_CrashExample_abs_1() throws Throwable {
        TraceReader.setMethodTraceItem(1);
        CrashExample thisObject  = (CrashExample) TraceReader.readObject(0);
    
        // load arguments
        Integer arg_1 = 0;
    
        // Method invocation
        thisObject.abs(arg_1);
      }
    }
    By running the generated test cases, you can reproduce the exception (crash). To compile and run the generated test cases, you need reCrash.jar and your subject program it in your class path.

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


Last updated: April 10, 2009