记一次奇怪的内存错误分析过程


这几天在给一个老项目扩展功能,发现了一个奇怪的问题,在群友的帮助下,经过痛苦的跟进,终于找到了问题原因,特此记录。

 

一:背景

这是在一个老旧的MFC项目中增加Duilib窗口的显示,没办法,MFC的窗口自绘实在累人,还是用Duilib来得方便。

在前期做窗口效果时,一切都很正常,可当我想要对接业务,在Duilib的窗口类中[GroupChatDlg]增加成员变量,并且在外部给这个成员变量赋值时,程序突然就崩溃了,断点查看这个成员变量的地址不对。

GroupChatDlg的类继承关系如下:

进一步进入MainFrame的构造函数中发现,我在MainFrame中的一个成员变量[一个char数组 char m_szTest[100]; ]的赋值也不正确,比如我 strcpy(szTest, “123456”); 结果再通过变量查看,他的值是”56”,而查看szTest –4的内存,他的又是完整的”123456”

 

 

二:分析跟进

这是一个比较老的项目了,而且项目代码量比较大,以前也没碰到过类似问题,一下子不知道从哪里开始分析了。

 

我第一能想到的是,赶紧创建一个测试项目,只把相关的文件加入进来,简化问题;结果却是在测试项目中一切正常。

 

这下没办法了,开始求助技术群的朋友们,大家也给出了各种可能的分析;后来在一位群友的帮助下,分析到了问题原因。

 

我是在一个MFC的项目中使用这个Duilib窗口的,创建这个GroupChatDlg的动作放在Project.cpp InitialInstance的函数中,通过分析发现,在Project.cpp中获取类MainFrame的大小是880

Int nSize = sizeof(MainFrame);

 

而在MainFrame的构造函数中通过这段代码获取到的nSize的值是876,比在外部获取的要少4个字节,这也与之前发现问题是szTest-4后的值就正常匹配。

 

问题渐渐明朗,现在的问题是在Project.cpp中看到的类对象与在MainFrame.cpp中的类对象的大小是有差异的,内存布局不一致,导致了我在构造中尝试赋值时的内存地址不对;而在后续对GroupChatDlg [他是MainFrame的子类] 成员变量赋值时会崩溃,也是一样的道理了。

 

那么到底是哪里导致了两处查看到的对象不一致呢?

 

群友说应该是引用了不同的头文件所致,网上也确实有相关的文章,跟我的问题现象非常像:

http://airekans.github.io/cpp/2014/03/11/cpp-debug-01/

 

排查了所有与此类相关的头文件,都没有找到有哪里会是不一样的,接下来我一步步往基类排查,获取相关的每个基类对象的size进行对比,到底是哪个对象的哪个成员不一样大所致。

 

最终定位到是CPaintManagerUI类中的一个成员变量:TOOLINFO m_ToolTip;

这个TOOLINFO的大小,在Project.cpp中获取到的大小是48,而在MainFrame中获取到的大小是44

TOOLINFO的定义如下:


 

typedef struct tagTOOLINFOA {

    UINT cbSize;

    UINT uFlags;

    HWND hwnd;

    UINT_PTR uId;

    RECT rect;

    HINSTANCE hinst;

    LPSTR lpszText;

#if (_WIN32_IE >= 0x0300)

    LPARAM lParam;

#endif

#if (_WIN32_WINNT >= 0x0501)

    void *lpReserved;

#endif

} TTTOOLINFOA, NEAR *PTOOLINFOA, *LPTTTOOLINFOA;

 

现在问题更加明朗了,应该是因为_WIN32_WINNT宏的定义不一致,导致了这个对象的成员不一致。

 

可又是哪里引起的呢?

进一步跟进发现,在MainFrame.cppProject.cpp中都有这样一行代码:

#include stdafx.h

这是引用预编译头文件,而在这个项目中的stdafx.h中的_WIN32_WINNT的定义是0x0501,不应该不对呀。

继续跟进,原来在MainFrame.cpp中引用的stdafx.h是在另外一个目录下的,而这个stdafx.h_WIN32_WINNT的定义是0x0500,终于找到它了,修改成0x0501后,问题解决。

 

这里MainFrame.cpp中引用 stdafx.h会指向另外一处的原因是因为原来的项目中include目录中加入一些头文件路径,而其中就有这个stdafx.h

 

三:结论

确实是由于引用了不同版本的头文件,引起了对象的定义不一致,而这个问题由于历史原因,隐藏得相对深了一些。

问题在于在什么项目中使用,而是在于头文件的引用不正确;这是一个比较深刻的教训,头文件的引用一定要慎重,不然造成了深坑,坑的还是自己呀!

 

在此特别感谢 ”﹏喲、叮当猫” 以及其他帮助我的科学家们。

 

更多信息,请访问:

http://www.ggniu.cn/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值