简 述: Visual Studio
断点调试之箭头偏移进错函数,怪异现象之捉🐛记。
[TOC]
本文初发于 “偕臧的小站“,同步转载于此。
背景
好久没有遇到这么有趣的 Bug 了,来抓一个调试指针出现偏移错误❌的🐛。
在 C++ 实现的派生类和类中重写的两个虚函数 A、B 后,代码实写调用 A 函数,断点 Debug 调试却命中 B 函数。💻 win10 21H2
📎 Visual Studio 2019
MyCollectLogImpl
为 IMyCollectLog
的一个派生类,然后代码中调用派生类的 OnCollectLogOne
函数,但调试的箭头和断点却进入了另一 OnCollectLogArray
函数;十分怪异之。
class IMyCollectLog : IMyUnknown {
public:
virtual long STDCALLTYPE OnCollectLogOne(const char* sKey, IMyBundle*) = 0;
virtual long STDCALLTYPE OnCollectLogArray(const char* sKey, IMyBundleArray) = 0;
};
class MyCollectLogImpl : public CloudService::IMyCollectLog
{
public:
long STDCALLTYPE OnCollectLogOne(const char* sKey, IMyBundle* pBundle) override {
if (!sKey || !pBundle)
return 0;
// TODO: do something
return 0;
}
long STDCALLTYPE OnCollectLogArray(const char* sKey, IMyBundleArray* pBundleArray) override {
if (!sKey || !pBundleArray)
return 0;
// TODO: do something
return 0;
}
// ... 定义其它成员函数和成员
};
调用处的函数为
void onInnerQueryEnd(const char* sKey, IMyBundle* pBundle) {
if (m_setCollLogPtr.empty())
return;
for (auto it : m_setCollLogPtr)
it->OnCollectLogOne(sKey, pBundle); // *** 写的是执行 OnCollectLogOne, 而非是 OnCollectLogArray, 虽然两者行参长得很像 ***
}
用一张图来解释就是:
问题
- 断点调试的箭头发生偏移到其它函数。本次遇到
- 断点调试时,断点和箭头均无法进入某一函数内部。以前遇过
两者实际为同一根因:
『根因1』Release 编译模式下关闭优化仍有优化,空实现的函数没有对应汇编
『根因2』跨模块加载、创建对象,其 .dll 接口和 .pdb 不对应
『根因3』.dll 和 .pdb 拷贝错了源对象、移动到了错的目标路径下
『根因4』.dll 和 .pdb 拷贝到正确的目标路径,被调试的程序未重启加载此插件(大部分需要)
解决
Release 模式下编译,即使关闭优化[1],实际仍有优化。 如实现一个空的函数,就会被优化掉,反汇编窗口中可查看无对应此函数的汇编语句。『简直是大坑』。
- Release 编译模式下关闭优化
- 实现某一函数时却暂不实现细节(仅有 if 判断指针为空和 return 语句,细节未写),仅想调试一下框架时,可在函数中添加一句
int a = 0
或例子打印语句
避免被编译器优化。 - 先切换 Debug 模式下编译,替换文件验证代码,在切回 Release 模式定位
注:
[1] Visual Studio 2019 项目属性页,”Configuration Properties - C/C++ - Optimization” 中 Optimization
设置为 Disabled (/Od)
;使 Release 模式的编译关闭所有优化。
系列地址
欢迎 star
⭐ 和 fork
🍴 这个系列的 C++ / QT / DTK
学习,附学习由浅入深的目录,这里你可以学到如何亲自编写这类软件的经验,这是一系列完整的教程,并且永久免费!”