web-dev-qa-db-fra.com

Test des pointeurs pour la validité (C/C++)

Est-il possible de déterminer (par programmation, bien sûr) si un pointeur donné est "valide"? Vérifier NULL est facile, mais qu’en est-il des choses comme 0x00001234? Lorsque vous essayez de déréférencer ce type de pointeur, une exception/un crash se produit.

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

Mise à jour pour clarification: Le problème ne vient pas des pointeurs obsolètes/libérés/non initialisés; Au lieu de cela, j'implémente une API qui prend les pointeurs de l'appelant (comme un pointeur sur une chaîne, un descripteur de fichier, etc.). L'appelant peut envoyer (intentionnellement ou par erreur) une valeur non valide en tant que pointeur. Comment puis-je prévenir un accident?

78
noamtm

Mise à jour pour clarification: Le problème ne concerne pas les pointeurs périmés, libérés ou non initialisés; Au lieu de cela, j'implémente une API qui prend les pointeurs de l'appelant (comme un pointeur sur une chaîne, un descripteur de fichier, etc.). L'appelant peut envoyer (intentionnellement ou par erreur) une valeur non valide en tant que pointeur. Comment puis-je prévenir un accident?

Vous ne pouvez pas faire cette vérification. Il est tout simplement impossible de vérifier si un pointeur est "valide". Vous devez avoir la certitude que lorsque les utilisateurs utilisent une fonction utilisant un pointeur, ils savent ce qu’ils font. S'ils vous transmettent 0x4211 en tant que valeur de pointeur, vous devez alors faire confiance à l'adresse qui pointe l'adresse 0x4211. Et s'ils frappaient "accidentellement" un objet, alors même si vous utilisiez une fonction système effrayante (IsValidPtr ou autre), vous risqueriez de tomber dans un bogue et de ne pas échouer rapidement.

Commencez à utiliser des pointeurs nuls pour signaler ce type de problème et dites à l'utilisateur de votre bibliothèque qu'il ne doit pas utiliser de pointeurs s'ils ont tendance à passer accidentellement des pointeurs non valides, sérieusement :)

70

Empêcher un blocage causé par l'appelant d'envoyer un pointeur non valide est un bon moyen de créer des bogues silencieux difficiles à trouver. 

N'est-il pas préférable que le programmeur utilisant votre API reçoive un message clair indiquant que son code est faux en le faisant planter au lieu de le cacher? 

30
Nailer

Sur Win32/64, il existe un moyen de le faire. Essayez de lire le pointeur et d’attraper l’exception SEH résultante qui sera lancée en cas d’échec. Si cela ne jette pas, alors c'est un pointeur valide.

Le problème avec cette méthode est qu’elle indique simplement si vous pouvez ou non lire les données du pointeur. Il ne fait aucune garantie sur la sécurité du type ni sur un nombre quelconque d'autres invariants. En général, cette méthode n’est utile que pour dire «oui, je peux lire cet endroit particulier en mémoire à un moment qui s’est écoulé». 

En bref, ne fais pas ça;)

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

26
JaredPar

Voici trois façons simples pour un programme C sous Linux d’obtenir une introspective sur l’état de la mémoire dans laquelle il s’exécute et sur les raisons pour lesquelles la question contient des réponses sophistiquées appropriées dans certains contextes.

  1. Après avoir appelé getpagesize () et arrondi le pointeur à une limite de page , Vous pouvez appeler mincore () pour savoir si une page est valide et Si elle fait partie du jeu de processus. Notez que cela nécessite quelques ressources du noyau, vous devriez donc le comparer et déterminer si l'appel de cette fonction est vraiment approprié dans votre api. Si votre api va traiter des interruptions ou lire des ports série En mémoire, il convient d'appeler cette opération pour éviter des comportements imprévisibles
  2. Après avoir appelé stat () pour déterminer s’il existe un répertoire/proc/self disponible, vous pouvez ouvrir et lire le fichier /proc/self/mapspour trouver des informations sur la région dans laquelle réside un pointeur. page de manuel de proc, le pseudo-fichier d’informations sur les processus .__ système. Évidemment, cela coûte relativement cher, mais vous pourriez être capable de mettre en cache le résultat de l'analyse dans un tableau. Vous pouvez effectuer une recherche efficace à l'aide d'une recherche binaire. Considérez également le/proc/self/smaps. Si votre API est pour le calcul haute performance, alors Le programme voudra connaître le/proc/self/numa qui est documenté Documenté dans la page de manuel de numa, la mémoire non uniforme Architecture.
  3. L'appel get_mempolicy (MPOL_F_ADDR) est approprié pour les applications de calcul hautes performances où plusieurs threads sont exécutés Et que vous gérez votre travail pour avoir une affinité pour la mémoire non uniforme. Ressources. Bien entendu, une telle approche vous indiquera également si un pointeur est valide.

