• Keine Ergebnisse gefunden

Verification Condition Generation

N/A
N/A
Protected

Academic year: 2022

Aktie "Verification Condition Generation "

Copied!
3
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Systeme hoher Sicherheit und Qualität, WS 17/18 - 1 -

Systeme hoher Sicherheit und Qualität Universität Bremen, WS 2017/2018

Christoph Lüth, Dieter Hutter, Jan Peleska

Lecture 10:

Verification Condition Generation

Systeme hoher Sicherheit und Qualität, WS 17/18 - 2 -

Frohes Neues Jahr!

Systeme hoher Sicherheit und Qualität, WS 17/18 - 3 -

Where are we?

 01: Concepts of Quality

 02: Legal Requirements: Norms and Standards

 03: The Software Development Process

 04: Hazard Analysis

 05: High-Level Design with SysML

 06: Formal Modelling with OCL

 07: Testing

 08: Static Program Analysis

 09: Software Verification with Floyd-Hoare Logic

 10: Correctness and Verification Condition Generation

 11-12: Model Checking

 13: Conclusions

Systeme hoher Sicherheit und Qualität, WS 17/18 - 4 -

VCG in the Development Cycle

Systeme hoher Sicherheit und Qualität, WS 17/18 - 5 -

Introduction

In the last lecture, we introduced Hoare triples. They allow us to state and prove correctness assertions about programs, written as 𝑃 𝑝 {𝑄}

We introduced two notions, namely:

Syntactic derivability, ⊢ 𝑃 𝑝 {𝑄} (the actual Floyd-Hoare calculus)

Semantic satisfaction, ⊨ 𝑃 𝑝 {𝑄}

Question: how are the two related?

The answer to that question also offers help with a practical problem: proofs with the Floyd-Hoare calculus are exceedingly long and tedious. Can we automate them, and how?

Systeme hoher Sicherheit und Qualität, WS 17/18 - 6 -

Correctness and Completeness

In general, given a syntactic calculus with a semantic meaning, correctness means the syntactic calculus implies the semantic meaning, and completeness means all semantic statements can be derived syntactically.

Cf. also Static Program Analysis

Correctness should be a basic property of verification calculi.

Completeness is elusive due to Gödel‘s first incompleteness theorem:

Any logics which is strong enough to encode the natural numbers and primitive recursion* is incomplete.**

* Or any other notion of computation.

** Or inconsistent, which is even worse.

Systeme hoher Sicherheit und Qualität, WS 17/18 - 7 -

Correctness of the Floyd-Hoare calculus

Proof: by induction on the derivation of ⊢ 𝑃 𝑝 𝑄 .

More precisely, for each rule we show that:

If the conclusion is ⊢ 𝑃 𝑝 𝑄, we can show ⊨ 𝑃 𝑝 𝑄

For the premisses, this can be assumed.

Example: for the assignment rule, we show that

Theorem (Correctness of the Floyd-Hoare calculus) If ⊢ 𝑃 𝑝 {𝑄}, then ⊨ 𝑃 𝑝 {𝑄}.

Systeme hoher Sicherheit und Qualität, WS 17/18 - 8 -

Completeness of the Floyd-Hoare calculus

Predicate calculus is incomplete, so we cannot hope F/H is complete. But we get the following:

To show this, we construct the weakest precondition.

Theorem (Relative completeness)

If ⊨ 𝑃 𝑝 {𝑄}, then ⊢ 𝑃 𝑝 𝑄 except for the proofs occuring in the weakenings.

Weakest precondition

Given a program c and an assertion P, the weakest precondition 𝑤𝑝(𝑐, 𝑃) is an assertion W such that 1. 𝑊 is a valid precondition ⊨ 𝑊 𝑐 𝑃

2. And it is the weakest such: for any other 𝑄 such that ⊨ 𝑄 𝑐 𝑃 , 𝑊 → 𝑄

(2)

