Comment faire pour traquer les “violation d'accès à l'adresse 00000000”
Je sais comment créer un .fichier de mappage pour traquer violation d'accès des erreurs lorsque le message d'erreur contient une adresse réelle.
Mais que faire si le message d'erreur dit
Access violation at address 00000000. Read of address 00000000.
Où dois-je commencer à chercher la cause de ce problème... ?
- Cela me rappelle de sous Turbo C, "pointeur Null affectation" quand il est géré dans le mauvais sens...
- Est-il reproduit? Si non, ajouter un outil comme madExcept et d'attente pour les rapports d'erreurs d'utiliser le débogueur et de regarder la trace de la pile.
- C'est à partir de l'ancien Turbo C jours, Sous le débogueur,Ajoutez une montre pour le pointeur de variable pointant vers la position 0, le juste exécuté la ligne en faisant un pas en elle, qui a causé la variable du pointeur pointant vers la position 0 de changement de valeur est la ligne qui a foiré. Surtout un pointeur d'erreur...
- Tommie, il pourrait y avoir de nombreuses variables de pointeur en tenant l'adresse de la valeur zéro. Pourquoi créer une montre sur l'un d'eux? Le changement de l'un d'entre eux ne serait pas l'origine de cette erreur. Cette erreur se produit lorsque le pointeur d'instruction est nulle, mais vous ne pouvez pas définir de regarder sur ce que ça change pour chaque instruction. Débogueur vous dit le précédent exécuté la ligne? Que débogueur se rendre trivial à résoudre ce problème.
- La réponse que vous avez accepté, n'est-ce pas vous dire beaucoup, de l'OMI.
Vous devez vous connecter pour publier un commentaire.
Une violation d'accès à n'importe où près de l'adresse '00000000' indique un pointeur null accès. Vous êtes à l'aide de quelque chose avant qu'il ne l'a jamais été créé, le plus probable, ou après avoir été FreeAndNil()'d.
Un grand nombre de fois, cela est causé par l'accès à un composant dans le mauvais endroit lors de la création de forme, ou de votre formulaire principal pour essayer d'accéder à quelque chose dans un datamodule qui n'a pas encore été créé.
MadExcept est donc assez facile de suivre ces choses, et il est gratuit pour une utilisation non commerciale. (En fait, une licence d'utilisation commerciale est assez bon marché, et vaut bien l'argent.)
Accepté la réponse ne raconte pas toute l'histoire.
Oui, chaque fois que vous voyez des zéros, un
NULL
pointeur est impliqué. C'est parce queNULL
est par définition zéro. Afin de l'appelant zéroNULL
peut-être pas dire grand chose.Ce est intéressant sur le message que vous obtenez est le fait que
NULL
est mentionné deux fois. En fait, le message que vous rapport semble un peu comme les messages Windows-marque de systèmes d'exploitation montrer à l'utilisateur.Le message dit que le adresse
NULL
essayé de lireNULL
. Donc, ça veut dire quoi? Plus précisément, comment un discours lu en lui-même?Nous pensons que généralement des instructions à une adresse de lecture et d'écriture de la mémoire à certaines adresses. Sachant que nous permet d'analyser le message d'erreur. Le message est d'essayer d'articuler l' instruction à adresse
NULL
essayé de lireNULL
.Bien sûr, il n'y a pas d'instruction à l'adresse
NULL
, c'est pourquoi nous pensons deNULL
spécial dans notre code. Mais chaque instruction peut être considéré comme commençant avec la tentative de lecture lui-même. Si les ProcesseursEIP
registre à l'adresseNULL
, puis le PROCESSEUR tente de lire l' opcode pour une instruction à partir de l'adresse 0x00000000 (NULL
). Cette tentative de lireNULL
va échouer, et de générer le message que vous avez reçu.Dans le débogueur, vous remarquerez que
EIP
est égal à 0 x 00000000 lorsque vous recevez ce message. Cela confirme la description que je vous ai donné.La question devient alors: "pourquoi mon programme tente d'exécuter le
NULL
adresse." Il y a trois possibilités qui viennent à l'esprit:NULL
, jamais initialisé le contraire, et sont déréférencement.NULL
entrée dans l'objet de la vtable. Ceux-ci sont créés dans votre code avec la syntaxevirtual function_name()=0
.ret
instruction, la valeur 0 x 00000000 (NULL
) est chargé à partir de l'écrasement de la mémoire spot. Ce type d'erreur, de débordement de pile, est l'éponyme de notre forum.Puisque vous parlez de ce que vous appelez une bibliothèque tierce, je ferai remarquer qu'il peut y avoir une situation de la bibliothèque vous attend pour fournir un non-
NULL
pointeur de fonction d'entrée à certaines API. Ceux-ci sont parfois connus comme "call back" des fonctions.Vous devrez utiliser le débogueur de réduire la cause de votre problème de plus, mais les possibilités énoncées devrait vous aider à résoudre l'énigme.
Vous lancer à la recherche à proximité de ce code que vous savoir couru, et vous vous arrêtez à la recherche lorsque vous atteignez le code que vous savoir ne fonctionne pas.
Ce que vous cherchez est probablement un endroit où votre programme appelle une fonction par le biais d'un pointeur de fonction, mais que le pointeur est null.
Il est également possible que vous ayez une corruption de la pile. Vous pourriez avoir écrasé une fonction de l'adresse de retour à zéro, et que l'exception se produit à la fin de la fonction. Vérifier les éventuels dépassements de la mémoire tampon, et si vous appelez les fonctions de la DLL, assurez-vous que vous avez utilisé la bonne convention d'appel et le nombre de paramètre.
Ce n'est pas un cas ordinaire de l'utilisation d'un pointeur null, comme un non affectés de l'objet de référence ou PChar. Dans ces cas, vous aurez un non-zéro "à l'adresse x" de la valeur. Puisque l'instruction produite à l'adresse zéro, vous savez que le CPU du pointeur d'instruction n'était pas au pointage de toutes les valide instruction. C'est pourquoi le débogueur ne peut pas vous montrer la ligne de code qui a causé le problème — là est aucune ligne de code. Vous devez le trouver par trouver le code qui mènent jusqu'à l'endroit où le PROCESSEUR a sauté à l'adresse non valide.
La pile d'appel peut-être encore intact, qui devrait au moins vous obtenez assez près de votre but. Si vous avez une corruption de la pile, cependant, vous pourriez ne pas être en mesure de faire confiance à la pile d'appel.
Si vous obtenez 'violation d'Accès à l'adresse 00000000.', vous appelez un pointeur de fonction qui n'a pas été attribué - peut-être un gestionnaire d'événement ou d'une fonction de rappel.
par exemple
Au lieu de
Si l'erreur est dans un troisième composant de partie, et vous pouvez suivre le code fautif en bas, utilisez un gestionnaire d'événements vide pour empêcher l'AV.
Quand je suis tombé sur ce problème j'ai l'habitude de commencer à regarder les endroits où je FreeAndNil() ou tout simplement xxx := NIL; les variables et le code par la suite.
Quand rien d'autre ne l'a aidé, j'ai ajouté une fonction Log() pour la sortie des messages provenant de divers endroits soupçonnés lors de l'exécution, et puis plus tard regardé le journal de trace où dans le code de la violation d'accès vient.
Il y a bien sûr beaucoup plus élégant des solutions disponibles pour le suivi de ces violations, mais si vous n'avez pas à votre disposition à l'ancienne, essai & erreur de méthode fonctionne très bien.
C'est probablement parce que vous êtes directement ou indirectement par l'intermédiaire d'un appel de la bibliothèque de l'accès à un pointeur NULL. Dans ce cas particulier, il semble que vous avez sauté à une adresse NULLE, ce qui est un bit b poilus.
Dans mon expérience, la meilleure façon de suivre ces bas sont à exécuter avec un débogueur, et dump une trace de la pile.
Alternativement, vous pouvez le faire "à la main" et d'ajouter beaucoup de l'exploitation forestière jusqu'à ce que vous pouvez suivre exactement quelle fonction (et éventuellement de LOC) cette violation s'est produite.
Prendre un coup d'oeil à Pile Traceur, qui peut vous aider à améliorer votre débogage.
Utilisation MadExcept. Ou JclDebug.
Je vais deuxième madExcept et outils similaires, à l'instar de Eurekalog, mais je pense que vous pouvez trouver une bonne façon avec FastMM aussi. Avec plein de debugmode activé, il devrait vous donner quelques indices de ce qui est mal.
De toute façon, même si Delphi utilise FastMM en tant que par défaut, il vaut la peine d'obtenir la pleine FastMM pour un contrôle supplémentaire sur la journalisation.
Voici un rapide correctif temporaire, au moins jusqu'à ce que vous redémarrez à nouveau, mais il va se débarrasser d'un persistantes d'accès. J'avais installé un programme qui fonctionne bien, mais pour une raison quelconque, il y a un point qui n'a pas installé correctement dans le bon fichier. Alors, quand il ne peut pas accéder au fichier, il apparaît le refus d'accès mais au lieu d'un seul, il continue d'essayer de la démarrer de sorte que même la recherche de l'emplacement de l'arrêter définitivement, il continuera à apparaître de plus en plus et de plus toutes les 3 secondes. Pour empêcher ça, au moins temporairement, procédez de la manière suivante...
Qui va empêcher la fenêtre de la persistance d'apparaître, au moins jusqu'à ce que vous redémarrez. Je sais que ça ne résout pas le problème, mais comme pour tout, il y a un processus d'élimination et cette étape sera de faire au moins un peu moins ennuyeux.