程序启动时访问了未初始化的类指针引发内存访问违例导致程序崩溃的问题排查

目录

1、问题说明

2、使用Windbg动态调试去初步分析

3、使用Windbg详细分析

4、最后


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html开源组件及数据库技术(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_2276111.html       最近在联调程序的新功能时,更新了底层模块的库之后,出现了启动报错导致程序启动失败的问题。这个问题有一定的代表性,在这里给大家分享一下问题的排查过程。

1、问题说明

       当前软件的新需求基本开发完成,目前正处于调试与bug修改的过程中,因为登录当前的平台出现注册失败的问题,软件重启了几次还是有问题,于是手动将代码中的dll都换成最新的版本(拷贝终端组件整体编译的库,更新加入到版本控制的底层库),并将头文件更新成最新的。更新完成后,在VS中重新编译代码,开启调试,结果程序一启动就报错了,弹出如下的提示框:

查看此时的函数调用堆栈,显示崩溃在medaisdk.dll中,但看不到中间的模块,如下:

这个崩溃是必现的,程序始终启动不起来,导致没法继续进行业务联调。

       此外,还有个奇怪的现象,同一个release版本的软件,在一个测试同事的Win10系统上启动并没有问题,可以正常运行。但在另一个测试同事的Win7系统中一启动就崩溃,是必现的!

后来排查得知,是代码中访问了一个未初始化的指针变量(野指针)引发内存访问违例导致的。在release下,未初始化的变量值不会自动初始化,是分配内存时内存中残留的值,是随机值。
所以从Win7和Win10系统中的不同表现可以看出,两个系统的内存管理机制是有差异的,正是因为有差异,导致同一个版本的软件在两个系统中有不同的表现。


    在这里,给大家重点推荐一下我的几个热门畅销专栏:

专栏1:(该专栏订阅量接近350个,有很强的实战参考价值,广受好评!)

C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931

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

专栏中的文章都是通过项目实战总结出来的(通过项目实战积累了大量的异常排查素材和案例),有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2: 

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

以多年的开发实战为基础,总结并讲解一些的C/C++基础与进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域的多个方面的内容,同时给出C/C++及网络方面的常见笔试面试题,并详细讲述Visual Studio常用调试手段与技巧!

专栏3: 

开源组件及数据库技术icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html

以多年的开发实战为基础,分享一些开源组件及数据库技术!


2、使用Windbg动态调试去初步分析

       于是决定使用Windbg动态分析一下,看看到底是什么原因导致的。因为程序启动时就发生了崩溃,没法先启动程序再把Windbg附加上去,所以需要直接使用Windbg去启动程序,这样才能监测到程序启动过程中的异常。

       用Windbg动态启动程序,感知到了异常,查看此时的函数调用堆栈,然后找来函数调用堆栈中相关模块的pdb文件,设置到Widnbg中,重新查看函数调用堆栈,堆栈中显示了详细的函数名称和代码行号:

从函数调用堆栈得知,在程序启动时调用了终端组件终端组件业务初始化接口,然后终端组件层在创建音视频组的编解码器时产生了内存访问违例,进而产生崩溃。

       初步怀疑可能是终端组件库与音视频库mediasdk.dll版本不一致导致的,可能是mediasdk.dll的头文件修改了(修改了函数参数或者修改了结构体),只发布了dll库文件,没有发布头文件导致的。当时因为手头有很多事情要处理,没有去深究这个问题,于是尝试让音视频组重新发布mediasdk.dll库和头文件,看看发布后还没有问题。

3、使用Windbg详细分析

       但mediasdk.dll库文件和头文件重新发布后,终端组件的相关模块重新编译,然后拷贝最新的终端组件及底层的库重新编译主程序,启动调试运行,结果启动时还是报错。看来并不是版本不对导致的问题。

      于是使用Windbg启动程序,感知到异常中断,拿来pdb文件,查看详细的函数调用堆栈,和维护mediasdk.dll模块的同事一起对照代码进行详细分析。崩溃时的堆栈如下:

从堆栈中可以看出,代码崩溃在mediasdk!CVidEncWrapper::Id函数中,查看该函数的源码,该函数中只是简单地返回一个整型变量的值:

所以引发问题的点应该不在该函数中,需要沿着函数调用堆栈往上看,看调用mediasdk!CVidEncWrapper::Id接口的函数。

       另外,查看发生崩溃的这条汇编指令,首先是访问了一个内核态地址0xcdcdf001引发的内存访问违例(用户态的代码不能访问内核态的内存地址)。然后查看这条汇编指令中用到的寄存器eax,崩溃时该寄存器的值为0xcdcdcdcd。以前我讲过一些C++程序中常见的异常值0xcdcdcdcd、0xdddddddd、0xfeeefeee等,这几个异常值的说明如下:

所以第一眼看到这个0xcdcdcdcd,根据上面的含义说明,就能大概判断代码中使用了未初始化的堆内存变量,可能是mediasdk!CVidEncWrapper::Id函数所在的类对象有问题,查看这条返回整型变量的汇编指令,按讲返回成员变量的值,当前类对象地址应该是存放在ecx寄存器中的,按讲返回成员变量的值,直接使用ecx就行,为啥会使用eax寄存器呢?

       要确定这个问题很简单,直接查看汇编代码上下文就知道了。于是在菜单栏中点击 View -> Disassembly,查看汇编代码上下文:

从汇编代码就找到答案了。对于被调用函数CVidEncWrapper::Id,主调函数肯定是将CVidEncWrapper类对象的首地址通过ecx传进来的,汇编代码中先将ecx中的C++类对象首地址,拷贝到[ebp-4]栈内存上,然后又将[ebp-4]栈内存中的值拷贝到eax中,然后执行发生崩溃的这条指令,所以执行该条崩溃指令时,eax中存放的就是当前类对象的首地址。

       所以给CVidEncWrapper::Id函数传入的CVidEncWrapper对象首地址为0xcdcdcdcd,肯定使用的是一个未初始化的指针变量导致的。所以沿着函数调用堆栈,查看调用CVidEncWrapper::Id的函数mediasdk!CKdvEncoder::CKdvEncoder,这是CKdvEncoder类的构造函数。根据函数调用堆栈中显示的cpp路径及代码行号,找到对应的源码位置,如下:

这行代码是一个打印日志的宏Mc_Enter,这就是个宏,并没有看到对CVidEncWrapper::Id函数调用啊,是不是Windbg中指示的行号有问题!
我不了解音视频组的代码,音视频组维护代码的也是一个刚接手的刚毕业小哥,对代码也不熟悉。于是以“Id()”为关键字搜索,看看是哪些地方调用了CVidEncWrapper::Id函数。结果刚才的那个打印日志的宏定义中调用了:

这就对上了,说明Windbg指示的行号是没问题的。对于宏,在代码编译时会被替换成定义的内容。

       这个打印日志的宏是放置在CXXXEncoder类的构造函数的入口处,而对指针变量m pcXXXVideoEncoder的初始化放在宏的下一行,所以在宏定义中访问了没有初始化的指针变量m_pcXXXVideoEncoder,该指针变量在Debug下会被初始化为0xcdcdcdcd(指针变量的内存区域中会被填充成0xcdcdcdcd),所以将0xcdcdcdcd作为一个CVidEncWrapper类对象的首地址,调用CVidEncWrapper::Id接口去读取类中的成员变量m dwIndex的值,读成员变量m dwIndex的值,就是去读取该变量在内存中的内容,即访问该变量的内存。

       类成员变量的内存位于所在CVidEncWrapper类对象中,是相对于类对象首地址的偏移,即eax+2234h = 0xcdcdcdcd + 2234h = 0xcdcdf001,所以要读取成员变量m dwIndex的值,就是去访问该变量的内存地址0xcdcdf001中的内容,但这个地址对于32为程序,是个内核态内存地址,当前代码是用户态的代码,是不能访问内核态地址的,所以产生了内存访问违例,程序进而发生崩溃。

       解决办法是,在CXXXEncoder构造函数中将对指针变量m_pcXXXVideoEncoder初始化的代码调整到打印日志那句宏Mc_Enter代码前面去就好了。保证在使用前就被初始化。

4、最后

       当前这个问题是必现的,为啥之前没有出过问题呢?查看音视频组代码的修改记录,在打印宏Mc_Enter的定义处,修改了宏的实现代码。当时修改代码后,只在release下做了测试,没有测试Debug版本的,这个问题在Debug下是必现的。

       最开始我们说过,使用问题库的Relase软件版本(通过release安装包安装的),在Win10系统上可以正常运行的,没有暴露出问题。但这个版本在Win7上启动会直接报错的,这是Win7和Win10中的内存管理机制不同导致的。现在大部分人用的都是Win10,所以可能很难将问题暴露出来。所以有两点需要注意一下:

1)Release版本没问题,不代表Debug版本没问题;
2)Win10系统上运行没问题,不代表在其他系统(比如Win7)上运行没问题。

