430 likes | 545 Views
Bandera: Extracting Finite-state Models from Java Code. Students and Post-docs. Faculty. James Corbett Matthew Dwyer John Hatcliff. Shawn Laubach Corina Pasareanu Robby Hongjun Zheng. Roby Joehanes Ritesh Desai Venkatesh Ranganath Oksana Tkachuk.
E N D
Bandera: Extracting Finite-state Models from Java Code Students and Post-docs Faculty James Corbett Matthew Dwyer John Hatcliff Shawn Laubach Corina Pasareanu Robby Hongjun Zheng Roby Joehanes Ritesh Desai Venkatesh Ranganath Oksana Tkachuk
Goal: Increase Software Reliability Trends: Size, complexity, concurrency, distributed Cost of software engineer………………………. Cost of CPU cycle……………………………….. Future: Automated Fault Detection
The Dream void add(Object o) { buffer[head] = o; head = (head+1)%size; } Object take() { … tail=(tail+1)%size; return buffer[tail]; } OK Program or Error trace Checker Property 1: … Property 2: … … Requirement
Model Checking OK Finite-state model or Error trace Model Checker (F W) Line 5: … Line 12: … Line 15:… Line 21:… Line 25:… Line 27:… … Line 41:… Line 47:… Temporal logic formula
?b1 L1 L4 ?b0 ?b1 !a1 ?err !a0 L2 L5 ?err ?b0 ?a1 L3 Spin Example proctype A(chan in, out) { byte mt; /* message data */ bit vr; L1: mt = (mt+1%MAX); out!mt,1; goto L2; L2: in?vr; if :: (vr == 1) goto L1 :: (vr == 0) goto L3 :: printf(“Error”); goto L5 fi; L3: out!mt,1; goto L2; L4: in?vr; if :: goto L1; :: printf(“Error”); goto L5 fi; L5: out!mt,0; goto L4 } Fragment of Alternating Bit Protocol
Conceptual View Explored State-Space (computation tree) ?b1 L1 L4 ?b0 ?b1 !a1 ?err !a0 L2 L5 ?err ?b0 ?a1 Implementation Pending Seen Before L3 [L1, (mt1, vr1), ….] Fragment of Alternating Bit Protocol Explicit State Model-checking
?b1 L1 L4 ?b0 ?b1 !a1 ?err !a0 L2 L5 ?err ?b0 ?a1 Pending Seen Before L3 Fragment of Alternating Bit Protocol Explicit State Model-checking Conceptual View Explored State-Space (computation tree) [L1, (mt1, vr1), ….] Implementation [L2, (mt2, vr2), ….] [L1, (mt1, vr1), ….]
?b1 L1 L4 ?b0 ?b1 !a1 ?err !a0 L2 L5 ?err ?b0 ?a1 Pending Seen Before L3 Fragment of Alternating Bit Protocol Explicit State Model-checking Conceptual View Explored State-Space (computation tree) [L1, (mt1, vr1), ….] [L2, (mt2, vr2), ….] Implementation [L3, (mt3, vr3), ….] [L1, (mt1, vr1), ….] [L5, (mt5, vr5), ….] [L2, (mt2, vr2), ….] [L1, (mt1’, vr1’), ..]
?b1 L1 L4 ?b0 ?b1 !a1 ?err !a0 L2 L5 ?err ?b0 ?a1 Pending Seen Before L3 Fragment of Alternating Bit Protocol Explicit State Model-checking Conceptual View Explored State-Space (computation tree) [L1, (mt1, vr1), ….] [L2, (mt2, vr2), ….] [L3, (mt3, vr3), ….] Implementation [L5, (mt5, vr5), ….] [L1, (mt1, vr1), ….] [L1, (mt1’, vr1’), ..] [L2, (mt2, vr2), ….] [L3, (mt3, vr3), ….]
?b1 L1 L4 ?b0 ?b1 !a1 ?err !a0 L2 L5 ?err ?b0 ?a1 Pending Seen Before L3 Fragment of Alternating Bit Protocol Explicit State Model-checking Conceptual View Explored State-Space (computation tree) [L1, (mt1, vr1), ….] [L2, (mt2, vr2), ….] [L3, (mt3, vr3), ….] [L5, (mt5, vr5), ….] Implementation [L1, (mt1’, vr1’), ..] [L1, (mt1, vr1), ….] [L2, (mt2, vr2), ….] [L3, (mt3, vr3), ….] [L5, (mt5, vr5), ….]
Why Try to Use Model Checking for Software? • Automatically check, e.g., • invariants, simple safety & liveness properties • absence of dead-lock and live-lock, • complex event sequencing properties, • In contrast to testing, gives complete coverage by exhaustively exploring all paths in system, • It’s been used for years with good success in hardware and protocol design “Between the window open and the window close, button X can be pushed at most twice.” This suggests that model-checking can complement existing software quality assurance techniques.
OK Finite-state model or Line 5: … Line 12: … Line 15:… Line 21:… Error trace Model Checker (F W) Temporal logic formula What makes model-checking software difficult? • Model construction Problems using existing checkers: • State explosion • Property specification • Output interpretation
Gap Model Construction Problem void add(Object o) { buffer[head] = o; head = (head+1)%size; } Object take() { … tail=(tail+1)%size; return buffer[tail]; } • Semantic gap: Model Checker Program Model Description Programming Languages methods, inheritance, dynamic creation, exceptions, etc. Model Description Languages automata
OK Finite-state model or Line 5: … Line 12: … Line 15:… Line 21:… Error trace Model Checker (F W) Temporal logic formula What makes model-checking software difficult? • Model construction Problems using existing checkers: • State explosion • Property specification • Output interpretation
Property Specification Problem • 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))))))))))
Property Specification Problem Forced to state property in terms of model rather than source: • We want to write source level specifications... Heap.b.head == Heap.b.tail • We are forced to write modellevel specifications... (((_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))
OK Finite-state model or Line 5: … Line 12: … Line 15:… Line 21:… Error trace Model Checker (F W) Temporal logic formula What makes model-checking software difficult? • Model construction Problems using existing checkers: • State explosion • Property specification • Output interpretation
Bit x1,…,xN 2^N states State Explosion Problem • Moore’s law and algorithm advances can help • Holzmann: 7 days (1980) ==> 7 seconds (2000) • Explosive state growth in software limits scalability • Cost is exponential in the number of components
OK Finite-state model or Line 5: … Line 12: … Line 15:… Line 21:… Error trace Model Checker (F W) Temporal logic formula What makes model-checking software difficult? • Model construction Problems using existing checkers: • State explosion • Property specification • Output interpretation
Line 5: … Line 12: … Line 15:… Line 21:… Line 25:… Line 27:… … Line 41:… Line 47:… Gap Error trace Output Interpretation Problem void add(Object o) { buffer[head] = o; head = (head+1)%size; } Object take() { … tail=(tail+1)%size; return buffer[tail]; } • Raw error trace may be 1000’s of steps long Model Description Program • Must map line listing onto model description • Mapping to source is made difficult by • Semantic gap & clever encodings of complex features • multiple optimizations and transformations
Graphical User Interface Optimization Control Checker Inputs Bandera Temporal Specification 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
Static Analyses Abstract Interpretation Optimizations void add(Object o) { buffer[head] = o; head = (head+1)%size; } Object take() { … tail=(tail+1)%size; return buffer[tail]; } Slicing Java Source Model Compiler Model Description Model extraction: compiling to model checker inputs: Addressing theModel Construction Problem • Numerous analyses, optimizations,two intermediate languages, multiple back-ends • Slicing, abstract interpretation, specialization • Variety of usage modes: simple...highly tuned
Using the pattern system: 2-bounded existence Between {open} and {close} {pushX} exists atMost {2}times; Addressing theProperty Specification Problem An extensible language based on field-tested temporal property specification patterns []((open /\ <>close) -> ((!pushX /\ !close) U (close \/ ((pushX /\ !close) U (close \/ ((!pushX /\ !close) U (close \/ ((pushX /\ !close) U (close \/ (!pushX U close))))))))))
Property Generate models customized wrt property! • Result: multiple models --- even as many as one per property Addressing theState Explosion Problem void add(Object o) { buffer[head] = o; head = (head+1)%size; } … Java Source Model Compiler Model Descriptions • Aggressive customization via slicing, abstract interpretation, program specialization
void add(Object o) { buffer[head] = o; head = (head+1)%size; } Object take() { … tail=(tail+1)%size; return buffer[tail]; } Java Source Line 5: … Line 12: … Line 15:… Line 21:… + simulator Like a debugger: error traces mapped back to source Addressing theOutput Interpretation Problem Model Description Intermediate Representations Model Checker Model Compiler Error trace • Run error traces forwards and backwards • Program state queried • Heap structures navigated • Locks, wait sets, blocked sets displayed
Translators Property Tool Abstraction Engine BIR Analyses BIRC SPIN dSPIN Java Jimple Parser SMV Slicer Simulator JPF Error Trace Display Bandera Architecture
Front End • Translates Java source to Jimple IR • Supports specification of property • Provides debugger-like step facilities for error traces Label1: if (x <= 0) goto Label2; t0 = y * 2; x = t0; Label2: … if (x > 0) x = y * 2; Java Jimple
Requirement: If a buffer becomes full, it will eventually become non-full. Bandera Specification: FullToNonFull: forall[b:BoundedBuffer]. {Full(b)} leads 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 () {…} }
indirectly relevant Slice mentioned in property Resulting slice Property-directed Slicing • slicing criterion generated automatically from observables mentioned in the property Source program • backwards slicing automatically finds all components that might influence the observables.
Slicing Criterion All statements that assign to head, tail. removed by slicing Included in slicing critirion indirectly relevant Property-directed Slicing /** * @observable EXP Full: (head == tail) */ class BoundedBuffer { Object [] buffer_; int bound; int head, tail; public synchronized void add(Object o) { while ( tail == head ) try { wait(); } catch ( InterruptedException ex) {} buffer_[head] = o; head = (head+1) % bound; notifyAll(); } ... }
int (n<0) : neg (n==0): zero (n>0) : pos Signs Signs x = zero; if (x == zero) x = pos; neg zero pos AbstractionSpecializer Collapses data domains via abstract interpretation: Code Data domains int x = 0; if (x == 0) x = x + 1;
PVS BASL Compiler Concrete Type Abstract Type Inferred Type Variable Bandera Abstraction Specification Language Jimple Abstracted Jimple Abstraction Engine Jimple Abstraction Component Functionality x int Signs y int Signs Signs done bool Bool Abstraction Library count int intAbs …. …. o Object Point b Buffer Buffer
Compiled Abstraction Specification 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 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 abstract(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) */ }
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) Specification Creation Tools 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}; end
Back End • Bandera Intermediate Representation (BIR) • guarded command language • includes: locks, threads, references, heap • info to help translators (live vars, invisible) loc s5: live { r0, r1 } when lockAvail(r0.lock) do { lock(r0.lock); } goto s6; loc s6: live { r1 } when true do invisible { r1.count = 0;} goto s7; entermonitor r0 r1.count = 0; … Jimple BIR
Bounded Buffer BIR process BoundedB() BoundedBuffer_ref = ref { BoundedBuffer_col, BoundedBuffer_col_0 }; BoundedBuffer_rec = record { bound_ : range -1..4; head_ : range -1..4; tail_ : range -1..4; BIRLock : lock wait reentrant; }; BoundedBuffer_col : collection [3] of BoundedBuffer_rec; BoundedBuffer_col_0 : collection [3] of BoundedBuffer_rec; ……. ………. loc s34: live { b2, b1, add_JJJCTEMP_0, add_JJJCTEMP_6, add_JJJCTEMP_8 } when true do invisible { add_JJJCTEMP_8 := (add_JJJCTEMP_6 % add_JJJCTEMP_8); } goto s35; loc s35: live { b2, b1, add_JJJCTEMP_0, add_JJJCTEMP_8 } when true do { add_JJJCTEMP_0.head_ := add_JJJCTEMP_8; } goto s36; loc s36: live { b2, b1, add_JJJCTEMP_0 } when true do { notifyAll(add_JJJCTEMP_0.BIRLock); } goto s37; loc s37: live { b2, b1, add_JJJCTEMP_0 } when true do { unlock(add_JJJCTEMP_0.BIRLock); } goto s38;
Bounded Buffer Promela typedef BoundedBuffer_rec { type_8 bound_; type_8 head_; type_8 tail_; type_18 BIRLock; } … … loc_25: atomic { printf("BIR: 25 0 1 OK\n"); if :: (_collect(add_JJJCTEMP_0) == 1) -> add_JJJCTEMP_8 = BoundedBuffer_col. instance[_index(add_JJJCTEMP_0)].tail_; :: (_collect(add_JJJCTEMP_0) == 2) -> add_JJJCTEMP_8 = BoundedBuffer_col_0. instance[_index(add_JJJCTEMP_0)].tail_; :: else -> printf("BIR: 25 0 1 NullPointerException\n"); assert(0); fi; goto loc_26; }
Translators • Plug-in component that interfaces to specific model checker • Translates BIR to checker input language • Parses output of checker for error trace • Currently • SPIN, dSPIN, SMV translators complete • JPF (from NASA Ames) integrated • XMC, FDR translators in progress
Case Studies • Small examples thus far (< 2000 loc) • illustrating use of property-pattern system and other components • Scheduler from DEOS real-time OS kernel • (1600, 22 classes, seven tasks) • Now trying systems up to 20,000 loc • collection of 15 open-source 100% pure Java • Jigsaw web-server from W3C • Tomcat, James(from Apache/Jakarta) • In general, 1-2 minutes for model extraction on (~2000k systems) • State space reductions can dramatically reduce cost
Summary • Bandera provides an open platform for experimentation • Separates model checking from extraction • uses existing model checkers • supports multiple model checkers • Specialize models for specific properties using automated support for slicing, abstraction, etc. • Designed for extensibility • well-defined internal representations and interfaces • We hope this will contribute to the definition of APIs for software model-checkers
Context of Project • Researchers with different backgrounds (programming languages, static analysis, verification of concurrent systems, software engineering) • Started on Bandera in November 1998 (previously built verification tools for Ada) • Funding from NASA, National Science Foundation, Honeywell, US Air Force
Current Status • A reasonable subset of concurrent Java • not handled: recursive methods, exceptions, inner classes, native methods, libraries(*) • You can play around with a “pre-alpha” version of the tools accompanied by a draft tutorial • Public release: October 2000 http://www.cis.ksu.edu/santos/bandera
Schedule of BRICS Mini-Course • Monday -- Overview • overview talk • basic demo • Tuesday -- Specifying Temporal Properties of Software • overview of temporal specification • review of CTL, LTL • temporal specification design patterns • example driven presentation of Bandera’s specification tools • Wednesday -- Details of Bandera Components • slicing concurrent Java programs • Bandera abstraction tools • model generation via Bandera’s back-end • summary of case studies (e.g., space-craft controller examples)