• Aucun résultat trouvé

Acc`es hors limite dans un tableau (local ou global) de taille fixe

Chapitre 5 Impl´ ementation

5.3 Traduction des conditions d’erreurs

5.3.2 Acc`es hors limite dans un tableau (local ou global) de taille fixe

fixe

Pour un acc`es tableau en g´en´eral, si l’analyse de valeur ne peut pas garantir que c’est un acc`es valide, c’est-`a-dire que la valeur consult´ee ou modifi´ee entre dans les bornes du tableau, elle ajoute une assertion avec, comme condition, la condition qui emp`eche l’acc`es hors limite. Dans le cas d’un tableau de taille fixe, l’analyse de valeur connaˆıt la taille du tableau et il est facile d’´etablir la condition de sˆuret´e entre l’indice d’acc`es et la taille du tableau correspondant.

Pour l’exemple elemInArray pr´esent´e dans la figure 5.3, l’analyse de valeur ne peut pas garantir que a est un indice valide dans T. Il ajoute donc l’assertion :

// a s s e r t (0 <= a ∧ a < 1 0 ) ;

avant la ligne 4.

Dans ce cas aussi, la traduction de la condition est directe. Il suffit de prendre la n´egation de la condition donn´ee par l’assertion. L’instruction conditionnelle qui remplace l’instruction mena¸cante est :

i f (!(0 <= a && a < 10)) error ();

e l s e

5.3. Traduction des conditions d’erreurs 1 char e l e m I n S t r( char * str , i n t a ){ 2 char y ; 3 y = *( str + a ); 4 return y ; 5 }

Figure 5.4 – Exemple avec un acc`es pointeur

1 char e l e m I n S t r( char * str , i n t a ){ 2 char y ; 31 i f ( p a t h c r a w l e r _ l e n g t h( str ) <= a || a < 0 ) 32 error (); 33 e l s e 3 y = *( str + a ); 4 return y ; 5 }

Figure 5.5 – L’exemple de la figure 5.4 apr`es l’ajout des branches d’erreur

5.3.3

Pointeur invalide ou acc`es hors limite dans un tableau de

taille variable

On consid`ere dans cette partie les tableaux de taille variable et les pointeurs globaux ou locaux ainsi que tout tableau ou pointeur en entr´ee d’une fonction. En effet, la taille d’un tableau en entr´ee est perdue par CIL, conform´ement `a la norme C.

Pour un acc`es par pointeur, ou dans un tableau de taille variable, si l’analyse de valeur ne connaˆıt pas la taille exacte du tableau consult´e, et trouve un risque d’acc`es invalide, elle ajoute une assertion avec, comme condition, la condition qui emp`eche l’acc`es invalide. Mais, dans ce cas, elle utilise la commande ACSL \valid.

Pour l’exemple elemInStr pr´esent´e dans la figure 5.4, si l’analyse de valeur ne peut pas garantir que a est un indice valide dans str, elle ajoute avant la ligne 3 l’assertion :

// @assert \ v a l i d ( s t r + a ) ;

Dans ce cas, la condition qui provoque l’erreur d´epend de la taille allou´ee pour str dans chaque cas de test. Cette taille fait partie des donn´ees de test qui doivent ˆetre d´e- termin´ees par PathCrawler. Nous allons voir comment nous ´etendons PathCrawler afin de lui permettre de r´ecup´erer la taille des tableaux donn´es en entr´ee, `a l’aide de la fonction nomm´ee pathcrawler_length d´ecrite ci-dessous.

Grˆace `a cette extension, la condition d’erreur sera simplement remplac´ee par :

1 s t r u c t _ _ p a t h c r a w l e r _ a r r a y { 2 void * ptr ; 3 size_t length ; 4 size_t e l e m e n t _ s i z e; 5 s t r u c t _ _ p a t h c r a w l e r _ a r r a y * next ; 6 }; 7 s t r u c t _ _ p a t h c r a w l e r _ a r r a y * _ _ p a t h c r a w l e r _ f i r s t _ a r r a y = NULL ;

Figure 5.6 – La structure __pathcrawler_array

ce qui la rend ex´ecutable lors de l’ex´ecution concr`ete et fera le lien avec la taille du tableau allou´e lors de l’ex´ecution symbolique. Le programme apr`es l’ajout des branches d’erreur est pr´esent´e dans la figure 5.5.

Extension pour la taille des tableaux pass´es en param`etres

