530 likes | 737 Views
Bandera Tool Set. Presented by: Dor Nir. Outline . Specification Language (LTL) Software verification problems Introduction to Bandera tool Set Bandera Specification Language (BSL) Data Type Abstraction Slicing Results and conclusions. The Vision. Program Approved. Formal System
E N D
Bandera Tool Set Presented by: Dor Nir
Outline • Specification Language (LTL) • Software verification problems • Introduction to Bandera tool Set • Bandera Specification Language (BSL) • Data Type Abstraction • Slicing • Results and conclusions
The Vision Program Approved Formal System Specification Requirements Automatic Verifier Counter example Use case Source Code
Specification Languages • Linear Temporal Logic (LTL) • Computation Tree Logic (CTL, CTL*) • Excplicit Clock Temporal Logic (XCTL) • Temporal Logic of Actions (TLA, TLA+) • Interval Temporal Logic (ITL)
Propositional Linear Temporal Logic P • O(p) – next • p – always • ◊p – eventually • pUq – Until • pWq – pUq V ٱp P P P P P P P P P q Notation: p => q ≡ ٱ(pq)
Some typical property patterns Recurrence • ◊p infinitely often • ◊p eventually always Precendence • pU(qUr) p* q* r • (pUq)Ur (p*q)* r • ¬pWq p cannot occur before q r P q
Mutual Exclusion Properties • Resource is never owned by P1 and P2, simultaneously • (P1_ownP2_own) • Whenever P1 has requested the resource it will eventually get it • (P1_reqP1_own) • If P1 requests the resource infinitely often (when the resource is • free then it will infinitely often get it (strong fairness) • (P1_req (P1_ownP2_own)) P1_own
OK Finite-state system Verification tool or Error trace (F W) Line 5: … Line 12: … Line 15:… Line 21:… Line 25:… Line 27:… … Line 41:… Line 47:… Specification Finite-state Verification
Finite-state Verification • Effective for analyzing properties of hardware systems Widespread success andadoption in industry
Software verification • Recent years have seen many efforts to apply those techniques to software Limited success due to the enormous state spaces associated with most software systems
symbolic state represents a set of states Original system Abstract system abstraction Safety: The set of behaviors of the abstract system over-approximates the set of behaviors of the original system Abstraction: the key to scaling up
Goals… • Verification tool for software, using abstraction. • Easy for writing specifications. • Use of existing verification tools. • Verification time is reasonable. • Easy to understand the counter example. • Reusable. (Specifications)
Graphical User Interface Optimization Control Checker Inputs ? void add(Object o) { buffer[head] = o; head = (head+1)%size; } Object take() { … tail=(tail+1)%size; return buffer[tail]; } Model Checkers Transformation & Abstraction Tools Checker Outputs Java Source Error Trace Mapping Bandera Bandera:An open tool set for model-checking Java source code Slicing Temporal Specification Abstract Interpretation Static Analysis
Issue: Rendering Requirement • Often difficult to formalize a requirement in temporal logic “Between the window open and the window close, button X can be pushed at most twice.” …is rendered in LTL as... []((open && <>close) -> ((!pushX && !close) U (close || ((pushX && !close) U (close || ((!pushX && !close) U (close || ((pushX && !close) U (close || (!pushX U close))))))))))
Graphical User Interface mismatch! CTL CSP void add(Object o) { buffer[head] = o; head = (head+1)%size; } Object take() { … tail=(tail+1)%size; return buffer[tail]; } SMV FDR Transformation & Abstraction Tools Java Source Bandera Issue: Checker Dependence Checker Inputs LTL LTL Temporal Specification Model Checkers Spin
Issue: Representation Dependence • Source’s representation Heap.b.head == Heap.b.tail • Model’s representation (((_collect(heap_b) == 1)\ && (BoundedBuffer_col.instance[_index(heap _b)].head == BoundedBuffer_col.instance[_index(heap _b)].tail) )\ || ((_collect(heap _b) == 3)\ && (BoundedBuffer_col_0.instance[_index(heap _b)].head == BoundedBuffer_col_0.instance[_index(heap _b)].tail) )\ || ((_collect(heap _b) == 0) && TRAP))
Problem summary • Rendering • Checker dependence • Representation dependence • Quantification
Quantification BSL: Bandera Specification Language • Propositions stated in terms of source code features • Based on an extensible system of temporal specification patterns • Heap objects are named via object quantification Temporal Property Specification (via pattern language) Assertion Property Specification (selective enabling) Predicate Definition Assertion Definition
Static/Instance Data Constraints • Invocation @observable [static] EXP <name> <exp>; @observable INVOKE <name> <exp>; • Return @observable RETURN <name> <exp>; • Arbitrary Locations @observable LOCATION[<label>] <name> <exp>; Predicate Forms
Semantic Issues (o1 != null) && (o1.next != null) && ( ) o1.next.value == 0
Quantification (Cont’d) forall[b:BoundedBuffer]. {Full(b)} leads to {!Full(b)} globally; (heap.b == null U (heap.b != null && ([](heap.b.head == heap.b.tail) -> <>(heap.b.head != heap.b.tail)))) || [](heap.b == null)
Given a software requirement... Methodology: Property Specification • Identify observables (propositions) in requirement • Define propositions in source Java-doc comments • Use GUI to select appropriate temporal pattern parameterized by declared observables • Add quantification if property contains instance propositions.
Initialization head tail head head tail tail Bounded Buffer class BoundedBuffer { Object [] buffer; int head; /* next available slot */ int tail; /* last available slot */ int bound; /* max # of elements */ public BoundedBuffer(int b) {…} public synchronized boolean isEmpty() {…} public synchronized void add(Object o) {…} public synchronized Object take () {…} } Add,Add Add,Take,Take
Initialization head tail Add,Add head head tail Add,Take,Take tail Bounded Buffer public BoundedBuffer(int b) { bound = b; buffer = new Object[bound]; head = 0; tail = bound-1; } public synchronized boolean isEmpty() { return head == ((tail+1) % bound); }
Initialization head tail Add,Add head head tail Add,Take,Take tail Bounded Buffer public synchronized void add(Object o) { while ( tail == head ) try { wait(); } catch (InterruptedException ex) {} buffer_[head] = o; head = (head+1) % bound; notifyAll(); } public synchronized Object take() { while (head == ((tail+1) % bound)) try { wait(); } catch (InterruptedException ex) {} tail = (tail+1) % bound; notifyAll(); return buffer_[tail]; }
Bounded Buffer Properties • Full buffers eventually become non-full • Indices always stay in range • Empty buffers must be added to before being taken from • Buffers are constructed with positive bounds
Requirement 1: If a buffer becomes full, it will eventually become non-full. Bandera Specification: FullToNonFull: {!Full(b)} responds to {Full(b)} globally; Property Specification /** * @observable * EXP Full: (head == tail); */ class BoundedBuffer { Object [] buffer; int head, tail, bound; public synchronized void add(Object o) {…} public synchronized Object take () {…} } forall[b:BoundedBuffer].
Bandera Specification: IndexRangeInvariant: {HeadRange(b) && TailRange(b)} is universal globally; Property Specification /** * @observable * EXP HeadRange: * head >= 0 && head < bound; * Exp TailRange: * tail >= 0 && tail < bound; */ Requirement 2: Indices always stay in range. class BoundedBuffer { Object [] buffer; int head, tail, bound; public synchronized void add(Object o) {…} public synchronized Object take () {…} } forall[b:BoundedBuffer].
Bandera Specification: NoTakeWhileEmpty: {take.Return(b)} is absent after {Empty(b)} until {add.Call(b)}; Property Specification /** * @observable * EXP Empty: * head == ((tail+1) % bound); */ Requirement 3: Empty buffers must added to before being taken from class BoundedBuffer { int head, tail, bound; public synchronized void add(Object o) {…} public synchronized Object take () {…} } /** * @observable INVOKE Call; */ /** * @observable RETURN Return; */ forall[b:BoundedBuffer].
Bandera Specification: PositiveBound: enable assertions {PositiveBound}; Property Specification Requirement 4: /** * @assert * PRE PositiveBound: * (b > 0); */ Buffers are constructed with positive bounds public BoundedBuffer(int b) { bound = b; buffer = new Object[bound]; head = 0; tail = bound-1; }
Quantification forall[b:BoundedBuffer].P(b) • Quantified set is not fixed • varies within executions • varies across executions • Solution • by adding a state variable (for b) that will eventually be bound non-deterministically to each instance • by enabling checking of the formula only when variable is bound to an instance
int (n<0) : NEG (n==0): ZERO (n>0) : POS Signs Signs x = ZERO; if (Signs.eq(x,ZERO)) x = Signs.add(x,POS); NEG ZERO POS Data Type Abstraction Collapses data domains via abstract interpretation: Code Data domains int x = 0; if (x == 0) x = x + 1;
Bandera hypothesis Abstraction of data domains is necessary Automated support for • Defining abstract domains (and operators) • Selecting abstractions for program components • Generating abstract program models • Interpreting abstract counter-examples will make it possible to • Scale property verification to realistic systems • Ensure the safety of the verification process
Bandera Abstraction Specification Language PVS Concrete Type Abstract Type Inferred Type Abstraction Definition Variable x int y int done bool count int BASL Compiler …. o Object b Buffer Program Abstracted Program Abstract Code Generator Abstraction in Bandera Signs Signs Signs bool Abstraction Library int …. Point Buffer
Automatic Generation Example: Start safe, then refine:+(NEG,NEG)={NEG,ZERO,POS} Forall n1,n2: neg?(n1) and neg?(n2) implies not pos?(n1+n2) Proof obligations submitted to PVS... Forall n1,n2: neg?(n1) and neg?(n2) implies not zero?(n1+n2) Forall n1,n2: neg?(n1) and neg?(n2) implies not neg?(n1+n2) Definition of Abstractions in BASL operator + add begin (NEG , NEG) -> {NEG} ; (NEG , ZERO) -> {NEG} ; (ZERO, NEG) -> {NEG} ; (ZERO, ZERO) -> {ZERO} ; (ZERO, POS) -> {POS} ; (POS , ZERO) -> {POS} ; (POS , POS) -> {POS} ; (_,_) -> {NEG,ZERO,POS}; /* case (POS,NEG),(NEG,POS) */ end abstraction Signs abstracts int begin TOKENS = { NEG, ZERO, POS }; abstract(n) begin n < 0 -> {NEG}; n == 0 -> {ZERO}; n > 0 -> {POS}; end
Compiled Compiling BASL Definitions public class Signs { public static final int NEG = 0; // mask 1 public static final int ZERO = 1; // mask 2 public static final int POS = 2; // mask 4 public static int abs(int n) { if (n < 0) return NEG; if (n == 0) return ZERO; if (n > 0) return POS; } public static int add(int arg1, int arg2) { if (arg1==NEG && arg2==NEG) return NEG; if (arg1==NEG && arg2==ZERO) return NEG; if (arg1==ZERO && arg2==NEG) return NEG; if (arg1==ZERO && arg2==ZERO) return ZERO; if (arg1==ZERO && arg2==POS) return POS; if (arg1==POS && arg2==ZERO) return POS; if (arg1==POS && arg2==POS) return POS; return Bandera.choose(7); /* case (POS,NEG), (NEG,POS) */ } abstraction Signs abstracts int begin TOKENS = { NEG, ZERO, POS }; abstract(n) begin n < 0 -> {NEG}; n == 0 -> {ZERO}; n > 0 -> {POS}; end operator + add begin (NEG , NEG) -> {NEG} ; (NEG , ZERO) -> {NEG} ; (ZERO, NEG) -> {NEG} ; (ZERO, ZERO) -> {ZERO} ; (ZERO, POS) -> {POS} ; (POS , ZERO) -> {POS} ; (POS , POS) -> {POS} ; (_,_)-> {NEG, ZERO, POS}; /* case (POS,NEG), (NEG,POS) */ end
Data Type Abstractions • Library of abstractions for base types contains: • Range(i,j),i..j modeled precisely, e.g., Range(0,0) is the signs abstraction • Modulo(k), Set(v,…) • Point maps all concrete values to unknown • User extendable for base types • Array abstractions • Specified by an index abstraction and an element abstraction • Class abstractions • Specified by abstractions for each field
Interpreting Results • For an abstracted program, a counter-example may be infeasible because: • Over-approximation introduced by abstraction • Example: x = -2; if(x + 2 == 0) then ... x = NEG; if(Signs.eq(Signs.add(x,POS),ZERO)) then ... {NEG,ZERO,POS}
Slicing • Generate reduced model • Program P with specification Φ • Bandera collect statements of interest From Φ (slicing criterion for Φ) • Compute P’: reduce version of P. • P |= Φ P’|= Φ
Slicing In Property • Does program dependence-based slicing to get a reduced version of P • dependences: data, control, interference, ready, wait • backwards slicing • Effectiveness based on structure of program Relevant
Counter-Example: Overview • Counter-example with a thousand states?!?! Bandera provides debugger-like features: • map states to source code • program tracing • create checkpoints • keep track of variables and objects • UML-like object displays • lock graphs
Using Bandera Launch the Bandera User Interface (BUI) from the command line Future runs: save which components you want to use in session files
Mandatory Performance Slide Threaded Pipeline b: basic d: defective variant r: response property p: precedence property n: no reductions s: slicing a: slicing + data abstraction
When to Use Model Checking • Control-related properties • assertions • pre- and post-conditions • simple data invariants • Container objects • Stacks • Queues • Verifying concurrent behavior • Necessity for counter-examples • Automatic property verification of source code