97 votes

Test de validité des pointeurs (C/C++)

Existe-t-il un moyen de déterminer (par programme, bien sûr) si un pointeur donné est "valide" ? Vérifier la présence de NULL est facile, mais qu'en est-il de choses comme 0x00001234 ? Lorsque l'on essaie de déréférencer ce type de pointeur, une exception ou un crash se produit.

Une méthode multiplateforme est préférable, mais une méthode spécifique à une plateforme (pour Windows et Linux) est également acceptable.

Mise à jour pour clarification : Le problème n'est pas lié à des pointeurs stables/libres/non initialisés ; à la place, j'implémente une API qui prend des pointeurs de l'appelant (comme un pointeur sur une chaîne, un handle de fichier, etc.) ). L'appelant peut envoyer (volontairement ou par erreur) une valeur invalide comme pointeur. Comment puis-je éviter un crash ?

0 votes

0 votes

Je pense que la meilleure réponse positive pour linux est donnée par George Carrette. Si cela n'est pas suffisant, envisagez de construire la table des symboles de fonctions dans la bibliothèque, ou même un autre niveau de table des bibliothèques disponibles avec leurs propres tables de fonctions. Puis vérifiez par rapport à ces tables exactes. Bien sûr, les réponses négatives sont également correctes : vous ne pouvez pas vraiment être sûr à 100% qu'un pointeur de fonction est valide ou non, à moins que vous n'imposiez de nombreuses restrictions supplémentaires à l'application utilisateur.

0 votes

La spécification API spécifie-t-elle réellement une telle obligation à respecter par l'implémentation ? Au fait, je prétends que l'on n'a pas supposé que vous êtes à la fois le développeur et le concepteur. Ce que je veux dire, c'est que je ne pense pas qu'une API spécifierait quelque chose comme "Dans le cas où un pointeur invalide est passé comme argument, la fonction doit gérer le problème et retourner NULL". Une API s'engage à fournir un service dans des conditions d'utilisation correctes, pas par des bidouillages. Néanmoins, cela ne fait pas de mal d'être un peu à l'abri des erreurs. L'utilisation d'une référence permet d'éviter la propagation de tels cas :)

78voto

Johannes Schaub - litb Points 256113

Mise à jour pour clarification : Le problème ne concerne pas les pointeurs périmés, libérés ou non initialisés ; à la place, j'implémente une API qui prend les pointeurs de l'appelant (comme un pointeur sur une chaîne, un handle de fichier, etc.) ). L'appelant peut envoyer (volontairement ou par erreur) une valeur invalide comme pointeur. Comment puis-je éviter un crash ?

Tu ne peux pas faire ce chèque. Il n'y a tout simplement aucun moyen de vérifier si un pointeur est "valide". Il faut croire que lorsque des personnes utilisent une fonction qui prend un pointeur, ces personnes savent ce qu'elles font. S'ils vous transmettent 0x4211 comme valeur de pointeur, alors vous devez croire qu'il pointe vers l'adresse 0x4211. Et s'ils touchent "accidentellement" un objet, alors même si vous utilisiez une fonction effrayante du système d'exploitation (IsValidPtr ou autre), vous vous retrouveriez quand même dans un bogue et vous n'échoueriez pas rapidement.

Commencez à utiliser des pointeurs nuls pour signaler ce genre de choses et dites aux utilisateurs de votre bibliothèque qu'ils ne doivent pas utiliser de pointeurs s'ils ont tendance à passer accidentellement des pointeurs invalides, sérieusement :)

0 votes

C'est probablement la bonne réponse, mais je pense qu'une fonction simple qui vérifie les emplacements mémoire courants en hexspeak serait utile pour le débogage général... En ce moment, j'ai un pointeur qui pointe parfois vers 0xfeeefeee et si j'avais une fonction simple que je pourrais utiliser pour faire des assertions autour de moi, il serait beaucoup plus facile de trouver le coupable... EDIT : Bien qu'il ne serait pas difficile d'en écrire une vous-même je suppose...

0 votes

