奇怪的内存损坏

时间:2011-05-06 23:13:16

标签: c++ memory-management stack libusb

当我使用WinDDK nmake编译器在'free'(发布版)中构建时,只会发生此错误,后者执行优化。我无法在“已检查”版本中重现此内容或使用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!!
}
  

日志输出:
  pre nullValue:0
  inFunc nullValue:0,251208
  post nullValue:251208
  post2 nullValue:251208,251208,251208
  注意:每次运行程序时,重新出现的数字(251208)都是不同的数字

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

  1. 最终我的问题是弄清楚如何解决问题(我无法避免这个问题)
  2. 但只是在堆栈/内存管理级别上,如何使NULL不为零并且文字值'0'打印为非零?
  3. 让我知道其他信息可能会有什么帮助...

2 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:0)

更新:所以,我终于得到了windbg来打破dll并检查一些事情。正如我最初所怀疑的那样,汉斯指出,由于不匹配的呼叫约定导致堆栈损坏。

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

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

总结答案:

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