从业务层的代码出发,去排查通用框架代码崩溃的问题

目录

1、问题说明

1.1、Release下崩溃,Debug下很难复现

1.2、用Windbg打开dump文件,发现崩溃在通用的框架代码中

2、进一步分析

2.1、使用IDA查看汇编代码尝试寻找崩溃的线索

2.2、在Windbg中查看相关变量的值

2.3、查看最近代码的修改记录,找到了引发问题的点

2.4、该问题中需要关注的点

3、问题总结

4、最后


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N6B9https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N6B9https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章正在更新中...)icon-default.png?t=N6B9https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N6B9https://blog.csdn.net/chenlycly/category_11931267.html       有时程序可能会崩溃在通用的框架代码中,但一般不是框架代码的问题,基本都是上层业务代码有问题导致的,框架代码中可能会引用业务层管理的业务类对象,如果引用的业务类对象有问题,则可能导致框架代码出异常。今天我们就来讲一个崩溃在通用框架代码中的实例,这个问题虽然比较简单,但有很多值得思考的细节,这个实例很有价值。下面详细讲述一下该问题实例的完整分析过程,以及有哪些值得思考的点与细节。

1、问题说明

       测试同事在测试新版本软件(Release版本)时,发现在执行某个常用的操作时会发生崩溃,且问题在测试PC机上是必现的,这个功能在前几天的版本中是没问题的。

1.1、Release下崩溃,Debug下很难复现

       最近,我们的开发人员在这个功能点上做了一些修改,新增了一些需求点,但开发人员在Debug下没有复现这个崩溃,一直查不出具体的原因。

       Debug下运行没问题,Release下运行有问题,这种现象我们之前也时不时的遇到。究其原因,可能是因为Debug下和Release下的内存管理分配机制是不一样的,Debug下会额外多分配一些内存存放调试信息。也有可能是变量未初始化引起的,Debug下会对变量自动进行初始化,比如:

* 0xcccccccc : Used by Microsoft's C++ debugging runtime library to mark uninitialised stack memory
* 0xcdcdcdcd : Used by Microsoft's C++ debugging runtime library to mark uninitialised heap memory

Release下不会对变量内存进行初始化,变量的值会是分配内存时内存中残留的随机值。这些是引发程序在Debug下和Release下运行不同表现现象的常见原因。此外,也有可能测试场景有所不同,开发同事这边Debug下的场景和测试同事那边的Release下的场景有差异,所以表现出不同的现象。

1.2、用Windbg打开dump文件,发现崩溃在通用的框架代码中

       程序在发生崩溃时,程序中安装的异常捕获模块捕获到异常并自动生成了包含异常上下文信息的dump文件,测试同事让我帮忙分析一下这个问题。取来dump文件,用Windbg打开,使用.ecxr命令切换到发生异常的那个线程,然后使用kn命令查看崩溃时的函数调用堆栈,如下所示:

首先查看崩溃的那条汇编指令,汇编指令中访问了很小的内存地址,所以触发了内存访问违例,引发崩溃。像是空指针引发的,但有待于进一步确定。

       然后查看崩溃时的函数调用堆栈。和以往大部分崩溃有所不同,大部分时候函数调用堆栈中显示都是与崩溃有直接关系的业务层代码的函数调用,但这次堆栈中显示的是duilib开源库中的框架代码,和具体的业务层代码没有直接的关系,所以这个问题有着一定的隐蔽性。

       所以这个问题没法快速定位出来,并且我这边也有开发任务,没有多余的时间和精力去详细研究这个问题,于是只能让相关开发人员自行排查,想办法复现问题,并详细查看最近修改的代码,看看能否找到引发问题的点。 

2、进一步分析

       开发同事排查了,但始终找不到引发问题的代码。出问题的功能点是软件的主要功能点,一操作就崩溃,导致后续的很多功能点测试没法展开了。所以这个崩溃需要尽快解决,于是又把我拉过来,希望尽快将这个问题解决掉。

2.1、使用IDA查看汇编代码尝试寻找崩溃的线索

       函数调用堆栈都是框架中的代码,没法直接找到引发崩溃的线索,于是尝试使用IDA查看汇编代码上下文,看看为什么会产生崩溃。用IDA打开函数调用的堆栈中的模块文件,将汇编代码与C++源码对照起来看:

但看下来并没有找到有效的线索。

