我们最近尝试将一些 Visual Studio 项目分解为库,并且在测试项目中一切似乎都编译和构建得很好,其中一个库项目作为依赖项。然而,尝试运行该应用程序给我们带来了以下令人讨厌的运行时错误消息:
运行时检查失败 #0 - ESP 的值未在函数调用中正确保存。这通常是调用使用不同调用约定声明的函数指针的结果。
我们甚至从未为我们的函数指定调用约定(__cdecl 等),将所有编译器开关保留为默认值。我检查过,项目设置对于跨库和测试项目的调用约定是一致的。
更新:我们的一位开发人员将“基本运行时检查”项目设置从“两者(/RTC1,相当于/RTCsu)”更改为“默认”,运行时消失了,程序运行明显正确。我根本不相信这一点。这是一个正确的解决方案,还是一个危险的黑客行为?
此调试错误意味着堆栈指针寄存器在函数调用后没有返回到其原始值,即pushes在函数调用之前没有跟随相同数量的pops通话后。
据我所知,有两个原因(都是动态加载的库)。 #1 是 VC++ 在错误消息中描述的内容,但我认为这不是最常见的错误原因(请参阅#2)。
1)调用约定不匹配:
调用者和被调用者对于谁将做什么没有达成适当的协议。例如,如果您调用的 DLL 函数是_stdcall
,但由于某种原因你将其声明为_cdecl
(VC++ 中默认)在您的调用中。如果您在不同的模块等中使用不同的语言,这种情况会经常发生。
您必须检查有问题的函数的声明,并确保它没有以不同的方式声明两次。
2)类型不匹配:
调用者和被调用者不是用相同的类型编译的。例如,一个公共标头定义了 API 中的类型并且最近发生了更改,并且一个模块被重新编译,但另一个模块没有重新编译 - 即某些类型在调用者和被调用者中可能具有不同的大小。
在这种情况下,调用者会推送一种大小的参数,但被调用者(如果您使用的是_stdcall
被调用者清理堆栈的地方)弹出不同的大小。因此,ESP 没有返回到正确的值。
(当然,这些参数以及它们下面的其他参数在被调用的函数中似乎是乱码,但有时您可以在没有明显崩溃的情况下幸存下来。)
如果您有权访问所有代码,只需重新编译即可。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)