繁体   English   中英

VS2005 C++ 损坏的 vtables

[英]VS2005 C++ broken vtables

我目前正在开发一个相当大(而且很旧,叹气)的代码库,最近升级到 VS2005 (SP1)。 我和我的团队正在更改/更新/替换此代码中的模块,因为我们是 go,但我们偶尔会遇到 vtables 似乎损坏的问题。 我不是 vtables 方面的专家,但这些肯定似乎被打破了。 错误表现为以下错误:

运行时检查失败 #0 - ESP 的值未在 function 调用中正确保存。 这通常是调用使用一种调用约定声明的 function 和使用不同调用约定声明的 function 指针的结果。

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

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

我想我的问题归结为什么会导致这种行为? 例如,当 class 层次结构过于复杂时,linker 中是否有任何已知错误? 有没有人见过类似的东西? 目前,我们能够通过将功能从受影响的 class 移动到内联(可怕的东西。)来解决我们的崩溃问题,但显然这不是一个可行的长期解决方案。

感谢您的任何见解!

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

SHFolder.lib、python25.lib、dxguid.lib、d3d9.lib、d3dx9.lib、dinput8.lib、ddraw.lib、dxerr9.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,ole32.lib,oleaut32.lib,uuid.lib,odbc32.lib, odbccp32.lib

我发现了问题。 真的很傻,但是导致问题的 class 层次结构有一个名为 GetObject 的虚拟 function 与 windows #define 冲突。 header 文件以不同的顺序包含这些 windows header 文件,这混淆了 Z3175B427346780BEECE873。 所以,实际上问题是 vtables 损坏了,但我没想到这是原因。 好吧,你每天都学到一些东西......

但是,非常感谢所有回复!

我认为这里的重要提示是“这通常是调用使用一个调用约定声明的 function 指针声明的一个调用约定的结果”该错误的一部分。 在我看来,调用者的 API 与处理调用的库之间存在不匹配。

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

编辑:您说该项目不使用任何 DLL。 static 库呢?

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

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

我遇到了完全相同的问题-在 object 上调用重载的虚拟 function 导致“ESP 未正确保存”错误,但调试显示编译器为此调用在 vtable 中生成了错误的偏移量,因此另一个 ZC1C42542068E68384F1 与 moreC参数被调用。 被调用的 function 更新了 ESP,就好像调用者在堆栈上推送了更多参数,这反过来导致返回时无效的 ESP 值。

在我将 header 文件(包括 class 错误)放在源文件顶部后,问题就消失了。 我还没有进一步调查究竟是什么原因造成的,但我想这是在同样的情况下——有些人定义了虚拟成员的声明。

希望能帮助其他遇到同样问题的人。

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

我有时发现 Build 命令可能会丢失需要重新编译的文件,这可能会导致您的消息。 再次,全面重建将使事情理顺。

当我遇到此错误之前,一直是涉及 COM 时。 它几乎总是与重入特别相关——您使用的是 COM 吗? 您使用的是 STA,消息过滤器吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM