内存越界引发线程函数调用堆栈回溯异常以及INT 3软中断实战分析案例分享

目录

1、问题说明

2、导出dump文件时只是遇到了INT 3软中断,并没有发生异常崩溃

3、函数中发生了栈内存越界,导致线程的栈回溯出异常,堆栈中只显示一行函数调用记录

3.1、处理Json数据时产生了异常

3.2、函数中发生栈内存越界,可能会导致线程的栈回溯出异常

3.3、将打印出来的Json数据与代码对照起来看,发现是数组越界了(栈内存越界)

4、遇到INT 3中断,可能此时代码出现了问题,可以查看此时的函数调用堆栈(附上INT 3软中断的详细说明)

5、最后


C++软件异常排查从入门到精通系列教程(核心精品专栏,订阅量已达8000多个,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C/C++实战专栏(重点专栏,专栏文章已更新500多篇,订阅量已达6000多个,欢迎订阅,持续更新中...)https://blog.csdn.net/chenlycly/article/details/140824370C++ 软件开发从入门到实战(重点专栏,专栏文章已更新300多篇,欢迎订阅,持续更新中...)https://blog.csdn.net/chenlycly/category_12695902.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_2276111.html       近日项目中遇到了一个比较有代表性的软件异常案例,其中有两点值得关注,一是在崩溃前先产生了INT 3软中断(系统模块中人为添加了INT 3软中断),二是代码中发生了栈内存越界导致线程栈回溯出异常。本文来详细讲述一下该案例的排查过程以及涉及到的这两个要点,以供大家借鉴或参考。

1、问题说明

       测试同事那边反馈了一个崩溃,但软件中安装的异常捕获模块并没有感知到,没有生成dump文件。这个问题在当前场景下是必现的,于是测试同事直接将Windbg附加到目标进程上进行调试,然后复现问题,尝试通过动态调试的Windbg去感知并捕获异常。

       问题复现后,Windbg中断下来,测试同事输入kn命令将此时的函数调用堆栈打印出来,然后将堆栈截图发到讨论群中:

然后用.dump命令从当前正在调试的Windbg中导出了dump文件,将dump文件发给我。

       取到dump文件后,用Windbg打开,输入.ecxr切换到异常上下文,然后输入kn,打印出来的堆栈只显示一行,如下所示:

这行中调用的是系统库接口(ntdll库中的RtlCaptureStackContext接口),并没有看到我们软件业务模块的接口调用,这点很奇怪。

2、导出dump文件时只是遇到了INT 3软中断,并没有发生异常崩溃

        后来看到讨论群里的截图,截图中可以看到当时只是产生了一个INT 3中断:

并不是崩溃,这个INT 3会让正在调试的Windbg中断下来,测试同事以为Windbg中断下来就是发生崩溃了(测试同事只会简单地使用Windbg,对于一些细节不了解),于是导出了dump文件。所以后面我们拿到dump文件后,使用.ecxr和kn命令并没看到有效的函数调用堆栈,只能看到系统库接口的调用。

       因为这个问题是必现的,我这边想直接用Windbg抓一次,抓一次发生异常崩溃时的dump。我先将软件运行起来,然后将Windbg附加到软件进程上,让测试同事把问题复现出来。问题复现时,先产生了一个INT 3中断:

输入g命令将这个中断跳过去,然后就发生了Access Violation内存访问违例的异常(此时才发生异常崩溃),于是用.dump命令导出了dump文件。

因为Windbg动态调试时非常卡,根本没法输入命令,使用事先拷贝好的.dump命令导出了dump文件。

       关于如何使用Windbg静态分析dump文件如何使用Windbg动态调试目标进程何时使用Windbg静态分析及何时动态调试以及使用Windbg分析问题的诸多细节与技巧,我在此就不赘述了,可以查看我之前写的专题文章:
使用Windbg分析dump文件定位软件异常的方法与操作步骤https://blog.csdn.net/chenlycly/article/details/146005441使用Windbg调试目标进程排查C++软件异常的一般步骤与要点分享https://blog.csdn.net/chenlycly/article/details/145826705何时使用Windbg静态分析?何时使用Windbg动态调试?https://blog.csdn.net/chenlycly/article/details/131806819【C++软件调试技术】使用Windbg分析软件异常时的诸多细节与技巧总结 https://blog.csdn.net/chenlycly/article/details/140742933

3、函数中发生了栈内存越界,导致线程的栈回溯出异常,堆栈中只显示一行函数调用记录

3.1、处理Json数据时产生了异常

       接下来用Windbg打开dump文件进行分析,输入.ecxr切换到发生异常的上下文,输入kn命令,结果堆栈中也只显示一行,不过这行中看到了业务模块接口的调用:

于是找到堆栈中模块的pdb文件,设置到Windbg中,重新将函数调用堆栈打印出来,可以看到函数中的具体行号,提供给该模块的维护人员,让他们详细分析一下崩溃的原因。

      点开这行前面的索引链接,显示出当前函数中相关变量的值,看到传入该函数的是Json数据,函数中要把这个Json数据要按节点读取出来,保存结构体变量中,然后投递给上层。看到Json数据,猜测可能是处理Json数据时出了异常,可能是以下原因导致的

1)在解析Json数据时产生了异常,比如平台侧修改了Json数据的格式,没通知终端侧,导致终端侧解析Json数据的代码产生了异常,这样的问题我们以前遇到过。
2)可能是Json串中某个节点的值是不正常的异常值,导致代码处理逻辑出问题。比如是个异常大的值,如果用该值作为for循环的条件,则会导致死循环。
3)Json数据中包含的数据对象个数大于本地对应的数组的个数,而本地没有判断数组是否超过长度,从而导致操作数组越界。本案例中的问题,就是这个原因导致的。下面会详细讲解本案例的这个问题场景。

