Domanda

Abbiamo un'applicazione C ++ nativa in esecuzione tramite COM + su un server Windows 2003. Di recente ho notato dal visualizzatore di eventi che le sue eccezioni generano, in particolare l'eccezione C0000005, che, secondo http://blogs.msdn.com/calvin_hsia/archive/2004/06/30/170344.aspx indica che il processo sta tentando di scrivere in memoria non all'interno del suo indirizzo spazio, noto anche come violazione dell'accesso.

La voce nel Visualizzatore eventi fornisce uno stack di chiamate:

  

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

Ora capisco che mi sta dando i nomi dei metodi da esaminare ma ho la sensazione che l'indirizzo alla fine di ogni riga (ad es. + 0xa26c) stia cercando di indicarmi una riga o un'istruzione specifica all'interno di quel metodo .

Quindi le mie domande sono:

  1. Qualcuno sa come potrei usare questo indirizzo o qualsiasi altra informazione in uno stack di chiamate per determinare su quale linea all'interno del codice sta cadendo?
  2. Ci sono risorse là fuori che potrei leggere per capire meglio gli stack di chiamate,
  3. Esistono strumenti freeware / opensource che potrebbero aiutare ad analizzare uno stack di chiamate, magari collegandosi a un file di simboli di debug e / o binari?

Modifica: Come richiesto, ecco il metodo che sembra causare il problema:

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);

}

Questo è il codice scritto più di 10 anni fa da un membro della nostra azienda che è scomparso da tempo, quindi non presumo di sapere esattamente cosa sta facendo ma so che è coinvolto nel processo di ridenominazione di una directory dei log da "Oggi" alla data specifica, ad es % 20.090.329. L'indicizzazione dell'array, il memcpy e l'indirizzo degli operatori lo rendono piuttosto sospetto.

Un altro problema che sembra avere è che ciò accade solo sul sistema di produzione, non siamo mai stati in grado di riprodurlo sui nostri sistemi di test o sistemi di sviluppo qui, il che ci permetterebbe di collegare un debugger.

Molto apprezzato! Andy

È stato utile?

Soluzione

se hai davvero bisogno di mappare quegli indirizzi alle tue funzioni, dovrai lavorare con il file .MAP e vedere dove puntano realmente quegli indirizzi.

Ma trovandomi nella tua situazione, preferirei indagare su questo problema con il debugger (ad es. debugger MSVS o windbg); in alternativa (se si verifica un arresto anomalo nel sito del cliente) è possibile generare un crash dump e studiarlo localmente; può essere eseguito tramite l'API MiniDumpWriteDump di Windows o l'utility ProcDump di SysInternals ( http://download.sysinternals.com/Files/procdump.zip ).

Assicurati che tutti i file dei simboli richiesti siano generati e disponibili (imposta anche il percorso del server dei simboli microsoft in modo che anche i punti di ingresso delle DLL di Windows vengano risolti).

IMHO questo è solo il sito web di cui hai bisogno: http://www.dumpanalysis.org - che è la miglior risorsa per coprire tutte le tue domande. Considera anche di dare un'occhiata a questo PDF - http://windbg.info/download/doc /pdf/WinDbg_A_to_Z_color.pdf

Altri suggerimenti

Altri lo hanno detto tra le righe, ma non esplicitamente. guarda:

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

L'offset 0xa26c è enorme , ben oltre la fine della funzione. il debugger ovviamente non ha i simboli corretti per LibFmwk, quindi si basa sulle esportazioni DLL e mostra l'offset rispetto a quello più vicino che riesce a trovare.

Quindi, sì, ottieni simboli adeguati e quindi dovrebbe essere un gioco da ragazzi. UTIL_GetDateFromLogByDayDirectory non è in errore qui.

Ai punti 2 e 3 si risponde facilmente:

3 ° punto. Qualsiasi debugger. Questo è ciò per cui sono fatti. Imposta il tuo debugger per interrompere questa eccezione speciale. Dovresti essere in grado di fare clic su di te attraverso il callstack e trovare le diverse chiamate nello stack (almeno Delphi può farlo, quindi anche Visual Studio dovrebbe essere in grado). Compilare senza ottimizzazioni se possibile. Anche OllyDBG potrebbe funzionare, forse in combinazione con la sua funzionalità di traccia.

2 ° punto. Qualsiasi informazione su x86 Assembler, Reverseengineering ... Prova: OpenRCE , Documentazione NASM , Community ASM .

1o punto. Il callstack ti dice le funzioni. Non so se sia scritto nell'ordine o nell'ordine opposto, quindi potrebbe essere che la prima riga sia l'ultima chiamata o la prima chiamata. Segui le chiamate con l'aiuto del debugger. A volte puoi cambiare tra asm e code (a seconda del debugger, dei file delle mappe ...). Se non hai la fonte - impara l'assemblatore, leggi il reverse engineering. Leggi la documentazione delle funzioni chiamate in componenti di terze parti. Forse non soddisfi una condizione preliminare.

Se puoi dire qualcosa in più sul programma (quali parti del codice sorgente hai, è coinvolta una chiamata in libreria ?, ...)


Ora qualche lettura del codice:

La funzione accetta un puntatore a una stringa con terminazione zero e un riferimento a un oggetto data. Si presume che il puntatore sia valido!

La funzione verifica se la stringa è in un formato specifico (% seguito da 8 cifre seguite da un \ 0). In caso contrario, restituisce false. Questo controllo (il grande if) accede al puntatore senza alcun controllo di validità. La lunghezza non viene controllata e se il puntatore punta da qualche parte in libertà, si accede a questo spazio. Non so se una stringa più corta causerà problemi. Non dovrebbe essere dovuto al modo in cui & amp; & amp; viene valutato.

Quindi viene allocata parte della memoria nello stack. La parte numerica della stringa viene copiata in essa (il che è ok) e il buffer ottiene la sua terminazione \ 0. L'atoide estrae i numeri. Ciò funzionerà a causa delle diverse posizioni iniziali utilizzate e della terminazione \ 0 dopo ogni parte. In qualche modo difficile ma carino. Alcuni commenti avrebbero chiarito tutto.

Questi numeri vengono quindi inseriti nell'oggetto. Dovrebbe essere valido poiché è passato nella funzione per riferimento. Non so se è possibile passare un riferimento a un oggetto eliminato, ma in questo caso potrebbe essere anche questo il tuo problema.

Ad ogni modo - tranne il controllo mancante per il puntatore di stringa, questa funzione è valida e non la causa del problema. È solo il luogo che genera l'eccezione. Cerca gli argomenti passati a questa funzione. Sono sempre validi? Effettua un po 'di registrazione.

Spero di non aver commesso errori importanti poiché sono un programmatore di Delphi. Se lo facessi, sentiti libero di commentare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top