Bandera: Extracting Finite-state
Models from Java Code
Faculty
James Corbett
Matthew Dwyer
John Hatcliff
Students and Post-docs
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
Property 1: …
Property 2: …
…
Requirement
or
Checker
Error trace
Model Checking
OK
Finite-state model
or
Model Checker
(F
W)
Temporal logic formula
Error trace
Line
Line
Line
Line
Line
Line
…
Line
Line
5: …
12: …
15:…
21:…
25:…
27:…
41:…
47:…
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
}
?b1
L1
?b1
!a1
L2
?a1
?b0
L4
!a0
?err
?err
L5
?b0
L3
Fragment of Alternating Bit Protocol
Explicit State Model-checking
Conceptual View
Explored State-Space (computation tree)
?b1
L1
?b1
!a1
L2
?a1
?b0
L4
!a0
?err
?err
L5
?b0
Implementation
Pending
L3
Fragment of Alternating Bit Protocol
[L1, (mt1, vr1), ….]
Seen Before
Explicit State Model-checking
Conceptual View
Explored State-Space (computation tree)
[L1, (mt1, vr1), ….]
?b1
L1
?b1
!a1
L2
?a1
?b0
L4
!a0
?err
?err
L5
?b0
Implementation
Pending
L3
Fragment of Alternating Bit Protocol
Seen Before
[L2, (mt2, vr2), ….] [L1, (mt1, vr1), ….]
Explicit State Model-checking
Conceptual View
Explored State-Space (computation tree)
[L1, (mt1, vr1), ….]
?b1
L1
?b1
!a1
L2
?a1
?b0
L4
[L2, (mt2, vr2), ….]
!a0
?err
?err
L5
?b0
Implementation
Pending
L3
Fragment of Alternating Bit Protocol
Seen Before
[L3, (mt3, vr3), ….] [L1, (mt1, vr1), ….]
[L5, (mt5, vr5), ….] [L2, (mt2, vr2), ….]
[L1, (mt1’, vr1’), ..]
Explicit State Model-checking
Conceptual View
Explored State-Space (computation tree)
[L1, (mt1, vr1), ….]
?b1
L1
?b1
?b0
!a1
L4
[L2, (mt2, vr2), ….]
!a0
?err
[L3, (mt3, vr3), ….]
L2
?a1
?err
L5
?b0
Implementation
Pending
L3
Fragment of Alternating Bit Protocol
Seen Before
[L5, (mt5, vr5), ….] [L1, (mt1, vr1), ….]
[L1, (mt1’, vr1’), ..] [L2, (mt2, vr2), ….]
[L3, (mt3, vr3), ….]
Explicit State Model-checking
Conceptual View
Explored State-Space (computation tree)
[L1, (mt1, vr1), ….]
?b1
L1
?b1
?b0
!a1
L4
[L2, (mt2, vr2), ….]
!a0
?err
[L3, (mt3, vr3), ….] [L5, (mt5, vr5), ….]
L2
?a1
?err
L5
?b0
Implementation
Pending
L3
Fragment of Alternating Bit Protocol
Seen Before
[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,
“Between the window open and the window
close, button X can be pushed at most twice.”
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
This suggests that model-checking can complement
existing software quality assurance techniques.
What makes model-checking
software difficult?
OK
Finite-state model
(F
W)
or
Error trace
Model Checker
Line
Line
Line
Line
Temporal logic formula
5: …
12: …
15:…
21:…
Problems using existing checkers:
Model construction
State explosion
Property specification
Output interpretation
Model Construction Problem
void add(Object o) {
buffer[head] = o;
head = (head+1)%size;
}
Object take() {
…
tail=(tail+1)%size;
return buffer[tail];
}
Program
Gap
Model Checker
Model Description
Semantic gap:
Programming Languages
methods, inheritance, dynamic creation, exceptions, etc.
Model Description Languages
automata
What makes model-checking
software difficult?
OK
Finite-state model
(F
W)
or
Error trace
Model Checker
Line
Line
Line
Line
Temporal logic formula
5: …
12: …
15:…
21:…
Problems using existing checkers:
Model construction
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 model level 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))
What makes model-checking
software difficult?
OK
Finite-state model
(F
W)
or
Error trace
Model Checker
Line
Line
Line
Line
Temporal logic formula
5: …
12: …
15:…
21:…
Problems using existing checkers:
Model construction
State explosion
Property specification
Output interpretation
State Explosion Problem
Cost is exponential in the number of
components
Bit x1,…,xN
2^N states
Moore’s law and algorithm advances can help
– Holzmann: 7 days (1980) ==> 7 seconds (2000)
Explosive state growth in software
limits scalability
What makes model-checking
software difficult?
OK
Finite-state model
(F
W)
or
Error trace
Model Checker
Line
Line
Line
Line
Temporal logic formula
5: …
12: …
15:…
21:…
Problems using existing checkers:
Model construction
State explosion
Property specification
Output interpretation
Output Interpretation Problem
Line
Line
Line
Line
Line
Line
…
Line
Line
void add(Object o) {
buffer[head] = o;
head = (head+1)%size;
}
Object take() {
…
tail=(tail+1)%size;
return buffer[tail];
}
Program
Gap
Model Description
Raw error trace may be 1000’s of steps long
Must map line listing onto model description
Mapping to source is made difficult by
5: …
12: …
15:…
21:…
25:…
27:…
41:…
47:…
Error trace
– Semantic gap & clever encodings of complex features
– multiple optimizations and transformations
Bandera:
An open tool set for model-checking Java source code
Graphical User Interface
Optimization Control
Checker
Inputs
Bandera
Temporal
Specification
Model
Checkers
void add(Object o) {
buffer[head] = o;
head = (head+1)%size;
}
Object take() {
…
tail=(tail+1)%size;
return buffer[tail];
}
Transformation &
Abstraction Tools
Java Source
Error Trace Mapping
Bandera
Checker
Outputs
Addressing the
Model Construction Problem
void add(Object o) {
buffer[head] = o;
head = (head+1)%size;
}
Object take() {
…
tail=(tail+1)%size;
return buffer[tail];
}
Java Source
Static Analyses
Abstract Interpretation
Slicing
Optimizations
Model Compiler
Model Description
Model extraction: compiling to model checker inputs:
Numerous analyses, optimizations,
two intermediate languages, multiple back-ends
Slicing, abstract interpretation, specialization
Variety of usage modes: simple...highly tuned
Addressing the
Property 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))))))))))
Using the pattern system: 2-bounded existence
Between {open} and {close}
{pushX} exists atMost {2} times;
Addressing the
State Explosion Problem
Property
void add(Object o) {
buffer[head] = o;
head = (head+1)%size;
}
…
Java Source
Model Compiler
Model Descriptions
Generate models customized wrt property!
Result: multiple models --- even as many as
one per property
Aggressive customization via slicing, abstract
interpretation, program specialization
Addressing the
Output Interpretation Problem
void add(Object o) {
buffer[head] = o;
head = (head+1)%size;
}
Model
Description
Intermediate Representations
Object take() {
…
tail=(tail+1)%size;
return buffer[tail];
}
Java Source
Model
Checker
Model Compiler
+ simulator
Error trace
Like a debugger: error traces mapped back to source
Run error traces forwards and backwards
Program state queried
Heap structures navigated
Locks, wait sets, blocked sets displayed
Line
Line
Line
Line
5: …
12: …
15:…
21:…
Bandera Architecture
Property Tool
Abstraction
Analyses Engine
BIRC
Translators
BIR
SPIN
dSPIN
Java
Jimple
Parser
SMV
Slicer
Error Trace Display
Simulator
JPF
Front End
Translates Java source to Jimple IR
Supports specification of property
Provides debugger-like step facilities
for error traces
if (x > 0)
x = y * 2;
Java
Label1: if (x <= 0) goto Label2;
t0 = y * 2;
x = t0;
Label2: …
Jimple
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 ()
{…}
}
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-directed Slicing
indirectly
relevant
Slice
mentioned
in property
Source program
Resulting
slice
slicing criterion generated automatically from
observables mentioned in the property
backwards slicing automatically finds all
components that might influence the observables.
Property-directed Slicing
/**
* @observable EXP Full: (head == tail)
*/
class BoundedBuffer {
Object [] buffer_;
int bound;
int head, tail;
Slicing Criterion
All statements
that assign to
head, tail.
removed by
slicing
public synchronized void add(Object o) {
while ( tail == head )
try { wait(); } catch ( InterruptedException ex) {}
buffer_[head] = o;
head = (head+1) % bound;
notifyAll();
}
...
}
Included in
slicing
critirion
indirectly
relevant
Abstraction
Specializer
Collapses data domains via abstract interpretation:
Code
int x = 0;
if (x == 0)
x = x + 1;
Data domains
int
(n<0) : neg
(n==0): zero
(n>0) : pos
Signs x = zero;
if (x == zero)
x = pos;
Signs
neg zero pos
Abstraction Component
Functionality
PVS
Variable
x
y
done
count
….
o
b
Concrete Abstract Inferred
Type
Type
Type
int
int
bool
int
Signs
Object
Buffer
Jimple
Jimple
Signs
Signs
Bool
intAbs
….
Point
Buffer
BASL
Compiler
Bandera
Abstraction
Specification
Abstraction
Library
Abstraction
Engine
Language
Abstracted
Jimple
Abstraction Specification
abstraction Signs abstracts int
begin
TOKENS = { NEG, ZERO, POS };
abstract(n)
begin
n < 0
n == 0
n > 0
end
-> {NEG};
-> {ZERO};
-> {POS};
operator + add
Compiled
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) */
}
Specification Creation Tools
abstraction Signs abstracts int
begin
TOKENS = { NEG, ZERO, POS };
abstract(n)
begin
n < 0
n == 0
n > 0
end
-> {NEG};
-> {ZERO};
-> {POS};
Automatic
Generation
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
Example: Start safe, then refine: +(NEG,NEG)={NEG,ZERO,POS}
Proof obligations submitted to PVS...
Forall n1,n2: neg?(n1) and neg?(n2) implies not pos?(n1+n2)
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)
Back End
Bandera Intermediate Representation (BIR)
– guarded command language
– includes: locks, threads, references, heap
– info to help translators (live vars, invisible)
entermonitor r0
r1.count = 0;
…
Jimple
loc s5: live { r0, r1 }
when lockAvail(r0.lock) do
{ lock(r0.lock); } goto s6;
loc s6: live { r1 }
when true do invisible
BIR
{ r1.count = 0;} goto s7;
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)
© Copyright 2026 Paperzz