基于开源CrashRpt与微软开源Detours技术深度改造的异常捕获库分享

embedded/2024/10/15 6:08:13/

目录

1、异常捕获模块概述

2、为什么需要异常捕获模块?

3、在有些异常的场景下是没有生成dump文件

CrashRpt%E4%BB%8B%E7%BB%8D-toc" style="margin-left:40px;">4、开源异常捕获CrashRpt介绍

CrashRpt%E7%9A%84%E6%94%B9%E8%BF%9B-toc" style="margin-left:40px;">5、对开源CrashRpt的改进


C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)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、异常捕获模块概述

       异常捕获模块是内置在程序中的,当程序发生异常,异常捕获模块感知(捕获)到,自动生成包含异常上下文的dump,文件,可能同时也会生成程序版本等信息的日志文件。事后,我们可以取来这些日志及dump文件去分析软件发生异常崩溃的原因。

       异常捕获模块一般是以函数回调的方式通知给主程序,此时主程序可以弹出相关的提示框,提示用户程序发生了异常崩溃,用户可以重新运行程序。程序中内置异常捕获模块,已经成为一种标配,大部分程序都会自带异常捕获模块。以PC版的微信为例,当微信发生崩溃时,其内置的异常捕获模块会捕获到异常并生成日志及dump文件,同时会弹出如下的发送错误报告的提示框:

提示框的下方会自动带上崩溃相关的文件,其中最后一个文件就是包含异常上下文信息的dump文件,点击确定则会将这些文件发送到腾讯远端的后台服务器上。腾讯后台的运维人员会收到通知,然后到服务器上将dump等文件下载下去分析。

       有些软件可能没有上传崩溃日志到服务器的功能,捕捉到异常时会自动将dump文件保存到指定的路径中,事后可以到该路径中取到对应的dump文件。如果客户机器上遇到崩溃,可以和客户联系,让客户帮忙从对应的路径中取来出dump文件发过去。

2、为什么需要异常捕获模块?

       在日常项目开发维护的过程中,会遇到这样那样的异常崩溃,分析这些异常崩溃最常用、最重要的途径就是事后分析异常发生时生成的dump文件

       要分析软件异常崩溃,首先要有dump文件,那包含异常上下文信息的dump文件是如何生成的呢?以前我们讲过生成dump文件的三种方式:

1)通过内置的异常捕获模块,去捕获软件发生的异常崩溃,自动生成包含异常上下文的dump文件。这是生成dump文件最常用的方式。
2)可以在动态调试的Windbg中,使用.dump命令手动导出包含异常上下文信息的dump文件。为啥要导出dump文件呢?既然Windbg在动态调试,为啥不能直接分析呢?在条件允许的情况下可以直接在Windbg中分析,但一时半会分析不出来问题时或者不能长时间占用用户的电脑时,就需要导出dump文件,供事后分析了。
3)可以从Windows任务管理中导出dump文件。在任务管理器的进程列表中找到目标进程,右键点击,在弹出的右键菜单中点击导出转储文件即可。这种方式首先要求出问题的程序进程还存活着的(进程还在的),比如程序发生卡死、死循环或者程序弹出报错提示框时(弹出报错提示框时,如果不点击提示框中的按钮将提示框关闭掉,则程序进程还在的)。

其中,通过异常捕获模块去生成dump文件,是最常用的一种方式。事后分析dump文件,也是我们分析和排查软件异常崩溃问题最常用的方法。

       关于dump文件及生成方式的详细说明,可以查看我之前写的文章:

dump文件类型与dump文件生成方法详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/127991002       有人可能会说,遇到问题,我直接使用IDE去调试不就行了,我不需要什么dump文件的!如果这样说,只能说其处理异常问题的经验太有限了!因为有些问题可能是很难复现的,或者问题只在客户的环境中复现,这样也就无从去调试代码了。再就是程序中有多个模块,不同的模块由不同的开发组负责,如果程序崩溃在底层的模块中,还需要底层去调试代码。底层模块的开发人员需要搭建调试环境,然后使用附加到进程的方式去调试代码。

       如果在程序中安装了异常捕获模块,在程序发生异常时自动生成包含异常上下文的dump文件,我们直接将dump文件取来分析就好了,就不用老想着如何去复现问题了。直接使用Windbg静态分析dump文件,查看发生异常的那条汇编指令以及发生异常的函数调用堆栈,一般就能快速地定位问题了,可以有效地提高我们排查问题和解决问题的效率。