此外,还有两点值得注意一下:

1)通过异常值0xcdcdcdcd,初步推断出是变量未初始化引起的,然后以这个线索为切入点,快速定位问题;
2)在崩溃的那条汇编代码中,没有通过ecx去访问类中成员变量的内存,而是使用eax,查看一下CVidEncWrapper::Id函数的汇编代码就知道了。查看上下文便知道,当前类对象的首地址已经传给了eax了,所以在崩溃的额那条汇编指令中使用了eax。

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

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

相关文章

20、XSS——XSS跨站脚本

文章目录 一、XSS漏洞概述1.1 XSS简介 二、XSS漏洞分类2.1 反射型XSS2.2 存储型XSS2.3 DOM型XSS 三、XSS payload构造以及变形3.1 XSS payload构造3.2 XSS payload 变形 一、XSS漏洞概述 1.1 XSS简介 XSS被称为跨站脚本攻击(Cross-site scripting)&…

k8s volumes and data

Overview 传统上,容器引擎(Container Engine)不提供比容器寿命更长的存储。由于容器被认为是瞬态(transient)的,这可能会导致数据丢失或复杂的外部存储选项。Kubernetes卷共享 Pod 生命周期,而不是其中的容器。如果容器终止,数据…

排序的简单理解(上)

1. 排序的概念及引用 1.1 排序的概念 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作(按照我们的需求能够有序的将数据信息排列起来)。 稳定性:假…

