Lecture 0: Introduction

COMS E6998 Formal Verification of System Software
Fall 2018
Ronghui Gu

1 Formal Verification

1.1 Why should we care?

1.2 Challenges

2. Methods to Approach the Goal

2.1 Testing?

Program testing can be used to show the presence of bugs, but never to show their absence. – Edsger Dijkstra

2.2 An alternative approach: formal verification …

2.2.1 Algorithmic Verification?

  bool av (program p) {
    if (p has bugs) {
      return false;
    }
    return true;
  }

2.2.2 Deductive Verification?

3. Holy Grail of Formal Verification

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.

4. Methods for Formal Verification

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!

4.1 Algorithmic verification

4.1.1 Model Checking

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: }

4.1.2 Symbolic Execution

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;
}

4.1.3 Abstract Interpretation

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}
}

4.2 Deductive verification

4.2.1 Hoare Logic

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;
}

4.3 Success stories from the mid-1990s