3.2、函数中发生栈内存越界,可能会导致线程的栈回溯出异常

       此处堆栈中只显示一行,有些奇怪,难道是当前函数中发生了栈内存越界,直接把堆栈中保存的主调函数的ebp栈基址覆盖了(通过函数中的栈基址将函数调用堆栈回溯出来),导致线程栈回溯不出来了?经后面分析,确实是这个原因导致的。

因为栈是从大地址向小地址方向分配使用的,如果当前函数中发生在栈内存越界,是从操作的起始地址向后面的大地址方向越界,可能会越界到存放主调函数的ebp栈基址值的内存区域(篡改了栈基址值),这样会导致回溯函数调用堆栈时出现问题,所以上面只能看到当前函数的调用, 且只显示一行调用记录:

        关于函数调用的栈分布以及线程函数调用堆栈的栈回溯原理,可以查看我之前写的专题文章:
C++函数调用栈分布详解(理解多个问题的切入点)https://blog.csdn.net/chenlycly/article/details/121001096C++栈回溯原理(C++异常排查面试题)https://blog.csdn.net/chenlycly/article/details/121002139


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

专栏1:【C++软件异常与异常排查从入门到精通系列教程】该精品技术专栏的订阅量已达到10000多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,已经更新到200篇以上!欢迎订阅!)

C++软件调试与异常排查从入门到精通系列文章汇总https://blog.csdn.net/chenlycly/article/details/125529931

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

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

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

专栏2:【C/C++实战进阶】(该专栏涵盖了C++多方面的内容,是当前重点打造的专栏,订阅量已达8000多个,专栏文章已经更新到500多篇,持续更新中...)

