Contenu | Rechercher | Menus

Annonce

DVD, clés USB et t-shirts Ubuntu-fr disponibles sur la boutique En Vente Libre

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 30/04/2021, à 14:53

zephyre123

Question sur le debuggage, pourquoi ce programme ne plante pas ?

Bonjour,

Je lis la documentation sur le debuggage suivante : https://c.developpez.com/cours/20-heure … _12#LXII-D
Et je pratique également.

J'ai testé ce code :

#include <stdio.h> 
#define TAILLE 10
int main ()
{
	int tab[TAILLE];

	tab[TAILLE+10]=100;

	printf("tab[20] = %d\n", tab[TAILLE + 10]);

	return 0;
}

Ce qui m'inquiète le plus c'est que mon programme ne plante jamais, je l'ai exécuté plus de 10 fois et j'ai toujours le résultat ci dessous :

tab[20] = 100

Hors je ne devrai pas avoir accès à tab[20] non ?
Car la taille du tableau est alloué avant compilation c'est bien ça.

Je ne comprends pas pourquoi mon programme ne plante pas et j'ai rien pas d'erreur de compilation ou exécution, pas de warning bref rien du tout !
Je ne sais même pas ou j'écris puisque normalement je n''ai pas accès à tab[20] = tab[TAILLE + 10]

Hors ligne

#2 Le 30/04/2021, à 15:50

Nuliel

Re : Question sur le debuggage, pourquoi ce programme ne plante pas ?

Bonjour,
La réponse va être un peu compliquée, mais le résumé est le suivant: ça ne crashe pas parce que tu écrases des données qui n'impactent pas la suite de l'exécution, mais ça pourrait faire tout et n'importe quoi dans d'autres situations.
En C, c'est au développeur de vérifier qu'il n'écrit pas en dehors d'un tableau. Ce code avec -Wall -Wextra devrait normalement donner un warning.

En réalité, tab[20] est compris comme le 21ème élément en partant de l'adresse contenue dans tab. Le tableau est contenu dans la stack (pile en français), plus précisément dans la stack frame de la fonction main. Cette stack contient les variables locales des fonctions, des valeurs enregistrées de registres comme rbp, la return address, les paramètres des fonctions lorsqu'elles sont nombreuses.... Bref plein de choses utiles au bon déroulement du programme. Mais il est possible que tu aies écrasé un truc inutile, comme une variable locale dont tu ne te sers plus.