Sous Microsoft Windows, la fonction QueryWorkingSetEx est décrite dans l'API Process Status (également dans l'API NUMA) . En corollaire à la programmation sophistiquée de l'API NUMA, cette fonction vous permet également de "tester la validité de simples pointeurs/C++) "travail, en tant que tel, il est peu probable qu’il soit déconseillé pendant au moins 15 ans.

24
George Carrette

Autant que je sache, il n'y a pas moyen. Vous devriez essayer d'éviter cette situation en définissant toujours les pointeurs sur NULL après avoir libéré de la mémoire.

15
Ferdinand Beyer

Jetez un oeil à this et this question. Jetez également un coup d'œil à pointeurs intelligents.

7
tunnuz

En ce qui concerne la réponse un peu plus haut dans ce fil:

IsBadReadPtr (), IsBadWritePtr (), IsBadCodePtr (), IsBadStringPtr () pour Windows.

Mon conseil est de rester loin d'eux, quelqu'un a déjà posté celui-ci: http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx

Un autre article sur le même sujet et du même auteur (je pense) est celui-ci: http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx ( "IsBadXxxPtr devrait vraiment s'appeler CrashProgramRandomly").

Si les utilisateurs de votre API envoient des données incorrectes, laissez-les planter. Si le problème est que les données transmises ne sont utilisées que plus tard (ce qui complique la recherche de la cause), ajoutez un mode de débogage dans lequel les chaînes, etc., sont consignées à l'entrée. Si elles sont mauvaises, cela sera évident (et probablement crash). Si cela se produit trop souvent, il peut être intéressant de sortir votre API du processus et de la laisser bloquer le processus de l'API au lieu du processus principal.

7
Fredrik

Tout d’abord, je ne vois aucun intérêt à essayer de vous protéger de l’appelant qui tente délibérément de provoquer un blocage. Ils pourraient facilement le faire en essayant d'accéder eux-mêmes via un pointeur invalide. Il existe de nombreuses autres manières - ils pourraient simplement écraser votre mémoire ou la pile. Si vous avez besoin de vous protéger contre ce genre de chose, vous devez exécuter un processus séparé utilisant des sockets ou un autre IPC pour la communication.

Nous écrivons beaucoup de logiciels qui permettent aux partenaires/clients/utilisateurs d’étendre les fonctionnalités. Inévitablement, tout bogue nous est signalé en premier, il est donc utile de pouvoir facilement montrer que le problème provient du code du plug-in. De plus, il y a des problèmes de sécurité et certains utilisateurs ont plus de confiance que d'autres.

Nous utilisons différentes méthodes en fonction des exigences de performance/débit et de la fiabilité. De plus préféré:

  • processus séparés utilisant des sockets (transmettant souvent des données sous forme de texte).

  • processus séparés utilisant la mémoire partagée (si de grandes quantités de données doivent être transmises).

  • le même processus sépare les threads via la file de messages (si les messages courts sont fréquents).

  • le même processus sépare les threads de toutes les données allouées d'un pool de mémoire.

  • même processus via appel direct de procédure - toutes les données transmises allouées à partir d'un pool de mémoire. 

Nous essayons de ne jamais recourir à ce que vous essayez de faire lorsque vous utilisez un logiciel tiers - en particulier lorsque les plug-ins/la bibliothèque nous sont fournis sous forme binaire plutôt que de code source.

