最近在调试几个问题时,发现跟abort函数有关,以前只是简单使用,现在却发现不简单,就多留意了下。

简介

abort中止当前进程并返回错误代码。异常终止一个进程。中止当前进程,返回一个错误代码。错误代码的缺省值是3。

代码

/***
*abort.c - abort a program by raising SIGABRT
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* defines abort() - print a message and raise SIGABRT.
*
*******************************************************************************/ #include <cruntime.h>
#include <stdlib.h>
#include <internal.h>
#include <awint.h>
#include <rterr.h>
#include <signal.h>
#include <oscalls.h>
#include <mtdll.h>
#include <dbgint.h> #ifdef _DEBUG
#define _INIT_ABORT_BEHAVIOR _WRITE_ABORT_MSG
#else /* _DEBUG */
#define _INIT_ABORT_BEHAVIOR _CALL_REPORTFAULT
#endif /* _DEBUG */ unsigned int __abort_behavior = _INIT_ABORT_BEHAVIOR; /***
*void abort() - abort the current program by raising SIGABRT
*
*Purpose:
* print out an abort message and raise the SIGABRT signal. If the user
* hasn't defined an abort handler routine, terminate the program
* with exit status of 3 without cleaning up.
*
* Multi-thread version does not raise SIGABRT -- this isn't supported
* under multi-thread.
*
*Entry:
* None.
*
*Exit:
* Does not return.
*
*Uses:
*
*Exceptions:
*
*******************************************************************************/ void __cdecl abort (
void
)
{
_PHNDLR sigabrt_act = SIG_DFL; #ifdef _DEBUG
if (__abort_behavior & _WRITE_ABORT_MSG)
{
/* write the abort message */
_NMSG_WRITE(_RT_ABORT);
}
#endif /* _DEBUG */ /* Check if the user installed a handler for SIGABRT.
* We need to read the user handler atomically in the case
* another thread is aborting while we change the signal
* handler.
*/
sigabrt_act = __get_sigabrt();
if (sigabrt_act != SIG_DFL)
{
raise(SIGABRT);
} /* If there is no user handler for SIGABRT or if the user
* handler returns, then exit from the program anyway
*/ if (__abort_behavior & _CALL_REPORTFAULT)
{
#if defined (_M_ARM) || defined (_CRT_APP)
__fastfail(FAST_FAIL_FATAL_APP_EXIT);
#else /* defined (_M_ARM) || defined (_CRT_APP) */
if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
__fastfail(FAST_FAIL_FATAL_APP_EXIT); _call_reportfault(_CRT_DEBUGGER_ABORT, STATUS_FATAL_APP_EXIT, EXCEPTION_NONCONTINUABLE);
#endif /* defined (_M_ARM) || defined (_CRT_APP) */
} /* If we don't want to call ReportFault, then we call _exit(3), which is the
* same as invoking the default handler for SIGABRT
*/ _exit();
} /***
*unsigned int _set_abort_behavior(unsigned int, unsigned int) - set the behavior on abort
*
*Purpose:
*
*Entry:
* unsigned int flags - the flags we want to set
* unsigned int mask - mask the flag values
*
*Exit:
* Return the old behavior flags
*
*Exceptions:
* None
*
*******************************************************************************/ unsigned int __cdecl _set_abort_behavior(unsigned int flags, unsigned int mask)
{
unsigned int oldflags = __abort_behavior;
__abort_behavior = oldflags & (~mask) | flags & mask;
return oldflags;
}

流程

从上面代码,我可以看到,abort的流程如下:

如果是调试版,且__abort_behavior为_WRITE_ABORT_MSG,则调用_NMSG_WRITE(_RT_ABORT);弹出crt异常提示框

点"中止"进程直接退出,点"忽略"后,就判断sigabrt_act的值,不等于SIG_DFL的话调用raise发送信号SIGABRT,然后调用_exit(3)退出

release版则会检测本机支不支持PF_FASTFAIL_AVAILABLE,支持就走windows快速失败机制,不支持就执行 _call_reportfault(_CRT_DEBUGGER_ABORT, STATUS_FATAL_APP_EXIT, EXCEPTION_NONCONTINUABLE);然后退出。

