无法追踪潜在的内存覆盖。窗户怪异
Posted
技术标签:
【中文标题】无法追踪潜在的内存覆盖。窗户怪异【英文标题】:Trouble tracking down a potential memory overwrite. Windows weirdness 【发布时间】:2008-12-12 16:44:02 【问题描述】:这让我发疯了。我在 Windows .lib 中使用了一些第 3 方代码,在调试模式下会导致类似于以下的错误:
Run-Time Check Failure #2 - Stack around the variable 'foo' was corrupted.
当对象超出范围或被删除时会引发错误。只需分配这些对象之一然后删除它就会引发错误。因此,我认为问题出在众多构造函数/析构函数之一中,但尽管遍历了每一行代码,我还是找不到问题。
但是,这只发生在在静态库中创建这些对象之一时。如果我在我的 EXE 应用程序中创建一个,则不会出现错误。第 3 方代码本身存在于静态库中。例如,这会失败:
**3RDPARTY.LIB**
class Foo : public Base
...
;
**MY.LIB**
void Test()
Foo* foo = new Foo;
delete foo; // CRASH!
**MY.EXE**
void Func()
Test();
但这会起作用:
**3RDPARTY.LIB**
class Foo : public Base
...
;
**MY.EXE**
void Func()
Foo* foo = new Foo;
delete foo; // NO ERROR
因此,删除“中间”.lib 文件会使问题消失,正是这种怪异让我发疯。 EXE 和 2 个库都使用相同的 CRT 库。链接没有错误。第 3 方代码使用继承,有 5 个基类。我已经尽可能多地注释掉了代码,同时仍在构建它,我只是看不到发生了什么。
因此,如果有人知道为什么 .lib 中的代码与 .exe 中的相同代码的行为不同,我很想听听。同上跟踪内存覆盖的任何提示!我正在使用 Visual Studio 2008。
【问题讨论】:
【参考方案1】:一种可能性是 calling convention 不匹配 - 确保您的库和可执行文件都设置为使用相同的默认调用约定(通常是 __cdecl)。要设置它,请打开您的项目属性并转到 Configuration Properties > C/C++ > Advanced 并查看 Calling Convention 选项。如果你用错误的调用约定调用一个函数,你会完全弄乱堆栈。
【讨论】:
所有项目都在使用__cdecl。崩溃仅在创建特定类型的对象时发生 - 其他对象工作正常。 嗯,这只是一个猜测——如果没有更多信息,很难从心理上调试别人的问题。 感谢亚当的指点。这个问题快把我逼疯了。我即将放弃第 3 方代码并尝试其他方法。【参考方案2】:好的,我找到了问题,如果有人感兴趣的话,这是一个破解程序。基本上,我的 .LIB 就出现了问题。已将_WIN32_WINNT
定义为0x0501
(Windows 2000 及更高版本),但我的EXE 和第3 方LIB 将其定义为0x0600
(Vista)。现在,第 3 方库包含的头文件之一是 sspi.h
,它定义了一个名为 SecurityFunctionTable
的结构,其中包括以下 sn-p:
#if OSVER(NTDDI_VERSION) > NTDDI_WIN2K
// Fields below this are available in OSes after w2k
SET_CONTEXT_ATTRIBUTES_FN_W SetContextAttributesW;
#endif // greater thean 2K
长话短说,这意味着 LIB 之间的对象大小不匹配,这会导致运行时检查失败。
上课!
【讨论】:
【参考方案3】:您的 .lib 文件是否与库的 .lib 链接?我从您的示例中假设您包含带有析构函数声明的标头;没有它,删除这样的类型是允许的,但可能会导致 UB(以一种奇怪的方式与必须在使用前定义某些东西的一般规则相反)。如果 .lib 文件未链接在一起,则自定义 operator delete
或析构函数可能存在一些奇怪的链接问题,虽然这不应该发生,但您永远无法确定它是否不会。
【讨论】:
【参考方案4】:没有看到更多代码,很难给你一个肯定的答案。但是,为了追踪内存覆盖,我推荐使用 WinDbg(微软免费提供,搜索“Debugging Tools for Windows”)。
当您将它附加到您的进程时,您可以让它为内存访问(读取、写入或执行)设置断点。总体而言,它确实非常强大,但它应该对您特别有帮助。
【讨论】:
【参考方案5】:当对象超出范围或被删除时会引发错误。
每当我遇到这个问题时,它都与使用与应用程序其他部分不同的 C++ 运行时版本的编译库有关。
【讨论】:
以上是关于无法追踪潜在的内存覆盖。窗户怪异的主要内容,如果未能解决你的问题,请参考以下文章
内存扩充的覆盖与交换以及内存空间的分配和回收的连续分配管理方式