L'utilisation d'un pool de mémoire est assez facile dans la plupart des cas et n'a pas besoin d'être inefficace. Si VOUS allouez les données en premier lieu, il est facile de comparer les pointeurs aux valeurs que vous avez attribuées. Vous pouvez également stocker la longueur allouée et ajouter des valeurs "magiques" avant et après les données pour vérifier le type de données et les dépassements de données valides.

6
Dipstick

Votre question suscite beaucoup de sympathie car je suis moi-même dans une position presque identique. J'apprécie les réponses fournies par de nombreuses réponses, qui sont correctes: la routine fournissant le pointeur devrait fournir un pointeur valide. Dans mon cas, il est presque inconcevable qu'ils aient pu corrompre le pointeur - mais s'ils avaient réussi à le faire, ce serait MON logiciel qui planterait, et MOI, qui serait blâmé.

Mon exigence n'est pas que je continue après une erreur de segmentation - ce serait dangereux - je veux simplement signaler ce qui est arrivé au client avant de le résilier pour qu'il puisse corriger son code plutôt que de me blâmer!

Voici comment je l’ai trouvé (sous Windows): http://www.cplusplus.com/reference/clibrary/csignal/signal/

Pour donner un synopsis:

#include <signal.h>

using namespace std;

void terminate(int param)
/// Function executed if a segmentation fault is encountered during the cast to an instance.
{
  cerr << "\nThe function received a corrupted reference - please check the user-supplied  dll.\n";
  cerr << "Terminating program...\n";
  exit(1);
}

...
void MyFunction()
{
    void (*previous_sigsegv_function)(int);
    previous_sigsegv_function = signal(SIGSEGV, terminate);

    <-- insert risky stuff here -->

    signal(SIGSEGV, previous_sigsegv_function);
}

Maintenant, ce semble se comporter comme je le souhaiterais (il affiche le message d'erreur, puis termine le programme) - mais si quelqu'un peut repérer un défaut, faites-le-moi savoir!

4
Mike Sadler

Ce n'est pas une très bonne politique d'accepter des pointeurs arbitraires comme paramètres d'entrée dans une API publique. Il est préférable d’avoir des types de "données simples" comme un entier, une chaîne de caractères ou une structure (je veux dire une structure classique avec des données simples à l’intérieur, bien sûr; officiellement tout peut être une structure).

Pourquoi? Comme d’autres le disent, il n’existe aucun moyen standard de savoir si un pointeur valide ou un pointeur pointé vers un courrier indésirable vous a été attribué.

Mais parfois, vous n'avez pas le choix - votre API doit accepter un pointeur.

Dans ces cas, l'appelant a le devoir de passer un bon pointeur. NULL peut être accepté comme une valeur, mais pas comme un pointeur sur un courrier indésirable.

Pouvez-vous vérifier de quelque façon que ce soit? Eh bien, ce que j'ai fait dans un cas comme celui-ci a été de définir un invariant pour le type pointé par le pointeur et de l'appeler dès que vous l'obtenez (en mode débogage). Du moins si l'invariant échoue (ou se bloque), vous savez que vous avez reçu une mauvaise valeur.

// API that does not allow NULL
void PublicApiFunction1(Person* in_person)
{
  assert(in_person != NULL);
  assert(in_person->Invariant());

  // Actual code...
}

// API that allows NULL
void PublicApiFunction2(Person* in_person)
{
  assert(in_person == NULL || in_person->Invariant());

  // Actual code (must keep in mind that in_person may be NULL)
}
2
Daniel Daranas

Sous Unix, vous devriez pouvoir utiliser un appel système du noyau qui vérifie le pointeur et renvoie EFAULT, tel que:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdbool.h>

bool isPointerBad( void * p )
{
   int fh = open( p, 0, 0 );
   int e = errno;

   if ( -1 == fh && e == EFAULT )
   {
      printf( "bad pointer: %p\n", p );
      return true;
   }
   else if ( fh != -1 )
   {
      close( fh );
   }

   printf( "good pointer: %p\n", p );
   return false;
}

int main()
{
   int good = 4;
   isPointerBad( (void *)3 );
   isPointerBad( &good );
   isPointerBad( "/tmp/blah" );

   return 0;
}

rentrant:

bad pointer: 0x3
good pointer: 0x7fff375fd49c
good pointer: 0x400793

Il y a probablement un meilleur système à utiliser que open () [peut-être un accès], car il est possible que cela conduise à la création d'un fichier codepath, et à une exigence de fermeture ultérieure.

2
Peeter Joot

Il n'y a pas de moyen portable de le faire, et le faire pour des plates-formes spécifiques peut être n'importe où entre difficile et impossible. Dans tous les cas, vous ne devriez jamais écrire de code qui dépend d'une telle vérification - ne laissez pas les pointeurs prendre des valeurs non valides.

2
anon

C++ ne contient aucune disposition permettant de tester la validité d'un pointeur en tant que cas général. On peut évidemment supposer que NULL (0x00000000) est mauvais et que divers compilateurs et bibliothèques préfèrent utiliser des "valeurs spéciales" ici et là pour faciliter le débogage (par exemple, si je vois un pointeur apparaître sous la forme 0xCECECECE dans Visual Studio, je le sais. J'ai fait quelque chose de mal) mais la vérité est que, comme un pointeur n'est qu'un index dans la mémoire, il est presque impossible de le savoir en regardant simplement le pointeur s'il s'agit du "bon" index. 

