COMS E6998 Formal Verification of System Software
Fall 2018
Ronghui Gu
Software Errors Cost Economy $312 Billion Annually. – Cambridge[2013]
void withdraw(account) { uint balance = bank.balance[account]; if (balance <= 0) { return; } bank.fund -= balance; receiverHandlePayment (account, balance); bank.balance[account] = 0; }
sort (int* a)
sort
to be correct?Program testing can be used to show the presence of bugs, but never to show their absence. – Edsger Dijkstra
bool av (program p) { if (p has bugs) { return false; } return true; }
NO! Because of the halting problem [Alan Turing 1936]: if av
exists then there is a paradox; thus av
can’t exist.
Proof.
Let “bug”=infinite loop=infloop()
. If p
is a program then let 'p(p)
be the program that when run, it will execute p
on input p
.
Assume av
exists. Create:
paradox(p:Prog) = if av(’p(p)) then infloop() else true
What does paradox(paradox)
do?
paradox(paradox)
loops forever then av(’paradox(paradox))=false
, thus paradox(paradox)
returns true. Contradictionparadox(paradox)
returns true, i.e., av(’paradox(paradox))=true
, thus paradox(paradox)
loops forever. ContradictionA non-constructive proof
3n+1
conjecture:
void collatz (int i) { while (i > 1) { if (i is even) i = i / 2; else i = 3 * i + 1; } }
Can we have a mathematical proof system to prove correctness/incorrectness for all programs?
Can we create a system L of logical axioms and rules, such that for any program p we can prove either
NO! If such a system L exists then we can create a fully automatic verification algorithm (simply systematically explore all logical derivations and eventually, in finite time, derive “p has a bug” or “p has no bug”.)
Hilbert’s program in early 1920s
NO! Kurt Gödel proved in 1931 (incompleteness theorems)that no such logical system exists.
“Any consistent formal system F within which a certain amount of elementary arithmetic can be carried out is incomplete; i.e., there are statements of the language of F which can neither be proved nor disproved in F.”
Soundness: If the verification method reports no failure, then the program under examination has no bug Completeness: If the verification method reports a failure, then the program under examination has a bug Termination: The verification method will terminate, giving back an answer.
However not all is lost! Sound and terminating systems can prove the correctness of virtually every program we would care about.
The scientific community continuously pushes the limits of these systems to extreme levels!
A model checker is a program that checks if a (transition) system satisfies a (temporal) property.
10: while (true) { 11: wait(turn == 0); // critical section critical section 12: work(); turn = 1; 13: } // concurrently with 20: while (true) { 21: wait(turn == 1); // critical section critical section 22: work(); turn = 0; 23: }
Evaluate the program on symbolic input values and use an automated theorem prover to check whether there are corresponding concrete input values that make the program fail.
foo (x) { if (x > 0) x = x + 1; else x = 1 - x; x = 8 / x; }
x0 > 0
x1 = x0 + 1
x1 = 0
x0 <= 0
x1 = 1 - x0
x1 = 0
foo (x) { // x:(-$, +$) if (x > 0) // x:(0, +$) x = x + 1; // x:(1, +$) else // x:(-$, 0] x = 1 - x; // x:[1, +$) x = 8 / x; // x:[1, +$) }
foo (x) { // x:(-$, +$) if (x > 0) // x:(0, +$) x = 2 * x + 1; // x:(1, +$) else // x:(-$, 0] x = 1 - 2 * x; // x:[1, +$) x = 8 / (x % 2); // x:[1, +$) }
foo (x) { // x:(-$, +$), x%2: {0, 1} if (x > 0) // x:(0, +$), x%2: {0, 1} x = 2 * x + 1; // x:(1, +$), x%2: {1} else // x:(-$, 0], x%2: {0, 1} x = 1 - 2 * x; // x:[1, +$), x%2: {1} x = 8 / (x % 2); // x:[1, +$), x%2: {1} }
Weakening Rule
Assignment Rule
Sequential Rule
Conditional Branch Rule
Partial Correctness of Loops Rule
// { T } (PRE) foo (x) { if (x > 0) { // { T ∧ x > 0 } (IF) // { x + 1 > 1 } (WEAK) x = x + 1; // { x > 1 } (ASG) // { x >= 1 } (WEAK) } else { // { T ∧ ~(x > 0) } (IF) // { 1 - x >= 1 } (WEAK) x = 1 - x; // { x >= 1 } (ASG) } // { x >= 1 } (IF) x = 8 / x; }