隐藏的秘密

上面讲的那些我相信大家都了解,但是,其实这个函数里,可能会引发多个异常。

调用_NMSG_WRITE(_RT_ABORT),会引发异常0x4001000A或0x40010006:

调用__fastfail(FAST_FAIL_FATAL_APP_EXIT);会引发异常0xc0000409子代码为FAST_FAIL_FATAL_APP_EXIT:

而调用_call_reportfault会引发异常STATUS_FATAL_APP_EXIT(0x40000015):

#if (defined (_M_IX86) || defined (_M_X64)) && !defined (_CRT_APP)
void __cdecl _call_reportfault(
int nDbgHookCode,
DWORD dwExceptionCode,
DWORD dwExceptionFlags
)
{
// Notify the debugger if attached.
if (nDbgHookCode != _CRT_DEBUGGER_IGNORE)
_CRT_DEBUGGER_HOOK(nDbgHookCode); /* Fake an exception to call reportfault. */
EXCEPTION_RECORD ExceptionRecord = {};
CONTEXT ContextRecord;
EXCEPTION_POINTERS ExceptionPointers = {&ExceptionRecord, &ContextRecord};
BOOL wasDebuggerPresent = FALSE;
DWORD ret = ; #if defined (_M_IX86) __asm {
mov dword ptr [ContextRecord.Eax], eax
mov dword ptr [ContextRecord.Ecx], ecx
mov dword ptr [ContextRecord.Edx], edx
mov dword ptr [ContextRecord.Ebx], ebx
mov dword ptr [ContextRecord.Esi], esi
mov dword ptr [ContextRecord.Edi], edi
mov word ptr [ContextRecord.SegSs], ss
mov word ptr [ContextRecord.SegCs], cs
mov word ptr [ContextRecord.SegDs], ds
mov word ptr [ContextRecord.SegEs], es
mov word ptr [ContextRecord.SegFs], fs
mov word ptr [ContextRecord.SegGs], gs
pushfd
pop [ContextRecord.EFlags]
} ContextRecord.ContextFlags = CONTEXT_CONTROL;
#pragma warning(push)
#pragma warning(disable:4311)
ContextRecord.Eip = (ULONG)_ReturnAddress();
ContextRecord.Esp = (ULONG)_AddressOfReturnAddress();
#pragma warning(pop)
ContextRecord.Ebp = *((ULONG *)_AddressOfReturnAddress()-); #elif defined (_M_X64)
__crtCaptureCurrentContext(&ContextRecord);
ContextRecord.Rip = (ULONGLONG) _ReturnAddress();
ContextRecord.Rsp = (ULONGLONG) _AddressOfReturnAddress()+; #endif /* defined (_M_X64) */ ExceptionRecord.ExceptionCode = dwExceptionCode;
ExceptionRecord.ExceptionFlags = dwExceptionFlags;
ExceptionRecord.ExceptionAddress = _ReturnAddress(); wasDebuggerPresent = IsDebuggerPresent(); /* Raises an exception that bypasses all exception handlers. */
ret = __crtUnhandledException(&ExceptionPointers); // if no handler found and no debugger previously attached
// the execution must stop into the debugger hook.
if (ret == EXCEPTION_CONTINUE_SEARCH && !wasDebuggerPresent && nDbgHookCode != _CRT_DEBUGGER_IGNORE) {
_CRT_DEBUGGER_HOOK(nDbgHookCode);
}
}