TeeChart.NET 2023.11.17 Crack

.NET 的 TeeChart 图表控件提供了一个出色的通用组件套件,可满足无数的图表需求,也针对重要的垂直领域,例如金融、科学和统计领域。 数据可视化 数十种完全可定制的交互式图表类型、地图和仪表指示器,以及完整的功能集&#xff0c…

医疗设备智慧管理助力医院提质增效,阿基米德amp;健康界实践分享

近日,苏州阿基米德网络科技有限公司与医疗领域头部级媒体健康界,联合举办“数智为擎 提质增效——医学装备智慧管理创新发展论坛”的直播活动。 直播现场,来自上海交通大学医学院附属同仁医院、中华医学会航海医学分会、苏州阿基米德的专家们…

统信UOS_麒麟KYLINOS上使用命令行配置NTP服务器

原文链接:统信UOS/麒麟KYLINOS上使用命令行配置NTP hello,大家好啊,今天我要给大家介绍的是在统信UOS/麒麟KYLINOS操作系统上使用命令行配置NTP(Network Time Protocol)服务器的方法。在内网环境下,许多企业…

13、C++异常处理

13、c异常处理 抛出异常捕获异常未抛出异常时的流程抛出异常时的流程捕获异常匹配顺序异常说明异常处理构造函数中的异常析构函数中的异常标准库异常类 抛出异常 throw 异常对象可以抛出基本类型的对象,如:throw -1;throw "内存分配失败!";也可以抛出类类…

FreeSSL申请免费域名证书

本文详细讲解如何申请免费证书,需要先准备好域名,将服务器IP和域名绑定。 1、注册FreeSSL账号 网址: https://freessl.org/ 2、申请流程 登录后首页输入域名,然后点击Create certificate,跳转到证书申请页面。 或者…

Pytorch深度强化学习1-6:详解时序差分强化学习(SARSA、Q-Learning算法)

目录 0 专栏介绍1 时序差分强化学习2 策略评估原理3 策略改进原理3.1 SARSA算法3.2 Q-Learning算法 0 专栏介绍 本专栏重点介绍强化学习技术的数学原理,并且采用Pytorch框架对常见的强化学习算法、案例进行实现,帮助读者理解并快速上手开发。同时&#…

