如何定位Release 版本中程序崩溃的位置 ---利用map文件 拦截windows崩溃函数

2023-11-09

1       案例描述
作为Windows程序员,平时最担心见到的事情可能就是程序发生了崩溃(异常),这时Windows会提示该程序执行了非法操作,即将关闭。请与您的供应商联系。呵呵,这句微软的“名言”,恐怕是程序员最怕见也最常见的东西了。


在一个大型软件的测试过程中,初期出现程序崩溃似乎成了不可避免的事。其实测试中出现程序崩溃并不可怕,反而是测试的成功。作为开发的我们更需要关心的是程序中的哪个函数或哪一行导致了系统崩溃,这样才能有针对性的进行改正。


本文描述了自己总结的几种定位崩溃的办法。


 


 


2       案例分析
 


以下是几种常见的崩溃现象及对应的处理办法:


1.        对于Release版本必现的崩溃且在Debug版本上也崩溃的程序。


解决思路:去掉所有断点,直接在Debug版本上运行程序,在程序崩溃时,VC会自动跳转定位到崩溃代码行, 这种方法最简单也最常用。


2.        对于在Debug版本上不崩溃但Release版本崩溃的程序,很有可能是Debug和Release版本的差异。例如Debug版本所有成员在构造时会被清0,而Release版本所有成员在构造时是内存里面的原始值,而且Debug有运行时库做保护,这些都会导致某些程序在Debug正常而Release崩溃。


解决思路:1)在程序中加打印,通过程序崩溃之前的打印定位出错位置; 2)逐段注释代码,直到程序不崩溃为止。这种方法耗时较长,对程序员要求较高,而且对于那种不是必现的bug或者很难搭建执行环境的情况就较难处理了。


3.        对于在客户现场崩溃的情况,显然不适合直接带一台电脑去调试。


解决思路:应该有文件记录下崩溃信息,客服人员可以将崩溃信息文件发送给程序员,以便程序员查询崩溃原因,然后利用编译时生成MAP文件(工程信息文件,存放在版本编译机中)的信息来定位问题函数或问题代码行。下面就这种方法展开讨论一下:


 


 


3       解决过程
 


对于上节第三种情况,也是最难解决的情况,解决过程如下:


1.      崩溃回调注册,拦截Windows程序崩溃;


2.      在回调处理中,输出崩溃原因,崩溃内存地址,崩溃堆栈;


3.      工程输出map文件;


4.      通过崩溃内存地址以及map文件找出崩溃的函数。


5.      使用COD文件精确定位崩溃行


 


3.1     崩溃回调注册
 


实际上,只靠Windows的错误消息对话框提供的信息量是很有限的。用SetUnhandledExceptionFilter注册自定义错误处理回调函数,可以替换Win32默认的异常处理过滤器(top-level exception filter),而且能打印出崩溃堆栈,这对定位崩溃原因非常有用。


SetUnhandledExceptionFilter的函数原型:


LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(


LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ); 


功  能:注册和注销异常处理回调;


用  法:第一次调用注册异常处理回调,第二次调用注销;


返回值:返回当前的exception filter。需要保存这个函数指针,在注销异常处理回调的时候,以此为参数再次调用SetUnhandledExceptionFilter。打印异常处理也需要此值。


参数: 异常处理的回调函数;


 


 


3.2     输出崩溃信息
 


崩溃信息在异常回调函数中打印,输出到程序执行目录下的文件:


异常处理回调的函数原形:


LONG WINAPI CallBackDebugInfo ( EXCEPTION_POINTERS *pException); 


功  能:异常处理回调处理,打印崩溃信息;


用  法:注册自定义错误处理回调:SetUnhandledExceptionFilter (CallBackDebugInfo);


返回值:EXCEPTION_CONTINUE_EXECUTION –  错误已经被修复,从异常发生处继续执行


EXCEPTION_CONTINUE_SEARCH    –  继续查找异常过滤器


EXCEPTION_EXECUTE_HANDLER   –  正常返回


参数: 崩溃信息结构,包含崩溃原因、崩溃模块、崩溃地址、崩溃堆栈等;


常见崩溃原因有:


EXCEPTION_ACCESS_VIOLATION = C0000005h   读写内存错误


EXCEPTION_INT_DIVIDE_BY_ZERO = C0000094h  除0错误


