Comment trouver un abus de pointeur en C
Par Arthur Hicken
7 juin 2012
3 min lire
Les pointeurs sont à la fois la force et le talon d'Achille de la programmation en C et C ++. Bien que les pointeurs vous permettent d'être très créatif et flexible dans la façon dont vous abordez la résolution d'un problème particulier, il est très facile d'introduire involontairement des défauts dans votre code. Les problèmes avec les pointeurs sont parmi les plus difficiles rencontrés par les programmeurs C. Il y a une génération, les techniques de force brute telles que l'insertion d'instructions d'impression dans le code étaient souvent la meilleure stratégie pour essayer de trouver ces problèmes.
Aujourd'hui, des outils de détection des erreurs de mémoire comme Assurer ++ peut détecter automatiquement les problèmes liés au pointeur au fur et à mesure que le code est détecté, ce qui économise beaucoup de temps et de maux de tête. Insure ++ trouve des problèmes dans les catégories suivantes:
- Opérations sur les pointeurs NULL Opérations sur les pointeurs non initialisés.
- Opérations sur des pointeurs qui ne pointent pas réellement vers des données valides.
- Opérations qui tentent de comparer ou de relier des pointeurs qui ne pointent pas sur le même objet de données.
- Appels de fonction via des pointeurs de fonction qui ne pointent pas réellement vers des fonctions.
- De nombreuses autres causes possibles d'un comportement indéfini ou d'un comportement défini par l'implémentation.
Insure ++ utilise un analyseur de code de pointe, ainsi que des centaines d'heuristiques, pour analyser le code de l'application, au cours desquels il signale plusieurs violations statiques possibles. Tout en analysant le code, il écrit un nouveau fichier de code source, avec une instrumentation appropriée insérée dans les «points problématiques» (par exemple, déréférencement de pointeur, sortie de portée, etc.), et le fichier source résultant est automatiquement compilé et tous les fichiers de code objet résultants sont liés dans un nouveau programme exécutable.
Exemple
Voici le code d'un programme «Hello world» qui utilise l'allocation de mémoire dynamique:
/ * * Fichier: hello.c * / #include #comprendre int main (int argc, char * argv []) {char * string, * string_so_far; int i, longueur; longueur = 0; pour (i = 0; i
L'idée de base de ce programme est que nous gardons une trace de la taille de chaîne actuelle dans la longueur variable. Au fur et à mesure que chaque nouvel argument est traité, nous ajoutons sa longueur à la variable de longueur et allouons un bloc de mémoire de la nouvelle taille. Notez que le code prend soin d'inclure le dernier caractère NULL lors du calcul de la longueur de la chaîne (ligne 14) ainsi que de l'espace entre les chaînes. Ces deux erreurs sont faciles à commettre. C'est un exercice intéressant pour voir à quelle vitesse vous pouvez trouver une telle erreur avec un outil de détection d'erreur de mémoire comme Parasoft Insure ++.
Le code copie l'argument dans le tampon ou l'ajoute, selon qu'il s'agit ou non du premier passage autour de la boucle. Enfin, le pointeur string_so_far pointe vers la nouvelle chaîne plus longue.
Si vous compilez et exécutez ce programme sous Insure ++, vous verrez des erreurs de «pointeur non initialisé» signalées pour le code «strcpy (string, string_so_far)». C'est parce que la variable string_so_far n'a été définie sur rien avant le premier voyage à travers la boucle d'arguments. Dans un petit exemple de code comme celui-ci, un tel problème est évident, mais même si l'erreur est enterrée dans un tas de centaines de milliers de lignes de code et beaucoup plus subtile que l'erreur ci-dessus, Insure ++ le trouvera à chaque fois.
Rapports Insure ++
Insure ++ signale tout problème détecté. Les rapports Insure ++ incluent des informations détaillées, notamment: sur le type de bogue, le fichier source et le numéro de ligne, le contenu réel de la ligne de code source, l'expression à l'origine du problème, avec des rapports comprenant:
- Le type de bogue, (par exemple EXPR_UNRELATED_PTRCMP)
- Le fichier source et le numéro de ligne, (par exemple foo.cc:42)
- Le contenu réel de la ligne de code source, (par exemple "while (p <g) {")
- L'expression qui a causé le problème, (par exemple «p <g»)
- Informations sur tous les pointeurs et blocs de mémoire impliqués dans le bogue:
- Les valeurs du pointeur
- Les blocs de mémoire pointés (le cas échéant) et tout décalage
- Les informations d'allocation de bloc:
- Trace de pile si allouée dynamiquement.
- Emplacement de la déclaration de bloc, (fichier source et numéro de ligne), s'il est alloué sur la pile ou globalement.
- Trace de pile de la désallocation du bloc, le cas échéant.
- La trace de pile montrant comment le programme est arrivé à l'emplacement du bogue.
Pour essayer Parasoft Insure ++, veuillez visiter https://www.parasoft.com/products/parasoft-insure/insure-request-a-demo/.
Crédit photo: Oskay