14.09.2014 Views

Sémantique Axiomatique ou Logique de Hoare - Ensiie

Sémantique Axiomatique ou Logique de Hoare - Ensiie

Sémantique Axiomatique ou Logique de Hoare - Ensiie

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>Sémantique</strong> <strong>Axiomatique</strong> <strong>ou</strong><br />

<strong>Logique</strong> <strong>de</strong> <strong>Hoare</strong><br />

C. Dubois<br />

ENSIIE<br />

(ENSIIE) <strong>Hoare</strong> 1 / 52


<strong>Sémantique</strong> axiomatique (logique <strong>de</strong> <strong>Hoare</strong>)<br />

P<strong>ou</strong>r les langages impératifs<br />

<strong>Sémantique</strong> orientée vers la preuve <strong>de</strong> programmes<br />

Avec cette métho<strong>de</strong> sémantique, un programme est vu comme un<br />

transformateur <strong>de</strong> propriétés logiques (comme la sémantique <strong>de</strong>s<br />

substitutions généralisées <strong>de</strong> B).<br />

(ENSIIE) <strong>Hoare</strong> 2 / 52


Le langage<br />

Syntaxe (abstraite) d’un “petit” langage impératif appelé<br />

communément WHILE :<br />

Expressions<br />

a ::= n | x | a + a | a ∗ a | a − a | a ÷ a<br />

Conditions<br />

b ::= true | false | a = a | a ≤ a | . . .<br />

Comman<strong>de</strong>s/instructions<br />

c ::= skip | x := a | c; c | if b then c else c | while b do c<br />

(ENSIIE) <strong>Hoare</strong> 3 / 52


Triplets <strong>de</strong> <strong>Hoare</strong><br />

triplet <strong>de</strong> <strong>Hoare</strong> : {P} i {Q} avec P, Q <strong>de</strong>s assertions logiques et i une<br />

instruction<br />

P est appelée la précondition, Q la postcondition.<br />

Elles constituent la spécification du programme.<br />

assertions logiques : formules du premier ordre, avec comme formules<br />

atomiques les expressions du langage <strong>de</strong> programmation<br />

Remarque importante : i<strong>de</strong>ntification entre les variables du programme<br />

et les variables <strong>de</strong>s assertions (si x est une variable du programme, au<br />

point <strong>de</strong> l’assertion, x signifie valeur <strong>de</strong> x en ce point)<br />

{P} i {Q} : lire<br />

si la propriété P est vraie p<strong>ou</strong>r les valeurs <strong>de</strong>s variables du programme<br />

avant l’exécution <strong>de</strong> i et si l’exécution termine alors la propriété Q<br />

est vraie après l’exécution <strong>de</strong> i<br />

correction partielle<br />

(ENSIIE) <strong>Hoare</strong> 4 / 52


P<strong>ou</strong>r correction totale : autre forme <strong>de</strong> triplet :<br />

[P] i [Q] : lire<br />

si la propriété P est vraie p<strong>ou</strong>r les valeurs <strong>de</strong>s variables du programme<br />

avant l’exécution <strong>de</strong> i alors l’exécution termine et la propriété Q est<br />

vraie après l’exécution <strong>de</strong> i<br />

Correction totale = correction partielle + preuve <strong>de</strong> terminaison<br />

(ENSIIE) <strong>Hoare</strong> 5 / 52


Dans la suite, n<strong>ou</strong>s considérerons la correction partielle<br />

P<strong>ou</strong>rquoi ne pas insister sur la terminaison ?<br />

Dans certains on ne veut pas la terminaison<br />

On simplifie le raisonnement<br />

Si nécessaire, on peut pr<strong>ou</strong>ver la terminaison séparément.<br />

(ENSIIE) <strong>Hoare</strong> 6 / 52


Exemple <strong>de</strong> spécification et <strong>de</strong> programme (Fact)<br />

{x = n ∧ n > 0}<br />

y := 1 ;<br />

while not(x = 1) do (y := y * x ; x := x - 1) od<br />

{y = n! ∧ n > 0}<br />

Ici n est variable logique (elle permet <strong>de</strong> se référer à la valeur initiale<br />

<strong>de</strong> x)<br />

(ENSIIE) <strong>Hoare</strong> 7 / 52


**<br />

* @param a an integer<br />

* @returns integer square root of a<br />

**/<br />

