Winapi 如何读取调用堆栈? 我们有一个本地的C++应用程序,它通过COM+在Windows 2003服务器上运行。我最近从event viewer中注意到,它抛出异常,特别是C0000005异常,这意味着进程试图写入不在其地址空间内的内存,也就是访问冲突

Winapi 如何读取调用堆栈? 我们有一个本地的C++应用程序,它通过COM+在Windows 2003服务器上运行。我最近从event viewer中注意到,它抛出异常,特别是C0000005异常,这意味着进程试图写入不在其地址空间内的内存,也就是访问冲突,winapi,visual-c++,native,memory-address,callstack,Winapi,Visual C++,Native,Memory Address,Callstack,事件查看器中的条目提供了一个调用堆栈: LibFmwk!UTIL_GetDateFromLogByDayDirectory(char const*,类utilCDate&)+0xa26c LibFmwk!UTIL_GetDateFromLogByDayDirectory(char const*,类utilCDate&)+0x8af4 LibFmwk!UTIL_GetDateFromLogByDayDirectory(char const*,类utilCDate&)+0x13a1 LibFmwk!

事件查看器中的条目提供了一个调用堆栈:

LibFmwk!UTIL_GetDateFromLogByDayDirectory(char const*,类utilCDate&)+0xa26c LibFmwk!UTIL_GetDateFromLogByDayDirectory(char const*,类utilCDate&)+0x8af4 LibFmwk!UTIL_GetDateFromLogByDayDirectory(char const*,类utilCDate&)+0x13a1 LibFmwk!utilCLogController::GetFLFInfoLevel(void)常量+0x1070 LibFmwk!utilCLogController::GetFLFInfoLevel(void)常量+0x186

现在,我知道它给了我方法名去看,但我感觉每行末尾的地址(例如+0xa26c)试图将我指向该方法中的特定行或指令

因此,我的问题是:

  • 有人知道我如何使用这个地址或调用堆栈中的任何其他信息来确定它在代码中的哪一行吗
  • 有没有我可以阅读的资源来更好地理解调用堆栈
  • 是否有任何免费/开源工具可以帮助分析调用堆栈,可能是通过附加到调试符号文件和/或二进制文件
  • 编辑: 根据要求,以下是导致问题的方法:

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

    这是我们公司的一位成员在10年前写的代码,他已经离开很久了,所以我不知道这到底在做什么,但我知道它涉及到将日志目录从“今天”重命名为特定日期的过程,例如%20090329。数组索引、memcpy和操作符地址确实让它看起来相当可疑

    我们似乎遇到的另一个问题是,这只发生在生产系统上,我们从未能够在我们的测试系统或开发系统上重现它,这将允许我们附加调试器

    非常感谢!
    Andy第2点和第3点很容易回答:

    第三点。任何调试器。这就是它们的用途。将调试器设置为在发生此特殊异常时中断。您应该能够通过调用堆栈单击自己,并在堆栈上找到不同的调用(至少delphi可以做到这一点,所以VisualStudio也应该能够做到)。如果可能,编译时不进行优化。OllyDBG可能也可以工作——可能与它的跟踪功能结合使用

    第二点。有关x86汇编程序、反向工程的任何信息。。。试试看:

    第一点。调用堆栈告诉您函数。我不知道它是按顺序写的,还是按相反的顺序写的——所以第一行可能是最后一个调用的函数,也可能是第一个调用的函数。在调试器的帮助下跟踪调用。有时您可以在asm和代码之间进行更改(取决于调试器、映射文件…)。如果您没有源代码学习汇编程序,请阅读有关反向工程的内容。阅读您在第三方组件中调用的函数的文档。也许你不满足一个先决条件

    如果你能告诉更多关于这个程序的信息(你有哪些部分的源代码,是否涉及库调用?,…)


    现在阅读一些代码:

    该函数接受指向以零结尾的字符串的指针和对日期对象的引用。假定指针是有效的

    该函数检查字符串是否为特定格式(%后跟8位数字,后跟\0)。如果不是这样,则返回false。此检查(大if)访问指针时不进行任何有效性检查。不检查长度,如果指针指向任意位置,则访问此空间。我不知道短字符串是否会导致问题。不应该是因为&&的计算方式

    然后在堆栈上分配一些内存。字符串的数字部分被复制到该字符串中(这是确定的),缓冲区将\0终止。原子能机构正在提取这些数字。这将起作用,因为使用了不同的开始位置和每个零件后的\0-终止。有点狡猾但很好。一些评论会把一切都说清楚

    然后将这些数字插入到对象中。它应该是有效的,因为它是通过引用传递到函数中的。我不知道您是否可以传递对已删除对象的引用,但如果是这种情况,这可能也是您的问题

    无论如何-除了缺少对字符串指针的检查外,此函数是可靠的,不是问题的原因。只有在这个地方才会抛出异常。搜索传递到此函数的参数。它们总是有效的吗?做一些日志记录


    我希望我没有犯任何重大错误,因为我是一名Delphi程序员。如果我这样做了-请随意评论。

    如果您真的需要将这些地址映射到您的函数,您需要使用.map文件并查看这些地址真正指向的位置

    但在您的情况下,我宁愿在调试器(例如MSVS调试器或windbg)下调查此问题;作为替代方案(如果崩溃发生在客户的站点),您可以生成崩溃转储并在本地进行研究-可以通过Windows MinidumpWriteDomainp API或SysInternals过程转储实用程序()完成

    确保所有必需的符号文件都已生成且可用(还应设置microsoft符号服务器路径,以便windows DLL的入口点也得到解析)

    这正是你需要的网站:-这是涵盖你所有问题的最佳资源。
    考虑一下这个PDF-< /P> < P>其他人在这两条线之间说了这句话,但不是明确的。看看:

    LibFmwk!UTIL_GetDateFromLogByDayDirectory(char const *,class utilCDate &) + 0xa26c
    
    0xa26c偏移量很大,远远超过函数的末尾。调试器显然没有LibFmwk的正确符号,因此它是