@quant le problème est que certains codes C et C++ pourraient faire de l'arithmétique de pointeur sur une adresse invalide sans vérification (sur la base du principe garbage-in, garbage-out) et transmettront donc un pointeur "arithmétiquement modifié" à partir d'une de ces adresses invalides bien connues. Les cas les plus courants sont la recherche d'une méthode à partir d'une table virtuelle inexistante basée sur une adresse d'objet invalide ou de type incorrect, ou simplement la lecture de champs à partir d'un pointeur vers une structure qui ne pointe pas vers une structure.

0 votes

Cela signifie essentiellement que vous ne pouvez prendre que des indices de tableau du monde extérieur. Une API qui doit se défendre contre l'appelant ne peut tout simplement pas avoir de pointeurs dans l'interface. Cependant, il serait toujours bon d'avoir des macros à utiliser dans les assertions sur la validité des pointeurs (que vous êtes obligé d'avoir en interne). Si un pointeur est garanti pointer à l'intérieur d'un tableau dont le point de départ et la longueur sont connus, cela peut être vérifié explicitement. Il est préférable de mourir d'une violation d'assertion (erreur documentée) que d'un déréférencement (erreur non documentée).

30voto

Nailer Points 1406

Empêcher un plantage causé par l'envoi par l'appelant d'un pointeur invalide est un bon moyen de rendre silencieux des bogues difficiles à trouver.

Ne vaut-il pas mieux que le programmeur qui utilise votre API reçoive un message clair indiquant que son code est bidon en le faisant planter plutôt que de le cacher ?

8 votes

Dans certains cas cependant, la vérification d'un mauvais pointeur dès l'appel de l'API est comment on échoue tôt. Par exemple, que se passe-t-il si l'API stocke le pointeur dans une structure de données où il ne sera déféré que plus tard ? Le fait de transmettre un mauvais pointeur à l'API provoquera une panne à un moment ultérieur aléatoire. Dans ce cas, il serait préférable d'échouer plus tôt, à l'appel de l'API où la mauvaise valeur a été introduite à l'origine.

28voto

JaredPar Points 333733

Sous Win32/64, il existe un moyen de le faire. Essayez de lire le pointeur et attrapez l'exception SEH qui sera levée en cas d'échec. Si l'exception n'est pas levée, c'est que le pointeur est valide.

Le problème avec cette méthode est qu'elle ne fait que renvoyer si vous pouvez ou non lire des données à partir du pointeur. Elle ne garantit pas la sécurité des types ou tout autre invariant. En général, cette méthode ne sert pas à grand-chose d'autre qu'à dire "oui, je peux lire cet endroit particulier de la mémoire à un moment qui est maintenant passé".

En bref, ne faites pas ça ;)

Raymond Chen a publié un billet de blog sur ce sujet : http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx

3 votes

@Tim, il n'y a aucun moyen de faire cela en C++.

7 votes

Ce n'est la "bonne réponse" que si vous définissez "pointeur valide" comme "qui ne provoque pas de violation d'accès/segfault". Je préfère le définir comme "pointe vers des données significatives allouées pour l'usage que vous allez en faire". Je dirais que c'est une meilleure définition de la validité d'un pointeur... ;)

0 votes

Il n'est pas possible de vérifier de cette manière si le pointeur est valide. Pensez à thread1() { .. if( IsValidPtr( p ) ) *p = 7 ; ... } thread2() { sleep( 1 ) ; delete p ; ...}

16voto

Ferdinand Beyer Points 27723

AFAIK, il n'y a aucun moyen. Vous devriez essayer d'éviter cette situation en mettant toujours les pointeurs à NULL après avoir libéré la mémoire.

4 votes

Mettre un pointeur à null ne vous donne rien, sauf peut-être un faux sentiment de sécurité.

0 votes

Ce n'est pas vrai. En particulier en C++, vous pouvez déterminer s'il faut supprimer les objets membres en vérifiant la présence de null. Notez également qu'en C++, il est valide de supprimer les pointeurs nuls, donc la suppression inconditionnelle des objets dans les destructeurs est populaire.

4 votes

Int * p = new int(0) ; int * p2 = p ; delete p ; p = NULL ; delete p2 ; // crash

7voto

tunnuz Points 5959

Jetez un coup d'œil à este y este question. Jetez également un coup d'œil à pointeurs intelligents .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X