最近在调试几个问题时,发现跟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. CentOS7 Git 安装

    最新git源码下载地址: https://github.com/git/git/releases https://www.kernel.org/pub/software/scm/git/ 1 移除旧版 ...

  2. 使用mysqldump命令进行mysql数据库备份

    1.用法 mysqldump -uroot -p --databases test > /home/test.sql mysqldump -uroot -h127.0.0.1 -p --data ...

  3. RabbitMQ的构架

    初识rabbitMQ RabbitMQ 是一个由 Erlang 语言开发的 AMQP 的开源实现. AMQP :Advanced Message Queue,高级消息队列协议.它是应用层协议的一个开放 ...

  4. iOS组件化实现方案

    作者原文iOS组件化 - 路由架构从0到1实战  合伙呀 1.CTMediator作为路由中间件 2.基础UI组件以pod形式引入,并且能够独立运行调试 3.基础工具组件以pod形式引入,并且能够独立 ...

  5. Redis 内存管理 源码分析

    要想了解redis底层的内存管理是如何进行的,直接看源码绝对是一个很好的选择 下面是我添加了详细注释的源码,需要注意的是,为了便于源码分析,我把redis为了弥补平台差异的那部分代码删了,只需要知道有 ...

  6. C# 1.0 新特性之异步委托(AP、APM)

    Ø  前言 C# 异步委托也是属于异步编程中的一种,可以称为 Asynchronous Programming(异步编程)或者 Asynchronous Programming Model(异步编程模 ...

  7. main 函数返回值

    [1]main函数 [2]main() 经典的C风格函数头,如下: main() 在C语言中,省略返回类型相当于说函数的类型为int. 但是,需要明确,C++逐步淘汰了这种用法. 另外,在C语言中,让 ...

  8. Springboot2+SpringSecurity+Oauth2+Mysql数据库实现持久化客户端数据

    目录 介绍 建表,初始化数据 工程配置 Authorization Server - Spring Security配置 Authorization Server - 授权服务器 Resource S ...

  9. 《 .NET并发编程实战》阅读指南 - 第1章

    先发表生成URL以印在书里面.等书籍正式出版销售后会公开内容.

  10. WPF 精修篇 多属性触发器

    原文:WPF 精修篇 多属性触发器 多属性触发器就是多个属性都满足在触发 在属性触发器上加了一些逻辑判断 举栗子 这个栗子里  textBox 要满足俩个条件 才能触发背景变色 1)textbox的 ...