Professional Documents
Culture Documents
Symbolic Execution: - Builds Predicates That Characterize
Symbolic Execution: - Builds Predicates That Characterize
(c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 1 (c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 3
(c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 4 (c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 5
Dealing with branching statements Executing while (high >= low) {
a sample program Add an expression that records the condition for the execution of
the branch (PATH CONDITION)
char *binarySearch( char *key, char *dictKeys[ ],
char *dictValues[ ], int dictSize) {
before
int low = 0; low = 0
int high = dictSize - 1; and high = (H-1)/2 -1
int mid;
int comparison;
and mid = (H-1)/2
Branching stmt while (high >= low) { while (high >= low)!!
mid = (high + low) / 2;
comparison = strcmp( dictKeys[mid], key );
if (comparison < 0) { after
low = mid + 1; low = 0
} else if ( comparison > 0 ) { and high = (H-1)/2 -1
high = mid - 1;
} else {
and mid = (H-1)/2
return dictValues[mid]; and (H-1)/2 - 1 >= 0 if the TRUE branch was taken
}
}
return 0;
... and not((H-1)/2 - 1 >= 0) if the FALSE branch was taken
(c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 6 (c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 7
(c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 8 (c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 9
Weaker preconditions Loops and assertions
• The weaker predicate L <= mid <= H is chosen based on • The number of execution paths through a program with
what must be true for the program to execute correctly loops is potentially infinite
• It cannot be derived automatically from source code • To reason about program behavior in a loop, we can
• it depends on our understanding of the code and our place within the loop an invariant:
rationale for believing it to be correct – assertion that states a predicate that is expected to be true
each time execution reaches that point.
• A predicate stating what should be true at a given point
can be expressed in the form of an assertion • Each time program execution reaches the invariant
assertion, we can weaken the description of program
• Weakening the predicate has a cost for testing: state:
– satisfying the predicate is no longer sufficient to find data that
– If predicate P represents the program state
forces program execution along that path.
• test data that satisfies a weaker predicate W is necessary to – and the assertion is W
execute the path, but it may not be sufficient – we must first ascertain P => W
• showing that W cannot be satisfied shows path infeasibility – and then we can substitute W for P
(c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 10 (c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 11
int low = 0;
Forall{i,j} 0 <= i < j < size :
int high = dictSize - 1; dictKeys[i] <= dictKeys[j] Instantiated invariant: Forall{i,j} 0 <= i < j < size :
int mid; dictKeys[i] <= dictKeys[j]
int comparison; and Forall{k} 0 <= k < size :
while (high >= low) { Invariant: in range dictKeys[k] = key => L <= k <= H
mid = (high + low) / 2;
Forall{i} 0 <= i < size : After executing: mid = (high + low)/2
comparison = strcmp( dictKeys[mid], key ); Invariant
if (comparison < 0) { dictKeys[i] = key =>
Forall{i} 0 <= i < size :
low = mid + 1; low <= i <= high low = L dictKeys[i] = key =>
} else if ( comparison > 0 ) { and high = H low <= i <= high
high = mid - 1;
} else {
and mid = M
return dictValues[mid]; and Forall{i,j} 0 <= i < j < size :
} dictKeys[i] <= dictKeys[j]
} and Forall{k} 0 <= k < size :
return 0;
dictKeys[k] = key => L <= k <= H
and H >= M >= L ….
(c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 14 (c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 15
(c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 16 (c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 17
Reasoning about Hoare triples:
Compositional reasoning
inference
• Follow the hierarchical structure of a program
– at a small scale (within a single procedure) premise
[I and C] S [I]
– at larger scales (across multiple procedures…)
[I] while(C){S} [I and notC]
conclusion
• Hoare triple: [pre] block [post]
Inference rule says:
if we can verify the premise (top),
• if the program is in a state satisfying the then we can infer the conclusion (bottom)
precondition pre at entry to the block, then
after execution of the block it will be in a state
satisfying the postcondition post
(c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 18 (c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 19
(c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 20 (c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 21
Reasoning about data structures and
Structural invariants
classes
• Data structure module = collection of • Structural characteristics that must be
procedures (methods) whose specifications are maintained as specified as structural invariants
strongly interrelated (~loop invariants)
• Contracts: specified by relating procedures to • Reasoning about data structures
an abstract model of their (encapsulated) inner
– if the structural invariant holds before execution
state
– and each method execution preserve the invariant
– …then the invariant holds for all executions
example:
Dictionary can be abstracted as {<key, value>}
independent of the implementation as a list, Example: Each method in a search tree class
tree, hash table, etc. maintains the ordering of keys in the tree
(c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 22 (c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 23
(c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 24 (c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 25