重复delete 对象指针后的 异常调用栈怪异 解析

news/2025/1/12 1:52:19/

Release版VC6 MFC程序 程序正常退出时得到一个如下异常调用栈:复制代码

0:000> kb# ChildEBP RetAddr      Args to Child              
WARNING: Frame IP not in any known module. Following frames may be wrong.
00 0019eb94 76124f2f     00c3afc8 0019ebdc 0019ebb8 0x8c73d01
01 0019ebdc 0079451a     00c3afc8 73d82ec0 00000001 USER32!IsZoomed+0xaf
02 0019ebe4 73d82ec0     00000001 73d35d1c 00c3afc8 JXC_MED!CMainFrame::`scalar deleting destructor'+0x8
03 0019ebec 73d35d1c     00c3afc8 00000000 73d35c0f MFC42!CControlFrameWnd::PostNcDestroy+0xb
04 0019ec2c 73d31e1d     00c3afc8 00c3afc8 00cae670 MFC42!CWnd::OnNcDestroy+0x10d
05 0019eca4 73d31b07     00000082 00000000 73dca448 MFC42!CWnd::OnWndMsg+0x2f4
06 0019ecc4 73d31a78     00000082 00000000 00000000 MFC42!CWnd::WindowProc+0x22
07 0019ed24 73d319d0     00c3afc8 00000000 00000082 MFC42!AfxCallWndProc+0x91
08 0019ed44 73dbe00c     00031002 00000082 00000000 MFC42!AfxWndProc+0x34
09 0019ed70 76135cab     00031002 00000082 00000000 MFC42!AfxWndProcBase+0x39
0a 0019ed9c 761267bc     73dbdfd3 00031002 00000082 USER32!_InternalCallWinProc+0x2b
0b 0019ee80 7612635a     73dbdfd3 00000000 00000082 USER32!UserCallWinProcCheckWow+0x3ac
0c 0019eee4 76133f87     01225f90 00000000 00000082 USER32!DispatchClientMessage+0xea
0d 0019ef28 77e62add     0019ef44 00000020 0019efac USER32!__fnNCDESTROY+0x37
0e 0019ef60 73d364c5     00031002 009a034c 009a1f14 ntdll!KiUserCallbackDispatcher+0x4d
0f 0019ef74 00794760     009a8968 00000000 00c3afc8 MFC42!CWnd::DestroyWindow+0x31
10 0019efb8 73d38fb4     00c3afc8 00c3afc8 00794965 JXC_MED!CMainFrame::DestroyWindow+0x13c [MainFrm.cpp @ 852] 
11 0019efd0 02b056f3     00000000 00794a45 00c3afc8 MFC42!CFrameWnd::OnClose+0xf5
12 0019efec 007949a3     00000000 73dca64c 00000001 ToolLib!CTFrameWnd::OnClose+0x13
13 0019f044 73d31e1d     00c3afc8 00c3afc8 00cae670 JXC_MED!CMainFrame::OnClose+0x3e [MainFrm.cpp @ 1133] 

顶层两个函数调用帧都是错的,地址怪异 ,没有函数名子通过反汇编校验,根据帧返回地址是 0079451a 判断出具体函数源码位置, 

JXC_MED!CMainFrame::`scalar deleting destructor':
00794512 56             push    esi
00794513 8bf1           mov     esi, this (ecx)
00794515 e814000000     call    JXC_MED!CMainFrame::~CMainFrame (79452e) //顶层栈实际上是在调用此析构函数中的代码
0079451a f644240801     test    byte ptr [esp+8], 1
0079451f 7407           je      JXC_MED!CMainFrame::`scalar deleting destructor'+0x16 (794528)
00794521 56             push    esi
00794522 e8338c0000     call    JXC_MED!operator delete (79d15a)
00794527 59             pop     this (ecx)
00794528 8bc6           mov     eax, esi
0079452a 5e             pop     esi
0079452b c20400         ret     4
JXC_MED!CMainFrame::~CMainFrame:
0079452e b806828200     mov     eax, 828206h
00794533 e8489b0000     call    JXC_MED!__EH_prolog (79e080)
00794538 51             push    this (ecx)
00794539 51             push    this (ecx)
0079453a 56             push    esi
0079453b 8bf1           mov     esi, this (ecx)
0079453d 57             push    edi
0079453e 8975f0         mov     dword ptr [ebp-10h], esi
00794541 c70668a98800   mov     dword ptr [esi], 88A968h
00794547 8b8e58040000   mov     this (ecx), dword ptr [esi+458h]
0079454d c745fc06000000 mov     dword ptr [ebp-4], 6
00794554 85c9           test    this (ecx), this (ecx)
00794556 7407           je      JXC_MED!CMainFrame::~CMainFrame+0x31 (79455f)
00794558 8b01           mov     eax, dword ptr [this(??) (ecx)] //通过指令飞越技术查出是这里出错,代码对应 delete loadWareWork;
0079455a 6a01           push    1
0079455c ff5004         call    dword ptr [eax+4]
0079455f a150889a00     mov     eax, dword ptr ds:[009A8850h]
00794564 83780400       cmp     dword ptr [eax+4], 0
00794568 741f           je      JXC_MED!CMainFrame::~CMainFrame+0x5b (794589)
00794623 c3             ret 

CMainFrame::~CMainFrame()
{if(loadWareWork) delete loadWareWork; //这个被重复删了 导至出错if (gpDb->IsOpen()){WriteOpLog(gpDb, gstrOprCode, GSP_OPLOG_MODULEID, "2", "退出系统"); }
}

在内存窗口中查看此变量周围已经被16进制 feee feee填充,看我博文 Microsoft平台开发,内存特征码识别有讲述通过16进制分辨内存数据,说明此内存区已经被heap free.

图1:指令飞越技术重现@eip内存地址 0x8c73d01

解决办法,将这段代码删掉,此处多余的代码,理由是此类型是CWnd子类。不及格的程序员-八神
创建时使用WS_CHILD类型创建,它会随着父窗体自动DESTORY, 并且子类重载函数 PostNcDestroy 并 delete this了,不需要这里再次delete。 

 


http://www.ppmy.cn/news/1028182.html

相关文章

基于centos7.9通过nginx实现负载均衡以及反向代理

摘要:负载均衡: 负载均衡是一种技术,用于在多个服务器之间分发传入的网络流量,以平衡服务器的负载,提高系统的可用性和性能。当您有多台服务器时,您可以使用负载均衡将请求分发到这些服务器上,从…

Linux-C++开发项目:基于主从Reactor模式的高性能并发服务器

目录 1.项目介绍2.1项目部署2.2安装版本较高的编译器 2.项目开发过程2.1网络库模块开发2.1.1简单日志宏的实现2.1.2Buffer模块实现2.1.3Socket模块实现2.1.4Channel模块实现2.1.5Poller模块实现2.1.6TimerWheel模块实现2.1.7EventLoop模块实现2.1.8整合测试12.1.9LoopThread模块…

Nacos AP架构集群搭建(Windows)

手写SpringCloud项目地址,求个star github:https://github.com/huangjianguo2000/spring-cloud-lightweight gitee:https://gitee.com/huangjianguo2000/spring-cloud-lightweigh 目录: 一:初始化MySQL 二:复制粘贴三份Nacos文…

【实战讲解】数据血缘落地实施

‍在复杂的社会分工协作体系中,我们需要明确个人定位,才能更好的发挥价值,数据也是一样,于是,数据血缘应运而生。 今天这篇文章会全方位的讲解数据血缘,并且给出具体的落地实施方案。 一、数据血缘是什么…

有关JSON的处理

JSON:(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript(欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读…

Mysql中插入数据,并返回自增主键的值

创建数据库和表使用 insert into 进行插入数据使用 RETURN_GENERATED_KEYS 进行返回插入的这条数据 具体方法如下: Testvoid addGetPk(){try{Statement stmt conn.createStatement();String sql String.format("insert into t_students values(null,%s,%s,%d…

k8s node 误删除了如何自动创建 csr重新加入集群

worker node 节点当部署晚 kubelet、kube-proxy就会加入集群,如何加入呢, [rootkube-node01 ssl]# mv kubelet-client-2023-08-13-01-19-00.pem kubelet-client-current.pem kubelet.crt kubelet.key /tmp/kubelet [rootkube-node01 ssl]# systemctl da…

Faker库详解 - Python中的随机数据生成器

文章目录 Faker介绍Faker安装Faker使用基本使用方法随机生成人物相关的基础信息随机生成地理相关的信息随机生成网络相关的信息随机生成日期相关的信息随机生成数字/字符串/文本随机生成列表/元组/字典/集合/迭代器/json随机生成文件相关的信息随机生成颜色/表情每次请求获取相…