int root (int a) {<br />

int i = 0;<br />

int k = 1;<br />

int sum = 1;<br />

while (sum


Spécification <strong>de</strong> root<br />

1 root comme une fonction partielle<br />

Precondition : a ≥ 0<br />

Postcondition : i ∗ i ≤ a < (i + 1) ∗ (i + 1)<br />

2 root comme une fonction totale<br />

Precondition : true<br />

Postcondition :<br />

(a ≥ 0 ) ⇒ i*i ≤ a < (i+1)*(i+1)<br />

∧<br />

(a < 0 ⇒ i=0)<br />

(ENSIIE) <strong>Hoare</strong> 9 / 52


Un état (mémoire) d’un programme associe une valeur à chaque<br />

variable du programme. Un état peut être vu comme une fonction <strong>de</strong>s<br />

variables vers les valeurs (ici entières).<br />

z := 0;<br />

x := 1;<br />

y := 2; (1)<br />

z := x + y; (2)<br />

Au point <strong>de</strong> programme (1), l’état σ 1 est {z ↦→ 0; x ↦→ 1; y ↦→ 2}<br />

Au point <strong>de</strong> programme (2), l’état σ 2 est {z ↦→ 3; x ↦→ 1; y ↦→ 2}<br />

(ENSIIE) <strong>Hoare</strong> 10 / 52


On dit qu’un état satisfait une assertion P quand l’interprétation <strong>de</strong> P<br />

est vraie lorsque les variables libres <strong>de</strong> P ont leur valeur c<strong>ou</strong>rante<br />

(dans l’état).<br />

z := 0;<br />

x := 1;<br />

y := 2; (1)<br />

z := x + y; (2)<br />

En (1), l’assertion z ≥ x est fausse,<br />

En (2), l’assertion z ≥ x est vraie.<br />

(ENSIIE) <strong>Hoare</strong> 11 / 52


Quelques triplets <strong>de</strong> <strong>Hoare</strong> vali<strong>de</strong>s<br />

{true} x := 5 { x=5 }<br />

{ x = y } x := x + 3 { x = y + 3 }<br />

{ x > 0 } x := x * 2 { x > -2 }<br />

{ x=a } if (x < 0) then x := -x else skip { x=abs(a) }<br />

Mais {x0 } n’est pas vali<strong>de</strong>.<br />

(ENSIIE) <strong>Hoare</strong> 12 / 52


<strong>Logique</strong> <strong>de</strong> <strong>Hoare</strong><br />

Langage d’assertions + ensemble <strong>de</strong> règles <strong>de</strong> déduction (règles<br />

d’ingérence) sur les triplets<br />

Les règles s’utilisent comme <strong>de</strong>s règles d’inférence <strong>de</strong> logique.<br />

P<strong>ou</strong>r montrer qu’un triplet est dérivable, on doit construire un arbre <strong>de</strong><br />

dérivation <strong>de</strong> racine le triplet à démontrer et en appliquant les règles<br />

d’inférence.<br />

1 règle par construction du langage + 2 règles logiques<br />

(ENSIIE) <strong>Hoare</strong> 13 / 52


Le langage d’assertions<br />

Ici le langage <strong>de</strong>s prédicats (logique du 1er ordre).<br />

P ::= b|P ∧ P|P ∨ P | ¬P|P ⇒ P|∀x.P|∃x.P<br />

T<strong>ou</strong>tes les expressions booléennes du langage impératif sont <strong>de</strong>s<br />

assertions<br />

Mélange <strong>de</strong>s variables du programme et <strong>de</strong>s variables logiques.<br />

Implicitement les variables prennent <strong>de</strong>s valeurs entières<br />

On dispose d’une sémantique p<strong>ou</strong>r ce langage d’assertions<br />

(ENSIIE) <strong>Hoare</strong> 14 / 52


Les règles d’inférence<br />

{P}skip{P} (skip)<br />

{P ∧ e}i 1 {Q} {P ∧ ¬e}i 2 {Q}<br />

{P}if e then i 1 else i 2 {Q}<br />

(if )<br />

{P[x → e]}x := e{P} (aff )<br />

{P}i1{Q} {Q}i2{R}<br />

(seq)<br />

{P}i1; i2{R}<br />

{I ∧ e}i{I}<br />

{I}while e do i{I ∧ ¬e} (while)<br />

⊢ P ⇒ P ′ {P ′ }i{Q}<br />

(consG)<br />

{P}i{Q}<br />

{P}i{Q ′ } ⊢ Q ′ ⇒ Q<br />

(consD)<br />

{P}i{Q}<br />

(ENSIIE) <strong>Hoare</strong> 15 / 52


The rule for the empty statement<br />

{P}skip{P}<br />

skip does not change the state ....<br />

(ENSIIE) <strong>Hoare</strong> 16 / 52


The rule (axiom) for the assignment statement<br />

{P[x ← e]}x := e{P}<br />

P[x → e] : it is the formula P where all the free occurrences of x<br />

are replaced by e.<br />

e.g. x > 1[x ← x + 1] is x + 1 > 1.<br />

Assignments change the state so we expect <strong>Hoare</strong> triples for<br />

assignments always to reflect that change.<br />

The meaning of this rule is clearer when read from right to left.<br />

Intuition :<br />

If we want x to have some property Q after the assignment, then<br />

that property must hold for the value (e) being assigned to x<br />

before the assignment is executed.<br />

{(x +1) > 5} x := x+1 {x > 5} is an instance of the assignment<br />

axiom<br />

(ENSIIE) <strong>Hoare</strong> 17 / 52


The rule for the sequence<br />

Imperative programs consist of a sequence of statements, affecting the<br />

store one after the other.<br />

{P}i1{Q} {Q}i2{R}<br />

{P}i1; i2{R}<br />

Instance example :<br />

{x > 2}x := x + 1{x > 3} {x > 3}x := x + 2{x > 5}<br />

{x > 2}x := x + 1; x := x + 2{x > 5}<br />

(ENSIIE) <strong>Hoare</strong> 18 / 52


Exercice<br />

temp := x;<br />

x:= y;<br />

y := temp<br />

Let P this program.<br />

Prove using the <strong>Hoare</strong>’s rules that<br />

is valid.<br />

{x = a ∧ y = b}P{x = b ∧ y = a}<br />

The standard approach consists in working backwards thr<strong>ou</strong>gh the<br />

co<strong>de</strong>.<br />

How ? Answer : a <strong>de</strong>rivation tree or a more linear presentation<br />

(ENSIIE) <strong>Hoare</strong> 19 / 52


The rule for the conditional statement<br />

{P ∧ cond}i 1 {Q} {P ∧ ¬cond}i 2 {Q}<br />

{P}if cond then i 1 else i 2 {Q}<br />

When a conditional is executed, either i 1 or i 2 is executed.<br />

Therefore, if the conditional is to establish Q, both i 1 and i 2 must<br />

establish Q.<br />

Similarly, if the precondition for the conditional is P, then it must<br />

also be a precondition for the two branches i 1 and i 2 .<br />

The choice between i 1 and i 2 <strong>de</strong>pends on evaluating cond in the<br />

initial state, so we can also assume cond to be a precondition for<br />

i 1 and ¬cond to be a precondition for i 2 .<br />

(ENSIIE) <strong>Hoare</strong> 20 / 52


Suppose we wish to prove :<br />

{x > 2}if x > 2 then y := 1 else y := −1{y > 0}<br />

The proof rule for conditionals suggests we prove :<br />

Simplifying :<br />

{x > 2 ∧ x > 2}y := 1{y > 0}<br />

{x > 2 ∧ ¬(x > 2)}y := −1{y > 0}<br />

{x > 2}y := 1{y > 0} (1)<br />

{false}y := −1{y > 0} (2)<br />

For subgoal (1) the assignment axiom tells us that<br />

{1 > 0}y := 1{y > 0}<br />

For subgoal (2) the assignment axiom tells us that<br />

How to go on ?<br />

−→ we need logical rules<br />

{−1 > 0}y := −1{y > 0}<br />

(ENSIIE) <strong>Hoare</strong> 21 / 52


Logical rules consG and ConsD<br />

A condition P is said stronger than Q in the cases where P ⇒ Q.<br />

Similarly Q is weaker than P.<br />

P ⇒ P ′ {P ′ }i{Q}<br />

{P}i{Q}<br />

(consG)<br />

It is safe to make a pre-condition more specific (stronger). This rule<br />

allows for strengthening pre-conditions<br />

An instance :<br />

(x = 4) ⇒ (x > 2) {x > 2}x := x + 1{x > 3}<br />

{x = 4}x := x + 1{x > 3}<br />

(ENSIIE) <strong>Hoare</strong> 22 / 52


{P}i{Q ′ } Q ′ ⇒ Q<br />

(consD)<br />

{P}i{Q}<br />

It is safe to weaken a post-condition so it says less. This rule allows for<br />

weakening post-conditions<br />

An instance :<br />

{x > 2}x := x + 1{x > 3} (x > 3) ⇒ (x > 1)<br />

{x > 2}x := x + 1{x > 1}<br />

(ENSIIE) <strong>Hoare</strong> 23 / 52


Come back to the conditional example<br />

To end the proof we can use twice the logical rule.<br />

Let us <strong>de</strong>tail the proof !<br />

From x > 2 ⇒ 1 > 0 (valid formula why ?) and<br />

from {1 > 0}y := 1{y > 0}<br />

we can <strong>de</strong>duce (with the logical rule on preconditions)<br />

{x > 2}y := 1{y > 0} (1)<br />

and also from false ⇒ (−1 > 0) (valid ! why ?) and from<br />

{−1 > 0}y := −1{y > 0}<br />

we can <strong>de</strong>duce (with the logical rule on preconditions)<br />

{false}y := −1{y > 0} (2)<br />

Altogether we obtain an inference tree (or <strong>de</strong>rivation tree) that sums up<br />

the <strong>de</strong>monstration and the way we have reasoned.<br />

(ENSIIE) <strong>Hoare</strong> 24 / 52


The rule for the loop<br />

I is called the loop invariant.<br />

{I ∧ cond}i{I}<br />

{I}while cond do i{I ∧ ¬cond}<br />

I remains true each time ar<strong>ou</strong>nd the loop (but not necessarily<br />

during execution of the loop body)<br />

If the loop terminates the control condition must be false, so<br />

¬cond appears in the post-condition.<br />

In the premise of the rule, the body of the loop i is only executed if<br />

cond is true, so it appears in the pre-condition.<br />

(ENSIIE) <strong>Hoare</strong> 25 / 52


Exercice<br />

Let L the following piece of co<strong>de</strong> :<br />

while (x


Exercice<br />

Let L the following piece of co<strong>de</strong> :<br />

while (i != n) do<br />

i:=i+1;<br />

s:=s+(2*i-1)<br />

Check s = i ∗ i is an invariant for L !<br />

(ENSIIE) <strong>Hoare</strong> 27 / 52


And now let’s prove a program !<br />

Program (with specification) :<br />

{ TRUE }<br />

i:=0;<br />

s:=0;<br />

while (i != n) do<br />

i:=i+1;<br />

s:=s+(2*i-1)<br />

{ s=n*n }<br />

(The sum of the first n odd numbers is n 2 )<br />

(ENSIIE) <strong>Hoare</strong> 28 / 52


Exercice<br />

On peut montrer :<br />

- {x = n ∧ n > 0} y := 1 {x = n ∧ n > 0 ∧ y = 1}<br />

- {x = n ∧ n > 0 ∧ y = 1}<br />

while not(x = 1) do y := y * x ; x := x - 1 od<br />

{y = n! ∧ n > 0}<br />

et conclure<br />

{x = n ∧ n > 0}<br />

y := 1 ; while not(x = 1) do y := y * x ; x := x - 1 od<br />

{y = n! ∧ n > 0}<br />

(ENSIIE) <strong>Hoare</strong> 29 / 52


Quelques remarques et questions sur les règles <strong>de</strong> <strong>Hoare</strong><br />

P<strong>ou</strong>r la plupart, règles dirigées par la syntaxe<br />

☹ Quand appliquer la règle <strong>de</strong> la conséquence ?<br />

☹ Comment tr<strong>ou</strong>ver les invariants ?<br />

☹ Comment pr<strong>ou</strong>ver les implications <strong>de</strong> la règle <strong>de</strong> conséquence ?<br />

Comment la démonstration automatique <strong>ou</strong> assistée entre-t-elle<br />

en jeu ?<br />

(ENSIIE) <strong>Hoare</strong> 30 / 52


Exercice<br />

Démontrer que p<strong>ou</strong>r P et p<strong>ou</strong>r t<strong>ou</strong>t i, on {P} i {true}<br />

Vérifier en utilisant les règles <strong>de</strong> <strong>Hoare</strong> que {P} while true do c {Q}<br />

est dérivable p<strong>ou</strong>r t<strong>ou</strong>t P, Q et c.<br />

(ENSIIE) <strong>Hoare</strong> 31 / 52


Correction <strong>de</strong>s règles<br />

Les règles <strong>de</strong> <strong>Hoare</strong> sont correctes : t<strong>ou</strong>t triplet dérivable est vali<strong>de</strong>.<br />

Plus formellement, on pr<strong>ou</strong>ve la correction par rapport à la sémantique<br />

opérationnelle du langage (voir plus tard, transparents ISL)<br />

(ENSIIE) <strong>Hoare</strong> 32 / 52


Plus faible précondition - Weakest Precondition<br />

But : automatiser <strong>de</strong>s preuves en logique <strong>de</strong> <strong>Hoare</strong><br />

Définition (Plus faible précondition)<br />

Soit i un programme et Q une formule (assertion). On notera WP(i, Q)<br />

la plus faible précondition telle que si i termine, alors i termine dans un<br />

état qui satisfait Q<br />

C’est une précondition qui amène à Q {WP(i, Q)}i{Q}<br />

C’est la plus faible : t<strong>ou</strong>te précondition qui amène à Q est plus forte<br />

(elle implique donc la plus faible)<br />

P<strong>ou</strong>r t<strong>ou</strong>t prédicat P, si {P}i{Q} alors P ⇒ WP(i, Q)<br />

Théorème (correction partielle avec WP)<br />

P<strong>ou</strong>r pr<strong>ou</strong>ver {P}i{Q} il suffit <strong>de</strong> pr<strong>ou</strong>ver P ⇒ WP(i, Q).<br />

(ENSIIE) <strong>Hoare</strong> 33 / 52


Calcul <strong>de</strong> WP<br />

Calcul <strong>de</strong> WP(i,Q) (c’est un prédicat) : (défini par induction sur la forme<br />

<strong>de</strong> l’instruction)<br />

WP(skip, Q)=Q<br />

WP(x :=e,Q) = Q[x/e]<br />

WP(i1 ;i2,Q) = WP(i1,WP(i2,Q))<br />

WP(if e then i1 else i2,Q) = (e ⇒ WP(i1,Q)) ∧ (¬ e ⇒ WP(i2,Q))<br />

Rappel : Q[x/e] désigne la formule Q dans laquelle on a remplacé<br />

t<strong>ou</strong>tes les occurences libres <strong>de</strong> x par e.<br />

WP(x :=x+y, x = 2 ∗ y)= x + y = 2 ∗ y<br />

(ENSIIE) <strong>Hoare</strong> 34 / 52


Exercice : - Calculer WP(x :=x+1 ; y :=y-1, x > y)<br />

=WP(x :=x+1 ; x > y − 1) = x + 1 > y − 1<br />

- Calculer WP(if (x>y) then x :=x-y else y :=y-x endif, x ≥ 0 ∧ y ≥ 0)<br />

=x > y ⇒ WP(x :=x-y ; x ≥ 0 ∧ y ≥ 0) ∧<br />

¬x > y ⇒ WP(y :=y-x ; x ≥ 0 ∧ y ≥ 0)<br />

=x > y ⇒ (x − y ≥ 0 ∧ y ≥ 0) ∧ ¬x > y ⇒ (x ≥ 0 ∧ y − x ≥ 0)<br />

- Pr<strong>ou</strong>ver le triplet suivant en utilisant le calcul <strong>de</strong> WP<br />

{x = x 0 }if pair(x) then x := x + 2 else x := x + 1{x > x 0 ∧ pair(x)}<br />

soit P = WP(.., x > x 0 ∧ pair(x)) =<br />

pair(x) ⇒ (x+2 > x 0 ∧pair(x+2))∧¬pair(x) ⇒ (x+1 > x 0 ∧pair(x+1))<br />

Il reste à montrer que x = x 0 ⇒ P, ce qui est vrai.<br />

(ENSIIE) <strong>Hoare</strong> 35 / 52


P<strong>ou</strong>r la b<strong>ou</strong>cle :<br />

WP(while e do i,Q) = pas <strong>de</strong> formule simple !<br />

En effet, while b do i est équivalent à if b then i ;while b do i else skip.<br />

WP(while b do i, Q) = WP(if b then i ;while b do i else skip, Q)<br />

= b ⇒ WP(i, WP(while b do i, Q)) ∧ ¬b ⇒ Q)<br />

Equation récursive (on sait la rés<strong>ou</strong>dre dans la théorie <strong>de</strong>s domaines<br />

mais ce n’est pas simple ! ! ! !)<br />

Impossible à calculer en général, et pas utilisable en pratique<br />

Y aurait-il quelque chose <strong>de</strong> plus simple à calculer et utilisable<br />

automatiquement ?<br />

⇒ Réponse = conditions <strong>de</strong> vérification<br />

(ENSIIE) <strong>Hoare</strong> 36 / 52


Programme annoté et Conditions <strong>de</strong> vérification<br />

On part d’un programme annoté (invariant <strong>de</strong> b<strong>ou</strong>cle et spécifications<br />

<strong>de</strong>s fonctions)<br />

On note VC(i,Q) la condition <strong>de</strong> vérification <strong>de</strong> i p<strong>ou</strong>r l’assertion Q<br />

(postcondition).<br />

VC(i,Q) plus forte que WP(i,Q)<br />

mais heureusement on a :<br />

p<strong>ou</strong>r P ∈ Pre(i, Q), P ⇒ VC(i,Q) et VC(i,Q) ⇒ WP(i,Q)<br />

avec Pre(i, Q)=l’ensemble <strong>de</strong>s assertions R telles que {R}i{Q}<br />

(ENSIIE) <strong>Hoare</strong> 37 / 52


Traditionnellement VC est calculé en arrière (en remontant le<br />

programme) :<br />

cette technique fonctionne bien avec du co<strong>de</strong> structuré<br />

on peut aussi faire le calcul en avant<br />

◮ ça marche aussi avec du co<strong>de</strong> non structuré, ex. assembleur<br />

◮ ce calcul utilise la technique <strong>de</strong> l’évaluation symbolique (cf c<strong>ou</strong>rs <strong>de</strong><br />

test 2A)<br />

VC : même calcul que précé<strong>de</strong>mment p<strong>ou</strong>r WP sauf p<strong>ou</strong>r la b<strong>ou</strong>cle :<br />

l’invariant est donné<br />

Le résultat <strong>de</strong> VC est un prédicat. Les constructions du langage ont<br />

disparu. Il peut être confié à n’importe quel pr<strong>ou</strong>veur. Voir par exemple<br />

l’approche multi-pr<strong>ou</strong>veur <strong>de</strong> Frama-C/Why.<br />

(ENSIIE) <strong>Hoare</strong> 38 / 52


VC(skip, Q)=Q<br />

VC(x :=e,Q) = Q[x/e]<br />

VC(i1 ;i2,Q) = VC(i1,VC(i2,Q))<br />

VC(if e then i1 else i2,Q) = (e ⇒ VC(i1,Q)) ∧ (¬ e ⇒ VC(i2,Q))<br />

VC(while e do invariant Inv i ,Q) =<br />

Inv<br />

(l’invariant est vérifié à l’entrée <strong>de</strong> la b<strong>ou</strong>cle)<br />

∧(∀x 1 . . . x m .Inv ∧ e ⇒ VC(i, Inv))<br />

(l’invariant est préservé par une itération)<br />

∧(¬e ⇒ Q)<br />

La postcondition est satisfaite lorsque la b<strong>ou</strong>cle termine<br />

(x 1 , . . . x n sont les variables modifiées dans i)<br />

On pose :<br />

VC’({P} i {Q}) = P ⇒ VC(i,Q)<br />

(ENSIIE) <strong>Hoare</strong> 39 / 52


Exemple : ret<strong>ou</strong>r sur le programme fact<br />

On prend p<strong>ou</strong>r invariant <strong>de</strong> b<strong>ou</strong>cle l’assertion<br />

y ∗ x! = n! ∧ n > 0 ∧ x > 0. Elle est notée Inv ci-<strong>de</strong>ss<strong>ou</strong>s.<br />

VC’({x = n ∧ n > 0} Fact {y=n ! ∧n > 0})=<br />

x=n ∧ n>0 ⇒ VC(y :=1 ;while ..., y=n ! ∧n > 0) =<br />

x=n ∧ n>0 ⇒ VC(y :=1, VC(while ..., y=n ! ∧n > 0)) =<br />

x=n ∧ n>0 ⇒ VC(y :=1 ; Inv ∧ (∀ x, y. Inv ∧ not(x=1) ⇒ y*x*(x-1) !=n ! ∧ x-1>0<br />

∧ n>0) ∧ (¬not(x=1) ∧ Inv ⇒ y=n ! ∧ n>0)=<br />

x=n ∧ n>0 ⇒ (Inv[y ← 1] ∧ (∀ x, y. Inv ∧ not(x=1) ⇒ y*x*(x-1) !=n ! ∧ x-1>0 ∧<br />

n>0) ∧ (¬ not(x=1) ∧ Inv ⇒ y=n ! ∧ n>0)[y← 1]) =<br />

x=n ∧ n>0 ⇒ ((1*x !=n ! ∧ x>0 ∧ n>0) ∧ (∀ x, y. Inv ∧ not(x=1) ⇒<br />

y*x*(x-1) !=n ! ∧ x-1>0 ∧ n>0) ∧ (¬not(x=1) ∧ 1*x !=n ! ∧ x>0 ∧ n>0 ⇒ 1=n !<br />

∧ n>0))<br />

La formule est grosse mais elle se décompose en petits morceaux qui<br />

peuvent se démontrer séparément.<br />

(ENSIIE) <strong>Hoare</strong> 40 / 52


VC peut être adapté p<strong>ou</strong>r pr<strong>ou</strong>ver l’arrêt d’une b<strong>ou</strong>cle si celle-ci est<br />

annotée par un variant (correction totale)<br />

VC(while e do Invariant Inv, Variant V i ,Q) =<br />

Inv<br />

∧(∀x 1 . . . x m .Inv ∧ e ⇒ VC(i, Inv))<br />

∧(¬e ⇒ Q)<br />

∧(Inv ⇒ V ∈ N)<br />

Le variant est une quantité positive<br />

∧(Inv ∧ e ∧ V = V 0 ⇒ VC(i, V < V 0 ))<br />

... qui décroit strictement au c<strong>ou</strong>rs d’une itération<br />

(x 1 , . . . x n sont les variables modifiées dans i)<br />

(ENSIIE) <strong>Hoare</strong> 41 / 52


Générateur <strong>de</strong> condition <strong>de</strong> vérification VC et triplet <strong>de</strong> <strong>Hoare</strong><br />

On vérifie que {VC(i, Q)}i{Q}<br />

ce qui signifie, informellement, VC(i,Q) est une précondition qui<br />

permet d’atteindre Q au final.<br />

Démonstration : par induction sur i (essayez !)<br />

Théorème fondamental :<br />

Si on peut pr<strong>ou</strong>ver la condition <strong>de</strong> vérification générée par VC’({P}<br />

i {Q}) alors le triplet est dérivable (i.e. on a {P} i {Q})<br />

Démonstration : elle se fait par induction sur i en montrant qu’il<br />

existe une dérivation dont les conditions d’applicabilité sont<br />

exactement celles calculées par VC({P} i {Q}).<br />

(essayez !)<br />

(ENSIIE) <strong>Hoare</strong> 42 / 52


Grâce aux programmes annotés et à VC, on obtient une métho<strong>de</strong><br />

réaliste p<strong>ou</strong>r faire <strong>de</strong> la preuve <strong>de</strong> programmes impératifs :<br />

1 Ecrire un programme contenant nécessairement <strong>de</strong>s assertions<br />

sur les b<strong>ou</strong>cles et (éventuellement) <strong>de</strong>s assertions sur les points<br />

difficiles <strong>de</strong> la preuve<br />

2 Transmettre ce co<strong>de</strong> annoté à un <strong>ou</strong>til qui engendre les conditions<br />

<strong>de</strong> vérification (i.e. qui implante la fonction VC <strong>ou</strong> VC’)<br />

3 Pr<strong>ou</strong>ver ces conditions <strong>de</strong> vérification (<strong>de</strong> préférence avec un<br />

pr<strong>ou</strong>veur automatique (simplify, Z3, Zenon par exemple) <strong>ou</strong><br />

interactif (Coq, Isabelle) par exemple)<br />

(ENSIIE) <strong>Hoare</strong> 43 / 52


P<strong>ou</strong>r aller plus loin sur les conditions <strong>de</strong> vérification :<br />

Les conditions <strong>de</strong> vérification sont conservées après une<br />

optimisation à la compilation<br />

Elles peuvent servir p<strong>ou</strong>r vérifier la correction d’une optimisation.<br />

Utilisables aussi bien sur du co<strong>de</strong> s<strong>ou</strong>rce et du co<strong>de</strong> bas niveau<br />

Conservation <strong>de</strong>s obligations <strong>de</strong> preuve entre JML/Java et<br />

BML/byteco<strong>de</strong> Java<br />

Gilles Barthe, Benjamin Grégoire, Mariela Pavlova : Preservation<br />

of Proof Obligations from Java to the Java Virtual Machine. IJCAR<br />

2008 : 83-99<br />

(ENSIIE) <strong>Hoare</strong> 44 / 52


De nombreux travaux ont fait suite à la logique <strong>de</strong> <strong>Hoare</strong> originale,<br />

p<strong>ou</strong>r étendre le formalisme et rés<strong>ou</strong>dre <strong>de</strong>s difficultés, par exemple :<br />

Avoir <strong>de</strong>s effets <strong>de</strong> bord dans les expressions.<br />

Traiter l’appel <strong>de</strong> s<strong>ou</strong>s-programmes.<br />

Pr<strong>ou</strong>ver la terminaison <strong>de</strong>s programmes (terminaison <strong>de</strong>s b<strong>ou</strong>cles<br />

while).<br />

Supporter les break, continue, les exceptions<br />

Manipuler <strong>de</strong>s structures <strong>de</strong> données complexes : tableaux,<br />

structures, etc.<br />

Manipuler les pointeurs : logique <strong>de</strong> séparation<br />

Travailler sur <strong>de</strong>s entiers bornés, et vérifier le non-débor<strong>de</strong>ment<br />

<strong>de</strong>s opérations sur les entiers.<br />

(ENSIIE) <strong>Hoare</strong> 45 / 52


Les assertions à la <strong>Hoare</strong> sont fortement utilisées dans les <strong>ou</strong>tils<br />

et langages p<strong>ou</strong>r les métho<strong>de</strong>s formelles.<br />

La notion <strong>de</strong> contrat (Eiffel, JML) est inspirée <strong>de</strong>s assertions à la<br />

<strong>Hoare</strong> ⇒ obligations p<strong>ou</strong>r les métho<strong>de</strong>s appelantes et les<br />

métho<strong>de</strong>s appelées.<br />

L’intégration <strong>de</strong> la vérification <strong>de</strong>s assertions au processus <strong>de</strong> la<br />

compilation donne naissance à ce que l’on appelle les<br />

compilateurs certifiants (certifying compilers)<br />

Plus largement les assertions servent à spécifier, vérifier, tester<br />

(ENSIIE) <strong>Hoare</strong> 46 / 52


TP : utilisation du plugin Jessie <strong>de</strong> Frama-C<br />

Frama-C : plateforme développé par le CEA p<strong>ou</strong>r la vérification <strong>de</strong><br />

programmes C (analyse statique, preuve déductive ...)<br />

www.ensiie.fr~/dubois/ISL10/JessieTP.html<br />

(ENSIIE) <strong>Hoare</strong> 47 / 52


Quelques mots sur Jessie<br />

Programmes C + annotations ACSL<br />

ACSL (Ansi C specification language), langage permettant <strong>de</strong><br />

spécifier le comportement <strong>de</strong>s programmes C (inspiré <strong>de</strong> JML,<br />

langage d’annotations p<strong>ou</strong>r les programmes Java)<br />

Langage du 1er ordre, syntaxe à la C<br />

Permet d’écrire <strong>de</strong>s contrats (requires, ensures), <strong>de</strong> mettre <strong>de</strong>s<br />

assertions dans le co<strong>de</strong> (assert)<br />

Correction totale : invariant, variant dans les b<strong>ou</strong>cles<br />

⇒ Génération d’obligations <strong>de</strong> preuve<br />

(ENSIIE) <strong>Hoare</strong> 48 / 52


Jessie utilise Why, générateur d’obligations <strong>de</strong> preuve (J.C Filliatre)<br />

(Jessie successeur <strong>de</strong> Caduceus)<br />

(ENSIIE) <strong>Hoare</strong> 49 / 52


(ENSIIE) <strong>Hoare</strong> 50 / 52


Les vérifications <strong>de</strong> Jessie<br />

vérifications <strong>de</strong> sûreté (safety checks)<br />

◮ Mémoire : validité <strong>de</strong>s accès à la mémoire<br />

◮ Entiers : absence d’overflows, validité <strong>de</strong>s opérations sur les entiers<br />

(absence <strong>de</strong> division par 0)<br />

vérifications fonctionnelles<br />

◮ invariants <strong>de</strong> représentation (par ex. alpha[i] et alpha_inv[i]<br />

cohérents)<br />

◮ invariants du modèle (α0 involution, α 1 permutation)<br />

◮ comportement <strong>de</strong>s opérations<br />

(ENSIIE) <strong>Hoare</strong> 51 / 52


Vérification ’Safety’<br />

Modèle mémoire<br />

Un pointeur p est représenté par une paire (adresse <strong>de</strong> base,<br />

décalage dans le bloc)<br />

valid (p) ≡ p ≠ null ∧ 0 ≤ offset(p) < blocklength(p)<br />

(ENSIIE) <strong>Hoare</strong> 52 / 52

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!