web-dev-qa-db-fra.com

Débogage des erreurs de violation d'accès?

Quels conseils pouvez-vous partager pour localiser et réparer les violations d'accès lors de l'écriture d'applications dans Delphi?

Je pense que les violations d'accès sont généralement causées par une tentative d'accès à quelque chose en mémoire qui n'a pas encore été créé, tel qu'un objet, etc.?

J'ai du mal à identifier ce qui déclenche les violations d'accès, puis à effectuer les modifications nécessaires pour essayer de les arrêter/corriger.

Un exemple est un projet personnel sur lequel je travaille actuellement. Je stocke dans la propriété TTreeView Node.Data des données pour chaque nœud. Les nœuds peuvent être sélectionnés et exportés plusieurs fois (l'exportation s'exécute via chaque nœud sélectionné et enregistre des données spécifiques dans un fichier texte - les informations enregistrées dans le fichier texte sont celles stockées dans le fichier nodes.data). Les fichiers peuvent également être importés dans l'arborescence (enregistrement du contenu des fichiers texte dans le fichier node.data).

Le problème dans cet exemple est que si j'importe des fichiers dans Treeview puis que je les exporte, cela fonctionne parfaitement. Cependant, si j'ajoute un nœud au moment de l'exécution et que je les exporte, je reçois:

"Violation d'accès à l'adresse 00405772 dans le module 'Project1.exe'. Lecture de l'adresse 00000388."

Ma pensée à ce sujet doit être la façon dont je donne les données aux nœuds créés, peut-être différemment de la façon dont je les attribue lors de leur importation, mais tout me convient. La violation d'accès s'affiche uniquement lors de l'exportation, ce qui ne se produit jamais avec les fichiers importés.

Je ne cherche PAS une solution à l'exemple ci-dessus, mais principalement des conseils et astuces sur la manière de rechercher et de corriger ce type d'erreur. Je ne reçois pas souvent de violations d'accès, mais quand je le fais, elles sont vraiment difficiles à repérer et à corriger.

Donc, des conseils et des astuces seraient très utiles.

20
user741875

Cela signifie que votre code accède à une partie de la mémoire à laquelle il n'est pas autorisé. Cela signifie généralement que vous avez un pointeur ou une référence d'objet pointant vers la mauvaise mémoire. Peut-être parce qu'il n'est pas initialisé ou est déjà publié.

Utilisez un débogueur, comme Delphi. Il vous indiquera sur quelle ligne de code le AV s'est produit. À partir de là, identifiez votre problème en examinant le nombre d'appels, les variables locales, etc. Cela peut également s'avérer utile si vous compilez avec les DCU Debug.

Si vous ne possédez pas de débogueur parce que cela ne se produit que du côté client, vous pouvez utiliser MadExcept ou JclDebug pour enregistrer l'exception avec callstack et vous l'envoyer. Il vous donne moins de détails mais pourrait vous orienter dans la bonne direction.

Certains outils pourraient permettre de résoudre ce type de problèmes plus tôt en vérifiant de manière plus agressive. Le gestionnaire de mémoire FastMM dispose de telles options.

MODIFIER

"Violation d'accès à l'adresse 00405772 Dans le module 'Project1.exe'. Lecture de l'adresse 00000388."

