350 likes | 571 Views
Zing: A Systematic State Explorer for Concurrent Software. Tony Andrews Shaz Qadeer Sriram K. Rajamani Jakob Rehof Microsoft Research. Model Checking. Finding bugs by systematically exploring all possible states of a model Works for control-dominated hardware and protocols
E N D
Zing: A Systematic State Explorer for Concurrent Software Tony Andrews Shaz Qadeer Sriram K. Rajamani Jakob Rehof Microsoft Research
Model Checking Finding bugs by systematically exploring all possible states of a model Works for control-dominated hardware and protocols Model is written manually by someone who understands the system Typical models are FSMs
Model Checking at MSR Check source code in common programming languages Model can be extracted automatically from the code Good models are not necessarily FSMs
Characteristics of Software Primitive values are more complicated • Pointers • Objects Control flow (transition relation) is more complicated • Functions • Function pointers • Exceptions States are more complicated • Unbounded graphs over values Variables are scoped • Locals • Shared scopes Much richer modularity constructs • Functions • Classes
What is Zing? • Zing is a framework for software model-checking • Language, compiler, runtime, tools • Supports key programming language constructs • Objects, functions, threads, channels, dynamic allocation • Enables easier extraction of models from code • Supports research in exploring large state spaces • New techniques implemented • compositional model checking • summarizing procedures with concurrency • Supports conformance checking
Applications of Zing • Check for errors in sets of web services whose behavior is described by BPEL4WS • Check web services for conformance with behavioral contracts • Check behavior of Windows device drivers under concurrent execution • Find errors in complex application protocols
What can we check for? • Assertion violations • Zing has assert(…) statement • Assertion violations are flagged as errors • Stuck states • Deadlock: a process is waiting for message that is never sent or condition that is never satisfied • Conformance • Does a communicating process conform to a specification (“contract”) ?
Outline • Overview • Zing “show and tell” • Architecture • State-space reduction algorithms • Conformance Checker
Zing State Explorer BPEL4WS checking BPEL Processes Buyer Seller Zing Model Auction House Reg Service
processes simple data types structures arrays enums communication message queues shared memory blocking non-determinism atomic blocks objects functions (methods) dynamic memory allocation exceptions range type sets variable-size arrays Zing features
Outline • Overview • Zing “show and tell” • Architecture • State-space reduction algorithms • Conformance Checker
Legend User user “source” Zing Source Code Product Groups model extraction Zing Compiler MSR Model-checker visualization (UML activity) Conformance Checker Zing object code (MSIL) event trace State browser visualization (call graph) Debugger Zing runtime library … Zing’s eco-system Domain- specific tools Visual Studio.NET
Zing Object Model Zing Application StateImpl Checkers, Simulators, etc. State State: contains state of the entire model Can query how many processes are in the state Can “execute” a particular process in the state for one atomic step and return the resulting state Can compare if two states are equal
Processes Process Process Process Stack … IP Locals Params Heap: complex types IP Locals Params … … Zing State Internals State Globals: simple types & refs
State explosion • 5 components, 100 states/component • Worst case: 10 billion states
Outline • Overview • Zing “show and tell” • Architecture • State-space reduction algorithms • Conformance Checker
Saving storage • Only states on the checkers stack are stored • For states not on the stack only a fingerprint is stored • In progress: • Store only “deltas” from previous states
State reduction • Abstract notion of equality between states • Avoid exploring “similar” states several times • Exploit structure and do this fully automatically while computing the fingerprint: s1 s2 f(s1) = f(s2) Heap1 100 200 a b 0 ptr Heap2 ptr 150 300 b 0 a
Interleaving reduction • Do not explore all interleavings between threads • Interleave only at transaction boundaries • Combine atomicity with summarization • Two level model checking algorithm
Transactions • In a well synchronized concurrent program • A thread’s computation can be viewed as a sequence of transactions • While analyzing a transaction, interleavings with other threads need not be considered • Furthermore: summarize transactions, leading to reuse and efficiency
How do you identify transactions? Lipton’s theory of reduction
x r=bal S2 S3 S4 r=bal x S2 T3 S4 z rel(this) r=bal y acq(this) x S5 S6 S7 S2 S3 S4 S0 S1 S2 rel(this) x acq(this) z y r=bal S2 S0 S5 T1 T6 S7 S2 T3 S4 Four atomicities • R: right movers • lock acquire • L: left movers • lock release • B: both right + left movers • variable access holding lock • N: non-movers • access unprotected variable
Transaction Any sequence of actions whose atomicities are in R*(N+)L* is a transaction R R R N R L L S5 S6 S7 S2 S0 S1 S3 S4 Transaction Precommit Postcommit
Transactions and summaries Corollary of Lipton’s theorem: No need to schedule other threads in the middle of a transaction If a procedure body occurs in a transaction, we can summarize it!
Resource allocator (1) bool available[N]; mutex m; int getResource() { int i = 0; L0: acquire(m); L1: while (i < N) { L2: if (available[i]) { L3: available[i] = false; L4: release(m); L5: return i; } L6: i++; } L7: release(m); L8: return i; } Choose N = 2 Summaries: <pc, i, m, (a[0],a[1])> <pc’, i’, m’, (a[0]’,a[1]’)> <L0, 0, 0, (0, 0)> <L8, 2, 0, (0,0)> <L0, 0, 0, (0, 1)> <L5, 1, 0, (0,0)> <L0, 0, 0, (1, 0)> <L5, 0, 0, (0,0)> <L0, 0, 0, (1, 1)> <L5, 0, 0, (0,1)>
Resource allocator (2) bool available[N]; mutex m[N]; int getResource() { int i = 0; L0: while (i < N) { L1: acquire(m[i]); L2: if (available[i]) { L3: available[i] = false; L4: release(m[i]); L5: return i; } else { L6: release(m[i]); } L7: i++; } L8: return i; } Choose N = 2 Summaries: <pc,i,(m[0],m[1]),(a[0],a[1]> <pc’,i’,(m[0]’,m[1]’),(a[0]’,a[1]’)> <L0, 0, (0,0), (0,0)> <L1, 1, (0,0), (0,0)> <L0, 0, (0,0), (0,1)> <L1, 1, (0,0), (0,1)> <L0, 0, (0,0), (1,0)> <L5, 0, (0,0), (0,0)> <L0, 0, (0,0), (1,1)> <L5, 0, (0,0), (0,1)> <L1, 1, (0,0), (0,0)> <L8, 2, (0,0), (0,0)> <L1, 1, (0,0), (0,1)> <L5, 1, (0,0), (0,0)> <L1, 1, (0,0), (1,0)> <L8, 2, (0,0), (1,0)> <L1, 1, (0,0), (1,1)> <L5, 1, (0,0), (1,0)>
Abstraction • Represent only aspects of the program relevant to property being checked • Automatic iterative refinement of abstractions • Use “regions” to construct conservative abstractions of the heap
Composition • Divide and conquer • Check one component of the model at a time • Requires behavioral contracts
Outline • Overview • Zing “show and tell” • Architecture • State-space reduction algorithms • Conformance Checker
Contract checking Does each implementation conform to its contract? Example: Does A conform to CA? Use only CB and CC (and not B and C during this check) CA CB CC A
CA Spec (Zing) Impl (Zing) CB CC Zing Conformance Checker A Contract checking
Conformance and Zing • Conformance was originally defined syntactically for CCS • Tony Hoare helped us generalize definition to make it purely semantic • makes no assumptions about the syntactic structure of the processes • can work for any system where we can observe externally visible behavior for processes • we have implemented exactly this on top of Zing!
Conformance Checker Stack dfsStack; Hashtable stateHash; voidaddState(State i, State s) { StatePair combinedState = new StatePair(i,s); if(!stateHash.contains(combinedState)){ stateHash.add(combinedState); dfsStack.push(combinedState); } } voiddoDfs(State initImpl, State initSpec) { addState(initImpl, initSpec); while(dfsStack.Count > 0) { StatePair pair = dfsStack.Peek(); State I = pair.first(); State S = pair.second(); State newI = I.GetNextSuccessor(); // lookup the events on the transition from I to newI if (newI == null) { if (isStable(I)){ // first get all the events we executed from I Event[][] IEvents = I.AccumulateEvents; if (!checkRefusals(S, IEvents)) { Console.WriteLine(“Contract over-promises”); generateError(I, S); return; } } dfsStack.Pop(); continue; } Event[] events = newI.Events; State newS = executeWithTrace (S, events); if (newS == null){ Console.WriteLine(“Implementation has unspecified behavior”); continue; } addState (newI, newS); } } StateexecuteWithTrace(State s, Event[]l ) { S’: S l S’, if such S’ exists null: otherwise } BoolcheckRefusals(State s, Event[][] L){ true: exists stable S’ such that S * S’, and for all l, if S’ l then l L false: otherwise }