Date post: | 01-Jan-2016 |
Category: |
Documents |
Upload: | adrienne-orr |
View: | 18 times |
Download: | 1 times |
Specifying Temporal Properties Specifying Temporal Properties of Software Using the of Software Using the Bandera Specification LanguageBandera Specification Language
James Corbett
Matthew Dwyer
John Hatcliff
Robby
[U. Hawaii]
[Kansas State]
[Kansas State]
[Kansas State]
http://www.cis.ksu.edu/santos/bandera
Bandera:Bandera:An open tool set for model-checking Java source codeAn open tool set for model-checking Java source code
Checker Inputs
CheckerOutputs
Optimization Control
Transformation &Abstraction Tools
ModelCheckers
Java Source
void add(Object o) { buffer[head] = o; head = (head+1)%size;}
Object take() { … tail=(tail+1)%size; return buffer[tail];}
Temporal Specification
Graphical User Interface
Error Trace Mapping
Bandera
Slicing
AbstractInterpretation
Static Analysis
?
Issue: Rendering RequirementIssue: 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.”
[]((open && <>close) -> ((!pushX && !close) U (close || ((pushX && !close) U (close || ((!pushX && !close) U (close || ((pushX && !close) U (close || (!pushX U close))))))))))
…is rendered in LTL as...
Graphical User Interface
Issue: Checker DependenceIssue: Checker Dependence
Checker Inputs
Transformation &Abstraction Tools
ModelCheckers
Java Source
void add(Object o) { buffer[head] = o; head = (head+1)%size;}
Object take() { … tail=(tail+1)%size; return buffer[tail];}
Temporal Specification
Bandera
LTL
LTL
Spin
CTL
SMV
CSP
FDR
mismatch!
Issue: Representation DependenceIssue: Representation Dependence
Source’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))
Heap.b.head == Heap.b.tail
Model’s representation
Issue: Issue: Naming Heap-allocated ObjectsNaming Heap-allocated Objects
Requirement:
If a buffer instance becomes full,it will eventually become non-full.
Consider multiple instances of a bounded buffer class...
In general, a heap object has no program-level name that persists throughout the lifetime of the object.
b1 b2 b3 Variables
Heap object
BSL: BSL: Bandera Specification LanguageBandera Specification Language
Assertion DefinitionPredicate Definition
Assertion PropertySpecification
(selective enabling)
Temporal PropertySpecification
(via pattern language)Quantification
Propositions stated in terms of source code features
Based on an extensible system of temporal specification patterns
Heap objects are named via object quantification
Assertion FormsAssertion Forms
Pre-conditions
@assert PRE <name> <exp>;
Post-conditions
@assert POST <name> <exp>;
Arbitrary Locations
@assert LOCATION[<label>] <name> <exp>;
/** * @assert * PRE foo: (I > 5); * POST bar: (I < 10); * LOCATION[here] checka: * (m.q.a == 4); */
public mymethod(int I) { … … here: … … }
Predicate FormsPredicate Forms Static/Instance Data Constraints
@observable [static] EXP <name> <exp>;
Invocation
@observable INVOKE <name> <exp>;
Return
@observable RETURN <name> <exp>;
Arbitrary Locations
@observable LOCATION[<label>] <name> <exp>;
Semantic IssuesSemantic Issues
Relationship between assertion PRE and predication INVOKE
@assert PRE <name> <exp>;
@observable INVOKE <name> <exp>;
IMPLICATION: holds if <exp> is true WHEN control is at entry of method (true otherwise)
CONJUNCTION: holds if <exp> is true AND control is at entry of method
Semantic IssuesSemantic Issues
o1.next.value == 0
(o1 != null) && (o1.next != null) && ( )
Methodology: Methodology: Property SpecificationProperty 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.
Given a software requirement...
Bounded Buffer 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 () {…}}
Initialization
head tail
Add,Add
head tail
Add,Take,Take
headtail
Bounded Buffer 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 tail
Add,Take,Take
headtail
Bounded Buffer 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]; }
Initialization
head tail
Add,Add
head tail
Add,Take,Take
headtail
Bounded Buffer PropertiesBounded Buffer Properties
Full buffers eventually become non-fullIndices always stay in rangeEmpty buffers must be added to before
being taken from Buffers are constructed with positive
boundsElements are always added in correct
position
Property SpecificationProperty Specification
class BoundedBuffer { Object [] buffer; int head, tail, bound;
public synchronized void add(Object o) {…}
public synchronized Object take () {…}}
Requirement 1:
If a buffer becomes full,it will eventually becomenon-full.
/** * @observable * EXP Full: (head == tail); */
Bandera Specification:
FullToNonFull: {!Full(b)} responds to {Full(b)} globally;
forall[b:BoundedBuffer].
Property SpecificationProperty Specification
class BoundedBuffer { Object [] buffer; int head, tail, bound;
public synchronized void add(Object o) {…}
public synchronized Object take () {…}}
Requirement 2:
/** * @observable * EXP HeadRange: * head >= 0 && head < bound; * Exp TailRange: * tail >= 0 && tail < bound; */
Indices always stay in range.
Bandera Specification:
IndexRangeInvariant: {HeadRange(b) && TailRange(b)} is universal globally;
forall[b:BoundedBuffer].
Property SpecificationProperty Specification
Requirement 3:
Empty buffers must added to before being taken from
Bandera Specification:
NoTakeWhileEmpty: {take.Return(b)} is absent after {Empty(b)} until {add.Call(b)};
forall[b:BoundedBuffer].
/** * @observable * EXP Empty: * head == ((tail+1) % bound);*/class BoundedBuffer { int head, tail, bound;
public synchronized void add(Object o) {…}
public synchronized Object take () {…}}
/** * @observable INVOKE Call; */
/** * @observable RETURN Return; */
Property SpecificationProperty Specification
Requirement 4:
Bandera Specification:
PositiveBound: enable assertions {PositiveBound};
Buffers are constructed with positive bounds
public BoundedBuffer(int b) { bound = b; buffer = new Object[bound]; head = 0; tail = bound-1;}
/** * @assert * PRE PositiveBound: * (b > 0);*/
QuantificationQuantification
forall[b:BoundedBuffer].P(b)
Solution
Quantified set is not fixed– varies within executions– varies across executions
– 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
Quantification (Cont’d)Quantification (Cont’d)
(!selected U (selected && P(b))) || []!selected[]!selected(!selected (selected && P(b)))
[1] new BoundedBuffer(n)
[2] new BoundedBuffer(m)
[3] new BoundedBuffer(k)
new BoundedBuffer(n)
new BoundedBuffer(m) new BoundedBuffer(m)
new BoundedBuffer(k) new BoundedBuffer(k)new BoundedBuffer(k)
!selected
!selected
!selected
[1] selected
[1] selected [2] selected [3] selected
[2] selected
!selected
[1] selected
Quantification (Cont’d)Quantification (Cont’d)
class BoundedBuffer { Object [] buffer; int head, tail, bound;
public BoundedBuffer(int n) { ... }}
class heap { public static BoundedBuffer b;}
class BoundedBuffer { Object [] buffer; int head, tail, bound;
public BoundedBuffer(int n) { ... if (heap.b == null && Bandera.choose()) { heap.b = this; } }}
Quantification (Cont’d)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)
Embedding AssertionEmbedding Assertion
class BoundedBuffer { Object [] buffer; int head, tail, bound;
public BoundedBuffer(int n) {…}
public synchronized void add(Object o) {…}}
Specification:
PositiveBound: enable assertions {PosBound}; /**
* @assertion * PRE PosBound1: (n > 0); */
public BoundedBuffer(int n) { Bandera.assert(n > 0); ...}
Test Result & AssessmentsTest Result & Assessments
Property Sliced Never-claim Stored States StatesBufferAssertions Yes - 17797IndexRangeInv Yes 14 45215IndexRangeInv, BufferAssertions Yes 14 115387FullToNonFull Yes 25 64687FullToNonFull, BufferAssertions Yes 25 154842
SummarySummary
Motivation:
Makes it easier for non-expert to write temporalspecifications for Java programs
Source level Pattern based approach Tool supports:
– automatic translation– guides for writing specification (GUI)– HTML documentation generation
How?