C/C++实战进阶(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与项目实战进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域多个方面的内容,包括C++基础及编程要点(模版泛型编程、STL容器及算法函数的使用等)、数据结构与算法C++11及以上新特性(开源代码中可能会用到很多新特性(比如WebRTC开源库),日常编码中也会用到部分新特性,面试时也会频繁地涉及到,学习新特性很有必要)、常用C++开源库的介绍与使用(比如SQLite、libcurl、libwebsockets、libevent、jsoncpp/RapidJson、Redis、RabbitMQ、MongoDB、MQTT、ZooKeeper、OpenCV、FFmpeg、SDL、GStreamer、Live555、ReactOS等)、代码分享(调用系统API、使用开源库)、常用编程技术(动态库、多线程、多进程、数据库及网络编程等)、软件UI编程(Win32/duilib/QT/MFC)、C++软件调试技术(引发C++软件异常的常见原因分析与总结、排查C++软件异常的手段与方法、分析C++软件异常的基础知识、使用常用软件分析工具分析C++软件问题、多个项目实战问题分析案例分享等)、设计模式(单例模式、工厂模式、观察者模式、状态模式等)、网络基础知识与网络问题分析进阶内容(实战问题分析实例分享)等。本专栏的内容都是建立在项目实践的基础上,来源于项目实战,服务于项目实战,很有实战参考价值!

专栏3:【分析C++软件问题的实用软件与高效工具实战案例集锦】

C++常用软件分析工具从入门到精通案例集锦汇总(专栏文章,持续更新中...)https://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++常用功能代码封装】

VC++常用功能开发汇总(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/124272585

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

专栏5:【C/C++软件开发从入门到实战】(本专栏涵盖了C++多方面的内容,是当前重点打造的专栏,专栏文章已经更新到300多篇,持续更新中!欢迎订阅!) 

C++ 软件开发从入门到精通(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_12695902.html

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


3.3、将打印出来的Json数据与代码对照起来看,发现是数组越界了(栈内存越界)

       查看运行日志看到平台传过来的Json数据中某类对象有26个:

但本端存放这些对象的数组中只有10个元素(数组长度是10),如下所示:

代码中在将Json串中某对象数据保存到数组中时,没有判断数组的长度,直接将26个对象保存进来了,所以导致操作数组时越界了。该数组所在的结构体定义成局部变量,所以发生的内存越界应该是栈内存越界,然后将堆栈中存放的主调函数的ebp栈基址给覆盖了,导致栈回溯出现了问题,所以堆栈中只看到一行记录。这样引发问题的原因和现象就完全一致了,能对得上了!

4、遇到INT 3中断,可能此时代码出现了问题,可以查看此时的函数调用堆栈(附上INT 3软中断的详细说明)

       如果要查看完整的函数调用堆栈,可能产生INT 3中断时可以看到,查看此时的函数调用堆栈可能也能找到问题。

      在代码的异常分支中可以插入软中断的汇编代码_asm INT 3:

// manual breakpoint
_asm INT 3;
printt("HeLlo INT 3!\n");

当代码执行到该异常分支时就会产生INT 3软中断,所以遇到INT 3中断可能就是为了提示当前代码可能出问题了。

       关于INT 3软中断的详细说明,翻看了张银奎老师的《软件调试》一书部分章节:(这本书推荐大家看一下,要多看书、看好书!

       可能是在代码的问题分支中添加了_asm INT 3这条语句,当代码执行到该异常分支时就会产生INT 3软中断,让调试器中断下来,提示用户当前程序可能出了异常,中断下来好让用户查看此时的函数调用堆栈,然后进行分析。

5、最后

       软件中发生栈内存越界,将主调函数的ebp栈基址给改写了,导致函数调用堆栈回溯出问题,以及代码中人为加入INT 3软中断,之前很少遇到,这次算是见识到实战案例了,所以在此记录总结一下,分享给大家。

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

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

相关文章

LeetCode 240: 搜索二维矩阵 II - 算法详解(秒懂系列

文章目录LeetCode 240: 搜索二维矩阵 II - 算法详解题目描述Java解决方案算法思路核心理念为什么选择右上角?可视化演示过程示例1:查找 target 5示例2:查找 target 20 (不存在)算法分析时间复杂度空间复杂度算法优势关键要点扩展思考LeetCo…

洛谷 B4071 [GESP202412 五级] 武器强化

思考难度低,但是代码难度相对较高的题,故做个记录。首先,题目说了要花费最少的钱,所以我们每次拿最便宜的材料给武器1思想:每次都拿最便宜的材料然后考虑一下这个思想是否正确,找一下反例,每次拿…

SQL工具30年演进史:从Oracle到Navicat、DBeaver,再到Web原生SQLynx

目录 一、1990s:厂商自带的数据库工具时代 二、2000s:Navicat等商业数据库管理工具崛起 三、2010s:DBeaver等开源SQL工具兴起 四、2020s:SQLynx,Web原生数据库管理工具 五、SQL工具30年时间线对比 六、总结&…

C语言制作扫雷游戏(拓展版赋源码)

目录 引言: 三个新功能实现 1.可以选择难度或自定义 实现难点解析 代码实现(附源码) 扫雷.c game.h game.c 2.对选择位置进行标记或取消标记 一.框架 我们先理一下思路 如何构造框架 二.取消标记函数 三.标记函数 四.加入清屏,进…

Python快速入门专业版(十):字符串特殊操作:去除空格、判断类型与编码转换

目录引1.去除空格:清理字符串的实用技巧1.1 三类去空格方法:strip()、lstrip()、rstrip()1.2 实战案例:处理用户输入的空格问题2.判断类型:验证字符串内容的特性2.1 常用类型判断方法2.2 实战案例:验证用户输入的合法性…

Gamma AI:AI演示文稿制作工具,高效解决PPT框架搭建难与排版耗时问题

你做 PPT 的时候是不是也常陷入 “两难”?要么对着空白幻灯片发呆,不知道怎么搭框架 —— 比如要做 “产品季度迭代复盘”,既想放数据又想讲问题,结果页面堆得像乱炖;要么好不容易凑完内容,又花两小时调排版…

【应用案例】AI 给医用过滤器 “找茬”:3 大难点 + 全流程解决方案

【应用案例】AI 给医用过滤器 “找茬”:3 大难点 全流程解决方案🎯医用过滤器进行医疗AI检测🎯先看痛点:医用过滤器检测难在哪?🎯AI检测方案:3步实现“零漏检”1. 硬件定制:让缺陷“…

【数据库相关】TxSQL新增数据库节点步骤

TxSQL新增数据库节点步骤准备工作与注意事项具体操作步骤第 1 步:在主库上创建复制专用账号第 2 步:对主库进行锁表并获取二进制日志坐标第 3 步:备份主库数据并传输到新从库第 4 步:主库解锁第 5 步:在新从库服务器上…

Jmeter快速安装配置全指南

1、JDK安装(Java Development Kit) 1.1.JDK下载 JDK下载址: Java Downloads | Oracle (jdk-8u211-windows-x64.exe) Android 基于 Java 语言开发,所以必须安装Java环境,Java 环境分JDK 和JRE ,JDK提…

设计模式最佳实践 - 模板模式 + 责任链模式

废话不多说,直接切入正题,本篇要讲的是 模板模式 责任链模式 实践。该最佳实践本身就是一种对 责任链模式的增强,模板模式通过 父类 强耦合,预定义好 责任链 next 方法 的前后一些切面行为,优雅简洁。先上示例&#x…

Python快速入门专业版(十一):布尔值与None:Python中的“真假”与“空值”(附逻辑判断案例)

目录引言:为什么“真假”与“空值”是编程的核心逻辑1.布尔值(bool):Python中的“真”与“假”1.1 布尔值的基础特性1.2 布尔运算:and、or、not的逻辑规则代码示例:基础布尔运算进阶特性:短路求…

C++学习知识小结

1. 什么是类?什么是对象?两者之间什么关系? 类是一类事物的共同特征的抽象描述,它定义这类所有的属性和方法 可以理解为模版类本身不占用空间,它只是一种定义,描述了对象一个是什么样子、能做什么 对象是根…

9. Mono项目与Unity的关系

1.Mono项目简介 2.Mono项目与Unity是如何结合的 3.从Mono到IL2CPP演变过程1.Mono项目简介 1).定义Mono是一个自由、开源的项目, 由Xamarin现属于微软主导开发; 它的目标是创建一个一套兼容于微软.NET Framework 的跨平台工具2).核心功能a.C#编译器能将你写的C#代码编译成IL(中间…

谷歌Genie 3:让你的照片变成可以玩的游戏世界

你是否曾凝视着一张完美的旅行照片,想象着如果能走进那个画面,自由探索会是怎样一种体验?或者,你是否曾被一幅画的奇幻氛围所吸引,渴望能在那片色彩斑斓的世界里奔跑跳跃?过去,这只是白日梦。而…

Cursor 提示词探索——如何打造真正懂自己的Agent

最近看到鱼皮的Cursor提示词分享(微信公众平台),刚好之前也在做Agent开发,跟提示词打交道的多,也经常发现 ai 蠢蠢的,一点不会根据提示词设计的来,按鱼皮的分享研究了一下,写了这篇博客。 Curs…

C++ 内存模型:用生活中的例子理解并发编程

C 内存模型:用生活中的例子理解并发编程 文章目录C 内存模型:用生活中的例子理解并发编程引言:为什么需要内存模型?核心概念:改动序列原子类型:不可分割的操作内存次序:不同的同步级别1. 宽松次…

AI急速搭建网站:Gemini、Bolt或Jules、GitHub、Cloudflare Pages实战全流程!

文章目录AI急速搭建网站:Gemini、Bolt或Jules、GitHub、Cloudflare Pages实战全流程!🚀 极速建站新范式:Gemini、Bolt.new、GitHub & Cloudflare Pages 全流程实战!第一步:创意可视化与代码生成 — Goo…

Qwen2.5-VL实现本地GPTQ量化

本文不生产技术,只做技术的搬运工!! 前言 公开的Qwen2.5-VL模型虽然功能非常强大,但有时面对专业垂直领域的问题往往会出现一些莫名其妙的回复,这时候大家一版选择对模型进行微调,而微调后的模型如果直接部署则显存开销过大,这时就需要执行量化,下面将介绍执行本地GPT…

【Redis】常用数据结构之Hash篇:从常用命令到使用场景详解

目录 1.前言 插播一条消息~ 2.正文 2.1Hash与String对比 2.2常用命令 2.2.1HSET 2.2.2HGET 2.2.3HEXISTS 2.2.4HDEL 2.2.5HKEYS 2.2.6HVALS 2.2.7HGETALL 2.2.8HMGET 2.2.9HLEN 2.2.10HSETNX 2.2.11HINCRBY 2.2.12HINCRBYFLOAT 2.3内部编码 2.3.1. ziplist&…

OSPF基础部分知识点

OSPF基础 前言 路由器 根据 路由表 转发数据包,路由表项 可通过手动配置 和动态路由协议 生成。(两种生成方式)静态路由比动态路由使用更少的带宽,并且不占用CPU资源来计算和分析路由更新。当网络结构比较简单时,只需配…