2.2、在Windbg中查看相关变量的值

       于是又在Windbg中尝试查看函数中相关变量的值,有时相关变量的值是排查问题的关键线索。查看CWindowWnd::__WndProc函数中相关变量的值,发现收到消息id为0xf,如下所示:

对应的消息为WM_PAINT消息(#define WM_PAINT   0x000f),为啥收到该消息会产生崩溃呢?

2.3、查看最近代码的修改记录,找到了引发问题的点

       当前出问题的这个功能点,不是我这边开发的,对相关的细节不清楚,于是让同事看svn上的修改记录,和他一起看都修改了哪些代码。

       当看到某个cpp的修改记录时,一眼看出了问题,相关代码片段如下所示:

程序在收到底层的某个消息时,会弹出一个提示框,这个提示框之前是模态的,后来应测试要求(模态框体验不好,要改成非模态的)将之改成非模态的。之前将模态框换成了非模态框,即本来是调用ShowModal显示模态框,后来改成调用ShowWindow接口显示非模态框。调用ShowModal接口时,窗口关闭时ShowModal才会返回,对应的函数中的局部变量窗口类对象CMicStateTipWnd dlg的生命周期和ShowModal接口一致,不会有问题。

       但改成ShowWindow后,窗口显示出来后,ShowWindow接口立即返回,这样就退出了当前函数,这样局部变量CMicStateTipWnd dlg的内存就自动释放了,但窗口已经创建出来了,窗口需要绘制,会产生WM_PAINT消息,就会进入到CWindowWnd::__WndProc静态函数中处理,就需要调用对应的窗口类CMicStateTipWnd对象,调用窗口类CMicStateTipWnd::HandleMessage去进行窗口的绘制刷新。但窗口类CMicStateTipWnd对象是局部变量,对象已经析构,内存已经释放引用已经释放内存的对象地址,所以就产生了崩溃。

2.4、该问题中需要关注的点

       这个地方有一点需要注意一下,特别是新人会容易混淆。

       窗口类CMicStateTipWnd对象在函数退出时自动析构销毁,但使用该类创建的窗口是不会跟着自动销毁的!窗口类对象的销毁是业务代码管理和控制的,而窗口创建成功后是操作系统管理的,窗口的销毁需要调用DestroyWindow去销毁,当然这是业务层去控制类对象与窗口的同步的!在这个问题中虽然窗口类CMicStateTipWnd对象析构了, 但窗口还在的,窗口会产生一些消息(比如本例中的WM_PAINT消息),这些消息会走到CWindowWnd::__WndProc静态函数中进行处理,当引用到CMicStateTipWnd对象,但对象已经析构了,所以导致内存访问违例,产生了崩溃!

3、问题总结

       本例中,程序崩溃在duilib界面库的框架代码中,这个通用框架用了很多年了,基本可以确定不是框架代码的问题,应该是上层业务代码的问题。在排查这类框架代码崩溃问题时,应该从上面的业务代码入手,要从业务层代码维护的窗口类对象入手,因为框架代码中会引用到业务层的类对象,如果业务层将类对象内存释放了,框架代码还访问该业务类对象,则会引发内存访问违例,引发崩溃。    

       虽然本例中涉及到的是UI界面框架,但项目代码中有使用了很多其他框架,这些框架代码可能也会出现类似的异常崩溃场景,所以对这个实例的排查思路及排查方法有参考意义。

       总之,如果程序崩溃在通用的框架代码中,一般不是框架的问题,基本都是上层业务代码的问题,应该从业务层代码入手,从框架中引用的业务层类对象入手(引用的业务层类对象是业务层维护和管理的)。比如,程序崩溃在QT库中,一般不是QT库有问题,基本都是上层业务代码的问题。再比如,崩溃在系统库或者C/C++运行时库中,不是系统库或运行时库有问题,一般都是上层业务代码有问题。可能是传入了不合法的参数,传入了不可访问的内存地址。

4、最后

        在编写代码时,要尽量考虑的全面一些,考虑尽可能多的场景,尽量将代码写的严谨缜密一点。遇到问题、排查问题时,一定要多关注细节,事后要进行积极的思考与总结。要搞清楚为什么会出问题以及问题是怎么解决的,对出问题的代码进行进一步或深入研究,要彻底搞清楚根源,这样下次再遇到类似问题代码时能快速做出反应!

       对于复杂的问题,事后要主动进行复盘,要搞清楚问题的来龙去脉(为什么会出这个问题?这个问题是如何解决的?),即便问题点所在的模块不是自己负责的,也要尽量去接触去了解。事后要积极地思考和总结,可以将以往遇到的一些问题给串联起来,将相关的知识点进行归纳,比如归纳出引发问题的常见原因积极常用的排查方法。

       细节出真知!要多关注细节,多提炼出一些值得关注和思考的点,甚至可以从一些看似简单的实例中找到一些有价值的点进行展开和总结。思考的多了,了解的技术细节和知识点就多了,可以总结的东西就越多,对一些编程问题与细节点理解的就更深刻了。在遇到新的问题时,就能在已取得的认知和积累的基础上做出快速反应,有更多更开阔的思路去排查问题。如果之前遇到的问题,后面又遇到了,或者遇到了类似的问题,依然是没有思路、没有头绪,不知从何查起,这就不应该了!

       对相关细节和编程点了解的更透彻后,能让我们在编写新的代码时能考虑的更加全面,在最开始编码时就能想到可能存在的潜在问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/47219.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SAP ABAPG开发屏幕自动生成日期的搜索帮助

代码如下: REPORT z_jason_test_f4 . TABLES: s031. PARAMETER p_spmon TYPE spmon DEFAULT sy-datum0(6) OBLIGATORY. SELECT-OPTIONS s_spmon FOR s031-spmon DEFAULT sy-datum0(6) OBLIGATORY. AT SELECTION-SCREEN ON VALUE-REQUEST…

Python面向对象植物大战僵尸

先来一波效果图 来看看如何设计游戏架构 import sysimport pygameclass BaseSprite(pygame.sprite.Sprite):def __init__(self, name):super().__init__()self.image pygame.image.load(name)self.rect self.image.get_rect()class AnimateSprite(BaseSprite):def __init__(…

C++信息学奥赛1131:基因相关性

这段代码的功能是比较两个字符串的相似度&#xff0c;并根据给定的阈值判断是否相似。 解析注释后的代码如下&#xff1a; #include <iostream> #include <string> using namespace std;int main() {double bf; // 定义双精度浮点数变量bf&#xff0c;用于存储阈…

MAC钓鱼并Root权限上线CS并权限维持,以及所有的坑如何解决

本文转载于&#xff1a;https://www.freebuf.com/articles/web/350592.html 作者&#xff1a;文鸯涂鸦智能安全实验室 制作MAC 一、下载工具 首先从github上下载CrossC2。链接&#xff1a;https://github.com/gloxec/CrossC2/releases/tag/v3.1.0。 根据你CS客户端的操作系统选…

python 打印沁园春 雪 居中对齐 文本对齐

以下是python 中使用 DebugInfo 模块居中对齐打印《沁园春・雪》的效果 引入模块 pip install DebugInfopython代码 # -*- coding:UTF-8 -*-# region 引入必要依赖 from DebugInfo.DebugInfo import * # endregion诗文 沁园春 雪 作者: 毛主席 北国风光&#xff0c;千里冰封…

Swagger2 使用

大家好 , 我是苏麟 , 今天带来Swagger的使用 . 官方文档 : 招摇文档 (swagger.io) 访问地址 : 在路径后加上doc.html 例如: http://localhost:8000/doc.html Swagger 使用 依赖 <!--Swagger依赖 核心--><dependency><groupId>io.springfox</groupId&g…

smartsofthelp 5.0 最专业的数据库优化工具,数据库配置优化,数据库高并发优化,SQL 语句优化...

下载地址:百度网盘 请输入提取码 SQL操作返回历史记录&#xff1a; 2023-08-21 20:42:08:220 输入&#xff1a;select version as 版本号 2023-08-21 20:42:08:223 输出&#xff1a;当前数据库实例版本号&#xff1a;Microsoft SQL Server 2012 - 11.0.2100.60 (X64) …

TheGem主题 - 创意多用途和高性能WooCommerce WordPress主题/网站

TheGem主题概述 – 适合所有人的TheGem 作为设计元素、样式和功能的终极 Web 构建工具箱而设计和开发&#xff0c;TheGem主题将帮助您在几分钟内构建一个令人印象深刻的高性能网站&#xff0c;而无需触及一行代码。不要在编码上浪费时间&#xff0c;探索你的创造力&#xff01…

docker优点简介和yum方式安装

一.docker简介 二.docker的优点 1.交付和部署速度快 2.高效虚拟化 3.迁移性和扩展性强 4.管理简单 三.docker的基本概念 1.镜像 2.容器 3.仓库 四.docker的安装部署 &#xff08;1&#xff09;点击容器 ​&#xff08;2&#xff09;选择docker-ce&#xff0c;根据相…

C# OpenCvSharp DNN 二维码增强 超分辨率

效果 项目 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using OpenCvSharp; using OpenCvSharp.Dnn; using OpenCvSh…

eNSP综合小实验:VRRP、MSTP、Eth-Trunk、NAT、DHCP等技术应用

完成下图要求&#xff1a; 拓扑图&#xff1a; 配置命令&#xff1a; 由于交换机日志太多不便于复制&#xff0c;所以就复制命令。大概步骤如下&#xff1a; 第一步先分配IP地址&#xff0c;在sw1和sw2上创建VLAN100用于e0/0/3口配IP&#xff0c;在sw1、sw2、sw3、sw4上创建VL…

ABAP 定义复杂的数据结构

最近有个需求是实现ABAP数据类型与JASON类型的转换。想要创建个ABAP的数据类型来接JASON类型是个挺麻烦的事。例如下面这个JASON数据&#xff0c;是个很简单的数据结构。但对ABAP来说有4层了&#xff0c;就有点复杂了。 不过ABAP的数据类型也是支持直接定义数据结构的嵌套的。如…

SpringBoot整合MongoDB(从安装到使用系统化展示)

SpringBoot整合MongoDB&#xff08;从安装到使用系统化展示&#xff09; MongoDB介绍 基础介绍 MongoDB是一种开源、面向文档的非关系型数据库管理系统&#xff08;NoSQL DBMS&#xff09;&#xff0c;它以其灵活性、可扩展性和强大的查询能力而闻名。MongoDB的设计理念是为了…

二、1.保护模式

访问外部硬件有两个方式&#xff1a; 将某个外设的内存映射到一定范围的地址空间中&#xff0c; CPU 通过地址总线访问该内存区域时会落到外设 的内存中&#xff0c;这种映射让 CPU 访问外设的内存就如同访问主板上的物理内存一样外设是通过 IO 接口与 CPU 通信的&#xff0c;…

6-1 使用函数求奇数和

分数 15 全屏浏览题目 切换布局 作者 C课程组 单位 浙江大学 本题要求实现一个函数&#xff0c;计算N个整数中所有奇数的和&#xff0c;同时实现一个判断奇偶性的函数。 函数接口定义&#xff1a; int even( int n ); int OddSum( int List[], int N ); 其中函数even将根据…

Azure如何调整虚拟机的大小

参考 https://blog.csdn.net/m0_48468018/article/details/132267096 创建虚拟机进入资源&#xff0c;点击大小选项&#xff0c;并对大小进行调整 点击如下图的cloud shell,进入Azure CLI,使用az vm resize 进行大小调整 命令中的g对应资源组&#xff0c;n对应虚拟机名称&am…

PHP“牵手”淘宝商品评论数据采集方法,淘宝API接口申请指南

淘宝天猫商品评论数据接口 API 是开放平台提供的一种 API 接口&#xff0c;它可以帮助开发者获取商品的详细信息&#xff0c;包括商品的标题、描述、图片等信息。在电商平台的开发中&#xff0c;详情接口API是非常常用的 API&#xff0c;因此本文将详细介绍详情接口 API 的使用…

【腾讯云 Cloud studio 实战训练营】云端 IDE 构建移动端H5

&#x1f431; 个人主页&#xff1a;不叫猫先生&#xff0c;公众号&#xff1a;前端舵手 &#x1f64b;‍♂️ 作者简介&#xff1a;2022年度博客之星前端领域TOP 2&#xff0c;前端领域优质作者、阿里云专家博主&#xff0c;专注于前端各领域技术&#xff0c;共同学习共同进步…

RGOS日常管理操作

RGOS日常管理操作 一、前言二、RGOS平台概述2.1、锐捷设备的常用登陆方式2.2、使用Console登入2.3、Telnet远程管理2.4、SSH远程管理2.5、登陆软件&#xff1a;SecureCRT 三、CLI命令行操作3.1、CLI命令行基础3.2、CLI模式3.3、CLI模式互换3.4、命令行特性3.4.1、分屏显示3.4.2…

多线程知识点

1.多线程 例如&#xff1a;一个短视频&#xff0c;一个线程复制管理视频&#xff0c;一个线程负责管理声音&#xff0c;一个线程负责管理弹幕 进程&#xff1a;Process,程序一旦开始运行就是是一个进程 线程&#xff1a;Thread&#xff0c;一个程序运行后&#xff0c;里面就包含…