研究下vc++的abort函数的更多相关文章

  1. 学习和研究下unity3d的四元数 Quaternion

    学习和研究下unity3d的四元数 Quaternion 今天准备学习和研究下unity3d的四元数 Quaternion 四元数在电脑图形学中用于表示物体的旋转,在unity中由x,y,z,w 表示 ...

  2. 信号之abort函数

    abort函数的功能是使异常程序终止. #include <stdlib.h> void abort(void); 此函数不返回 此函数将SIGABRT信号发送给调用进程(进程不应忽略此信 ...

  3. Windows 下VC++6.0制作、使用动态库和静态库

    Windows 下VC++6.0制作.使用动态库和静态库 一.VC++6.0制作.使用静态库 静态库制作 1.如图一在VC++6.0中new一个的为win32 static library工程并新建一 ...

  4. VC API常用函数简单例子大全(1-89)

    第一个:FindWindow根据窗口类名或窗口标题名来获得窗口的句柄,该函数返回窗口的句柄 函数的定义:HWND WINAPI FindWindow(LPCSTR lpClassName ,LPCST ...

  5. 研究下JavaScript中的Rest參数和參数默认值

    研究下JavaScript中的Rest參数和參数默认值 本文将讨论使 JavaScript 函数更有表现力的两个特性:Rest 參数和參数默认值. Rest 參数 通常,我们须要创建一个可变參数的函数 ...

  6. 64位下pwntools中dynELF函数的使用

    这几天有同学问我在64位下怎么用这个函数,于是针对同一道题写了个利用dynELF的方法 编译好的程序 http://pan.baidu.com/s/1jImF95O 源码在后面 from pwn im ...

  7. [笔记]linux下和windows下的 创建线程函数

    linux下和windows下的 创建线程函数 #ifdef __GNUC__ //Linux #include <pthread.h> #define CreateThreadEx(ti ...

  8. windows下的getopt/getoptlong函数

    windows下的getopt/getoptlong函数 getopt/getopt_long函数是GNU C中的函数,在linux编程中很常用到.这里就不介绍了. windows下没有找到类似的函数 ...

  9. 在String()构造器不存在的情况下自定义一个MyString()函数,实现如下内建String()方法和属性:

    在String()构造器不存在的情况下自定义一个MyString()函数,实现如下内建String()方法和属性: var s = new MyString("hello"); s ...

随机推荐

  1. redis启动出现错误 can't chdir ...

    启动redis出现以下错误:[15816] *********** # Can't chdir to ’**********‘ :No such file or directory 解决方法:手动创建 ...

  2. Java : Hibernate 动态+分页+自定义字段+自定义实体类查询

    // 组合查询public List<ListBookDTO> listSetDSL(PublishingHouse publishingHouse,Integer minDiscount ...

  3. 2019-11-29-WPF-多个-StylusPlugIn-的事件触发顺序

    原文:2019-11-29-WPF-多个-StylusPlugIn-的事件触发顺序 title author date CreateTime categories WPF 多个 StylusPlugI ...

  4. html 图片滚动代码

    我自己也在用的,网页常用!分享出来 最简单易懂源码 <!--下面是向上滚动代码--> <div id=butong_net_top style=overflow:hidden;hei ...

  5. el-upload进度条无效,on-progress无效问题解决方案

    事先声明,本人系.net后端老菜鸟,vue接触没有多长时间,如果存在技术分享错误,切莫见怪,第一次写博,还请大佬们多多担待,转载请注明出处谢谢! 最近项目用到饿了么上传,于是参照官网接入el-uplo ...

  6. 玩透二叉树(Binary-Tree)及前序(先序)、中序、后序【递归和非递归】遍历

    基础预热: 结点的度(Degree):结点的子树个数:树的度:树的所有结点中最大的度数:叶结点(Leaf):度为0的结点:父结点(Parent):有子树的结点是其子树的根节点的父结点:子结点/孩子结点 ...

  7. 适合新手入门Spring Security With JWT的Demo

    Demo 地址:https://github.com/Snailclimb/spring-security-jwt-guide .欢迎 star! Spring Security 是Spring 全家 ...

  8. 开发--CentOS-7安装及配置

    开发|CentOS-7安装及配置 本文主要进行详细讲解CentOS7.5系统的安装过程,以及CentOS系统初始化技术.我并不想将这篇文章变成一个教程,尽管我将详细的进行每一步的讲解,enjoy! 前 ...

  9. 使用Git Bash向GitHub上传本地项目

    第一步:下载Git Bash(https://gitforwindows.org/),安装的过程是一路下一步,就不细说啦: 第二步:打开Git Bash,如下图显示: 第三步:现在让我们先放一放Git ...

  10. RISC-V GNU 工具链:安装与使用

    1. 安装Wmware和unbuntu,我安装的是Wmware workstation pro 12.1.1 build-3770994, unbuntu 是18.04.2 amd版本, ubuntu ...