EXCEPTION_STACK_OVERFLOW = C00000FDh  堆栈溢出或者越界


EXCEPTION_GUARD_PAGE = 80000001h 由Virtual Alloc建立起来的属性页冲突


EXCEPTION_NONCONTINUABLE_EXCEPTION = C0000025h不可持续异常,程序无法恢复执行,异常处理例程不应处理这个异常


EXCEPTION_INVALID_DISPOSITION = C0000026h在异常处理过程中系统使用的代码


EXCEPTION_BREAKPOINT = 80000003h  调试时中断(INT 3)


EXCEPTION_SINGLE_STEP = 80000004h  单步调试状态(INT 1)


 


3.3     输出map文件
 


map文件记录程序的全局符号、源文件和代码行号信息,是整个程序工程信息的静态文本。通过文本阅读工具如Ultra Edit或记事本就可以打开Map文件。


在 VC 中,打开“Project Settings”选项页,选择 C/C++ 选项卡,并在最下面的 Project Options 里面输入:/Zd ,然后选择 Link 选项卡,选中“Generate mapfile”复选框。并在最下面的 Project Options 里面输入:/mapinfo:lines,表示生成 map 文件时,加入行信息。


 


 


最后编译就可以生成 MAP 文件,可以在工程的Debug或Release目录下找到刚刚生成的MAP文件,文件名为“工程名.map”。


 


3.4     使用map文件找出崩溃函数
      通过上面的步骤,已经得到了 MAP 文件,那么我们该如何利用它呢?下面一步步演示使用MAP文件定位程序崩溃行的过程。


      1.我们先在代码中加入非法内存操作(最常见的异常)的代码:


BOOL CMainFrameDlg::OnInitDialog()


