【问题标题】:Weird memory corruption奇怪的内存损坏
【发布时间】:2011-08-20 13:12:33
【问题描述】:

仅当我在“免费”(发布)中使用 WinDDK nmake 编译器构建时才会出现此错误,该编译器执行优化。我无法在“已检查”构建或使用 VS 编译中重现此问题。

这是我的代码中发生的事情的伪代码:

main()
{
   //variable init and other code
    fprintf(log, "pre nullValue: %lu\n", NULL);  //printf added for debugging
   otherFunc();
   funcWithError(str1, str2, NULL);
    fprintf(log, "post nullValue: %lu\n", NULL); 
    fprintf(log, "post2 nullValue: %lu, %lu, %lu\n", NULL, 0, NULL);
}

BOOL otherFunc()
{
   //variable init and other code
   callToDll();
    //...doing stuff
   libusb_usb_open(var1);    //If I remove this line there is no problem!!
    //...doing more stuff
}

BOOL funcWithError(char* s1, char* s2, FUNC_PTR fp)
{
    fprintf(log, "inFunc nullValue: %lu, %lu\n", NULL, fp);
   if(fp != NULL)
      return FALSE;        //This line is being executed erroneously!!
}

日志输出:
前空值:0
inFunc nullValue: 0, 251208
发布空值:251208
post2 nullValue: 251208, 251208, 251208
注意:每次程序运行时重复出现的数字(251208)都是不同的数字

只需更改一行即可修复/导致它。这是libusb usb_open 电话。

  1. 最终我的问题是弄清楚如何解决问题(我无法避免那个电话)
  2. 但只是在堆栈/内存管理级别上,怎么可能让 NULL 不为零并且将文字值 '0' 打印为非零?

让我知道其他信息可能会有所帮助...

【问题讨论】:

  • 也许参数传递约定到 libusb_usb_open 有问题,这会导致一些堆栈损坏。这是 64 位应用程序吗?也许你应该使用 %llu 而不是 %lu。找出问题的最佳方法是在汇编程序中调试这部分代码并检查发生了什么。
  • 是的,我正在尝试保存查看程序集,所以我想我会发布。它是在 x86 机器上为 x86 编译的,所以不是 64 位的。所以 %llu 什么都不做。

标签: c++ memory-management stack libusb


【解决方案1】:

不是一个完全灌篮。但是堆栈很可能会变得不平衡。在调试器中(是的,您可以调试发布版本),在调用前后检查 ESP 寄存器的值。应该是一样的。如果函数的调用约定错误,则不会。就像 __stdcall 与 __cdecl。

当您使用 nmake.exe 构建程序时,这可以很好地隐藏自己,很容易忘记在调试构建中打开 /RTCs 选项,因此会发出堆栈检查代码。 ESP 寄存器倾向于在函数返回时自行恢复。直到您构建了发布版本,其中函数被内联并且 EBP 的使用被优化掉,因此 ESP 不再自我恢复。

【讨论】:

    【解决方案2】:

    更新:所以,我终于让 windbg 闯入 dll 并检查一些东西。正如我最初怀疑和 Hans 指出的那样,这是由不匹配的调用约定引起的堆栈损坏。

    仅在发布版本中可见的是编译器优化了 0/Null 值以使用 ebx 寄存器值而不是传递 0。在 OtherFunc() 中,优化使用 ebx 来存储其他几个值,然后调用 Usb_Open() 损坏了堆栈,然后当 OtherFunc() 尝试弹出堆栈以恢复原始 ebx 值时,它恢复了垃圾而不是“0”。所以,在 main() 中,每个对 NULL 的优化引用都在使用这个垃圾值。

    注意:其他 dll 调用没有破坏堆栈的原因是因为它们是无参数的。

    所以总结一下答案:

    1. 使用正确的约定调用 libusb(libusb 使用 __cdecl 调用约定,NMAKE 默认使用 __stdcall)
    2. 即使 NULL 和“0”在源代码中被硬编码,编译器也可以优化为使用寄存器而不是传递值,并且寄存器会因错误代码而损坏。

    【讨论】:

      猜你喜欢
      • 2016-12-30
      • 1970-01-01
      • 2016-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-14
      • 2011-12-14
      相关资源
      最近更新 更多