DART: Directed Automated Random Testing Koushik Sen University of Illinois Urbana-Champaign Joint work with Patrice Godefroid and Nils Klarlund.

Slides:



Advertisements
Similar presentations
Cristian Cadar, Peter Boonstoppel, Dawson Engler RWset: Attacking Path Explosion in Constraint-Based Test Generation TACAS 2008, Budapest, Hungary ETAPS.
Advertisements

Leonardo de Moura Microsoft Research. Z3 is a new solver developed at Microsoft Research. Development/Research driven by internal customers. Free for.
1 Symbolic Execution Kevin Wallace, CSE
Masahiro Fujita Yoshihisa Kojima University of Tokyo May 2, 2008
Symbolic Execution with Mixed Concrete-Symbolic Solving
PLDI’2005Page 1June 2005 Example (C code) int double(int x) { return 2 * x; } void test_me(int x, int y) { int z = double(x); if (z==y) { if (y == x+10)
A Program Transformation For Faster Goal-Directed Search Akash Lal, Shaz Qadeer Microsoft Research.
Abstraction and Modular Reasoning for the Verification of Software Corina Pasareanu NASA Ames Research Center.
Finding bugs: Analysis Techniques & Tools Comparison of Program Analysis Techniques CS161 Computer Security Cho, Chia Yuan.
1 Symbolic Execution for Model Checking and Testing Corina Păsăreanu (Kestrel) Joint work with Sarfraz Khurshid (MIT) and Willem Visser (RIACS)
1/20 Generalized Symbolic Execution for Model Checking and Testing Charngki PSWLAB Generalized Symbolic Execution for Model Checking and Testing.
Symbolic execution © Marcelo d’Amorim 2010.
David Brumley, Pongsin Poosankam, Dawn Song and Jiang Zheng Presented by Nimrod Partush.
Concolic Modularity Testing Derrick Coetzee University of California, Berkeley CS 265 Final Project Presentation.
Hybrid Concolic Testing Rupak Majumdar Koushik Sen UC Los Angeles UC Berkeley.
Dynamic Symbolic Execution CS 8803 FPL Oct 31, 2012 (Slides adapted from Koushik Sen) 1.
Testing and Analysis of Device Drivers Supervisor: Abhik Roychoudhury Author: Pham Van Thuan 1.
CSE503: SOFTWARE ENGINEERING SYMBOLIC TESTING, AUTOMATED TEST GENERATION … AND MORE! David Notkin Spring 2011.
Pexxxx White Box Test Generation for
Synergy: A New Algorithm for Property Checking
PLDI’2005Page 1June 2005 DART: Directed Automated Random Testing Patrice Godefroid Nils Klarlund Koushik Sen Bell Labs Bell Labs UIUC.
DART Directed Automated Random Testing Patrice Godefroid, Nils Klarlund, and Koushik Sen Syed Nabeel.
Evaluation of DART DART: Directed Automated Random Testing Godefroid, Klarlund, Sen.
Finding the Weakest Characterization of Erroneous Inputs Dzintars Avots and Benjamin Livshits.
. Memory Management. Memory Organization u During run time, variables can be stored in one of three “pools”  Stack  Static heap  Dynamic heap.
Looper: Lightweight Detection of Infinite Loops at Runtime Presenter: M. Amin Alipour Software Design Laboratory
CSCI 5801: Software Engineering
CS527: (Advanced) Topics in Software Engineering Overview of Software Quality Assurance Tao Xie ©D. Marinov, T. Xie.
Automating Software Testing Using Program Analysis -Patrice Godefroid, Peli de Halleux, Aditya V. Nori, Sriram K. Rajamani,Wolfram Schulte, and Nikolai.
CREST Internal Yunho Kim Provable Software Laboratory CS Dept. KAIST.
Symbolic Execution with Mixed Concrete-Symbolic Solving (SymCrete Execution) Jonathan Manos.
CUTE: A Concolic Unit Testing Engine for C Technical Report Koushik SenDarko MarinovGul Agha University of Illinois Urbana-Champaign.
Designing For Testability. Incorporate design features that facilitate testing Include features to: –Support test automation at all levels (unit, integration,
CS265: Program Analysis, Testing, and Debugging
1 VeriSoft A Tool for the Automatic Analysis of Concurrent Reactive Software Represents By Miller Ofer.
Unit Testing 101 Black Box v. White Box. Definition of V&V Verification - is the product correct Validation - is it the correct product.
Xusheng Xiao North Carolina State University CSC 720 Project Presentation 1.
jFuzz – Java based Whitebox Fuzzing
An Undergraduate Course on Software Bug Detection Tools and Techniques Eric Larson Seattle University March 3, 2006.
Learning Symbolic Interfaces of Software Components Zvonimir Rakamarić.
CSV 889: Concurrent Software Verification Subodh Sharma Indian Institute of Technology Delhi Scalable Symbolic Execution: KLEE.
Symbolic and Concolic Execution of Programs Information Security, CS 526 Omar Chowdhury 10/7/2015Information Security, CS 5261.
A Test Case + Mock Class Generator for Coding Against Interfaces Mainul Islam, Christoph Csallner Software Engineering Research Center (SERC) Computer.
The Yogi Project Software property checking via static analysis and testing Aditya V. Nori, Sriram K. Rajamani, Sai Deep Tetali, Aditya V. Thakur Microsoft.
CS265: Dynamic Partial Order Reduction Koushik Sen UC Berkeley.
PROGRAMMING TESTING B MODULE 2: SOFTWARE SYSTEMS 22 NOVEMBER 2013.
Grigore Rosu Founder, President and CEO Professor of Computer Science, University of Illinois
CUTE: A Concolic Unit Testing Engine for C Koushik SenDarko MarinovGul Agha University of Illinois Urbana-Champaign.
Introduction to Software Analysis CS Why Take This Course? Learn methods to improve software quality – reliability, security, performance, etc.
( = “unknown yet”) Our novel symbolic execution framework: - extends model checking to programs that have complex inputs with unbounded (very large) data.
/ PSWLAB Evidence-Based Analysis and Inferring Preconditions for Bug Detection By D. Brand, M. Buss, V. C. Sreedhar published in ICSM 2007.
Lazy Annotation for Program Testing and Verification (Supplementary Materials) Speaker: Chen-Hsuan Adonis Lin Advisor: Jie-Hong Roland Jiang December 3,
1 Validation of Security Protocols Joint work with Gul Agha, Michael Greenwald, Carl Gunter, Sanjeev Khanna, Darko Marinov, Jose Meseguer, Prasanna Thati,
Dynamic Symbolic Execution (aka, directed automated random testing, aka concolic execution) Slides by Koushik Sen.
Week 6 MondayTuesdayWednesdayThursdayFriday Testing III Reading due Group meetings Testing IVSection ZFR due ZFR demos Progress report due Readings out.
Symbolic Execution in Software Engineering By Xusheng Xiao Xi Ge Dayoung Lee Towards Partial fulfillment for Course 707.
CSE 331 SOFTWARE DESIGN & IMPLEMENTATION SYMBOLIC TESTING Autumn 2011.
Symstra: A Framework for Generating Object-Oriented Unit Tests using Symbolic Execution Tao Xie, Darko Marinov, Wolfram Schulte, and David Notkin University.
Willem Visser Stellenbosch University
Automated Pattern Based Mobile Testing
A Test Case + Mock Class Generator for Coding Against Interfaces
runtime verification Brief Overview Grigore Rosu
DART and CUTE: Concolic Testing
High Coverage Detection of Input-Related Security Faults
All You Ever Wanted to Know About Dynamic Taint Analysis & Forward Symbolic Execution (but might have been afraid to ask) Edward J. Schwartz, Thanassis.
Elided to examples only
Automatic Test Generation SymCrete
Example (C code) int double(int x) { return 2 * x; }
CUTE: A Concolic Unit Testing Engine for C
SOFTWARE ENGINEERING INSTITUTE
Presentation transcript:

DART: Directed Automated Random Testing Koushik Sen University of Illinois Urbana-Champaign Joint work with Patrice Godefroid and Nils Klarlund

2 Software Testing Testing accounts for 50% of software development cost Software failure costs USA $60 billion annually  Improvement in software testing infrastructure can save one-third of this cost “The economic impacts of inadequate infrastructure for software testing”, NIST, May, 2002 Currently, software testing is mostly done manually

3 Simple C code int double(int x) { return 2 * x; } void test_me(int x, int y){ int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); }

4 Automatic Extraction of Interface Automatically determine (code parsing)  inputs to the program arguments to the entry function  variables: whose value depends on environment external objects  function calls: return value depends on the environment external function calls For simple C code  want to unit test the function test_me  int x and int y : passed as an argument to test_me forms the external environment

5 Generate Random Test Driver Generate a test driver automatically to simulate random environment of the extracted interface  most general environment  C – code Compile the program along with the test driver to create a closed executable. Run the executable several times to see if assertion violates

6 Random test-driver main(){ int tmp1 = randomInt(); int tmp2 = randomInt(); test_me(tmp1,tmp2); } int double(int x) { return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Random Test Driver

7 Random test-driver main(){ int tmp1 = randomInt(); int tmp2 = randomInt(); test_me(tmp1,tmp2); } int double(int x) { return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Random Test Driver Probability of reaching abort() is extrememly low

8 Limitations Hard to hit the assertion violated with random values of x and y  there is an extremely low probability of hitting assertion violation Can we do better?  Directed Automated Random Testing White box assumption

9 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); }

10 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution t1=36t1=m concrete statesymbolic stateconstraints

11 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution t1=36, t2=-7t1=m, t2=n concrete statesymbolic stateconstraints

12 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution t1=36, t2=-7t1=m, t2=n concrete statesymbolic stateconstraints

13 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=36, y=-7x=m, y=n concrete statesymbolic stateconstraints

14 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=36, y=-7, z=72x=m, y=n, z=2m concrete statesymbolic stateconstraints

15 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=36, y=-7, z=72x=m, y=n, z=2m 2m != n concrete statesymbolic stateconstraints

16 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=36, y=-7, z=72x=m, y=n, z=2m 2m != n concrete statesymbolic stateconstraints

17 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=36, y=-7, z=72x=m, y=n, z=2m 2m != n solve: 2m = n m=1, n=2 concrete statesymbolic stateconstraints

18 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution t1=1t1=m concrete statesymbolic stateconstraints

19 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution t1=1, t2=2t1=m, t2=n concrete statesymbolic stateconstraints

20 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution t1=1, t2=2t1=m, t2=n concrete statesymbolic stateconstraints

21 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=1, y=2x=m, y=n concrete statesymbolic stateconstraints

22 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=1, y=2, z=2x=m, y=n, z=2m concrete statesymbolic stateconstraints

23 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=1, y=2, z=2x=m, y=n, z=2m 2m = n concrete statesymbolic stateconstraints

24 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=1, y=2, z=2x=m, y=n, z=2m 2m = n m != n+10 concrete statesymbolic stateconstraints

25 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=1, y=2, z=2x=m, y=n, z=2m 2m = n m != n+10 concrete statesymbolic stateconstraints

26 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=1, y=2, z=2x=m, y=n, z=2m 2m = n m != n+10 concrete statesymbolic stateconstraints

27 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=1, y=2, z=2x=m, y=n, z=2m 2m = n m != n+10 solve: 2m = n and m=n+10 m= -10, n= -20 concrete statesymbolic stateconstraints

28 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution t1=-10t1=m concrete statesymbolic stateconstraints

29 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution t1=-10, t2=-20t1=m, t2=n concrete statesymbolic stateconstraints

30 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution t1=-10, t2=-20t1=m, t2=n concrete statesymbolic stateconstraints

31 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=-10, y=-20x=m, y=n concrete statesymbolic stateconstraints

32 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=-10, y=-20, z=-20x=m, y=n, z=2m concrete statesymbolic stateconstraints

33 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution x=-10, y=-20, z=-20 x=m, y=n, z=2m 2m = n concrete statesymbolic stateconstraints

34 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution 2m = n m = n+10 x=-10, y=-20, z=-20 x=m, y=n, z=2m concrete statesymbolic stateconstraints

35 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } Concrete Execution Symbolic Execution 2m = n m = n+10 x=-10, y=-20, z=-20 x=m, y=n, z=2m Program Error concrete statesymbolic stateconstraints

36 DART Approach main(){ int t1 = randomInt(); int t2 = randomInt(); test_me(t1,t2); } int double(int x) {return 2 * x; } void test_me(int x, int y) { int z = double(x); if(z==y){ if(x != y+10){ printf(“I am fine here”); } else { printf(“I should not reach here”); abort(); } z==y x!=y+10 NY NY Error

37 DART in a Nutshell Dynamically observe random execution and generate new test inputs to drive the next execution along an alternative path  do dynamic analysis on a random execution  collect symbolic constraints at branch points  negate one constraint at a branch point (say b)  call constraint solver to generate new test inputs  use the new test inputs for next execution to take alternative path at branch b  (Check that branch b is indeed taken next)

38 More details Instrument the C program to do both  Concrete Execution Actual Execution  Symbolic Execution and Lightweight theorem proving (path constraint solving) Dynamic symbolic analysis Interacts with concrete execution Instrumentation also checks whether the next execution matches the last prediction.

39 Experiments Tested a C implementation of a security protocol (Needham-Schroeder) with a known attack  406 lines of code  Took less than 26 minutes on a 2GHz machine to discover middle-man attack In contrast, a software model-checker (VeriSoft) and a hand-written nondeterministic model of the attacker took hours to discover the attack

40 Larger Experiment oSIP (open-source session initiation protocol)   30,000 lines of C code (version 2.0.9)  600 externally visible functions Results  crashed 65% of the externally visible functions within 1000 iterations  no nullity check for pointers Focused on oSIP parser  can externally crash oSIP server  osip_message_parse() : pass a buffer of size 2.5 MB with no 0 or “|” character  tries to copy the packet to stack using alloca(size) this fails: returns NULL pointer  this NULL pointer passed to another function does not check for nullity and crashes

41 Advantage of Dynamic Analysis over Static Analysis struct foo { int i; char c; } bar (struct foo *a) { if (a->c == 0) { *((char *)a + sizeof(int)) = 1; if (a->c != 0) { abort(); } Reasoning about dynamic data is easy Due to limitation of alias analysis “static analyzers” cannot determine that “a->c” has been rewritten  BLAST would infer that the program is safe DART finds the error  sound

42 Further advantages 1 foobar(int x, int y){ 2 if (x*x*x > 0){ 3 if (x>0 && y==10){ 4 abort(); 5 } 6 } else { 7 if (x>0 && y==20){ 8 abort(); 9 } 10 } 11 } static analysis based model-checkers would consider both branches  both abort() statements are reachable  false alarm Symbolic execution gets stuck at line number 2 DART finds the only error

43 Discussion In comparison to existing testing tools, DART is  light-weight  dynamic analysis (compare with static analysis) ensures no false alarms  concrete execution and symbolic execution run simultaneously symbolic execution consults concrete execution whenever dynamic analysis becomes intractable  real tool that works on real C programs completely automatic Software model-checkers using abstraction (SLAM, BLAST)  starts with an abstraction with more behaviors – gradually refines  static analysis approach – false alarms  DART: executes program systematically to explore feasible paths

44 Current Work: CUTE at UIUC CUTE: A Concolic Unit Testing Engine (FSE’05)  For C and Java  Handle pointers Can test data-structures Can handle heap  Bounded depth search  Use static analysis to find branches that can lead to assertion violation use this info to prune search space  Concurrency Support  Probabilistic Search Mode  Find bugs in Cryptographic Protocols  times faster than the DART implementation reported in PLDI’05