Systeme hoher Sicherheit und Qualität, WS 17/18 - 9 -

Constructing the weakest precondition

Consider a simple program and its verification:

Note how proof is constructed backwards systematically.

The idea is to construct the weakest precondition inductively.

This also gives us a methodology to automate proofs in the calculus.

𝑥 = 𝑋 ∧ 𝑦 = 𝑌

↔ 𝑦 = 𝑌 ∧ 𝑥 = 𝑋 z := y;

𝑧 = 𝑌 ∧ 𝑥 = 𝑋 y := x;

𝑧 = 𝑌 ∧ 𝑦 = 𝑋 x := z;

𝑥 = 𝑌 ∧ 𝑦 = 𝑋

Systeme hoher Sicherheit und Qualität, WS 17/18 - 10 -

Constructing the weakest precondition

There are four straightforward cases:

(1)𝑤𝑝 𝐬𝐤𝐢𝐩, 𝑃 = 𝑃 (2)𝑤𝑝 𝑋 ≔ 𝑒, 𝑃 = 𝑃 [𝑒 / 𝑋]

(3)𝑤𝑝 𝑐0; 𝑐1, 𝑃 = 𝑤𝑝(𝑐0, 𝑤𝑝 𝑐1, 𝑃 )

(4)𝑤𝑝 𝐢𝐟 𝑏 𝑐0 𝐞𝐥𝐬𝐞 𝑐1, 𝑃 = (𝑏 ∧ 𝑤𝑝 𝑐0, 𝑝 ) ∨ (¬ 𝑏 ∧ 𝑤𝑝 𝑐1, 𝑃 )

The complicated one is iteration (unsurprisingly, since it is the source of the computational power and Turing-completeness of the language). It can be given recursively:

(5)𝑤𝑝 𝐰𝐡𝐢𝐥𝐞 𝑏 𝑐 , 𝑃 = ¬ 𝑏 ∧ 𝑃 ∨ 𝑤𝑝 𝑐, 𝑤𝑝 𝐰𝐡𝐢𝐥𝐞 𝑏 𝑐 , 𝑃

A closed formula can be given, but it can be infinite and is not practical. It shows the relative completeness, but does not give us an effective way to automate proofs.

Hence, 𝑤𝑝(𝑐, 𝑃) is not effective for proof automation, but it shows the right way: we just need something for iterations.

Systeme hoher Sicherheit und Qualität, WS 17/18 - 11 -

Verification Conditions: Annotations

The idea is that we have to give the invariants manually by annotating them.

We need a language for this:

Arithmetic expressions and boolean expressions stays as they are.

Statements are augmented to annotated statements:

S ::= x := a | skip | S1; S2 | if (b) S1 else S2 | assert P | while (b) inv P S

Each while loop needs to its invariant annotated.

This is for partial correctness, total correctness also needs a variant: an expression which is strictly decreasing in a well-founded order such as (<, ℕ) after the loop body.

The assert statement allows us to force a weakening.

Systeme hoher Sicherheit und Qualität, WS 17/18 - 12 -

Preconditions and Verification Conditions

We are given an annotated statement 𝑐, a precondition P and a postcondition Q.

We want to know: when does ⊨ 𝑃 𝑐 {𝑄} hold?

For this, we calculate a precondition 𝑝𝑟𝑒(𝑐, 𝑄) and a set of verification conditions 𝑣𝑐 𝑐, 𝑄 .

The idea is that if all the verification conditions hold, then the precondition holds:

𝑅 𝑅∈𝑣𝑐(𝑐, 𝑄)

⇒ ⊨ 𝑝𝑟𝑒 𝑐, 𝑄 𝑐 𝑄

For the precondition 𝑃, we get the additional weaking 𝑃 ⇒ 𝑝𝑟𝑒 𝑐, 𝑄 .

Systeme hoher Sicherheit und Qualität, WS 17/18 - 13 -

Calculation Verification Conditions