当然,并不是说有了dump文件,就一定不需要复现问题了。在个别情况下,通过分析dump文件很难排查出问题时,可以尝试去复现问题(找到复现问题的操作规律),找到问题发生的场景,这样可能去辅助分析问题的。所以有时候,为了排查分析问题,我们需要使用多种手段与方法的!


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

专栏1:(该专栏订阅量已达到420多个,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!)

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

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


3、在有些异常的场景下是没有生成dump文件

       即便程序中安装了异常捕获模块,在某些异常的场景下,可能也是没有生成dump文件的。这里面是有多种原因的。

       首先,异常捕获模块不是万能的,只能捕捉(感知)到大部分的异常,但不能捕获所有的异常,这和异常捕获模块的捕获机制的缺陷有关。其次,可能在生成dump文件时产生了二次崩溃,生成的dump文件是空的。对于没有生成dump文件的场景,就只能尝试Windbg的动态调试了,将Windbg附加到目标进程上,和目标进程一起跑,一旦程序发生异常,作为正在调试的调试器Windbg,会第一时间感知到并中断下来,此时去查看函数调用堆栈去分析就好了。

       再者就是,程序只是发生了闪退,但程序没有发生异常崩溃。比如我们在项目中遇到的两个典型的场景,一个是在用开源库jsoncpp时错误地解析json串中的字段类型时,jsoncpp发现类型错误,就直接认为是致命的,直接调用abort接口将进程终止了。还有一个场景是,我们在使用开源库WebRTC时,当调用malloc动态申请内存失败时(可能是程序内存不足导致的申请失败),malloc返回NULL,WebRTC认为内存申请不到了,业务没法正常运行下去,认为这是致命的,程序没有继续活着的意义了,直接调用abort强行将进程终止了。

       对于这两种强行终止进程的场景,并没有发生C++上的异常,只是代码人为地终止了进程。从现象上看,程序直接闪退了(没了),给人一种程序发生异常崩溃导致程序闪退的感觉,其实程序并没有发生异常崩溃,是代码人为终止进程的。对于这种强行终止进程的场景,就需要使用Windbg动态调试了,将Windbg附加到目标进程上,和目标进程一起跑,C函数abort内部会产生一个特殊的异常,让让调试器Windbg中断下来,此时查看函数调用堆栈,就知道是调用了abort强行终止进程的,然后继续结合函数调用堆栈去分析问题了。

       对于使用开源jsoncpp和开源WebRTC遇到的强行终止进程的问题,具体细节可以去查看我之前写的文章:

C++程序中执行abort等操作导致没有生成dump文件的问题案例分析icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/129003869       此外,有时即使拿到了dump文件,可能也需要用Windbg进行动态调试的。比如从现有dump文件中分析不出问题时或者看到的函数调用堆栈不全或有问题,可以尝试使用Windbg进行动态调试。再比如,以前我们讲过,有时可能要查看相关变量的值,这些变量的值可能是排查问题的关键线索,但异常捕获模块生成的dump文件是小dump文件(比如几百KB或几MB,只保存了小部分内存信息),只能部分变量的值,有些变量的值是看不到的,但这些变量可能是分析问题的关键线索,这时也可以尝试使用Windbg进行动态调试,动态调试时可以看到所有变量的值。

       对于通过查看相关变量值去快速定位问题的案例,可以查看我的文章:
通过查看Windbg中变量值去定位C++软件异常问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125731044       对于很好复现的问题,使用Windbg动态调试很方便的,将Windbg挂到目标进程上,快速复现问题,Windbg感知到异常中断下来,就可以立即分析了。对于不好复现或者很难复现的问题,只能每次启动程序测试时都将Windbg挂上去,等待复现为止。

      关于何时使用Windbg静态分析与动态调试,可以查看我的文章:

何时使用Windbg静态分析?何时使用Windbg动态调试?icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131806819

CrashRpt%E4%BB%8B%E7%BB%8D">4、开源异常捕获CrashRpt介绍

       如何去设计异常捕获库呢?大家都会想到使用系统API函数SetUnhandledExceptionFilter去设置异常回调,当程序发生异常时就会调用设置的回调函数,然后在回调函数中调用API函数MiniDumpWriteDump去生成dump文件。但使用这种方式,缺陷很明显,很多异常捕获不到,可以选择开源异常捕获库。

       常见的开源捕获库有CrashRpt和Google开源CrashPad,今天我们来重点介绍一下CrashRptCrashRpt 是一个免费的、轻量级的开源错误报告库开源库,旨在拦截C++程序中的异常,收集有关崩溃的技术信息并通过互联网向软件供应商发送错误报告,用于 Windows C++应用程序中。

