论文部分内容阅读
随着多线程等并发技术的发展,多线程编程技术被越来越广泛地应用于实际中。多线程技术通过提高CPU的利用率,减少资源的浪费,从而大大提高了程序执行的效率。各种编程语言,如Java, C++等,也提出了各自的并发编程模型。这些并发编程模型,也被越来越多地应用于实际的开发之中,并且被证明可以极大地提高程序运行速度。但是与此同时,并发程序也由于其执行行为的不确定性,在发生错误后很难被开发人员定位;而错误发生后也往往需要花费开发人员大量的时间来重现错误发生的场景。典型的如数据竞争(Data Race),死锁(Deadlock)以及操作原子性的违反(Atomicity Violation),这些并发程序独有的错误大大增加了测试及修正并发程序的难度。基于以上几点,很大一部分传统的程序测试方法在并发程序中并不适用。而线程间调度的不可确定性,也对并发程序的测试提出了新的要求。为了更加方便地调试并发程序,记录及回放(Record & Replay)的方法被引入到了并发程序的测试之中。对于并发程序的记录及回放,目前存在两种方法:基于内容(Content-based)的以及基于顺序(Order-based)的方法。基于内容的方法可以准确地重现对于内存的读写内容,而基于顺序的方法则关注于线程间(inter-thread)事件的执行顺序。这两种方法有各自的优点及局限性:基于内容的方法由于内存读写数量的巨大,往往会生成过大的记录文件;而基于顺序的记录回放方法则需要线程执行过程中准确地重现线程间所有事件的执行顺序。对于并发程序中的程序错误(Software Bugs),目前已有的方法主要是通过长时间的压力测试(Stress Testing)重现错误。但是这样的方法除了需要耗费大量的时间以外,也无法保证能重现特定的并发错误。基于以上的需求,本文特别关注于并发程序中对于程序错误的记录及确定性的回放。使用Soot对Java字节码进行插装,将在原始程序的基础上生成两个版本的程序:记录及回放版本。运行记录版本的程序,将在程序运行同时记录下线程间事件的执行逻辑顺序。通过研究及扩展单线程程序错误重现架构,本文提出了工具ConCrash以在并发程序崩溃后自动生成多线程的测试用例以及程序运行的逻辑时钟顺序记录文件。通过运行这些测试用例并调用回放版本的程序,并发程序的崩溃场景可以被确定性地重现。本文的主要贡献在于以下几点:提出了一个轻量级及可扩展的对于多线程程序错误的捕捉重现技术,并可以同时与其他静态分析的前端技术相结合。实现了基于Java语言的原型,ConCrash,并且可以在程序崩溃后自动生成模拟多线程场景的JUnit测试用例。通过对基准程序及实际应用的测试使用,全面评估了ConCrash的有效性及性能额外开销,提出了未来工作的方向。