• Aucun résultat trouvé

3.3 Abstraction de la machine

3.3.1 Le domaine S ]

Nous définissons une première abstraction naïve, imitant la structure des états concrets : S]

> (représentant une valeur inconnue) si plusieurs valeurs sont possibles. S’il existe une variable pour laquelle aucune valeur n’est possible, cela implique qu’il n’y a aucun état possible. Nous notons ⊥ ∈ S]

0 l’état abstrait correspondant à ce scénario.

Définition 3.10. Le domaine abstrait S0] est défini par :

S0] := (V → Z32∪ {>}) ∪ {⊥}

La fonction d’interprétation abstraite sur S]

0 est définie de manière similaire à la

définition de I sur le domaine concret. Il suffit d’étendre l’arithmétique sur Z32 à Z32∪

{>}, en définissant toute opération contenant un opérand > comme ayant pour résultat > : le résultat d’un calcul contenant une inconnue est, dans le cas général, inconnu. Quelques différences : (a) l’instruction scratch d est traduite par une mise à > de d, et (b) l’information apportée par l’instruction assume c, a ne peut être utilisée que si c vaut “=”, ou si la condition dans a contredit les informations portées par l’état (par exemple, (c, a) = (≤, r1 ∼0) et s](r1) = 8), auquel cas l’état obtenu est ⊥.

ldr r2, [fp, #-16] seti t2, −16

add t1, r11, t2

load r2, t1, N32

Figure 3.8 – Charge-

ment dans le pile Un défaut majeur immédiat de cette simple représen-

tation est son impuissance à travailler avec des variables dans la pile (de type mSP+k) sans connaître la valeur du

pointeur de pile, pointeur qui n’est pas forcément connu avant l’analyse ! La Figure 3.8 illustre ce problème sur un code de chargement très courant de variable rangée dans la pile. L’adresse est calculée à partir d’un registre contenant

un pointeur vers la pile8, décalé d’un déplacement constant (ici k = −16). En l’absence

d’information sur la valeur de ce pointeur de pile, l’adresse sera évaluée à > + k = >. Ainsi, ce domaine abstrait peut difficilement travailler avec des données rangées dans la pile.

3.3.2

Le domaine S

]

Nous étendons S]

0 pour représenter symboliquement la valeur du pointeur de pile

en début d’analyse. Le registre qui contient cette information est défini par les conven- 8. En réalité, le registre ARM fp (ebp en x86) est le frame pointer, qui indique le début du contexte de la fonction en cours. C’est par le biais d’adresses relatives à ce pointeur qu’un programme accède typiquement à des informations rangées dans la pile, à l’intérieur d’une fonction.

tions de chaque jeu d’instructions (r13 en ARM, r1 en PowerPC...). Cette constante

symbolique, notée SP, correspond à la valeur du pointeur de pile au point où l’analyse du programme a commencé (entrée d’une fonction ou d’un programme).

Définition 3.11. Nous définissons le domaine des constantes comme l’ensemble

des valeurs sur 32 bits, relatives au pointeur de pile initial SP ou non. Z32]:= Z32∪SP Z32

Toute l’arithmétique de Z32 n’est pas définie sur Z32], par exemple l’addition

de SP + 4 et SP + 0 n’est pas permise. Nous enrichissons donc dans ce domaine par l’ajout d’un élément > :

C] := Z32]∪ {>}

On peut ainsi définir toutes les opérations sur C] :

∀k, k0 ∈ Z32, ∀c ∈ C], ∀k, k0 ∈ Z32, ∀c ∈ C],

(SP + k) + k0 := SP + (k + k0) (SP + k) − k0 := SP + (k − k0) k+ (SP + k0) := SP + (k + k0) k −(SP + k0) := > (SP + k) + (SP + k0) := > (SP + k) − (SP + k0) := k − k0 c+ > = > + c = > c − > = > − c = >

Et ainsi de suite pour les autres opérateurs arithmétiques. L’application d’opé- rateurs logiques sur SP Z32 résulte toujours en > : nous n’autorisons pas (conser-

vativement) ce type d’opérateurs pour le calcul d’adresse.

