Question

Nous avons une application C ++ native exécutée via COM + sur un serveur Windows 2003. J'ai récemment remarqué dans l'observateur d'événements que ses exceptions de lancement, en particulier l'exception C0000005, qui, selon http://blogs.msdn.com/calvin_hsia/archive/2004/06/30/170344.aspx signifie que le processus tente d'écrire en mémoire en dehors de son adresse. espace, alias violation d'accès.

L'entrée dans l'observateur d'événements fournit une pile d'appels:

  

LibFmwk! UTIL_GetDateFromLogByDayDirectory (char const *, classe utilCDate & amp;) + 0xa26c   LibFmwk! UTIL_GetDateFromLogByDayDirectory (char const *, classe utilCDate & amp;) + 0x8af4   LibFmwk! UTIL_GetDateFromLogByDayDirectory (char const *, classe utilCDate & amp;) + 0x13a1   LibFmwk! UtilCLogController :: GetFLFInfoLevel (void) const + 0x1070   LibFmwk! UtilCLogController :: GetFLFInfoLevel (void) const + 0x186

Maintenant, je comprends que cela me donne des noms de méthode à regarder, mais j’ai le sentiment que l’adresse à la fin de chaque ligne (par exemple + 0xa26c) essaie de me diriger vers une ligne ou une instruction spécifique dans cette méthode. .

Mes questions sont donc les suivantes:

  1. Est-ce que quelqu'un sait comment utiliser cette adresse ou toute autre information dans une pile d'appels pour déterminer quelle ligne du code tombe?
  2. Existe-t-il des ressources que je pourrais lire pour mieux comprendre les piles d'appels,
  3. Existe-t-il des outils gratuits / opensource pouvant aider à analyser une pile d'appels, par exemple en les associant à un fichier de symbole de débogage et / ou à des fichiers binaires?

Modifier: Comme demandé, voici la méthode qui semble être à l'origine du problème:

BOOL UTIL_GetDateFromLogByDayDirectory(LPCSTR pszDir, utilCDate& oDate)
{
BOOL bRet = FALSE;

if ((pszDir[0] == '%') &&
    ::isdigit(pszDir[1]) && ::isdigit(pszDir[2]) &&
    ::isdigit(pszDir[3]) && ::isdigit(pszDir[4]) &&
    ::isdigit(pszDir[5]) && ::isdigit(pszDir[6]) &&
    ::isdigit(pszDir[7]) && ::isdigit(pszDir[8]) &&
    !pszDir[9])
{
    char acCopy[9];
    ::memcpy(acCopy, pszDir + 1, 8);
    acCopy[8] = '\0';

    int iDay = ::atoi(&acCopy[6]);
    acCopy[6] = '\0';
    int iMonth = ::atoi(&acCopy[4]);
    acCopy[4] = '\0';
    int iYear = ::atoi(&acCopy[0]);

    oDate.Set(iDay, iMonth, iYear);

    bRet = TRUE;
}

return (bRet);

}

Ce code a été écrit il y a plus de 10 ans par un membre de notre société parti depuis longtemps. Je ne prétends donc pas savoir exactement ce que cela fait, mais je sais qu'il est impliqué dans le processus de changement de nom d'un répertoire de journaux. de 'Aujourd'hui' à la date précise, par exemple % 20090329. L’indexation du tableau, la mémoire et l’adresse des opérateurs le rendent plutôt suspect.

Un autre problème semble être que cela ne se produit que sur le système de production. Nous n'avons jamais été en mesure de le reproduire ici sur nos systèmes de test ou de développement, ce qui nous permettrait d'attacher un débogueur.

Très apprécié! Andy

Était-ce utile?

La solution

si vous avez vraiment besoin de mapper ces adresses sur vos fonctions, vous devez travailler avec le fichier .MAP et voir où ces adresses pointent vraiment.