Dynamic_cast et RTTI permettent d'effectuer diverses astuces, notamment pour vous assurer que l'objet pointé est du type que vous souhaitez, mais ils exigent tous que vous indiquiez quelque chose de valide. 

Si vous voulez vous assurer que votre programme peut détecter les pointeurs "non valides", voici mon conseil: définissez chaque pointeur que vous déclarez soit sur NULL, soit sur une adresse valide immédiatement après sa création, puis définissez-le sur NULL immédiatement après avoir libéré la mémoire sur laquelle il pointe. Si vous êtes diligent à propos de cette pratique, alors vérifier que NULL est tout ce dont vous avez besoin. 

2
Toji

Définir le pointeur sur NULL avant et après l’utilisation est une bonne technique. Ceci est facile à faire en C++ si vous gérez des pointeurs dans une classe, par exemple (une chaîne):

class SomeClass
{
public:
    SomeClass();
    ~SomeClass();

    void SetText( const char *text);
    char *GetText() const { return MyText; }
    void Clear();

private:
    char * MyText;
};


SomeClass::SomeClass()
{
    MyText = NULL;
}


SomeClass::~SomeClass()
{
    Clear();
}

void SomeClass::Clear()
{
    if (MyText)
        free( MyText);

    MyText = NULL;
}



void SomeClass::Settext( const char *text)
{
    Clear();

    MyText = malloc( strlen(text));

    if (MyText)
        strcpy( MyText, text);
}
2
Tim Ring

Cet article MEM10-C. Définir et utiliser une fonction de validation du pointeur indique qu'il est possible d'effectuer une vérification dans une certaine mesure, en particulier sous Linux. 

1
Marek Szanyi

Comme d'autres l'ont dit, vous ne pouvez pas détecter de manière fiable un pointeur invalide. Considérez certaines des formes qu'un pointeur invalide pourrait prendre:

Vous pourriez avoir un pointeur nul. Vous pouvez facilement vérifier et faire quelque chose à ce sujet.

Vous pourriez avoir un pointeur sur quelque part en dehors de la mémoire valide. Ce qui constitue une mémoire valide varie en fonction de la manière dont l'environnement d'exécution de votre système configure l'espace d'adressage. Sur les systèmes Unix, il s’agit généralement d’un espace d’adresse virtuel commençant à 0 et atteignant un nombre élevé de mégaoctets. Sur les systèmes embarqués, cela pourrait être assez petit. Il pourrait ne pas commencer à 0, dans tous les cas. Si votre application s'exécute en mode superviseur ou en mode équivalent, votre pointeur peut référencer une adresse réelle, qui peut être sauvegardée ou non avec de la mémoire réelle.

