• Aucun résultat trouvé

3.5 Vers une abstraction paramétrée et composable

4.1.2 Parcours avec interprétation abstraite du programme

4.1.2.1 Interprétation sur un CFG acylique indépendant

Nous considérons dans un premier temps des CFG indépendants : ceux-ci ne doivent pas avoir d’appels de fonction nécessitant l’analyse d’un autre CFG. Le domaine des

états se que nous utiliserons finalement pour l’analyse de programme est décrit par la

Définition 4.2.

Définition 4.2. Les états utilisés pour l’analyse du programme sont constitués

d’ensembles de couples d’un chemin et de l’état abstrait lui correspondant. Autre- ment dit, le domaine de ces états, appelés états du programme, est

X := P(S ×b Π(G))

Remarque. Si les états de Sb peuvent être vus comme des conjonctions de propriétés (un état ˆs = (θ, q) représente une conjonction de chaque v = θ(v) et chaque pi ∈ p)

vraies pour un chemin, les ensembles d’états abstraits de X peuvent être vus comme une disjonction de propriétés vraies en un point du programme (pour tout chemin). De la même façon que nous pouvons définir une fonction a

b S(θ, p) = V v∈θ(v = θ(v)) ∧ V pi∈ppi

décrivant les propriétés d’un état de Sb, la fonction aX(s) = Ws,π)∈sa b

S(ˆs) décrirait les

propriétés exprimées par les états abstraits d’un s ∈ X. Un état de X exprime donc une disjonction de conjonctions de propriétés vraies en un point du programme.

Nous étendons naturellement la fonction d’interprétation abstraite ˆI pour raisonner sur une séquence d’instructions sémantiques (un bloc de base, donc).

∀i1, i2, . . . , in∈ Isem, ∀ˆs ∈S,b

ˆI[i1; i2; . . . ; in](ˆs) := ˆI[in] ◦ . . . ◦ ˆI[i2] ◦ ˆI[i1](ˆs)

Nous définissons enfin la fonction d’interprétation d’un bloc de base pour un état du programme.

Définition 4.3. Soit s ∈ X = P(S ×b Π(G)) un état du programme, et b un bloc de base de G, associé à une séquence d’instructions sémantiques Ib. Alors, nous