Pour traiter les alarmes sur les tableaux (et pointeurs) en entr´ee de la fonction sous test, on a besoin de connaˆıtre la taille du tableau donn´e en entr´ee. Cependant, le langage C ne nous permet pas de connaˆıtre la taille des tableaux donn´es en entr´ee d’une fonction. En effet, la taille d’un tableau allou´e dynamiquement n’est pas r´ecup´erable dans le code C apr`es son allocation.

Rappelons que la fonction sizeof donne bien le nombre d’octets occup´es par un ta- bleau de taille fixe. Mais un tableau de taille variable est consid´er´e comme un pointeur, dont la taille est de quatre octets utilis´es pour stocker l’adresse de la zone point´ee (sur une machine 32 bits).

Nous ´etendons PathCrawler afin de lui permettre de r´ecup´erer la taille des tableaux en entr´ee d’une fonction, en le dotant de la fonction pathcrawler_length. En effet, nous surchargeons les fonctions d’allocation et de lib´eration de m´emoire afin de sauvegarder la taille allou´ee `a chaque fois. La fonction pathcrawler_length prend un pointeur en entr´ee et permet de r´ecup´erer la taille allou´ee pour ce pointeur pass´e en param`etre. Dans ce qui suit, nous expliquons les modifications apport´ees en d´etails.

Parmi les rˆoles du lanceur, il y a l’allocation de la m´emoire n´ecessaire aux entr´ees de la fonction sous test (voir section 3.3.3). Nous lui ajoutons une nouvelle fonctionnalit´e, qui consiste `a enregistrer la taille des tableaux allou´es dynamiquement par le lanceur avant un cas de test, afin que nous puissions la restituer ensuite par la fonction pathcraw- ler_length. Pour cela, nous modifions l’impl´ementation des deux fonctions pathcraw-

ler_alloc et pathcrawler_free, dont les rˆoles initiaux ´etaient respectivement d’allouer

et de lib´erer la zone m´emoire n´ecessaire pour chaque param`etre.

5.3. Traduction des conditions d’erreurs 1 void * p a t h c r a w l e r _ a l l o c( i n t length , i n t e l e m e n t _ s i z e) { 2 s t r u c t _ _ p a t h c r a w l e r _ a r r a y * elem ; 3 elem = malloc (s i z e o f ( s t r u c t _ _ p a t h c r a w l e r _ a r r a y )); 4 i f ( elem == 0) 5 return 0;

6 void * ptr = malloc ( length * e l e m e n t _ s i z e ); 7 i f ( ptr == 0){

8 free ( elem );

9 return 0;

10 }

11 s t r u c t _ _ p a t h c r a w l e r _ a r r a y ** pnext = & _ _ p a t h c r a w l e r _ f i r s t _ a r r a y ; 12 while (* pnext && (* pnext ) - > ptr < ptr )

13 pnext = & ((* pnext ) - > next ); 14 elem - > ptr = ptr ;

15 elem - > next = * pnext ; 16 elem - > length = length ;

17 elem - > e l e m e n t _ s i z e = e l e m e n t _ s i z e; 18 * pnext = elem ;

19 return ptr ; 20 }

Figure 5.7 – La fonction pathcrawler_alloc

liste chaˆın´ee contenant les descripteurs des tableaux allou´es. Chaque ´el´ement de la liste instancie la structure __pathcrawler_array pr´esent´ee dans la figure 5.6. Cette structure contient le descripteur d’un tableau allou´e et inclut quatre champs :

– le premier contient l’adresse de la zone m´emoire allou´ee pour le tableau, – le champ length correspond au nombre d’´el´ements dans ce tableau, – le champ element_size correspond `a la taille de chaque ´el´ement et – le champ next fait r´ef´erence au prochain ´el´ement de la liste chaˆın´ee.

Notre nouvelle impl´ementation de pathcrawler_alloc est pr´esent´ee dans la figure 5.7. Elle commence par allouer un ´el´ement pour stocker un nouveau descripteur de tableau (ligne 3). Ensuite on alloue la m´emoire n´ecessaire pour le tableau (ligne 6). On cherche la place du descripteur dans la liste (lignes 12–13). On initialise les informations du descrip- teur (lignes 14–17). On place le descripteur dans la liste et on retourne le tableau allou´e. Notre nouvelle impl´ementation de pathcrawler_free est pr´esent´ee dans la figure 5.8. Elle cherche le descripteur correspondant `a ce tableau dans la liste des descripteurs (lignes 3–4). La ligne 7 relie l’´el´ement pr´ec´edent `a l’´el´ement suivant de descripteur du tableau `a lib´erer. On lib`ere le descripteur (ligne 8) et ensuite on lib`ere la zone m´emoire allou´ee pour le tableau (lignes 9–10).

1 void * p a t h c r a w l e r _ f r e e( void * ptr )) {

2 s t r u c t _ _ p a t h c r a w l e r _ a r r a y ** pnext = & _ _ p a t h c r a w l e r _ f i r s t _ a r r a y ; 3 while (* pnext != NULL && (* pnext ) - > ptr < ptr )

4 pnext = &((* pnext ) - > next );

5 i f (* pnext != NULL && (* pnext ) - > ptr == ptr ) { 6 s t r u c t _ _ p a t h c r a w l e r _ a r r a y * current = * pnext ; 7 * pnext = current - > next ;

8 free ( current ); 9 i f ( ptr != NULL ) 10 free ( ptr ); 11 } 12 return; 13 }

Figure 5.8 – La fonction pathcrawler_free

1 i n t p a t h c r a w l e r _ l e n g t h( void * ptr ) {

2 s t r u c t _ _ p a t h c r a w l e r _ a r r a y * cur = _ _ p a t h c r a w l e r _ f i r s t _ a r r a y ; 3 while ( cur != NULL && cur - > ptr < ptr ) {

4 cur = cur - > next ;

5 }

6 i n t len = 0;

7 i f ( cur != NULL && cur - > ptr == ptr ) { 8 len = cur - > length ;

9 }

10 return len ; 11 }

5.4. Traitement des exceptions

Documents relatifs