Bien évidemment je peux approfondir, mais ça va devenir compliqué (au passage c'est un de mes domaines favoris)

Pour le fun, tu peux aussi accéder à des cases négatives: lire tab[-2] ça peut marcher dans certains cas

Dernière modification par Nuliel (Le 30/04/2021, à 16:08)


[ poster un retour de commande ] [ poster une photo ]
Thinkpad x220, Dell latitude E7270 (i7 6600U, 16 Go de RAM, ...), Thinkstation E32 modifié: i5-4570, GTX 1060 6 Gb, 16 Gb de RAM, ...
Mon nouveau blog: nuliel.fr

Hors ligne

#3 Le 30/04/2021, à 16:17

Amiralgaby

Re : Question sur le debuggage, pourquoi ce programme ne plante pas ?

Nuliel a écrit :

Ce code avec -Wall -Wextra devrait normalement donner un warning.

Et bien aucun warning figure toi !

même moi je trouve cela bizarre.


Vive la communauté du Libre !!!

Hors ligne

#4 Le 30/04/2021, à 16:26

Nuliel

Re : Question sur le debuggage, pourquoi ce programme ne plante pas ?

Ah merde, effectivement...
Quelques tests:

nuliel@nuliel-desktop:~/programmes_C/test_C$ clang -Wall -Wextra main.c 
main.c:7:2: warning: array index 20 is past the end of the array (which contains 10 elements) [-Warray-bounds]
        tab[TAILLE+10]=100;
        ^   ~~~~~~~~~
main.c:5:2: note: array 'tab' declared here
        int tab[TAILLE];
        ^
main.c:9:27: warning: array index 20 is past the end of the array (which contains 10 elements) [-Warray-bounds]
        printf("tab[20] = %d\n", tab[TAILLE + 10]);
                                 ^   ~~~~~~~~~~~
main.c:5:2: note: array 'tab' declared here
        int tab[TAILLE];
        ^
2 warnings generated.
nuliel@nuliel-desktop:~/programmes_C/test_C$

Pendant ce temps, chez gcc:

nuliel@nuliel-desktop:~/programmes_C/test_C$ gcc -Wall -Wextra -Warray-bounds main.c 
nuliel@nuliel-desktop:~/programmes_C/test_C$

...
scan build voit rien

nuliel@nuliel-desktop:~/programmes_C/test_C$ scan-build-11 gcc -Wall -Wextra -Warray-bounds main.c 
scan-build: Using '/usr/lib/llvm-11/bin/clang' for static analysis
scan-build: Analysis run complete.
scan-build: Removing directory '/tmp/scan-build-2021-04-30-172311-7587-1' because it contains no reports.
scan-build: No bugs found.
nuliel@nuliel-desktop:~/programmes_C/test_C$

cppcheck c'est bon

nuliel@nuliel-desktop:~/programmes_C/test_C$ cppcheck main.c 
Checking main.c ...
main.c:7:5: error: Array 'tab[10]' accessed at index 20, which is out of bounds. [arrayIndexOutOfBounds]
 tab[TAILLE+10]=100;
    ^
main.c:9:30: error: Array 'tab[10]' accessed at index 20, which is out of bounds. [arrayIndexOutOfBounds]
 printf("tab[20] = %d\n", tab[TAILLE + 10]);
                             ^
nuliel@nuliel-desktop:~/programmes_C/test_C$

Avec sanitizer:

nuliel@nuliel-desktop:~/programmes_C/test_C$ gcc -Wall -Wextra -fsanitize=undefined main.c 
nuliel@nuliel-desktop:~/programmes_C/test_C$ ./a.out 
main.c:7:5: runtime error: index 20 out of bounds for type 'int [10]'
main.c:7:16: runtime error: store to address 0x7ffd6aa8f6c0 with insufficient space for an object of type 'int'
0x7ffd6aa8f6c0: note: pointer points here
 01 00 00 00  65 71 77 88 40 56 00 00  a0 26 28 d4 d5 7f 00 00  00 00 00 00 00 00 00 00  3d 30 39 20
              ^ 
main.c:9:30: runtime error: index 20 out of bounds for type 'int [10]'
main.c:9:2: runtime error: load of address 0x7ffd6aa8f6c0 with insufficient space for an object of type 'int'
0x7ffd6aa8f6c0: note: pointer points here
 01 00 00 00  64 00 00 00 40 56 00 00  a0 26 28 d4 d5 7f 00 00  00 00 00 00 00 00 00 00  3d 30 39 20
              ^ 
tab[20] = 100
nuliel@nuliel-desktop:~/programmes_C/test_C$

undefined c'est pour undefined behavior

Dernière modification par Nuliel (Le 30/04/2021, à 16:27)


[ poster un retour de commande ] [ poster une photo ]
Thinkpad x220, Dell latitude E7270 (i7 6600U, 16 Go de RAM, ...), Thinkstation E32 modifié: i5-4570, GTX 1060 6 Gb, 16 Gb de RAM, ...
Mon nouveau blog: nuliel.fr

Hors ligne

#5 Le 30/04/2021, à 16:50

Nuliel

Re : Question sur le debuggage, pourquoi ce programme ne plante pas ?

Malheureusement gcc ne voit pas toutes les erreurs possibles, clang non plus, cppcheck non plus, scan-build non plus, les sanitizers non plus (qui eux nécessitent de lancer le programme pour rencontrer l'erreur), mais en utilisant plusieurs outils on arrive normalement à couvrir presque tous les cas qui posent problème.
Pour info, j'ai fait des tests il y a peu de temps sur de nombreux comportements indéfinis (y compris out of bounds), et aucun outil ne les détecte tous, mais avec plusieurs on a plus de chances de trouver plus de comportements indéfinis.
Dans les comportements que j'ai testé: déréférencement de pointeur nul/vers une variable plus définie, la modification de littéraux, la modification de variables définies comme constantes, les dépassement d'entier (integer overflow): décalage à gauche/droite trop de fois, décalage avec exposant négatif, valeur d'un flottant négatif mis dans un entier non signé.

Pour en revenir à l'écriture "indéfinie", je peux détailler bien plus si ça vous intéresse

Dernière modification par Nuliel (Le 30/04/2021, à 16:55)


[ poster un retour de commande ] [ poster une photo ]
Thinkpad x220, Dell latitude E7270 (i7 6600U, 16 Go de RAM, ...), Thinkstation E32 modifié: i5-4570, GTX 1060 6 Gb, 16 Gb de RAM, ...
Mon nouveau blog: nuliel.fr

Hors ligne

#6 Le 30/04/2021, à 17:34

zephyre123

Re : Question sur le debuggage, pourquoi ce programme ne plante pas ?

Donc en résumé y a que cppcheck qui voit l'erreur => bonne outils
De ce que j'ai pu en lire ce n'est pas un compilateur mais une sorte de débuggeur vous confirmez ?
Comment je fais pour lancer cppcheck et le vérifier à mon tour svp ?

Dernière modification par zephyre123 (Le 30/04/2021, à 17:35)

Hors ligne

#7 Le 30/04/2021, à 17:38

Nuliel

Re : Question sur le debuggage, pourquoi ce programme ne plante pas ?

Comme je l'ai dit au dessus, il n'y a aucun outil qui trouve tous les comportements indéfinis (parce qu'il y en a une grande quantité, lire et écrire en dehors d'un tableau n'est qu'un exemple), mais les outils sont au final complémentaires.
Il n'y a pas de bon ou de mauvais outil de debug.

Tout simplement

sudo apt install cppcheck

pour l'installer

cppcheck fichier.c

pour vérifier que ça marche.

Sinon le sanitizer sous gcc l'a vu et clang l'a vu aussi.

En gros le programmeur a une grande liberté en C, mais il doit pas faire n'importe quoi sous peine d'avoir soit des comportements étranges/crashs ou des bugs qui peuvent devenir très problématiques (je pense en particulier aux buffer overflow)

Dernière modification par Nuliel (Le 30/04/2021, à 17:40)


[ poster un retour de commande ] [ poster une photo ]
Thinkpad x220, Dell latitude E7270 (i7 6600U, 16 Go de RAM, ...), Thinkstation E32 modifié: i5-4570, GTX 1060 6 Gb, 16 Gb de RAM, ...
Mon nouveau blog: nuliel.fr

Hors ligne