Nous redéfinissons la mémoire, en séparant le tas (heap) et les variables globales, accessibles par adresses absolues de la forme k, de la pile (stack), accessible uniquement avec des adresses relatives à un pointeur de pile SP, de la forme SP + k.

Définition 3.12. Pour une architecture 32 bits, nous redéfinissons la mémoire par

Mem] := {mk, k ∈ Z32} ∪ {mSP+k, k ∈ Z32}

= {ma, a ∈ Z32]}

et définissons V], le domaine des variables avec cette mémoire réorganisée :

V] := Reg ∪ Tmp ∪ Mem]

Les variables dans la pile (de la forme mSP+k ∈ Mem]) sont donc désormais indexées

uniquement par rapport à ce SP initial. Ainsi, par exemple, m8192 est une cellule mé-

moire dans le tas, et mSP−4 est une cellule mémoire dans la pile du programme.

Une fois le domaine des constantes définies, nous pouvons redéfinir le domaine abstrait :

Définition 3.13. Un état abstrait peut être :

(i) une application de chaque variable vers une constante, dans ~S := V] → C]

(ii) ⊥, l’état impossible

Le domaine abstrait S] est donc défini par

S] := ~S ∪ {⊥} = (V] → C]) ∪ {⊥}

Notons sp ∈ Reg, le registre correspondant au pointeur de pile donné par le jeu d’instructions. Il suffit maintenant, pour pouvoir traiter des données dans la pile, de s’assurer que l’état initial s] utilisé en début d’analyse de programme assigne à sp la

constante symbolique SP : s](sp) = SP+0. Cette propriété est, par définition, toujours

valide en début d’analyse.

Afin de permettre la concrétisation de ce domaine abstrait vers S, nous notons κSP

l’adresse de départ de la pile. Cette adresse peut être différente à chaque exécution et est un paramètre de l’exécution d’un programme inconnu pendant l’analyse statique. Cette constante κSP ∈ Z32 représente le contexte d’exécution du programme et paramétrise

Définition 3.14. Nous définissons la fonction de concrétisation d’une constante

dans un contexte d’exécution :

κSP` γZ32] : Z32] −→ Z32 c 7−→      k si c = k, k ∈ Z32 κSP+ k si c = SP + k, k ∈ Z32

Nous considérerons par la suite ce contexte d’exécution κSP comme implicite. La

concrétisation de S] se définit simplement :

Définition 3.15. La fonction de concrétisation γS] : S]→ P(S) est définie par :

κSP ` ∀s]∈ S], γS](s]) :=               s ∈ S ∀v ∈ Var , s](v) = s(v) ∨ s](v) = > ∧ ∀ma ∈ Mem], s](ma) = s(mγ Z32](a)) ∨ s ](m a) = >    si s] ∈ ~Ssi s] = ⊥

void f(const int x) { if(x > 10) { /* a */ } if(x == 2) { /* b */ } } Figure 3.9 – Conflit indétectable par S]

Bien que ce premier problème de représentation de la pile soit adressé par le domaine abstrait S], celui-ci reste trop simple

pour trouver des propriétés non triviales sur le programme, no- tamment celles qui peuvent permettre la détection de chemins infaisables non triviaux, autres que du code (dynamiquement) mort. Les seuls ensembles de valeurs considérées pour chaque variable du programme sont des singletons ou la valeur incon- nue > – en réalité, ce domaine abstrait s’approche d’un 1-set (cf. Section 2.3.4.2).

La Figure 3.9 donne un exemple de programme (représenté

en C, pour simplifier) où l’interprétation avec S] souffre du manque d’expressivité de

cette abstraction. Lorsque x est inconnu, le chemin qui passe par a et b est infaisable, mais l’information x > 10 issue du décodage du code machine, certainement traduit avec des instructions sémantiques assume, ne pourra pas être représentée dans S].

3.4

Abstraction par prédicats