Mais étant dans votre situation, je préférerais étudier ce problème sous le débogueur (par exemple, le débogueur MSVS ou windbg); Comme alternative (si un crash survient sur le site du client), vous pouvez générer un vidage sur incident et l’étudier localement - vous pouvez le faire via l’API Windows MiniDumpWriteDump ou l’utilitaire SysInternals ProcDump ( http://download.sysinternals.com/Files/procdump.zip ).

Assurez-vous que tous les fichiers de symboles requis sont générés et disponibles (configurez également le chemin du serveur de symboles Microsoft afin que les points d'entrée des DLL Windows soient également résolus).

IMHO c'est juste le site Web dont vous avez besoin: http://www.dumpanalysis.org - qui est la meilleure ressource pour couvrir toutes vos questions. Pensez également à consulter ce fichier PDF - http://windbg.info/download/doc /pdf/WinDbg_A_to_Z_color.pdf

Autres conseils

D'autres l'ont dit entre les lignes, mais pas explicitement. regardez:

LibFmwk!UTIL_GetDateFromLogByDayDirectory(char const *,class utilCDate &) + 0xa26c

Le décalage 0xa26c est énorme , bien au-delà de la fin de la fonction. le débogueur n'a évidemment pas les symboles appropriés pour LibFmwk, il se base donc sur les exportations de DLL et affiche le décalage par rapport à celui le plus proche qu'il peut trouver.

Alors, oui, procurez-vous les symboles appropriés et ça devrait être un jeu d'enfant. UTIL_GetDateFromLogByDayDirectory n'est pas en cause ici.

Il est facile de répondre aux points 2 et 3:

3ème point. Tout débogueur. C'est pour ça qu'ils sont faits. Configurez votre débogueur pour qu'il interrompt cette exception spéciale. Vous devriez pouvoir cliquer vous-même sur la pile d'appels et trouver les différents appels de la pile (au moins delphi peut le faire, ainsi Visual Studio devrait également pouvoir le faire). Compiler sans optimisations si possible. OllyDBG pourrait également fonctionner, peut-être en combinaison avec sa fonctionnalité de trace.

2ème point. Toute information sur l'assembleur x86, la Reverseengineering ... Essayez: OpenRCE , Documentation NASM , Communauté ASM .

1er point. Le callstack vous indique les fonctions. Je ne sais pas si elle est écrite dans l'ordre ou dans l'ordre inverse. La première ligne est donc peut-être la dernière fonction appelée ou la première fonction appelée. Suivez les appels à l'aide du débogueur. Parfois, vous pouvez changer entre asm et code (en fonction du débogueur, des fichiers de cartes, etc.). Si vous n'avez pas la source - apprendre l'assembleur, lisez à propos du reverse engineering. Lisez la documentation des fonctions que vous appelez dans des composants tiers. Peut-être que vous ne remplissez pas une condition préalable.

Si vous pouvez en dire un peu plus sur le programme (quelles parties du code source avez-vous, un appel à la bibliothèque est-il impliqué?, ...)

Maintenant, lecture de code:

La fonction accepte un pointeur sur une chaîne terminée par zéro et une référence à un objet de date. Le pointeur est supposé être valide!

La fonction vérifie si la chaîne est dans un format spécifique (% suivi de 8 chiffres suivi d'un \ 0). Si ce n'est pas le cas, il retourne faux. Ce contrôle (le gros si) accède au pointeur sans vérification de validité. La longueur n'est pas vérifiée et si le pointeur pointe quelque part dans la nature, on accède à cet espace. Je ne sais pas si une chaîne plus courte causera des problèmes. Cela ne devrait pas à cause de la manière & amp; & amp; est évalué.

Ensuite, de la mémoire est allouée sur la pile. La partie numérique de la chaîne est copiée dans celle-ci (ce qui est ok) et le tampon obtient sa fin \ 0. Les atois extraient les chiffres. Cela fonctionnera à cause des différents emplacements de départ utilisés et de la terminaison \ 0 après chaque partie. En quelque sorte difficile mais sympa. Certains commentaires auraient tout clarifié.

Ces nombres sont ensuite insérés dans l'objet. Il devrait être valide puisqu'il est passé à la fonction par référence. Je ne sais pas si vous pouvez transmettre une référence à un objet supprimé, mais si tel est le cas, cela pourrait également être votre problème.

Quoi qu'il en soit - à l'exception de la vérification manquante pour le pointeur de chaîne, cette fonction est saine et non la cause de votre problème. C'est seulement l'endroit qui jette l'exception. Recherchez les arguments passés dans cette fonction. Sont-ils toujours valables? Faites un peu de journalisation.

J'espère n'avoir commis aucune erreur majeure en tant que programmeur pour Delphi. Si je le faisais, n'hésitez pas à commenter.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top