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

目录

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、最后

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

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

5.6.webrtc三大线程

那今天呢?我们来介绍一下web rtc的三大线程,那为什么要介绍这三大线程呢?最关键的原因在于web rtc的所有其他线程都是由这三大线程所创建的。那当我们将这三个线程理解清楚之后呢?我们就知道其他线程与它们之间是怎样关系&#xf…

PDF怎么转成PPT文件免费?一个软件解决

随着科技的不断发展和进步,电子文档已经成为我们日常工作和学习中不可或缺的一部分。PDF作为一种跨平台的文件格式,以其可靠性和易读性而备受推崇。然而,在某些情况下,我们可能需要PDF怎么转成PPT文件免费,以便更好地展…

day24

复制目录到指定路径 file-App下的src目录复制到 D:/aaa public static void copy(File src, File dest) throws IOException {//0. 创建出目标路径if (!dest.exists()){dest.mkdirs();}//0.0 判断dest是否存在,如果不存在,创建爱你出来,不能复…

糖尿病视网膜病变,黄斑病变,年龄相关检测研究(Matlab代码)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

DataWindowHTTP在linux环境的安装和测试

DataWindowHTTP在linux环境的安装和测试 *此非必要文档,如果在window环境使用,则无需参考。对于linux os,apache,php安装熟悉的朋友,也无需参考此文档的安装部分,只需要参考配置部分即可。 *最后修改日期…

图片怎么转换成pdf格式?可以试试这样转换

图片怎么转换成pdf格式?图片转换成PDF格式是一个常见的需求,无论是为了方便存储还是为了分享文件,将图片转换成PDF格式都是一个不错的选择。有许多软件和在线工具可以帮助你完成这个任务,下面就给大家介绍一款转换工具。 【迅捷PD…

两款开箱即用的Live2d

目录 背景第一款:开箱即用的Live2d在vue项目中使用html页面使用在线预览依赖文件地址配置相关参数成员属性源码 模型下载 第二款:换装模型超多的Live2d在线预览代码示例源码 模型下载 背景 从第一次使用服务器建站已经三年多了,记得那是在2…

统一git使用方法,git状态变迁图,git commit提交规范

目录 说明 统一git使用方法 git状态变迁图 git commit 提交规范 说明 多次工作中多名员工不懂git多次技术分享,自行查资料学习git并使用,会出现使用各种偏僻的命令,异常问题无法解决;或出现带url的git合并提交。主要是学的不…

抖音短视频矩阵系统源码开发搭建技术开源分享

前言:抖音矩阵号/抖音短视频SEO矩阵系统源码开发,优化排名。 短视频获客系统支持短视频智能剪辑、短视频定时发布,短视频排名查询及优化,智能客服等,那么短视频seo系统开发时需要开发哪些功能呢?今天我就跟…

【CSS Grid网格布局】常用属性,示例代码解读

Grid布局是一种二维布局系统,可以将页面划分为行和列,并将元素放置在这些行和列的交叉点上。以下是Grid布局的一些常用属性: grid-template-columns/grid-template-rows:用于定义网格的列和行的大小和数量。可以指定具体的尺寸值…

STP知识总结

目录 生成树协议 导致问题 生成树 存在算法 1、802.1D 接口状态 收敛时间 结构变化 802.1D 缺点 2、PVST cisco私有 3、PVST 缺点 4、快速生成树 快速原理 边缘接口 5、MSTP/MST/802.1S 生成树协议 生成树协议是一种工作在OSI网络模型中第二层(数据链路层…

(排序) 剑指 Offer 51. 数组中的逆序对 ——【Leetcode每日一题】

❓剑指 Offer 51. 数组中的逆序对 难度:困难 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。 示例 1: 输入: [7,5,6,4] 输出: 5 限制&#xff…

生产环境下的终极指南:使用 Docker 部署 Nacos 集群和 MySQL

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

3种清除logo的方法,使其干净整洁 自然无痕

信息爆炸的时代,我们每天都和图片打交道经常会遇到一些带有水印的图片。这些水印可能是品牌的标志或者是版权信息,但有时候它们会干扰到我们对图片的欣赏和使用。那么,怎么去掉图片logo水印呢? 毕竟影响图片美感,使用也不方便&a…

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

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

七夕节日表白:七大网页风格与其适用人群

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

【Spring Boot】JdbcTemplate数据连接模板 — 使用JdbcTemplate操作数据库

使用JdbcTemplate操作数据库 成功在Spring Boot项目中集成JdbcTemplate后,如何使用JdbcTemplate数据库连接模板操作数据库呢?接下来以示例演示JdbcTemplate实现学生信息的增、删、改、查等操作,让我们在实践中边学边用,更好地理解…

【算法刷题之数组篇(2)】

目录 1.leetcode-35. 搜索插入位置(简单)2.leetcode-74. 搜索二维矩阵(中等)3.leetcode-73. 矩阵置零(中等)4.leetcode-56. 合并区间(中等)5.leetcode-54. 螺旋矩阵(中等…

opencv进阶11-LBPH 人脸识别(人脸对比)

人脸识别的第一步,就是要找到一个模型可以用简洁又具有差异性的方式准确反映出每个人脸的特征。识别人脸时,先将当前人脸采用与前述同样的方式提取特征,再从已有特征集中找出当前特征的最邻近样本,从而得到当前人脸的标签。 OpenC…

电子电路学习笔记之SA1117BH-1.2TR——LDO低压差线性稳压器

关于LDO调节器(Low Dropout Regulator)是一种电压稳压器件,常用于电子设备中,用于将高电压转换为稳定的低电压。它能够在输入电压和输出电压之间产生较小的差异电压,因此被称为"低压差稳压器"。 LDO调节器通…