Vous pouvez avoir un pointeur sur votre mémoire valide, même dans votre segment de données, bss, stack ou heap, mais sans pointer sur un objet valide. Une variante de ceci est un pointeur qui désignait un objet valide, avant que quelque chose de mauvais ne lui soit arrivé. Les mauvaises choses dans ce contexte incluent la désallocation, la corruption de mémoire ou la corruption de pointeur.

Vous pourriez avoir un pointeur illégal complet, tel qu'un pointeur avec un alignement illégal pour la chose référencée.

Le problème s'aggrave encore lorsque vous considérez des architectures basées sur des segments/décalages et d'autres implémentations de pointeurs étranges. Ce genre de chose est normalement caché du développeur par de bons compilateurs et une utilisation judicieuse des types, mais si vous voulez percer le voile et essayer de déjouer le système d'exploitation et les développeurs de compilateur, eh bien, vous le pouvez, mais il n'y a pas de moyen générique pour le faire, il gérera tous les problèmes que vous pourriez rencontrer.

La meilleure chose à faire est de permettre le crash et de fournir de bonnes informations de diagnostic.

1
John Grieggs

En effet, quelque chose pourrait être fait dans certaines circonstances: par exemple, si vous voulez vérifier si une chaîne de pointeur de chaîne est valide, utiliser write (fd, buf, szie), syscall peut vous aider à faire la magie: fd sera un descripteur de fichier temporaire fichier que vous créez pour test, et buf pointant sur la chaîne que vous testez, si le pointeur est invalide, write () renverrait -1 et errno aura la valeur EFAULT, ce qui indique que buf se trouve en dehors de votre espace adresse accessible.

1
Wenlin.Wu

En général, c'est impossible à faire. Voici un cas particulièrement méchant:

struct Point2d {
    int x;
    int y;
};

struct Point3d {
    int x;
    int y;
    int z;
};

void dump(Point3 *p)
{
    printf("[%d %d %d]\n", p->x, p->y, p->z);
}

Point2d points[2] = { {0, 1}, {2, 3} };
Point3d *p3 = reinterpret_cast<Point3d *>(&points[0]);
dump(p3);

Sur de nombreuses plates-formes, cela affichera:

[0 1 2]

Vous forcez le système d'exécution à interpréter de manière incorrecte des bits de mémoire, mais dans ce cas, cela ne va pas planter car ils ont tous un sens. Cela fait partie de la conception du langage (observez le polymorphisme de style C avec struct inaddr, inaddr_in, inaddr_in6), de sorte que vous ne pouvez pas vous protéger de manière fiable contre cette plate-forme.

1
Tom

C'est incroyable la quantité d'informations trompeuses que vous pouvez lire dans les articles ci-dessus ...

Et même dans la documentation Microsoft msdn, IsBadPtr est censé être banni. Oh bien - je préfère travailler avec les applications que de planter. Même si le travail à terme est susceptible de ne pas fonctionner correctement (à condition que l'utilisateur final puisse continuer avec l'application).

En googlant, je n'ai trouvé aucun exemple utile pour Windows - j'ai trouvé une solution pour les applications 32 bits, 

http://www.codeproject.com/script/Content/ViewAssociatedFile.aspx?rzp=%2FKB%2Fsystem%2Fdetect-driver%2F%2fdsid&langue=fr = 2 & ovid = 2

mais je dois également prendre en charge les applications 64 bits, cette solution ne fonctionnant donc pas pour moi.

Mais j'ai récolté les codes sources de Wine et j'ai réussi à créer un code similaire, qui fonctionnerait également pour les applications 64 bits. Pour ce faire, associez le code ici:

#include <typeinfo.h>   

typedef void (*v_table_ptr)();   

typedef struct _cpp_object   
{   
    v_table_ptr*    vtable;   
} cpp_object;   



#ifndef _WIN64
typedef struct _rtti_object_locator
{
    unsigned int signature;
    int base_class_offset;
    unsigned int flags;
    const type_info *type_descriptor;
    //const rtti_object_hierarchy *type_hierarchy;
} rtti_object_locator;
#else