Votre problème résulte donc en un AV aux adresses 00405772 dans le module 'Project1.exe'. Le débogueur Delphi vous amènera à la bonne ligne de code (ou utilisera l'erreur de recherche).

Il essaie de lire la mémoire à l'adresse 00000388. C'est assez proche de 00000000 (nil), donc cela voudrait probablement dire qu'il faut accéder à un pointeur/une référence à un tableau ou à un tableau dynamique qui est nil. S'il s'agissait d'un tableau d'octets, il s'agirait de l'élément 388. Il pourrait également s'agir d'un champ d'objet assez volumineux ou d'un enregistrement comportant de nombreux champs. Le pointeur/référence de l'objet ou de l'enregistrement serait nil.

22
Lars Truijens

Je constate que les violations d'accès vraiment difficiles à trouver ne se produisent pas toujours lorsque j'exécute dans un débogueur. Pire encore, ils arrivent aux clients et non à moi. La réponse acceptée mentionne cela, mais je pense vraiment qu'il faut lui donner plus de détails: MadExcept fournit une trace de pile qui me fournit des informations de contexte précieuses et m'aide à voir où le code échoue ou a des exceptions non gérées (ce n'est pas uniquement pour les violations d'accès). Il offre même aux clients un moyen de vous envoyer les rapports de bogues par courrier électronique directement à l'intérieur de votre programme. Cela conduit à plus de violations d'accès trouvées et corrigées, rapportées par vos bêta-testeurs ou vos utilisateurs.

Deuxièmement, j'ai remarqué que les astuces et les avertissements du compilateur détectent certains des problèmes les plus courants. Nettoyez les astuces et les avertissements et vous rencontrerez peut-être de nombreuses violations d'accès et autres problèmes subtils. Oublier de déclarer correctement vos destructeurs, par exemple, peut conduire à un avertissement du compilateur, mais à de sérieux problèmes lors de l'exécution.

Troisièmement, j'ai trouvé des outils tels que Pascal Analyzer de Peganza et la fonctionnalité audits et métriques de certaines éditions de Delphi peut vous aider à identifier les zones de votre code qui présentent des problèmes. En guise d'exemple concret, Pascal Analyzer a trouvé des endroits où j'oubliais de faire quelque chose d'important, qui conduisait à un blocage ou à une violation d'accès.

Quatrièmement, vous pouvez difficilement battre la technique consistant à demander à un autre développeur de critiquer votre code. Vous vous sentirez peut-être un peu penaud par la suite, mais vous allez apprendre quelque chose, espérons-le, et vous améliorer dans ce que vous faites. Il y a de fortes chances qu'il existe plus d'un moyen d'utiliser une vue arborescente, et plus d'un moyen de faire le travail que vous faites, et une meilleure architecture, et une manière propre de faire les choses se traduiront par un code plus fiable ne casse pas chaque fois que vous le touchez. Il n’existe pas une liste finie de règles permettant de produire du code propre, c’est plutôt un effort à vie et une question de degrés. Vous seriez surpris de voir à quel point un code d'aspect innocent peut être un foyer d'accidents potentiels, de violations d'accès, de conditions de concurrence, de gels et de blocages. 

18
Warren P

J'aimerais mentionner un autre outil que j'utilise lorsque d'autres outils ne parviennent pas à détecter les logiciels antivirus. C'est SafeMM ( version plus récente ). Une fois, cela m'a indiqué la procédure des 5 lignes. Et je devais regarder plus de 10 minutes, afin de voir le AV qui s'est passé là-bas. Probablement ce jour-là, mes compétences en programmation n'étaient pas à leur maximum, mais vous savez, les mauvaises choses ont tendance à se produire exactement ces jours-là.

3
Torbins

Je veux juste mentionner d'autres techniques de débogage ou de "garde du code" qui n'étaient pas mentionnées dans les réponses précédentes:

Outils "locaux":
* Utilisez FastMM dans DebugMode - demandez-lui d'écrire des zéros chaque fois qu'il distribue de la mémoire. Cela ralentira PAINFULLY votre programme, mais vous avez une énorme chance de trouver des erreurs comme essayer d'accéder à un objet libéré.
* Utilisez FreeAndNil (Obj) au lieu de Obj.Free. Certains se plaignaient que cela créait des problèmes mais sans donner un exemple clair où cela pourrait se produire. De plus, Emarcadero a récemment ajouté la recommandation d’utiliser FreeAndNil dans son manuel (enfin!).
* TOUJOURS compiler l'application en mode Release et Debug. Assurez-vous que les options du projet sont correctement définies pour le mode débogage. Les paramètres DEFAULT pour le mode de débogage ne sont PAS corrects/complets - enfin pas dans Delphi XE7 et Tokyo. Peut-être qu'un jour ils définiront les options correctes pour le mode débogage. Donc, activez les choses comme

  • " Cadres de pile
  • "Génération de fichier de carte (détaillée)" 
  • "Vérification de la plage", 
  • "Informations de référence de symbole"
  • "Informations de débogage" 
  • "Vérification de débordement"
  • "Assertions" 
  • "Debug DCUs" 
  • Désactivez les "optimisations du compilateur"!

Outils tiers: 

  • Utilisez MadShi ou EurekaLog (je recommanderais MadShi à EurekaLog) 
  • Utiliser le ApplicationVerfier de Microsoft 
1
Rigel