{


         ::SetProp(m_hWnd,AfxGetApp()->m_pszExeName, (HANDLE)1);


         s32 *p=NULL;


         *p= 123;


 


2.执行程序,程序在开始就异常,在异常打印文件中打印了如下信息:


======================== 崩溃信息 ==========================


崩溃时间: 2009/06/02 16:58:22


崩溃原因:非法内存操作


异常代码 = c0000005


异常地址 = 0x0045a76f


异常模块: E:\ccroot\liuxiaojing_Enterprise\Enterprise_VOB\70-nms1\pcmt2\prj_win32\Release\pcmt2.exe


Section name: .text - offset(rva) : 0x0005976f


---------------------- Trips of Stack ----------------------


E:\ccroot\liuxiaojing_Enterprise\Enterprise_VOB\70-nms1\pcmt2\prj_win32\Release\pcmt2.exe


name : pcmtver - location: 2bef


3.确定崩溃地址是:0x0005976f,在Map文件中定位函数:


0001:00059420 ?OnCreate@CMainFrameDlg@@IAEHPAUtagCREATESTRUCTA@@@Z 0045a420 f  MainFrameDlg.obj


 0001:00059460       ?SetTooltips@CMainFrameDlg@@AAEXXZ 0045a460 f   MainFrameDlg.obj


 0001:00059700       ?OnTranslate@CMainFrameDlg@@IAEJIJ@Z 0045a700 f   MainFrameDlg.obj


 0001:00059730       ?OnInitDialog@CMainFrameDlg@@MAEHXZ 0045a730 f   MainFrameDlg.obj


 0001:00059a10  ?OnSysCommand@CMainFrameDlg@@IAEXIJ@Z 0045aa10 f   MainFrameDlg.obj


 0001:00059c20       ?OnPaint@CMainFrameDlg@@IAEXXZ 0045ac20 f   MainFrameDlg.obj


根据00059730< 0005976f < 00059a10 ,确定是在CMainFrameDlg 的OnInitDialog函数中的某一行产生了异常。


3.5     使用map代码行定位崩溃行区间
 


Line numbers for .\Release\MainFrameDlg.obj(E:\ccroot\liuxiaojing_Enterprise\Enterprise_VOB\70-nms1\pcmt2\source\MainFrameDlg.cpp) segment .text


   498 0001:00059647   499 0001:00059667   501 0001:0005966e   502 0001:000596af


   503 0001:000596ed   506 0001:00059700   507 0001:00059703   508 0001:00059708


   510 0001:0005970f   511 0001:00059720   512 0001:00059723   515 0001:00059730


   516 0001:0005974e   521 0001:0005976d   524 0001:0005977e   526 0001:0005978b


我们在map文件的代码行信息里查找不超过计算结果0x0005976f,但可以找最接近的数。发现是MainFrameDlg.cpp 文件中的:521 0001:0005976d,而程序实际崩溃行在519(注释行和空行也要计算在内),非常接近实际崩溃行了,考虑到程序实际执行的是汇编指令,我们可以在(516 ~524)行区间内寻找到实际崩溃行。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何定位Release 版本中程序崩溃的位置 ---利用map文件 拦截windows崩溃函数 的相关文章

  • 【C/C++】报错问题积累

    1 出现Deprecated declaration XXX give arg types c文件中 有没有参数的函数时 声明需要加void即 main c void fun main h void fun void
  • fastcgi的环境变量

    FCGI ROLE RESPONDER SCRIPT FILENAME scripts 5 cgi QUERY STRING aaa 11111111111111 bbb 2222222222222222 ccc 3333333333333
  • R语言学习笔记:分析学生的考试成绩

    孩子上初中时拿到过全年级一次考试所有科目的考试成绩表 正好可以用于R语言的统计分析学习 为了不泄漏孩子的姓名 就用学号代替了 感兴趣可以下载测试数据进行练习 num class chn math eng phy chem politics
  • [原]Pro*C介绍-内嵌SQL

    Translate by Z Jingwei Document address http www db stanford edu ullman fcdb oracle or proc html Pro C介绍内嵌SQL 概要 Pro C语法
  • 五. python面向对象(多态 和metaclass=abc.ABCMeta)

    一 多态 多肽 一种事物的多种形态 叫多肽 例如 动物 animal 猫 狗 animal py 文件 动物类 都有名字这个属性 和吃这个方法 class Animal object def init self name self name
  • 简析多级指针解引用

    转自 简析多级指针解引用 指针是C语言中公认的最为强大的语法要素 但同时也是最难理解的语法要素 它曾给程序员带来了无数麻烦和痛苦 以致于在C语言之后诞生的很多新兴 语言中我们再也难觅指针的身影了 下面是一个最简单的C语言指针的例子 int
  • C/C++中浮点数格式学习——以IEEE75432位单精度为例

    这是浮点数的通常表示形式 在IEEE754中 单精度浮点数有如下形式 32位单精度 单精度二进制小数 使用32个比特存储 1 8 23位长 S Exp Fraction 31 30至23偏正值 实际的指数大小 127 22至0位编号 从右边
  • 互联网创业盈利模式指南

    看了很多创业的case 都有点下笔千言 离题万里的 情况 就是很多case都很精彩 但是公司 的价值最终是落实到 给创业者和投资人的回报的 因此 所有的case 最终都是 落实到盈利 模式上 一位投资人士说的很明确 中国的盈利模式很简单 就
  • 【C++】VS code如何配置使用C++(手把手教学)

    博 主 米码收割机 技 能 C Python语言 公众号 测试开发自动化 获取源码 商业合作 荣 誉 阿里云博客专家博主 51CTO技术博主 专 注 专注主流机器人 人工智能等相关领域的开发 测试技术 VS code如何配置使用C 手把手教
  • vector,list,deque区别

    http blog csdn net renkaihao article details 6803866 vector和built in数组类似 它拥有一段连续的内存空间 并且起始地址不变 因此它能非常好的支持随即存取 即 操作符 但由于它
  • floor(),ceil()函数

    地板 天花板函数 均包含在math h中 意思分别为 返回不大于形参的最小整数和不小于形参的最大整数 include
  • Dev-C++之开启装逼效果

    Dev C 是个不错的C IDE 在10年前 它是很不错 在现在 它是个以界面丑陋和调试像吃粑粑这两点著称 如下图 实在是丑到离谱 丑到无法忍受 可是没办法呀 人家CCF规定比赛用这个 你个小蒟蒻吵什么 我现在就来讲讲怎么把你的Dev C
  • stat 函数解析

    stat 函数的简单使用 stat 函数是用来获取文件的各种属性的一个linux下的常用API函数 函数原型为int stat const char path struct stat buf stat定义如下 struct stat dev
  • 一个简单的参数帮助框架,c实现

    文章目录 具体实现如下 include
  • C 语言教程:数据类型和格式说明符

    C 语言中的数据类型 C 中的变量必须是指定的 数据类型 并且您必须在 printf 函数中使用 格式说明符 来显示它 创建变量 int myNum 5 整数 没有小数点 float myFloatNum 5 99 浮点数 char myL
  • C++中的并发多线程网络通讯

    C 中的并发多线程网络通讯 一 引言 C 作为一种高效且功能强大的编程语言 为开发者提供了多种工具来处理多线程和网络通信 多线程编程允许多个任务同时执行 而网络通信则是现代应用程序的基石 本文将深入探讨如何使用C 实现并发多线程网络通信 并
  • C/C++编程中的算法实现技巧与案例分析

    C C 编程语言因其高效 灵活和底层的特性 被广大开发者用于实现各种复杂算法 本文将通过10个具体的算法案例 详细探讨C C 在算法实现中的技巧和应用 一 冒泡排序 Bubble Sort 冒泡排序 Bubble Sort 是一种简单的排序
  • C++ 中 const 和 constexpr 关键字解析:常量、函数和指针

    很多 C 的初学者看到 const 这个关键字的第一反应都是一头雾水 主要是因为 const 可 以出现在很多的位置 以及后面加入的 constexpr 更是常常感到困惑 今天就为大家一一解释出现它们的含义和以及作用 const 关键字 c
  • 在 OS X 上的 virtualenv 中安装 scrapy 加密时发生错误 [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我正在安装 scrapypip in virtualenv on OS X 10 11 当它安装密码学时 它说 buil
  • C中的内存使用问题

    请帮忙 操作系统 Linux 其中 sleep 1000 中 此时 top 显示Linux任务 给我写了7 7 MEM使用 valgrind 未发现内存泄漏 我明白 写得正确 所有 malloc 结果都是 NULL 但是为什么这次 睡眠 我

随机推荐

  • java pv uv_前端数据收集(pv/uv)

    所谓web 即使你我素未谋面 便知志趣相投 足不出户 亦知世界大 01 什么是PV UV 网站流量分析 是指在获得网站访问量基本数据的情况下对有关数据进行统计 分析 从中发现用户访问网站的规律 并将这些规律与网络营销策略等相结合 从而发现目
  • Cadence Allegro(8):生成网络报表(Netlist)

    Cadence Allegro 8 生成网络报表 Netlist 前提摘要 PCB设计软件版本 原理图设计 Pad Designer 16 6 PCB设计 PCB Editor 16 6 个人说明 限于时间紧迫以及作者水平有限 本文错误 疏
  • selenium chrome java 无头模式使用cdp设置navigator.permission

    Chrome Devtools Protocol 前提 chromium无头模式下和gui模式是不同的 userData无法指定 也无法通过模拟点击alert授权 或者进入chrome settings 通过selenium控制授权 因为无
  • 奶牛碑文。

    include
  • 八大数据结构

    八大数据结构 数据结构分类 1 数组 2 栈 3 队列 4 链表 5 树 6 散列表 7 堆 8 图 1 数组 数组是可以再内存中连续存储多个元素的结构 在内存中的分配也是连续的 数组中的元素通过数组下标进行访问 数组下标从0开始 例如下面
  • ORACLE 生成唯一id

    1 创建一个序列 create sequence id 序列名称 increment by 1 以1递增 start with 1 从1开始 maxvalue 999999999 最大值 2 创建函数调用上边创建的序列 CREATE FUN
  • PyCharm 使用教程:PyCharm常用技巧指南,轻松学会

    在 PyCharm 中 打开已有的项目有 3 种方式 欢迎界面中选择open 菜单栏中选择 File gt open 打开远程 Git 的项目 在 PyCharm 中 打开已有的项目可以在第一次打开的欢迎界面中选择open来打开你电脑中已经
  • 【‘XXX‘ is declared but its value is never read.】

    遇到问题了 引入一个弹窗组件 已经import了 也在template中写了弹窗组件 但是弹窗就是不出来 1 看看报错信息 没啥报错 2 看看代码 import中的代码暗淡了 鼠标移入出现上面的报错 突然想起来没有在component中写入
  • breach靶场练习详细全过程

    补充 桥接 nat host only三种网络模式的区别 模式 特点 场景 bridge桥接模式 特点 虚拟机使用物理机的网卡 不用虚拟网卡 占用一个ip 需要配置ip以后才可以访问互联网 场景 虚拟机需要连接实体设备的时候 nat网络地址
  • 最好用的 6 个 React Tree select 树形组件测评与推荐

    本文完整版 最好用的 6 个 React Tree select 树形组件测评与推荐 React Tree select 树形组件 1 React Sortable Tree 全功能 树状单选多选 可拖拽 过滤搜索 多种主题可选 2 Rea
  • android开发浏览器!写给1-3年安卓程序员的几点建议,聪明人已经收藏了!

    前言 作为一个程序员 如果你在新知识 新技术面前仍一无所知 依然吃着十多年前的老本 那你在知识技术上肯定落伍 如果又未能进入管理层面 那你肯定就会被长江的后浪拍在沙滩上了 而不少与时俱进 善于学习的程序员他们仍是行业的中坚力量 这只是说明当
  • 面试利器(二)-------插入排序(直接插入排序和希尔排序(Shell排序))

    一 直接插入排序 抓住关键字 插入 1 基本思想 顺序地把待排序的序列中的各个数据按其关键字的大小 插入到已排序的序列的适当位置 2 运行过程 1 将待排序序列的第一个数据看做一个有序序列 把第二个数据到最后一个数据当成是未排序序列 2 从
  • openblas第一弹:openblas 使用说明和常用接口介绍

    openblas 使用说明 openblas 是一个开源的矩阵计算库 包含了诸多的精度和形式的矩阵计算算法 就精度而言 包括float和double 两种数据类型的数据 其矩阵调用函数也是不一样 不同矩阵 其计算方式也是有所不同 姑且认为向
  • C++设计模式 - 组合模式(Composite)

    数据结构模式 常常有一 些组件在内部具有特定的数据结构 如果让客户程序依赖这些特定的数据结构 将极大地破坏组件的复用 这时候 将这些特定数据结构封装在内部 在外部提供统一的接口 来实现与特定数据结构无关的访问 是一种行之有效的解决方案 典型
  • 遗传算法基本介绍

    1 主要解决什么问题 是一种仿生全局优化算法 2 原理 思路是什么 选择 优胜劣汰 交叉 变异 一些重要概念 生物遗传概念在遗传算法中的对应关系 编码策略 常用的遗传算法编码方法主要有 二进制编码 浮点数编码等 可以证明 二进制编码比浮点数
  • 在html中加入网址,网页超链接怎么做,添加超链接网址的的详细步骤

    此系列教程主要讲解HTML从基础到精通 自己能够设计一个完整的前端网页项目 程序员写代码 在HTML中添加图片其实很简单 就是添加一个img的标签 图片标签的语法 一般有src alt width height四种属性就够用了 效果 图片的
  • 智能音箱借ChatGPT重获“新生”?

    曾经靠语音助手红极一时的智能音箱 近年来的市场表现却欠佳 据洛图科技发布的最新 中国智能音箱零售市场月度追踪 报告显示 2022年中国智能音箱总销量为2631万台 同比下降28 市场销售额为75 3亿元 同比下降25 而IDC发布的2023
  • 华为OD机试 - 太阳能板最大面积(Java)

    题目描述 给航天器一侧加装长方形或正方形的太阳能板 图中的红色斜线区域 需要先安装两个支柱 图中的黑色竖条 再在支柱的中间部分固定太阳能板 但航天器不同位置的支柱长度不同 太阳能板的安装面积受限于最短一侧的那根支柱长度 如图 现提供一组整形
  • 计算机中的打印机,如何添加打印机,教您电脑如何添加打印机

    打印机是我们工作中不可缺少的办公设备 那如果电脑上没安装打印机 可以进行打印吗 我们可以通过连接到同一网络上的打印机进行打印作业 那电脑怎样进行添加打印机呢 下面 小编给大家带来了电脑添加打印机的图文 打印机是现在我们办公设备的必要用品之一
  • 如何定位Release 版本中程序崩溃的位置 ---利用map文件 拦截windows崩溃函数

    1 案例描述 作为Windows程序员 平时最担心见到的事情可能就是程序发生了崩溃 异常 这时Windows会提示该程序执行了非法操作 即将关闭 请与您的供应商联系 呵呵 这句微软的 名言 恐怕是程序员最怕见也最常见的东西了 在一个大型软件