abort c linux

2015-04-09 22:26:03 kanguolaikanguolaik 阅读数 3559

一、代码

        abort()、exit()

#include <stdio.h>
#include <stdlib.h>

static void atexit_handle_1(void)
{
        printf("atexit_handle_1\n");
}

static void atexit_handle_2(void)
{
        printf("atexit_handle_2\n");
}


//abort()、exit()
int main(int argc, char*argv[])
{
        atexit(atexit_handle_1);
        atexit(atexit_handle_2);

        printf("output.\n");

        //abort()
        //abort();

        //exit()
        exit(EXIT_SUCCESS);

        printf("this line should never output.\n");

        return 0;
}

二、输出结果

        abort()输出结果:


        exit()输出结果:


2019-04-12 10:10:45 rikeyone 阅读数 1972

SIGABRT被阻塞

还有一个信号SIGABRT要特别说明,表示异常终止信号,当系统调用abort()时会发送SIGABRT信号,那么如果阻塞了该信号会影响abort()函数的使用吗?
经过测试,事实证明并不会,因为abort()的内部实现已经确保了该函数调用器件,SIGALRM信号不会被阻塞。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void sig_handler(int sig)
{
    printf("signal catch:%d\n", sig);
}

int handle_test(void)
{
    signal(SIGABRT, sig_handler);
    printf("abort after 3 seconds\n");
    sleep(3);
    abort();
}

int block_test(void)
{
    sigset_t mask;

    sigemptyset(&mask);
    sigaddset(&mask, SIGABRT);
    sigprocmask(SIG_BLOCK, &mask, NULL);
    printf("abort after 3 seconds\n");
    sleep(3);
    abort();
}


int main()
{
//  handle_test();
    block_test();
    while(1);
}
                   

结果如下:

$ ./abort 
abort after 3 seconds
已放弃 (核心已转储)

SIGABRT被捕捉

如果SIGABRT被注册了一个捕获函数,那么执行abort()还会导致进程终止吗?
经过测试,事实证明依然会让系统终止,因为abort()执行完捕获函数后会恢复为默认,然后重新发送SIGABRT。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void sig_handler(int sig)
{
    printf("signal catch:%d\n", sig);
}

int handle_test(void)
{
    signal(SIGABRT, sig_handler);
    printf("abort after 3 seconds\n");
    sleep(3);
    abort();
}

int block_test(void)
{
    sigset_t mask;

    sigemptyset(&mask);
    sigaddset(&mask, SIGABRT);
    sigprocmask(SIG_BLOCK, &mask, NULL);
    printf("abort after 3 seconds\n");
    sleep(3);
    abort();
}

int main()
{
    handle_test();
    while(1);
}

结果如下:

$ ./abort 
abort after 3 seconds
signal catch:6
已放弃 (核心已转储)

abort使用注意

经过前面的测试可知,abort()函数一定会使得进程终止。

abort实现:

void
abort(void)         /* POSIX-style abort() function */
{
    sigset_t            mask;
    struct sigaction    action;

    /* Caller can't ignore SIGABRT, if so reset to default */
    sigaction(SIGABRT, NULL, &action);
    if (action.sa_handler == SIG_IGN) {
        action.sa_handler = SIG_DFL;
        sigaction(SIGABRT, &action, NULL);
    }
    if (action.sa_handler == SIG_DFL)
        fflush(NULL);           /* flush all open stdio streams */

    /* Caller can't block SIGABRT; make sure it's unblocked */
    sigfillset(&mask);
    sigdelset(&mask, SIGABRT);  /* mask has only SIGABRT turned off */
    sigprocmask(SIG_SETMASK, &mask, NULL);
    kill(getpid(), SIGABRT);    /* send the signal */

    /* If we're here, process caught SIGABRT and returned */
    fflush(NULL);               /* flush all open stdio streams */
    action.sa_handler = SIG_DFL;
    sigaction(SIGABRT, &action, NULL);  /* reset to default */
    sigprocmask(SIG_SETMASK, &mask, NULL);  /* just in case ... */
    kill(getpid(), SIGABRT);                /* and one more time */
    exit(1);    /* this should never be executed ... */
}

从这个实现中可以看出:

  1. 它保证该信号不能被忽略,也保证该信号不能被阻塞,
  2. 如果有对SIGABRT注册了捕获函数,那么会先执行捕获函数
  3. 捕获函数执行后如果依然进程没有退出,那么恢复捕获函数为默认(终止),然后再次发送SIGABRT给进程。
