Pergunta

Nós temos um aplicativo nativo C ++ em execução via COM + em um servidor Windows 2003. Eu recentemente notado a partir do visualizador de eventos que suas exceções Arremessar, especificamente a exceção C0000005, que, de acordo com http://blogs.msdn.com/calvin_hsia/archive/2004/06/30/170344.aspx significa que o processo está tentando escrever para a memória não dentro de seu endereço espaço, aka de violação de acesso.

A entrada no visualizador de eventos fornece uma pilha de chamadas:

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

Agora, eu entendo que a sua me dando nomes de métodos para ir olhar, mas tenho uma sensação de que o endereço no final de cada linha (por exemplo, + 0xa26c) está tentando me apontar para uma linha específica ou instrução dentro desse método .

Então, minhas perguntas são:

  1. Alguém sabe como eu poderia usar esse endereço ou qualquer outra informação em uma pilha de chamadas para determinar qual linha dentro do código de seu cair sobre?
  2. Existem recursos lá fora que eu poderia ler para entender melhor pilhas de chamadas,
  3. Existem algumas ferramentas freeware / opensource que poderiam ajudar na análise de uma pilha de chamadas, talvez anexando a um arquivo e / ou binários de símbolos de depuração?

Edit: Conforme solicitado, aqui é o método que parece estar causando o 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);

}

Este é um código escrito mais de 10 anos atrás por um membro da nossa empresa, que há muito tempo já se foi, então eu não presumir saber exatamente o que isso está fazendo, mas eu sei que é envolvido no processo de renomear um diretório log de 'Hoje' para a data específica, por exemplo, % 20090329. A matriz indexação, memcpy e endereço dos operadores fazem com que pareça bastante suspeito.

Outro problema parece que temos é que isso só acontece no sistema de produção, nunca fui capaz de reproduzi-lo em nossos sistemas de teste ou sistemas de desenvolvimento aqui, que nos permita anexar um depurador.

Muito apreciada! Andy

Foi útil?

Solução

Se você realmente precisa mapear esses endereços às suas funções -. Você vai precisar para trabalhar com arquivo .MAP e ver onde esses endereços realmente apontar para

Mas estar na sua situação eu preferiria investigar este problema sob depurador (debugger ou windbg por exemplo MSVS); como alternativa (se acidente acontece no local do Cliente) você pode gerar despejo de memória e estudá-lo localmente - isso pode ser feito através do Windows MiniDumpWriteDump API ou o utilitário SysInternals ProcDump ( http://download.sysinternals.com/Files/procdump.zip ).

Certifique-se de que todos os arquivos de símbolos necessários são gerados e disponíveis (também de configuração do Microsoft caminho do servidor de símbolo tão pontos de entrada que o Windows DLLs' ficar resolvido também).

IMHO este é apenas o site que você precisa: http://www.dumpanalysis.org - que é o melhor recurso para cobrir todas as suas perguntas. Considere também dar uma olhada neste PDF - http://windbg.info/download/doc /pdf/WinDbg_A_to_Z_color.pdf

Outras dicas

Outros disseram isso em-entre as linhas, mas não explicitamente. olhada em:

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

O 0xa26c offset é enorme , maneira além do fim da função. o depurador, obviamente, não têm os símbolos adequados para LibFmwk então ao invés ele está contando com as exportações DLL e mostrando o deslocamento em relação ao mais próximo que pode encontrar.

Então, sim, obter símbolos adequados e, em seguida, ele deve ser uma brisa. UTIL_GetDateFromLogByDayDirectory não está em falta aqui.

Ponto 2 e 3 são facilmente respondidas:

3 Point. Qualquer depurador. Isso é o que eles são feitos para. Defina o seu depurador para quebrar neste exceção especial. Você deve ser capaz de clicar-se através da pilha de chamadas e encontrar as diferentes chamadas na pilha (pelo menos Delphi pode fazer isso, estúdio tão visual deve ser capaz também). Compilar sem optimizações, se possível. OllyDbg pode funcionar tão bem -. Talvez em combinação com a sua funcionalidade de rastreamento

2º Point. Qualquer informação sobre x86 Assembler, engenharia reversa ... Tente: OpenRCE , NASM Documentação , ASM Comunidade.

1º Point. O callstack diz-lhe as funções. Eu não sei se ele é escrito em ordem ou em ordem inversa - por isso pode ser que a primeira linha é a última chamada de função ou a função primeira chamada. Siga as chamadas com a ajuda do depurador. Às vezes você pode mudar entre asm e código (dependendo do depurador, mapear arquivos ...). Se você não tem o código-fonte - aprender assembler, ler sobre engenharia reversa. Leia a documentação das funções que você chama em componentes de terceiros. Talvez você não satisfazer uma condição prévia.

Se você pode dizer um pouco mais sobre o Programa (que partes do código-fonte que você tem, é um chamado biblioteca envolvidos ?, ...)


Agora, alguns de leitura de código:

A função aceita um ponteiro para uma seqüência de zero terminada e uma referência a um objeto de data. O ponteiro é considerado válido!

A função verifica meteorológicas a cadeia está em um formato específico (% seguido de 8 dígitos seguidos por um \ 0). Se este não for o caso, ele retorna false. Esta verificação (o grande se) acessa o ponteiro sem qualquer verificação de validade. O comprimento não está marcada e se o ponteiro está apontando em algum lugar na selva, este espaço é acessado. Eu não sei se um fio mais curto causará problemas. Ele não deve por causa da maneira && é avaliada.

Em seguida, parte da memória é alocada na pilha. O número-parte da string é copiada para ele (que é ok) eo buffer recebe o \ 0 rescisão. Os atois extrair os números. Isto irá funcionar por causa das diferentes start-locais utilizados e a \ 0-terminação depois de cada parte. De alguma forma complicado, mas agradável. Alguns comentários teria feito tudo claro.

Estes números são, então, inserida dentro do objecto. Ele deve ser válido, uma vez que é passado para a função por referência. Eu não sei se você pode passar uma referência a um objeto excluído, mas se este for o caso, este pode ser o seu problema também.

De qualquer forma - exceto a verificação de falta para a cadeia de ponteiro, esta função é sólida e não a causa do seu problema. É apenas o lugar que lança a exceção. Procurar argumentos que são passados ??para esta função. eles estão sempre válido? Fazer algum registro.

Espero não fazer qualquer grandes erros que eu sou um programador Delphi. Se eu fiz -. Sentir-se livre para comentar

scroll top