1)CrashRpt 可以处理主线程和用户模式程序的所有工作线程中的异常:SEH 异常(Structured Exception Handling 结构化异常处理)、未处理C++类型异常、信号和 CRT (C运行时)错误。在 CrashRpt 可以处理的错误类型中,有:NULL 指针分配、访问冲突、无限递归、堆栈溢出、内存耗尽等。
2)CrashRpt能生成错误报告,包括小型崩溃转储minidump文件、可扩展的崩溃描述XML文件、应用程序自定义的文件(如程序日志文件)等。

CrashRpt%E7%9A%84%E6%94%B9%E8%BF%9B" style="background-color:transparent;">5、对开源CrashRpt的改进

       CrashRpt对多线程支持的不好,导致很多异常捕获不到。另外,CrashRpt在捕获到异常时,会自动自动截屏、录制视频和发送邮件,这些功能其实是什么用处的,直接把它们裁剪掉。对于发送邮件,CrashRpt中是直接使用socket实现的,其稳定性不太好,如果需要用到这个功能,可以使用开源库libcurl,libcurl中支持POP3和SMTP邮件协议。

       为了解决CrashRpt很多异常捕获不到的问题,我们首先添加了对多线程的支持,然后引入了微软的Detours技术,有效地提高了异常捕获的效率,基本可以捕获90%以上的异常。捕获到异常后,就会生成dump文件,事后使用Windbg去分析dump文件即可。对于没捕捉到的异常的场景,则需要使用使用Windbg进行动态调试了,上面这些场景我也详细讲到了。

如果要获取到该改进的异常捕获库,可以联系微信kvsthingking

       关于如何使用Windbg去静态分析dump文件,可以查看我的文章:
使用Windbg分析dump文件的一般步骤及要点详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/130873143      关于如何使用Windbg去动态调试目标进程,可以查看我的文章:

使用Windbg调试目标进程的一般步骤及要点详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/135484906


http://www.ppmy.cn/embedded/8718.html

相关文章

深入了解MySQL中的SQL函数

深入了解MySQL中的SQL函数可以极大地提升数据处理的能力和灵活性。这些函数涵盖了从数学计算、字符串操作、日期时间处理到复杂的聚合和窗口函数。在这篇文章中,我们将详细讨论MySQL中的各种SQL函数,包括它们的用途、使用场景和一些高级技巧。 数学函数…

关于前端的那些知识点

1.CommonJs和Es6(ECMAScript 6 )模块化的相同点和不同点 // 相同点: // ---对引入的对象赋值,即对象内部的值的改变// 不同点: // 1.CommonJs require模块运行时加载,而Es6模块编译时输出接口 // 2.CommonJs require模块同步加载(排队加载),而es6模块异步加载(就是同时…

人人可拥有刘强东同款数字人分身!

每个人都可以拥有东哥同款数字人分身直播间进行直播带货,怎样克隆自己的数字人形象? 青否数字人克隆源码的克隆效果媲美真人: 仅需将真人录制的2-6分钟视频上传至克隆端后台,系统便会自动启动自动克隆。3-5小时后,即可…

微服务之分布式链路追踪

一、概述 1.1背景 在微服务框架中,一个由客户端发起的请求在后端系统中会经过多个不同的的服务节点调用来协同产生最后的请求结果,每一个前段请求都会形成一条复杂的分布式服务调用链路,链路中的任何一环出现高延时或错误都会引起整个请求最…

如何使用ChatGPT仿写一篇学术论文

点击下方▼▼▼▼链接直达AIPaperPass ! AIPaperPass - AI论文写作指导平台 目录 1.仿写的目的 2.根据专业方向搜集合适的文献 3.总结想要仿写的文献 4.使用ChatGPT一步一步仿写 5.书籍介绍 AIPaperPass智能论文写作平台 深入地阅读和分析你研究领域的相关文…

.net反射(Reflection)

文章目录 一.概念:二.反射的作用:三.代码案例:四.运行结果: 一.概念: .NET 反射(Reflection)是指在运行时动态地检查、访问和修改程序集中的类型、成员和对象的能力。通过反射,你可…

使用Python进行容器编排Docker Compose与Kubernetes的比较

👽发现宝藏 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 随着容器化技术的普及,容器编排成为了管理和部署容器化应用程序的重要环节。在容…

第四章 Linux账号和权限管理

目录 一、管理员账户和组账户 1、用户账号和组账号概述 (1)Linux基于用户身份对资源访问进行控制 2、用户账号文件/etc/passwd (1)保存用户名称、宿主目录、登录shell等基本信息 3、用户账号文件/etc/shadow (1…