根据发生异常的汇编指令以及函数调用堆栈,从内存的角度出发,估计出问题的可能原因,确定排查方向,快速定位C++软件问题

目录

1、前言

2、初步分析dump文件

3、加载更多模块的pdb文件,可能能看到更多行的函数调用堆栈

4、从内存的角度去看,估计是访问了野指针导致的,沿着这个怀疑的方向快速地定位了问题

5、最后


C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/125529931C/C++实战专栏(专栏文章已更新460多篇,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/140824370C++ 软件开发从入门到精通(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/category_12695902.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/category_2276111.html       最近在项目中遇到了一个崩溃问题,取来dump文件,用Windbg打开分析,查看函数调用堆栈,将堆栈对照着源码分析,并没有发现明显的问题,找不到问题排查的切入点或线索。后来查看发生异常的那条汇编指令,并对照着异常时函数调用堆栈中调用的函数,从内存的角度出发,大概估计出了可能的原因,确定了一个大致的方向,然后按照这个方向快速定位了问题本文分享一下这个问题的大概排查思路与过程,以供借鉴或参考。

1、前言

       当我们查看崩溃时的函数调用堆栈,如果最终崩溃在系统库或第三方开源库中,一般不是系统库或第三方开源库有问题,是上层的业务库有问题导致的。有时也会崩溃在项目中常用的通用库中,通用库可能用了好几年了,基本是不会发生崩溃的,所以问题一般也是发生在上层模块中,应该从上层模块入手进行排查。

       此外,C++软件中的异常或崩溃,大多都是与内存相关的,比如访问空指针或野指针、内存越界、内存泄漏、线程栈溢出、堆内存被破坏、内存不足等。所以我们分析问题时,尽量从内存的角度出发(C++软件异常大部分都是与内存相关的),尝试着估计原因,寻找线索,沿着估摸的方向去分析,可能很快就能定位问题。

       今天讲的这个实例,就是从内存的角度去看,根据发生异常的那条汇编指令以及异常时的函数调用堆栈,从内存的角度出发,估计可能是访问了野指针(指针指向的内存地址已经被释放了)引发的,然后沿着这个方向分析,快速地定位了这个问题。

2、初步分析dump文件

       程序崩溃时,程序中安装的异常捕获模块感知到了,并自动生成了dump文件。取来了dump文件,用Windbg打开,使用.ecxr命令切换到发生异常的那个线程,然后使用kn命令查看函数调用堆栈。根据堆栈中涉及到的模块,确定要去拿哪些模块的pdb文件,使用lm查看模块的时间戳,根据时间戳到保存软件版本的文件服务器上找到pdb文件(我们的软件版本统一放到文件服务器上保存的)。

        将pdb文件的路径设置到Windbg中,然后输入.ecxr命令切换到发生异常的线程:

当前发生的是0xc0000005内存访问违例的异常,即访问了不该访问的内存。于是查看发生崩溃的那条汇编指令,如上所示,这条汇编指令中访问了0x352ba8f0,是访问这个内存地址产生的异常,但这个内存地址没有明显的异常。0x352ba8f0既不是访问空指针时的很小的内存地址(地址位于0-64KB范围的,禁止访问),也不是很大的内核态内存地址(用户态的代码禁止访问内核态的地址)所以从这条崩溃的汇编指令中没有看出明显的异常。


        在这里,给大家重点推荐一下我的几个热门畅销专栏,欢迎订阅:(博客主页还有其他专栏,可以去查看)

专栏1:该精品技术专栏的订阅量已达到530多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!欢迎订阅!)

C++软件调试与异常排查从入门到精通系列文章汇总icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据多年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法,详细讲述了C++软件的调试方法与手段,以图文并茂的方式给出具体的项目问题实战分析实例(很有实战参考价值),带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

考察一个开发人员的水平,一是看其编码及设计能力,二是要看其软件调试能力!所以软件调试能力(排查软件异常的能力)很重要,必须重视起来!能解决一般人解决不了的问题,既能提升个人能力及价值,也能体现对团队及公司的贡献!

专栏中的文章都是通过项目实战总结出来的,包含大量项目问题实战分析案例,有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2:(本专栏涵盖了C++多方面的内容,是当前重点打造的专栏,订阅量已达170多个,专栏文章已经更新到460多篇,持续更新中...)

C/C++实战进阶(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与项目实战进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域多个方面的内容,包括C++基础及编程要点(模版泛型编程、STL容器及算法函数的使用等)、数据结构与算法、C++11及以上新特性(不仅看开源代码会用到,日常编码中也会用到部分新特性,面试时也会涉及到)、常用C++开源库的介绍与使用、代码分享(调用系统API、使用开源库)、常用编程技术(动态库、多线程、多进程、数据库及网络编程等)、软件UI编程(Win32/duilib/QT/MFC)、C++软件调试技术(排查软件异常的手段与方法、分析C++软件异常的基础知识、常用软件分析工具使用、实战问题分析案例等)、设计模式、网络基础知识与网络问题分析进阶内容等。

专栏3:  

C++常用软件分析工具从入门到精通案例集锦汇总(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/131405795

常用的C++软件辅助分析工具有SPY++、PE工具、Dependency Walker、GDIView、Process Explorer、Process Monitor、API Monitor、Clumsy、Windbg、IDA Pro等,本专栏详细介绍如何使用这些工具去巧妙地分析和解决日常工作中遇到的问题,很有实战参考价值!

专栏4:   

VC++常用功能开发汇总(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/124272585

将10多年C++开发实践中常用的功能,以高质量的代码展现出来。这些常用的高质量规范代码,可以直接拿到项目中使用,能有效地解决软件开发过程中遇到的问题。

专栏5: 

C++ 软件开发从入门到精通(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/category_12695902.html

根据多年C++软件开发实践,详细地总结了C/C++软件开发相关技术实现细节,分享了大量的实战案例,很有实战参考价值。


3、加载更多模块的pdb文件,可能能看到更多行的函数调用堆栈

       在没加载pdb文件或者加载部分pdb文件时,可能看到的函数调用堆栈比较少,但加载更多的pdb文件之后,可能可以看到更多行的函数调用堆栈这样可能更有利于问题的排查。这个现象,我们在项目中多次遇到了,比如设置系统库的pdb在线下载地址(微软系统库pdb文件下载服务器)后,可能能看到更多行的函数调用堆栈。

       本案例中也遇到了,最开始只取了部分模块的pdb文件,只能看到6行函数调用堆栈,如下所示:

图中的config.dll模块没有加载pdb文件,后来根据lm命令显示的时间戳:

到文件服务器上找来了对应时间点的pdb文件。在Windbg加载到这个pdb文件之后,使用kn命令重新查看函数调用堆栈:

明显看到,调用堆栈中多了很多行。行数越多越详细,越有利于问题的排查。

       此外,有时路径下有没有模块的二进制文件,可能对函数调用堆栈也有一定的影响,我们在项目中遇到过。

4、从内存的角度去看,估计是访问了野指针导致的,沿着这个怀疑的方向快速地定位了问题

       发生异常时的函数调用堆栈如下所示:

从堆栈的最上面可以看出,程序崩溃在directui.dll模块中。这个directui.dll库,我们用了很多年了,一直比较稳定。虽然最终崩溃在directui.dll库中,但一般问题都出在上层的模块中(应该从上层模块去入手排查),到上层模块config.dll中去查找原因。

       我们再来看崩溃的这条汇编指令:

汇编指令中访问了0x352ba8f0内存地址,产生了内存访问违例,但这个内存地址没有看出明显的异常。0x352ba8f0既不是访问空指针时的很小的内存地址(地址位于0-64KB范围的,禁止访问),也不是很大的内核态内存地址(用户态的代码禁止访问内核态的地址)。

       我们知道,很多内存访问违例的问题,可能是访问空指针或野指针触发的。访问空指针时,会访问很小的内存地址,地址位于0-64KB之内的内存地址是禁止访问的,会触发内存访问违例。访问野指针,就是访问已经释放的内存区域,一般也会触发内存访问违例,因为内存已经释放。

事实上,访问已经释放的内存,不一定会触发内存访问违例。这个要看系统的脸色,系统允许你访问,就不会引发访问违例;系统不允许你访问,就会触发访问违例。

       既然不是访问空指针引发的内存访问违例,那怀疑可能是访问了野指针导致的。崩溃的汇编指令位于directui库的CDuiImage::GetBits接口中,崩溃在访问当前CDuiImage类的数据成员产生的崩溃,所以当前这个CDuiImage对象有问题,而根据崩溃时的函数调用堆栈:

这个CDuiImage对象是依附在上层的CCfgServerContainDlg窗口类对象中的,所以应该是这个CCfgServerContainDlg窗口类对象有问题。于是根据函数调用堆栈,去查看C++源码,照着访问野指针的思路去阅读与问题相关的源码上下文。最后看下来发现,果然是野指针导致的。本案例主要讲述排查思路、方法及相关细节要点,具体问题代码的排查过程就不在此展开了。

       正是沿着访问野指针的思路去排查代码,快速地定位了问题,所以排查方向很重要,比漫无目的地查看源码要好很多。所以在遇到问题时,我们可以根据现有的信息及现象,估计出一个或多个可能的排查方向,然后沿着这些方向去逐一的排查。

5、最后

       引发本案例问题的原因,并不复杂,但排查的思路和过程却有一定的参考价值。在排查过程中涉及到的一些细节和知识点是值得关注和推敲的。所以在此将相关内容分享出来,以供大家借鉴或参考。

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

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

相关文章

力扣OJ算法题:合并两个有序链表

—————————————————————————————————————————— 正文开始 OJ算法题:合并两个有序链表 思路 创建一个新的空链表(可以用malloc优化)和两个指针L1、L2分别指向两个链表,遍历两个链表&am…

taro底部导航,Tabbar

没有特别的幸运,那么就特别的努力!!! 配置信息 官方给出: 在 app.config 中按正常填写 tabBar 项的相关配置(为了向下兼容),并把 tabBar 项的 custom 字段设置为 true。但我试过 c…

Chromium 中chrome.contextMenus扩展接口实现分析c++

一、chrome.contextMenus 使用 chrome.contextMenus API 向 Google Chrome 的上下文菜单中添加项。您可以选择从右键菜单中添加的对象类型,例如图片、超链接和页面。 权限 contextMenus 您必须在扩展程序的清单中声明 "contextMenus" 权限&#xff0c…

R语言机器学习算法实战系列(十二)线性判别分析分类算法 (Linear Discriminant Analysis)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍LDA的原理LDA的步骤教程下载数据加载R包导入数据数据预处理数据描述数据切割构建模型预测测试数据评估模型模型准确性混淆矩阵模型评估指标ROC CurvePRC Curve保存模型总结优点:缺…

Ubuntu(22.04)本地部署Appsmith

Ubuntu(22.04)安装Appsmith 简要介绍 Appsmith 是一个开源的低代码开发平台,旨在帮助开发者和非开发者快速构建定制化的内部应用程序和管理工具。通过直观的拖拽界面和丰富的预配置组件,Appsmith 让用户无需编写大量代码即可创建…

Postman使用-基础篇

前言 本教程将结合业界广为推崇和使用的RestAPI设计典范Github API,详细介绍Postman接口测试工具的使用方法和实战技巧。 在开始这个教程之前,先聊一下为什么接口测试在现软件行业如此重要? 为什么我们要学习Postman? 现代软件…

数据轻松上云——Mbox边缘计算网关

随着工业4.0时代的到来,工厂数字化转型已成为提升生产效率、优化资源配置、增强企业竞争力的关键。我们凭借其先进的边缘计算网关与云平台技术,为工厂提供了高效、稳定的数据采集与上云解决方案。本文将为您介绍Mbox边缘计算网关如何配合明达云平台&…

React 基础阶段学习计划

React 基础阶段学习计划 目标 能够创建和使用React组件。理解并使用State和Props。掌握事件处理和表单处理。 学习内容 环境搭建 安装Node.js和npm 访问 Node.js官网 下载并安装最新版本的Node.js。打开终端或命令行工具,输入 node -v 和 npm -v 检查是否安装…

【Python】爬虫

Python爬虫是一种自动化下载网页内容的程序。以下是一个简单的Python爬虫示例,使用requests库获取网页,并用BeautifulSoup解析网页。 首先,你需要安装必要的库: pip install requests pip install beautifulsoup4 以下是一个简…

基于SpringBoot微信小程序的书院预约系统【附源码】

基于SpringBoot微信小程序的书院预约系统 效果如下: 微信小程序首页界面 用户登录界面 书院信息界面 会议室界面 管理员登录界面 管理员主界面 用户界面 书院信息界面 会议室界面 会议室预约界面 研究背景 随着社会的快速发展,计算机技术的影响是全面…

SpringBoot 单元测试 - 登录认证在 Spring Boot 上的标准单元测试写法。

👉 请投票支持这款 全新设计的脚手架 ,让 Java 再次伟大! 不要使用 SpringBootTest 使用 SpringBootTest 进行单元测试会启动整个 Spring Boot 容器,并引入整个项目的 development&test 依赖。缺点是速度慢、体积大、测试目标…

HarmonyOS Next应用开发——图像PixelMap变换

【高心星出品】 图像变换 图片处理指对PixelMap进行相关的操作,如获取图片信息、裁剪、缩放、偏移、旋转、翻转、设置透明度、读写像素数据等。图片处理主要包括图像变换、位图操作,本文介绍图像变换。 图形裁剪 // 裁剪图片 x,y为裁剪的起…

【element-tiptap】如何把分隔线改造成下拉框的形式?

当前的分隔线只有细横线这一种形式 但是咱们可以看一下wps中的分隔线,花里胡哨的 这些在wps里都需要使用快捷键打出来,真没找到菜单在哪里 那么这篇文章咱们就来看一下如何改造分隔线组件,改造成下拉框的形式,并且把咱们想要的分…

如何调试浏览器中的内存泄漏?

聚沙成塔每天进步一点点 本文回顾 ⭐ 专栏简介⭐ 如何调试浏览器中的内存泄漏?1. 什么是内存泄漏?2. 调试内存泄漏的工具3. 如何使用 Memory 面板进行内存调试3.1 获取内存快照(Heap Snapshot)获取内存快照的步骤:快照…

【ShuQiHere】深入解析数字电路中的锁存器与触发器

深入解析数字电路中的锁存器与触发器 🤖🔌 在数字电路设计中,**锁存器(Latch)和触发器(Flip-Flop)**是实现时序逻辑的基本元件。它们能够存储状态,是构建复杂数字系统的关键。本文将…

Dockerfile 中关于 RUN 的奇怪写法 -- 以 | 开头

在一个大型的官方镜像中 &#xff0c;我通过 docker history --no-trunc <image_id> 看到&#xff0c;该镜像某一步的构建过程是&#xff1a; RUN |3 CUDA_VERSION12.4.1.003 CUDA_DRIVER_VERSION550.54.15 JETPACK_HOST_MOUNTS /bin/sh -c if [ -n "${JETPACK_HOS…

如何自定义一个自己的 Spring Boot Starter 组件(从入门到实践)

文章目录 一、什么是 Spring Boot Starter&#xff1f;二、为什么要自定义 Starter&#xff1f;三、自定义 Starter 的基本步骤1. 创建 Maven 项目2. 配置 pom.xml3. 创建自动配置类4. 创建业务逻辑类5. 创建 spring.factories 四、使用自定义 Starter五、总结推荐阅读文章 在使…

Android广播限制Background execution not allowed: receiving Intent { act=

“Background execution not allowed: receiving Intent”这个错误信息通常出现在Android应用开发中&#xff0c;特别是在处理后台任务或接收广播&#xff08;Broadcast&#xff09;时。这个错误表明应用试图在后台执行某些操作&#xff0c;但Android系统出于电池优化和用户体验…

【二刷hot100】day 4

终于有时间刷刷力扣&#xff0c;求实习中。。。。 目录 1.最大子数组和 2.合并区间 3.轮转数组 4.除自身以外数组的乘积 1.最大子数组和 class Solution {public int maxSubArray(int[] nums) {//就是说可以转换为计算左边的最大值&#xff0c;加上中间的值&#xff0c…

1.6,unity动画Animator屏蔽某个部位,动画组合

动画组合 一边跑一边攻击 using System.Collections; using System.Collections.Generic; using UnityEngine;public class One : MonoBehaviour {private Animator anim;// Start is called before the first frame updatevoid Start(){anim GetComponent<Animator>();…