définissons la fonction I[b](s) := [ (ˆs,π)∈s n ˆ I[Ib](ˆs), π o

nous définissons également

I[e](s) := [

s,π)∈s

n

ˆI[Ie](ˆs), π . eo

Ceci fait, il est simple d’adapter l’Algorithme 3 pour qu’il calcule les états abstraits en tout point du programme. L’état initial s~ entre le CFG avec l’état abstrait identité

1 b

S et le chemin constitué de l’arc ~ seul. À chaque itération, nous récupérons les états

sur les arcs en entrée dans une variable s, interprétons le bloc b, et écrivons s sur chaque arc en sortie après interprétation de celui-ci.

Algorithme 4 : Interprétation abstraite d’un CFG acylique indépendant Données : G= (V, E, , ω), le CFG.

Résultat : {se| e ∈ E}, l’ensemble des états associés à chaque arc de G ;

sG, contenant chaque chemin d’exécution de G, associé à l’état abstrait

représentant son exécution

pour e ∈ E faire se← nil s~ ← {(1 b S,~)} wl ← {sink(~)}

tant que wl 6= ∅ faire

b ← pop(wl) pred ← ins(b)

si ∀e ∈ pred, se 6= nil alors

s ←S

e∈predse

s ← I[b](s) succ ← outs(b)

pour e ∈ succ faire

se← I[e](s)

wl ← wl ∪ {sink(e)} sG ← ∪e∈ins(ω)se

L’exécution de l’Algorithme 4 permet de dégager deux résultats :

1. Chaque arc e du CFG est associé à un état se, contenant un ensemble de chemins

et d’états abstraits leur correspondant ; ces derniers permettant de vérifier la satisfiabilité des premiers, comme nous le verrons au Chapitre 5. Grâce à ce résultat, nous sommes d’ores et déjà en mesure de détecter des chemins infaisables dans tout CFG acylique indépendant.

et leur état abstrait correspondant ; cet état modélise l’effet de l’exécution de la fonction représentée par G.

Ce dernier résultat va nous permettre d’étendre l’Algorithme 4 pour traiter les appels (non récursifs) de fonctions.

4.1.2.2 Appels de fonction

Les appels de fonctions sont représentés dans les CFG par des blocs d’appel, ou blocs virtuels, comme cela a été expliqué en Section 3.1.2.1. Ces blocs, ne contenant eux-mêmes aucune instruction, sont rattachés à une fonction (par son adresse) et re- présentent son exécution (Figure 4.1). Ces blocs sont munis d’un unique arc de sortie, correspondant à l’arc de retour de la fonction appelée.

(a) Bloc d’appel à une fonction f (b)Sémantique décrite par le bloc d’appel

Figure 4.1 – Illustration de la sémantique des blocs d’appel de fonction Définition 4.4. Pour tout bloc b d’un CFG, nous notons C (b) l’ensemble des CFG

attachés au bloc b. Cet ensemble C (b) est • un singleton si b est un bloc d’appel ;

• l’ensemble vide pour tout autre bloc de base.

L’analyse d’un CFG contenant des appels de fonction nécessite donc l’analyse des CFG appelés. Ces dépendances sont établies par le Graphe d’Appel du Programme ou Program Call Graph (PCG), mais peuvent aussi être simplement découvertes au fil de l’exécution de l’algorithme (en commençant par l’analyse du CFG principal du programme).

Algorithme 5 : Interprétation abstraite d’un CFG acylique Données : G= (V, E, , ω), le CFG ;

{sGk | ∃b ∈ V, GkC (b)}, les états correspondant à l’exécution des

CFG appelés, préalablement calculés

Résultat : {se| e ∈ E}, l’ensemble des états associés à chaque arc de G ;

sG, contenant chaque chemin d’exécution de G, associé à l’état

abstrait représentant son exécution

pour e ∈ E faire se← nil s~ ← {(1 b S,~)} wl ← {sink(~)}

tant que wl 6= ∅ faire

b ← pop(wl) pred ← ins(b)

si ∀e ∈ pred, se 6= nil alors

s ←S e∈predse siC (b) = ∅ alors s ← I[b](s) sinon si ∃G0,C (b) = {G0} alors s ← s ◦ sG0 succ ← outs(b)

pour e ∈ succ faire

se← I[e](s)

wl ← wl ∪ {sink(e)} sG ← ∪e∈ins(ω)se

L’Algorithme 5, supportant les appels de programme, requiert donc les états résul- tant de l’analyse des CFG des fonctions appelées par le CFG analysé G, c’est-à-dire {sGk| ∃b ∈ V, GkC (b)}.

Nous étendons la fonction de composition sur les états du programme comme une forme de produit cartésien :

Définition 4.5. La composition de deux états du programme s, s0 ∈ X est définie par : s ◦ s0 :=    (ˆs ◦ ˆs0 , π.π0)   (ˆs, π) (ˆs0, π0)  ∈   s s0     

Pour un état s en un point d’appel énumérant p chemins, et une fonction f contenant q chemins d’exécution représentés dans sf, l’interprétation de l’appel à cette fonction

résultera logiquement en p × q chemins représentés dans s ◦ sf.

L’Algorithme 5 peut maintenant s’écrire avec une simple modification par rapport à l’Algorithme 4 : au moment de l’interprétation d’un bloc, nous effectuons une com- position lorsqu’il s’agit d’un bloc d’appel (qui est, pour rappel, vide d’instructions).

Cet algorithme permet effectivement l’interprétation abstraite de tout programme sans boucle. La gestion des boucles est donc la dernière étape vers une analyse de flot complète.