2020-01-06 14:58:31 yexiangCSDN 阅读数 88

一、介绍

abort()首先取消阻止SIGABRT信号,然后为调用过程引发该信号。除非捕获到SIGABRT信号并且信号处理程序不返回,否则这将导致过程异常终止。
如果abort()函数导致进程终止产生核心存储文件(core默认名字),则所有打开的流都将关闭并刷新。

raise() 发送一个信号给调用进程或者线程,单线程中相当于 kill(getpid(),sig)
多线程中相当于 pthread_kill(pthread_self(),sig)。一般来说raise是pthread_kill实现的

二、接口函数

#include <stdlib.h>

void abort(void);
无参数无返回值

#include <signal.h>

int raise(int sig);
参数:
	sig: 参考kill -l 信号值
返回值:
	0代表成功,非0失败	

三、实例

1.abort

// abort
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <utime.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <dirent.h>
#include <limits.h>
#include <malloc.h>
#include <signal.h>

int main(int argc, char *argv[])
{
	sigset_t set; // 信号集合
	int i = 0;
	
	sigemptyset(&set); // 清空信号集合
	sigaddset(&set, SIGABRT); // SIGABRT 加入 set 集合
	
	// 阻止SIGABRT信号传递,看abort是否取消了阻止SIGABRT信号
	sigprocmask(SIG_BLOCK, &set, NULL);
	
	sleep(3);
	printf("sleep 3"); //没有换行,看abort调用是否刷新流
	abort();

	return 0;
}
yexiang@ubuntu:<_EVENT_SIG>$ ./a.out 
sleep 3Aborted (core dumped) //产生core 文件

有人有疑问为什么我没看到core 文件,大部分是没开core功能

yexiang@ubuntu:<_EVENT_SIG>$ ulimit -a
core file size          (blocks, -c) 0 // 0代表关闭

yexiang@ubuntu:<_EVENT_SIG>$ ulimit -c 5 //尝试设置5kb 试试
yexiang@ubuntu:<_EVENT_SIG>$ ulimit -a  
core file size          (blocks, -c) 5

2.raise

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <utime.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <dirent.h>
#include <limits.h>
#include <malloc.h>
#include <signal.h>

int main(int argc, char *argv[])
{

	sleep(3);
	printf("sleep 3"); //没有换行,看raise调用是否刷新流
	raise(SIGABRT);

	return 0;
}
yexiang@ubuntu:<_EVENT_SIG>$ ./a.out 
Aborted (core dumped) //产生core 文件但没刷新流

 

2014-04-15 18:26:26 boyxulin1986 阅读数 517

ARM定义了有七种异常,当有异常发生时,ARM会根据异常的类型自动执行异常向量表中的指令。
这几种异常具体如下:
reset      SVC +0x00
undefine   UND +0x04
SWI        SVC +0x08
prefetch   ABT +0x0c
data abort ABT +0x10
IRQ        IRQ +0x18
FIQ        FIQ +0x1c

以下简单说说在编程中本人常见的几种异常:
1. 除零异常,
当被除数为零时,就会发生除零异常;
此时kernel会发出Signal 8(SIGFPE)

2. un-align data abort,
未对齐的数据访问导致的data abort。
例如,
int* pi_test = (int *)0x44332211;
*pi_test = 0;
这时系统就会产生un-align data abort。
因为现代的编译器已经越来越智能,编译时能够给指针一个对齐的地址,
所以这种异常并不是很常见;

3. data abort
这是编程中及其常见的一类abort,
比如空指针的读写、写rodata section等等都会发出这种abort。
此时kernel会发出Signal 11(SIGSEGV)Segmentation fault出来。

4. prefetch abort
ARM CPU根据一个地址预取指令,发现地址取不出数据或无法访问时,
就会触发预取指令异常。
typedef void (*pf_abort)(void);

pf_abort pf_abort_func = 0x44556678;

/* call pf_abort_func */
pf_abort_func();
运行程序就会abort了。

幸运的是,以上介绍的几种abort大部分情况下都能通过系统产生的core文件来debug出问题点。
PC+LR+linux tools(readelf/nm/objdump)来查到地址对应的符号。

abort是常见的一类变成错误,作为程序员应该要以平常心对待之。
另外从另一个角度来讲,多使用ASSERT+error handling可以帮助你写出更健壮的程序。

2010-05-20 03:30:00 Poechant 阅读数 10508