Techniques based on (systematic) state-space exploration
Many different flavours
Success stories
Hardware verification
UPPAAL
Heuristic bug finders
Usually based on a combination of mentioned methods
Mainly focussing on implicit specifications
Sometimes difficult to only report genuine bugs
Example - Clang
void f(void) {
int * x = malloc(10 * sizeof(int));
}
int main(void) {
f();
return 0;
}
clang --analyze main.c
main.c:5:11: warning: Value stored to 'x' during its initialization is never read [deadcode.DeadStores]
5 | int* x = malloc(10 * sizeof(int));
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~
main.c:6:3: warning: Potential leak of memory pointed to by 'x' [unix.Malloc]
6 | }
Identify set $\text{Err} \subseteq S$ of error states
System $(S, I, \rightarrow)$ is safe if there is no path
$s_0 \rightarrow s_1 \rightarrow ... \rightarrow s_n$ with $s_0 \in I$ and $s_n \in \text{Err}$
Safety of program = unreachability in graph $(S, \rightarrow)$
If no error state can be reached for any possible input, the program is safe
Example
bool a, b;
while(!a || !b) {
if (a)
b = true;
a = !a;
}
assert(b);
Explicit-state model checking
Explicitly construct graph $(S, I, \rightarrow)$
Check reachability of error states
Example tools: Spin, Java Path Finder
Problem: state-space explosion
E.g., prog. with ten 32-bit integers has $\geq 2^{320}$ states
Several solutions exist
E.g., based on state space abstraction, or bounding the number of steps in state exploration
Check videos of prior course offering (link on Studium)
Deductive Verification
Recap contracts
Contracts define pre- and postconditions
For function contracts:
Precondition must be upheld by the caller of the function
Postcondition must be guaranteed by the function
Contracts can also be put on individual statements
If precondition holds before executing statement $s$, then the postcondition must
hold after execution of $s$ has finished
How can we apply this to C programs?
Background - Hoare Logic
At each position (state) in a program we have a set of properties that are true
With each statement that we execute these properties change
Mathematical basis: Hoare logic
An Axiomatic Basis for Computer Programming (Hoare, 1969)
Describe a computation step as a Hoare triple $\{P\}\; C \:\{Q\}$
Whenever property $P$ holds, then after executing $C$ (if $C$ terminates), $Q$ will hold
Example: $\{\Phi\}\; \textbf{nop} \:\{\Phi\}$
Background - Weakest Precondition Calculus
Hoare logic gives us a formalism, but no algorithm
Weakest precondition calculus
Guarded commands, non-determinancy and formal derivation of programs (Dijkstra, 1975)
Given the postcondition $Q$ and a computation $C$, we can mechanically derive a weakest precondition $P'$
If $P \Rightarrow P'$ then we have proven the contract
Example: For $\{P\}\; x := a \:\{x = 42\}$ the weakest precondition is $\{a = 42\}$
Example
/*
PRE: a > 0
POST: ret > 0
*/
int f(int a) {
int x = a;
x = 2 * x;
x = x + 2;
return x;
}
Example
/*
PRE: a > 0
POST: ret > 0
*/
int f(int a) {
int x = a;
x = 2 * x;
x = x + 2;
/* { x > 0 } */
return x;
}
Example
/*
PRE: a > 0
POST: ret > 0
*/
int f(int a) {
int x = a;
x = 2 * x;
/* { x + 2 > 0 } */
x = x + 2;
/* { x > 0 } */
return x;
}
Example
/*
PRE: a > 0
POST: ret > 0
*/
int f(int a) {
int x = a;
x = 2 * x;
/* { x > -2 } */
x = x + 2;
/* { x > 0 } */
return x;
}
Example
/*
PRE: a > 0
POST: ret > 0
*/
int f(int a) {
int x = a;
/* { 2 * x > -2 } */
x = 2 * x;
/* { x > -2 } */
x = x + 2;
/* { x > 0 } */
return x;
}
Example
/*
PRE: a > 0
POST: ret > 0
*/
int f(int a) {
int x = a;
/* { x > -1 } */
x = 2 * x;
/* { x > -2 } */
x = x + 2;
/* { x > 0 } */
return x;
}
Example
/*
PRE: a > 0
POST: ret > 0
*/
int f(int a) {
/* { a > -1 } */
int x = a;
/* { x > -1 } */
x = 2 * x;
/* { x > -2 } */
x = x + 2;
/* { x > 0 } */
return x;
}
Example
/*
PRE: a > 0
POST: ret > 0
*/
int f(int a) {
/* { a > -1 } => is implied by PRE */
int x = a;
/* { x > -1 } */
x = 2 * x;
/* { x > -2 } */
x = x + 2;
/* { x > 0 } */
return x;
}
WP calculus - revisit
For a computation $C$ and a postcondition $Q$, WP calculus provides us with $wp$ s.t.:
$\{wp(C, Q)\}\; C\; \{Q\}$ is a valid Hoare triple