View
214
Download
2
Category
Preview:
Citation preview
1
Symbolic Execution for Model Checking and Testing
Corina Păsăreanu (Kestrel)
Joint work with Sarfraz Khurshid (MIT) and Willem Visser (RIACS)
2
Paper
• Khurshid, S., Pasareanu, C.S., and Vissser, W., “Generalized Symbolic Execution for Model
Checking and Testing”, in Proc. of the 9th International Conference on Tools and Algorithms for the Construction and Analysis of Systems (TACAS 2003). April 2003, Warsaw, Poland.
3
Motivation
void Executive::startExecutive(){ runThreads(); …}void Executive::executePlan(…) { while(!empty) executeCurrentPlanNode();} …
Rover ExecutiveFuture mission software: - concurrent - complex, dynamically allocated data structures (e.g., lists or trees) - highly interactive: - with complex inputs - large environment - should be extremely reliable
Input plan
complex input structure
concurrency,dynamic data (lists, trees)
execute action
environment/rover status
Current practice in checking complex software:
large environment data
Mars Rover
Testing: - requires manual input - typically done for a few nominal input cases - not good at finding concurrency bugs - not good at dealing with complex data structures
Model checking: - automatic, good at finding concurrency bugs - not good at dealing with complex data structures - feasible only with a small environment
- and a small set of input values
4
Our symbolic execution framework
Extends model checking • to programs that have complex inputs with unbounded (very large) dataAutomates test input generation
Provides:A novel symbolic execution algorithm• Handles dynamic data (e.g., lists and trees), concurrency• Uses lazy initialization:
– Initializes the components of the program’s inputs on an ``as-needed'' basis– No a priori bound on input sizes– Uses preconditions to initialize inputs only with valid values
A source to source translation to instrument a program• Enables standard model checkers to perform symbolic execution of the
program• Uses “off-the-shelf” decision procedures
5
Symbolic Execution
Code:
(PC=“path condition”)
- “Simulate” the code using symbolic values instead of program numeric data
Symbolic execution tree: x:X,y:YPC: true
x:X,y:YPC: X>Y
x:X,y:YPC: X<=Y
true false
x:X+Y,y:YPC: X>Y
x:X+Y,y:XPC: X>Y
x:Y,y:XPC: X>Y
x:Y,y:XPC: X>Y Y-X>0
x:Y,y:XPC:X>Y Y-X<=0
true false
FALSE!
Not reachable
int x, y;
if (x > y) { x = x + y; y = x - y; x = x - y; if (x – y > 0) assert (false); }
6
Algorithm: Lazy Initialization
To symbolically execute method m of class C:• create a new object, o, of class C• set all its fields to uninitialized values• invoke o.m()
when m accesses field f
if (f is uninitialized) {if (f is reference field of type T) {
non-deterministically initialize f to– null– a new object of class T (with un-initialized field values)– a previously initialized object of class T
}if (f is numeric (string) field)
initialize f to a new symbolic value}
7
Generalized Symbolic Execution
E0
next
E1next
t
E2next
...
Code:
( = “unknown yet”)
E0next
E1next
t
E0
next
E1next
t
E2next
PC: E0-E1>0 PC: E0-E1<=0
truefalse
...
-“Simulate” the code using symbolic values instead of program numeric data.-Enumerate input structures lazily.
Symbolic execution tree:E0
nextPC: true
Precondition: acyclic list!
E0next
null E0next
E1next
E0
next ......
E0next
E1next
t
null E0next
E1next
t
E2next
E0next
E1
t next
E0next
E1
next
t
......
class Node { int elem; Node next;
Node swapNode() { if (next != null) if (elem – next.elem > 0) { Node t = next; next = t.next; t.next = this; return t; } return this; } }
8
class Node { int elem; Node next;
Node swapNode() { if (next != null) if (elem – next.elem > 0) { Node t = next; next = t.next; t.next = this; return t; } return this; } }
Code:
Results of Analysis
E0next
null
E0next
E1next
E0
next
E0next
E1next
null
E0next
E1next
E2next
E0next
E1
next
E0next
E1
next
Input list + Constraint Output list
E0>E1
none
E0≤E1
none
E0>E1
E0>E1
E0>E1
E1next
E0next
E2next
E1next
E0
next
E1next
E0
next
E1next
E0next
null
E0next
E1next
E0
next
E0next
null
Null pointer exception!
9
Framework
Model checking
Program instrumentation
Decision procedures
Instrumented program
Correctness specification
continue/backtrack
Counterexample(s)/test suite[heap+constraint+thread scheduling]
Source program
Path condition (data)
Heap configuration
Thread scheduling
State:
10
Implementation for Java
• Uses Korat (MIT) for program instrumentation• Uses Java PathFinder model checker toolset• Uses Omega library as a decision procedure
– for integer linear constraints
Framework:• Can be used as a symbolic execution tool with backtracking
– Handles multithreaded programs• No state matching
– Un-decidable in general• Good for finding counter-examples to safety properties
– Programs with loops can have infinite execution trees– Uses breadth first search or depth first search with limited depth
• Used to– check for null pointer exceptions, rich properties in multithreaded
programs– generate test inputs for code coverage of an Altitude Switch used in flight
control software (~ 2000 Java lines)
11
Code Instrumentation
Code:
class Expression { static PathCondition _pc;
Expression_minus(Expression e) { … }}
class PathCondition { … Constraints c;
boolean _updateGT (Expression e1, Expression e2) {
boolean result = choose_boolean();
if (result) c.add_constraintGT(e1,e2)); else c.add_constraintLE(e1,e2));
if (! c.is_satisfiable()) backtrack();
return result; } }
class Node { Expression elem; boolean _elem_is_initialized; Node next; boolean _next_is_initialized;
Node swapNode() { if (_get_next() != null) if (Expression._pc._updateGT(_get_elem()._minus(_get_next() . _get_elem() ), new IntegerConstant(0) ) { Node t = _get_next() ; _set_next (t._get_next() ); t._set_next (this); return t; } return this; } }
class Node { int elem; Node next;
Node swapNode() { if (next != null) if (elem – next.elem > 0) { Node t = next; next = t.next; t.next = this; return t; } return this; } }
12
Related work
• Symbolic execution and program testing– EFFIGY [King’76]
• Static analysis– ESC [Detlefs et al’98]– TVLA [Sagiv et al’98]
• Software model checking– VeriSoft [Godefroid’97]– JPF [Visser et al’00]– Bandera (KSU), SLAM (Microsoft)
• Specification-based testing– Korat [ISSTA ’02]
• ...
13
Conclusions
• Framework for symbolic execution– Handles dynamic data and concurrency– Program instrumentation enables any model checker to
perform symbolic execution– Used for checking rich properties of multithreaded
programs with complex inputs and for test input generation
• Future work:– Investigate
• Widening and abstraction techniques to help termination• Different decision procedures and constraint solvers (to
handle non-linear constraints and floats)
– Case studies
14
Demo
class List { Node header; static class Node { int elem; Node next; } void swap2() { // swaps the first two nodes if (header == null) return; if (header.next == null) return; Node t = header; header = header.next; t.next = t.next.next; header.next = t; }}
15
Problem: convergence
Symbolic execution tree:
void test(int n) { int x = 0; while(x < n) x = x + 1; }
Code:n:SPC:true
n:S,x:0PC:true
n:S,x:1PC:0<S
n:S,x:0PC:0<S
n:S,x:0PC:0>=S
n:S,x:1PC:0<S & 1>=S
n:S,x:1PC:0<S & 1<S
....
Recommended