typedef struct
{
    unsigned int signature;
    int base_class_offset;
    unsigned int flags;
    unsigned int type_descriptor;
    unsigned int type_hierarchy;
    unsigned int object_locator;
} rtti_object_locator;  

#endif

/* Get type info from an object (internal) */  
static const rtti_object_locator* RTTI_GetObjectLocator(void* inptr)  
{   
    cpp_object* cppobj = (cpp_object*) inptr;  
    const rtti_object_locator* obj_locator = 0;   

    if (!IsBadReadPtr(cppobj, sizeof(void*)) &&   
        !IsBadReadPtr(cppobj->vtable - 1, sizeof(void*)) &&   
        !IsBadReadPtr((void*)cppobj->vtable[-1], sizeof(rtti_object_locator)))  
    {  
        obj_locator = (rtti_object_locator*) cppobj->vtable[-1];  
    }  

    return obj_locator;  
}  

Et le code suivant peut détecter si le pointeur est valide ou non, vous aurez probablement besoin d’ajouter une vérification NULL:

    CTest* t = new CTest();
    //t = (CTest*) 0;
    //t = (CTest*) 0x12345678;

    const rtti_object_locator* ptr = RTTI_GetObjectLocator(t);  

#ifdef _WIN64
    char *base = ptr->signature == 0 ? (char*)RtlPcToFileHeader((void*)ptr, (void**)&base) : (char*)ptr - ptr->object_locator;
    const type_info *td = (const type_info*)(base + ptr->type_descriptor);
#else
    const type_info *td = ptr->type_descriptor;
#endif
    const char* n =td->name();

Cela donne le nom de classe du pointeur - je pense que cela devrait suffire à vos besoins.

Une chose qui me fait peur, c’est encore la performance de la vérification du pointeur - le code ci-dessus fait déjà 3-4 appels d’API en cours - peut-être excessif pour les applications urgentes.

Ce serait bien si quelqu'un pouvait mesurer le temps système nécessaire à la vérification du pointeur par rapport aux appels C++/c ++ gérés.

1
TarmoPikaro

Il n'y a aucun moyen de faire cette vérification en C++. Que devez-vous faire si un autre code vous transmet un pointeur non valide? Tu devrais te planter. Pourquoi? Consultez ce lien: http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx

0
zildjohn01

ces liens peuvent être utiles 

_CrtIsValidPointer Vérifie qu'une plage de mémoire spécifiée est valide pour la lecture et l'écriture (version de débogage uniquement) . http://msdn.Microsoft.com/en-us/library/0w1ekd5e.aspx

_CrtCheckMemory Confirme l'intégrité des blocs de mémoire alloués dans la pile de débogage (version de débogage uniquement) . http://msdn.Microsoft.com/en-us/library/e73x0s4b.aspx

0
Khachatur

La suite fonctionne dans Windows (quelqu'un l'a suggéré auparavant):

copie statique statique (void * cible, const void * source, taille int) { __essayer { CopyMemory (cible, source, taille); } __except (EXCEPTION_EXECUTE_HANDLER) { doQuelque chose (- peu importe -); } }

La fonction doit être une méthode statique, autonome ou statique d'une classe . Pour tester en lecture seule, copiez les données dans le tampon local . Pour tester en écriture sans modifier le contenu, écrivez-les sur . Vous pouvez uniquement tester les premières/dernières adresses . Si le pointeur n'est pas valide, le contrôle sera transmis à 'quelque chose',

0
user2089173

Addendum à la (aux) réponse (s) acceptée (s):

Supposons que votre pointeur ne puisse contenir que trois valeurs - 0, 1 et -1, où 1 correspond à un pointeur valide, -1 à un autre et à un autre non valide. Quelle est la probabilité que votre pointeur soit NULL, toutes les valeurs étant également probables? 1/3. Maintenant, enlevez le cas valide, donc pour chaque cas invalide, vous avez un ratio 50:50 pour intercepter toutes les erreurs. Ça a l'air bien non? Échelle ceci pour un pointeur de 4 octets. Il y a 2 ^ 32 ou 4294967294 valeurs possibles. Parmi celles-ci, UNE seule valeur est correcte, une valeur est NULL et il vous reste 4294967292 autres cas non valides. Recalculer: vous avez un test pour 1 cas non valides (4294967292+ 1). Une probabilité de 2.xe-10 ou 0 dans la plupart des cas pratiques. Telle est la futilité du chèque NULL.