QGIS 加载在线XYZ地图图层

QGIS 加载在线XYZ地图图层 定义并添加必应XYZ图层 Go to Layer > Add Layer > Add XYZ Layer…Click NewName as BingMaps(as you wish)URL as http://ecn.t3.tiles.virtualearth.net/tiles/a{q}.jpeg?g1click OkSelect XYZ Connections as Bing Maps(Which you creat…

PR自动剪辑视频工具AI智能剪辑插件AutoPod

推荐一款可以提高剪辑效率,节约时间成本的AI人工智能自动剪辑视频制作工具pr插件Autopod,辅助你更快地完成视频内容的编辑工作。 Autopod 插件是一款应用于 Adobe Premiere Pro 软件的插件,用于自动剪辑。该插件能够识别和处理视频和音频素材…

飞天使-linux操作的一些技巧与知识点4

文章目录 ansible配置文件的优先级尝试开始进行操作ansible常用模块ansible 的playbook示例安装phpplaybook中变量的引用 ansible yum install -y ansible 测试是否可用 ansible localhost -m ping /etc/ansible/ansible.cfg :主配置文件,配置 ansible…

大公司求我用Kotlin写个通用爬虫模板

bug虐我千百遍,我待他如初恋。每次深夜挑灯都是我与bug较量的时间。今天我要说的就是写一个爬虫模版,自动抓取百度图片的教程,这次使用Kotlin编写的爬虫程序在Scrapy框架下完成的,如有不足欢迎指正。 首先,使用Kotlin编…

angular form 组件、双向绑定;反应式表单

1.使用双向绑定,以及angular的表单提交功能 app.moudle中引入 双向绑定 [(ngModel)]"text" ​​​​​​​ 效果 提交表单 2.反应式表单 在app.module.ts中引入在组件中引入,并放在一个变量里 在初始化时实列化这个module 定义规则 在html…

Linux:环境变量

目录 1.基本变量 2.通过代码获取环境变量 2.1 main传参 2.2 全局变量environ 2.3 系统调用getenv() 3.在脚本文件中添加环境变量 4.环境变量通常是具有全局属性 1.基本变量 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数…

商用中央空调市场分析:预计2028年将达到628亿元

商用空调一直以来都没有一个相对比较明确的概念,一直以来被认为是制冷空调市场的一个细分子行业。现在比较一致的观点是,可以纳入商用空调范畴的产品可以包括户式中央空调产品、部分传统中央空调产品以及部分家用空调。商用空调已普遍采用直流变频领先技…

泡沫玻璃市场分析:预计2028年将达到14亿美元

泡沫玻璃最早是由美国匹兹堡康宁公司发明的,是由碎玻璃、发泡剂、改性添加剂和发泡促进剂等,经过细粉碎和均匀混合后,再经过高温熔化,发泡、退火而制成的无机非金属玻璃材料。它是由大量直径为1~2毫米的均匀气泡结构组成。其中吸声…

Linux 常用命令----mktemp 命令

文章目录 基本用法实例演示高级用法注意事项 mktemp 命令用于创建一个临时文件或目录,这在需要处理临时数据或进行安全性测试时非常有用。使用 mktemp 可以保证文件名的唯一性,避免因文件名冲突而导致的问题。 基本用法 创建临时文件: 命令 mktemp 默认…

Go语言基础知识学习(一)

Go基本数据类型 bool bool型值可以为true或者false,例子: var b bool true数值型 类型表示范围int8有符号8位整型-128 ~ 127int16有符号16位整型-32768 ~ 32767int32有符号32位整型-2147783648 ~ 2147483647int64有符号64位整型uint8无符号8位整型0 ~ 255uint16…

优思学院|如何建立公司运营指标体系?如何推行六西格玛改进运营指标?

关键绩效指标 (KPI) 是测量您团队或组织朝重要商业目标进展表现如何的量化指标,组织会在多个层面使用 KPI,这视乎您想要追踪何指标而定,您可以设定全组织的、特定团队的、或甚至是个人 KPI。 良好的KPI能让公司管理者掌握组织的营运是否进度…