简 述: Visual Studio 断点调试之箭头偏移进错函数,怪异现象之捉🐛记。

[TOC]


本文初发于 “偕臧的小站“,同步转载于此。


背景

  好久没有遇到这么有趣的 Bug 了,来抓一个调试指针出现偏移错误❌的🐛。 

  在 C++ 实现的派生类和类中重写的两个虚函数 A、B 后,代码实写调用 A 函数,断点 Debug 调试却命中 B 函数。💻 win10 21H2 📎 Visual Studio 2019


  MyCollectLogImplIMyCollectLog 的一个派生类,然后代码中调用派生类的 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. 断点调试的箭头发生偏移到其它函数。本次遇到
  2. 断点调试时,断点和箭头均无法进入某一函数内部。以前遇过

两者实际为同一根因:

『根因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 模式的编译关闭所有优化。


系列地址

QtExamples

欢迎 star ⭐ 和 fork 🍴 这个系列的 C++ / QT / DTK 学习,附学习由浅入深的目录,这里你可以学到如何亲自编写这类软件的经验,这是一系列完整的教程,并且永久免费!”