0
dirkgently

Sous Windows, j'utilise ce code:

void * G_pPointer = NULL;
const char * G_szPointerName = NULL;
void CheckPointerIternal()
{
    char cTest = *((char *)G_pPointer);
}
bool CheckPointerIternalExt()
{
    bool bRet = false;

    __try
    {
        CheckPointerIternal();
        bRet = true;
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
    }

    return  bRet;
}
void CheckPointer(void * A_pPointer, const char * A_szPointerName)
{
    G_pPointer = A_pPointer;
    G_szPointerName = A_szPointerName;
    if (!CheckPointerIternalExt())
        throw std::runtime_error("Invalid pointer " + std::string(G_szPointerName) + "!");
}

Usage:

unsigned long * pTest = (unsigned long *) 0x12345;
CheckPointer(pTest, "pTest"); //throws exception
0
Artkov

IsBadReadPtr (), IsBadWritePtr (), IsBadCodePtr (), IsBadStringPtr () pour Windows.
Celles-ci prennent du temps proportionnellement à la longueur du bloc, donc pour vérifier son intégrité, je vérifie simplement l'adresse de départ.

0
pngaz

Vous savez, un nouveau pilote (du moins sous Linux) capable de le faire ne serait probablement pas si difficile à écrire.

Par contre, ce serait une folie de construire de tels programmes. À moins que vous n'ayez un usage vraiment spécifique et unique pour une telle chose, je ne le recommanderais pas. Si vous construisez une application volumineuse chargée avec des contrôles de validité de pointeur constants, elle sera probablement terriblement lente.

0
dicroce

J'ai vu diverses bibliothèques utiliser une méthode pour vérifier la mémoire non référencée et autres. Je crois qu’elles "ignorent" simplement les méthodes d’allocation de mémoire et de désallocation (malloc/free), qui ont une logique qui garde une trace des pointeurs. Je suppose que cela est excessif pour votre cas d'utilisation, mais ce serait une façon de le faire.

0
sebnow

Techniquement, vous pouvez remplacer l'opérateur new (et delete ) et collecter des informations sur toute la mémoire allouée. Vous pouvez ainsi disposer d'une méthode pour vérifier si la mémoire de segment de mémoire est valide.

  1. vous avez toujours besoin d'un moyen de vérifier si le pointeur est alloué sur stack ()

  2. vous devrez définir le pointeur 'valide':

a) la mémoire sur cette adresse est alloué 

b) mémoire à cette adresse est start adresse de l'objet (par exemple, l'adresse n'est pas au milieu d'un énorme tableau )

c) mémoire à cette adresse est début adresse de l'objet de attendu type

En fin de compte : L’approche en question n’est pas une méthode C++, vous devez définir des règles garantissant que la fonction reçoit des pointeurs valides.

0
noonex

vous devriez éviter ces méthodes car elles ne fonctionnent pas. blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx - JaredPar 15 févr. 09 à 16:02

S'ils ne fonctionnent pas - la prochaine mise à jour de Windows résoudra le problème? S'ils ne fonctionnent pas au niveau du concept - la fonction sera probablement supprimée complètement de Windows api. 

La documentation MSDN affirme qu'ils sont interdits, ce qui est probablement dû à un défaut de conception ultérieure de l'application (par exemple, vous ne devriez généralement pas manger d'indicateurs non valides en silence - si vous êtes en charge de la conception de l'application complète bien sûr) et des performances/temps de vérification de pointeur.

Mais vous ne devriez pas prétendre qu'ils ne fonctionnent pas à cause de certains blogs ..__ Dans mon application de test, j'ai vérifié qu'ils fonctionnaient bien.

0
TarmoPikaro