Sémantique Axiomatique ou Logique de Hoare - Ensiie
Sémantique Axiomatique ou Logique de Hoare - Ensiie
Sémantique Axiomatique ou Logique de Hoare - Ensiie
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