C++ VS2005 C++;破表

C++ VS2005 C++;破表,c++,visual-studio-2005,vtable,C++,Visual Studio 2005,Vtable,我目前正在开发一个相当大的代码库,最近升级到了VS2005(SP1)。我和我的团队正在更改/更新/替换此代码中的模块,但有时会遇到vtables似乎损坏的问题。我不是vtables方面的专家,但这些似乎肯定是坏的。这些错误会显示为以下错误: 运行时检查失败#0-未在函数调用中正确保存ESP的值。这通常是调用使用一个调用约定声明的函数以及使用另一个调用约定声明的函数指针的结果 当然,此错误可能还有很多其他原因,但在调试(调试构建)时,我可以实际验证要操作的对象的vtables是否看起来奇怪: 引用

我目前正在开发一个相当大的代码库,最近升级到了VS2005(SP1)。我和我的团队正在更改/更新/替换此代码中的模块,但有时会遇到vtables似乎损坏的问题。我不是vtables方面的专家,但这些似乎肯定是坏的。这些错误会显示为以下错误:

运行时检查失败#0-未在函数调用中正确保存ESP的值。这通常是调用使用一个调用约定声明的函数以及使用另一个调用约定声明的函数指针的结果

当然,此错误可能还有很多其他原因,但在调试(调试构建)时,我可以实际验证要操作的对象的vtables是否看起来奇怪:

引用每个vtable的堆栈和堆看起来很好,指向vtables的指针与映射文件完全匹配。这向我表明,这不是内存覆盖错误或类似错误,因为这样会影响堆栈和堆,而不是vtables的存储位置。(它们存储在一个只读区域,对吗?)无论如何,到目前为止一切似乎都很好。但是当查看vtable的内存时,我发现所有值(如果我将它们解释为指针)都不匹配映射文件中的任何条目,尽管它们在相同的范围内(例如0x00f203db 0x00f0f9be 0x00ecdda7 0x00f171e1),而且许多值甚至没有对齐到4个字节。我不知道VS2005如何构建vtables的所有细节,但我认为这是错误的。如果这是正确的行为,也许有人能给我解释一下

我想我的问题可以归结为什么会导致这种行为?例如,当具有太复杂的类层次结构时,链接器中是否存在已知的bug?以前有人见过类似的东西吗?目前,我们可以通过将函数从受影响的类移动到内联(可怕的东西!)来避免崩溃,但显然这不是一个可行的长期解决方案

谢谢你的洞察力

更新:有人问我关于这个项目的更多细节,当然我会提供这个。然而,首先,问题并不完全与ESP值未保存错误有关。我最感兴趣的是为什么我在vtable中看到奇怪的值。也就是说,这里有一些额外的信息:解决方案依赖于几个外部和内部项目,但这些项目在很长一段时间内都没有改变,它们都使用相同的调用约定。它似乎在破坏的代码都在解决方案的一个相当标准的C++“主”项目中。所有代码都是使用相同的编译器生成的。该解决方案也不使用任何DLL,而是使用大量静态库的链接:


SHFolder.lib、python25.lib、dxguid.lib、d3dx9.lib、dinput8.lib、ddraw.lib、dxer9.lib、ws2_32.lib、mss32.lib、Winmm.lib、vtuneapi.lib、vttriggers.lib、DbgHelp.lib、kernel32.lib、user32.lib、gdi32.lib、winspool.lib、comdlg32.lib、advapi32.lib、shell32.lib、oleaut32.lib、uuid.lib、odbc32.lib、,lib

我认为这里的一个重要提示是“这通常是调用使用一个调用约定声明的函数,而函数指针使用另一个调用约定声明的结果”错误的一部分。在我看来,调用方的API和处理调用的库之间似乎不匹配

此外,您可能会混合使用不同编译器生成的代码。关于这个项目的性质,你还能告诉我们什么?您正在调用的函数是否位于外部库中?或者您可以调试整个调用堆栈吗


编辑:您说过项目不使用任何DLL。静态库呢?

每当我收到这样的消息时,答案总是涉及重新编译部分或全部代码。作为第一步,我会尝试全面重建。Sqook关于外部库的建议听起来也很合理,如果可能的话,还需要使用与主代码相同的调用约定重新编译该库


我有时发现Build命令可能会丢失需要重新编译的文件,这可能会导致您的消息。再次强调,全面重建将解决问题。

当我以前遇到这个错误时,总是涉及COM。
几乎总是与再进入相关——你在使用COM吗?是否使用STA、消息过滤器?

注意增量链接和“编辑+继续”对函数地址(包括v表条目)的影响。它的工作原理是通过跳转表间接地进行方法调用。这允许链接器在需要重新定位方法时修补跳转表,而无需重新链接整个图像。跳转表中的地址相隔5个字节。它们不会出现在.map文件中。切换到程序集视图并跟踪调用的执行时,很容易看到


这也是您应该用来诊断RTC故障的技术。找出实际调用的方法。最可能的原因是,您已将虚拟方法添加到类中,但该类的客户端未重新编译。使用v形工作台中的错误插槽。当更改接口而不是IID时,通常也是COM问题。

我发现了这个问题。确实很愚蠢,但导致问题的类层次结构有一个名为GetObject的虚拟函数,它与同名的windows#define冲突。头文件以不同的顺序包含这些windows头文件,这使链接器感到困惑。所以,事实上问题是vtables被破坏了,但我没想到这是原因!你每天都能学到一些东西


然而,非常感谢所有回复

我遇到了完全相同的问题-在对象上调用重载虚拟函数会导致“ESP未正确保存”错误,