• Aucun résultat trouvé

Schéma de preuve de correction de la traduction des contrats de fonction

(fonction sous vérification)

α-CHECK-POST (Endf, p) π 7→(I, e) (Endf,ensuresp;) α 7→ I ·(Endf, fassert(e);)

La figure 4.15 illustre la justification de correction de la traduction des contrats pour la fonction sous vérification sur un schéma générique normalisé de fonction. La partie gauche de la figure montre une fonction f disposant d’un contrat, avec un corps quel- conque A. En partie droite est affiché le code résultant de la traduction de cette fonction, où chaque ensemble d’instructions (regroupées avec une accolade) est mis en relation avec l’annotation du programme original dont il est la traduction.

Par hypothèse, la précondition de la fonction sous vérification est vraie, ce qui correspond aux lignes 3–4 du code généré. Si la fonction modifie une des left-values n’appartenant pas à la clauseassigns, alors la mémoire d’erreur est obtenue (casF-2), ce qui correspond

au cas où l’un desfassertdes lignes 10–12 du code généré renvoie faux. Si la postcon-

dition n’est pas vérifiée à la fin de la fonction, on obtient la mémoire d’erreur (casF-3), ce

qui correspond au cas où lefassertdes lignes 13–14 du code généré renvoie faux.

Fonctions appelées

Considérons enfin une fonction f appelée, dont le contrat est composé d’une clause

requires, d’une clause assigns et d’une clauseensures. La traduction des contrats d’une

fonction appelée réutilise les règles α-CHECK-ASSIGNS et α-CHECK-POST de la partie

précédente. En revanche, afin de vérifier la précondition d’une fonction appelée et non la supposer vraie, la règle α-ASSUME-PREest remplacée par la règle α-CHECK-PRE:

α-CHECK-PRE (Begf, p) π 7→(I, e) (Begf,requiresp;) α 7→ I ·(Begf, fassert(e);)

La figure 4.16 illustre la justification de correction de la traduction des contrats pour les fonctions appelées. La partie gauche de la figure montre une fonction f disposant d’un contrat, avec un corps quelconque A. En partie droite est affiché le code résultant de la traduction de cette fonction, où chaque ensemble d’instructions (regroupées avec une accolade) est mis en relation avec l’annotation du programme original dont il est la tra- duction.

Si la précondition n’est pas vérifiée au début de la fonction, alors la mémoire d’erreur est obtenue (casF-1), ce qui correspond aux lignes 3–4 du code généré. Si la fonction modifie

1 /*@ requires p1; 2 assigns X; 3 ensures p2; */ 4 f(...) { 5 Begf: ; 6 A 7 Endf: ; 8 } 1 f(...) { 2 Begf: ;

3 int e1; Spec2Code(p1, e1);

4 fassert(e1); 5 type_x1 assigns_x1 = x1; 6 ... 7 type_xN assigns_xN = xN; 8 A 9 Endf: ; 10 fassert(x1 == assigns_x1); 11 ... 12 fassert(xN == assigns_xN);

13 int e2; Spec2Code(p2, e2);

14 fassert(e2);

15 }

FIGURE4.16 – Schéma de preuve de correction de la traduction des contrats de fonction

(fonction appelée)

une des left-values n’appartenant pas à la clauseassigns, alors la mémoire d’erreur est

obtenue (casF-2), ce qui correspond au cas où l’un desfassertdes lignes 10–12 du code

généré renvoie faux. Si la postcondition n’est pas vérifiée à la fin de la fonction, on obtient la mémoire d’erreur (casF-3), ce qui correspond au cas où lefassertdes lignes 13–14 du

code généré renvoie faux.

C

ONCLUSION DU CHAPITRE

L’objectif de ce chapitre était de définir une traduction en C des annotationsE-ACSLpour

la génération de tests et de fournir une justification de la correction de cette traduction. Nous avons tout d’abord présenté le processus de la traduction dans sa généralité. Puis nous avons défini les règles permettant pour chaque terme et prédicat E-ACSL d’obte-

nir un code C calculant cette expression tout en préservant la sémantique d’E-ACSL. Ces

règles nous ont permis de définir les règles de traduction des annotationsE-ACSL:assert, requires,typically,assigns,ensures,loop invariant,loop assignsetloop variant. Ces diffé-

rentes instrumentations des annotations nous permettront par la suite de détecter diffé- rentes contradictions entre le code et la spécification.

Grâce à notre justification de correction, nous pouvons assurer l’absence de faux positifs lors de la génération de tests sur le programme instrumenté : si une erreur est trouvée par la génération de tests alors il y a une erreur dans le programme d’origine. Cette propriété est énoncée comme une implication si l’on considère le langage C et le langage E-ACSL

dans leur ensemble, mais si on se restreint au sous-ensemble du langage décrit par la grammaire du chapitre précédent il y a probablement une équivalence, c’est-à-dire que s’il y a une erreur dans le programme original et si la traduction des annotations E-ACSL

est correcte, alors il y a une erreur dans le programme instrumenté et elle est révélée par la génération de tests.

La justification de cette propriété est fournie de manière formelle pour les assertions et de manière informelle mais intuitive et rigoureuse pour les contrats de boucle et les contrats de fonction.

5

VÉRIFICATION À L’EXÉCUTION DES

ANNOTATIONS LIÉES AU MODÈLE

MÉMOIRE

D

ans ce chapitre nous abordons la vérification dynamique des annotations liées au modèle mémoire. Ceci requiert de pouvoir simuler un modèle mémoire bas niveau afin de pouvoir surveiller les opérations bas niveau des programmes C (allocations, initia- lisations, etc.). En revanche, le modèle mémoire utilisé par le générateur de tests struc- turels que nous utilisons n’est pas assez bas niveau et ne permet donc pas l’exécution symbolique de ces constructions. En conséquence, nous changeons d’approche pour ces propriétés. En effet, contrairement au chapitre 4, ces annotations ne seront pas vérifiées par test structurel mais par validation à l’exécution (runtime assertion checking).

Dans un premier temps nous présentons les différentes annotations que nous ne pou- vons pas traiter par génération de tests et que nous qualifions d’opérations de bas niveau (partie 5.1). Puis nous présentons quelques détails de conception de notre modèle mé- moire (partie 5.2). Enfin nous abordons les principes de l’instrumentation nécessaire pour la vérification de ces annotations (partie 5.3).

5.1 A

NNOTATIONS LIÉES AU MODÈLE MÉMOIRE

Définissons d’abord quelques notions. Les objets de la mémoire sont des blocs. Chaque bloc est caractérisé par une adresse de base, une taille (en nombre d’octets) et un contenu (qui peut être initialisé ou non). Tout ceci constitue le modèle mémoire.

Les annotations E-ACSL que nous considérons sont décrites dans la figure 5.1. Cette

figure est une extension de la grammaire des termes et des prédicatsE-ACSLdéfinie au

chapitre 3. term: := ... | \base_addr(term) | \block_length(term) | \offset(term) pred : := ... | \valid(term) | \valid_read(term) | \initialized(term)