Intuitively, we calculate the verification conditions by stepping through the program backwards, starting with the

postcondition 𝑄.

For each of the four simple cases (assignment, sequencing, case distinction and 𝒔𝒌𝒊𝒑), we calculate new current postcondition 𝑄

At each iteration, we calculate the precondition 𝑅 of the loop body working backwards from the invariant 𝐼, and get two verification conditions:

The invariant 𝐼 and negated loop condition implies 𝑄.

The invariant 𝐼 and loop condition implies 𝑅.

Asserting 𝑅 generates the verification condition 𝑅 ⇒ 𝑄.

Let‘s try this.

Systeme hoher Sicherheit und Qualität, WS 17/18 - 14 -

Example: deriving VCs for the factorial.

{ 0 <= n }

{ 1 == (1-1)! && (1- 1) <= n } p := 1;

{ p == (1-1)! && (1- 1) <= n } c := 1;

{ p == (c-1)! && (c- 1) <= n } while (c <= n)

inv (p == (c-1)! && c-1 <= n) { { p*c == ((c+1)-1)! && ((c+1)- 1) <= n } p := p* c;

{ p == ((c+1)-1)! && ((c+1)- 1) <= n } c := c+1;

{ p == (c-1)! && (c- 1) <= n } } { p == (c-1)! && (c- 1) <= n && ! (c <= n) } { p = n! }

VCs (unedited):

1. p == (c-1)! && (c- 1) <= n && ! (c <= n)

==> p= n!

2. p == (c-1)! && c-1 <= n && c<= n

==> p* c= ((c+1)-1)! && ((c+1)-1) <= n 3. 0 <= n ==> 1= (1-1)! && 1-1 <= n

VCs (simplified):

1. p == (c-1)! && (c- 1) <= n && c> n

==> p= n!

2. p == (c-1)! && c-1 <= n && c<= n

==> p* c= c!

2. p == (c-1)! && c-1 <= n && c<= n

==> c <= n

3. 0 <= n ==> 1= 0! && 0 <= n

Systeme hoher Sicherheit und Qualität, WS 17/18 - 15 -

Formal Definition

Calculating the precondition:

𝑝𝑟𝑒 𝐬𝐤𝐢𝐩, 𝑄 = 𝑄 𝑝𝑟𝑒 𝑋 ≔ 𝑒, 𝑄 = 𝑄 𝑒 / 𝑋 𝑝𝑟𝑒(𝑐0; 𝑐1, 𝑄 = 𝑝𝑟𝑒(𝑐0, 𝑝𝑟𝑒 𝑐1, 𝑄 )

𝑝𝑟𝑒 𝐢𝐟 𝑏 𝑐0 𝐞𝐥𝐬𝐞 𝑐1, 𝑄 = 𝑏 ∧ 𝑝𝑟𝑒 𝑐0, 𝑄 ∨ ¬ 𝑏 ∧ 𝑝𝑟𝑒 𝑐1, 𝑄 𝑝𝑟𝑒 𝐚𝐬𝐬𝐞𝐫𝐭 𝑅, 𝑄 = 𝑅

𝑝𝑟𝑒 𝐰𝐡𝐢𝐥𝐞 𝑏 𝐢𝐧𝐯 𝐼 𝑐, 𝑄 = 𝐼

Calculating the verification conditions:

𝑣𝑐 𝑠𝑘𝑖𝑝, 𝑄 = ∅ 𝑣𝑐 𝑋 ≔ 𝑒, 𝑄 = ∅

𝑣𝑐 𝑐0; 𝑐1, 𝑄 = 𝑣𝑐 𝑐0, 𝑝𝑟𝑒 𝑐1, 𝑄 ∪ 𝑣𝑐 𝑐1, 𝑄 𝑣𝑐 𝐢𝐟 𝑏 𝑐0 𝐞𝐥𝐬𝐞 𝑐1, 𝑄 = 𝑣𝑐 𝑐0, 𝑄 ∪ 𝑣𝑐 𝑐1, 𝑄

𝑣𝑐 𝐰𝐡𝐢𝐥𝐞 𝑏 𝐢𝐧𝐯 𝐼 𝑐, 𝑄 = 𝑣𝑐 𝑐, 𝐼 ∪ {𝐼 ∧ 𝑏 ⇒ 𝑝𝑟𝑒 𝑐, 𝐼 , 𝐼 ∧ ¬𝑏 ⇒ 𝑄}

𝑣𝑐 𝐚𝐬𝐬𝐞𝐫𝐭 𝑅, 𝑄 = 𝑅 ⇒ 𝑄

The main definition:

𝑣𝑐𝑔 𝑃 𝑐 𝑄 = 𝑃 ⇒ 𝑝𝑟𝑒 𝑐, 𝑄 ∪ 𝑣𝑐(𝑐, 𝑄)

Systeme hoher Sicherheit und Qualität, WS 17/18 - 16 -

Correctness of VC

The correctness calculus is correct: if we can prove all the verifcation conditons, the program is correct w.r.t to given pre- and postconditions.

Formally:

Proof: by induction on 𝑐.

Theorem (Correctness of the VCG calculus)

Given assertions 𝑃 and 𝑄 (with 𝑃 the precondition and 𝑄 the postcondition), and an annotated program, then

𝑅

𝑅∈𝑣𝑐𝑔(𝑐, 𝑄)

⇒ ⊨ 𝑃 𝑐 𝑄

(3)

Systeme hoher Sicherheit und Qualität, WS 17/18 - 17 -

Using VCG in Real Life

We have just a toy language, but VCG can be used in real life.

What features are missing?

Modularity: the language must have modularity concepts, e.g. functions (as in C), or classes (as in Java), and we must be able to verify them separately.

Framing: in our simple calculus, we need to specify which variables stay the same (e.g. when entering a loop). This becomes tedious when there are a lot of variables involved; it is more practical to specify which variables may change.

References: languages such as C and Java use references, which allow aliasing. This has to be modelled semantically;

specifically, the assignment rule has to be adapted.

Machine arithmetic: programs work with machine words and floating point representations, not integers and real numbers. This can be the cause of insidious errors.

Systeme hoher Sicherheit und Qualität, WS 17/18 - 18 -

VCG Tools

Often use an intermediate language for VCG and front-ends for concrete programming languages.

The Why3 toolset (http://why3.lri.fr)

A verification condition generator

Front-ends for different languages:

C (Frama-C), Java (defunct?)

Boogie (Microsoft Research)

Frontends for programming languages such C, C#, Java.

VCC – a verifying C compiler built on top of Boogie

Interactive demo:

https://www.rise4fun.com/Vcc/

Systeme hoher Sicherheit und Qualität, WS 17/18 - 19 -

VCC Example: Binary Search

A correct (?) binary search implementation:

#include <limits.h>

unsigned int bin_search(unsigned int a [], unsigned int a_len, unsigned int key) {

unsigned int lo= 0;

unsigned int hi= a_len;

unsigned int mid;

while (lo <= hi) {

mid= (lo+ hi)/2;

if (a[mid] < key) lo= mid+1;

else hi= mid;

}

if (!(lo < a_len && a[lo] == key)) lo= UINT_MAX;

return lo;

}

Systeme hoher Sicherheit und Qualität, WS 17/18 - 20 -

VCC: Correctness Conditions?

We need to annotate the program.

Precondition:

a is an array of length a_len;

The array a is sorted.

Postcondition:

Let r be the result, then:

if r is UINT_MAX, all elements of a are unequal to key;

if r is not UINT_MAX, then a[r] == key.

Loop invariants:

hi is less-equal to a_len;

everything „left“ of lo is less then key;

everything „right“ of hi is larger-equal to key.

Systeme hoher Sicherheit und Qualität, WS 17/18 - 21 -

VCC Example: Binary Search

Source code as annotated for VCC:

#include <limits.h>

#include <vcc.h>

unsigned int bin_search(unsigned int a [], unsigned int a_len, unsigned int key) _(requires \thread_local_array(a, a_len))

_(requires \forall unsigned int i, j; i < j && j < a_len ==> a[i] <= a[j]) _(ensures \result != UINT_MAX ==> a[\result] == key)

_(ensures \result == UINT_MAX ==> \forall unsigned int i; i < a_len ==> a[i] != key) {

unsigned int lo= 0;

unsigned int hi= a_len;

unsigned int mid;

while (lo <= hi) _(invariant hi <= a_len)

_(invariant \forall unsigned int i; i < lo ==> a[i] < key) _(invariant \forall unsigned int i; hi <= i && i < a_len ==>a[i] >= key) {

mid= (lo+ hi)/2;

if (a[mid] < key) lo= mid+1;

else hi= mid;

}

if (!(lo < a_len && a[lo] == key)) lo= UINT_MAX;

return lo;

}

Systeme hoher Sicherheit und Qualität, WS 17/18 - 22 -

Binary Search: the Corrected Program

Corrected source code:

#include <limits.h>

#include <vcc.h>

unsigned int bin_search(unsigned int a [], unsigned int a_len, unsigned int key) _(requires \thread_local_array(a, a_len))

_(requires \forall unsigned int i, j; i < j && j < a_len ==> a[i] <= a[j]) _(ensures \result != UINT_MAX ==> a[\result] == key)

_(ensures \result == UINT_MAX ==> \forall unsigned int i; i < a_len ==> a[i] != key) {

unsigned int lo= 0;

unsigned int hi= a_len;

unsigned int mid;

while (lo < hi) _(invariant hi <= a_len)

_(invariant \forall unsigned int i; i < lo ==> a[i] < key) _(invariant \forall unsigned int i; hi <= i && i < a_len ==>a[i] >= key) {

mid= (hi-lo)/2+ lo;

if (a[mid] < key) lo= mid+1;

else hi= mid;

}

if (!(lo < a_len && a[lo] == key)) lo= UINT_MAX;

return lo;

}

Systeme hoher Sicherheit und Qualität, WS 17/18 - 23 -

Summary

Starting from the relative completeness of the Floyd-Hoare calculus, we devised a verification condition generation (vcg) calculus which makes program verification viable.

Verification condition generation reduces the question whether the given pre/postconditions hold for a program to the validity of a set of logical properties.

We do need to annotate the while loops with invariants.

Most of these logical properties can be discharged with automated theorem provers.

To scale to real-world programs, we need to deal with framing, modularity (each function/method needs to be verified independently), and machine arithmetic (integer word arithmetic and floating-points).

Referenzen

ÄHNLICHE DOKUMENTE

I Lecture 2: Concepts of Safety and Security, Norms and Standards I Lecture 3: Quality of the Software Development Process I Lecture 4: Requirements Analysis.. I Lecture 5:

(1) it supports querying of the semantic data with a keyword based approach, so the users do not need to learn a semantic query language, (2) it helps users find relevant results

The BOEMIE Ontology repository comprehends a set of OWL files containing assertional information, also called ABoxes, where each ABox contains the rich semantic metadata of a

It was already known to Aristotle, named later by the scholastics called it a dicto simpliciter ad dictum secundum quid, which means ‘from the unquali- fied statement to the

All p-values were first corrected using the BH method (i.e., corrections accounted for comparisons for the 3 groups of children) then corrected again using the Bonferroni method

[r]

In AI, full parsing is very important for both grouping words and classification. Table 2 sum- marizes relative experimental results. Line 2 is the AI performance when gold

This unary function can be seen as the linguistic constraints (syntactic subcategorisation + selection restrictions) the head run imposes on the word denotations appearing