[英]Abort function in C
程序1:
#include<stdio.h>
#include<signal.h>
void handler(int sig);
void main()
{
printf("PID: %d\n",getpid());
signal(SIGABRT,handler);
while(1){
printf("Hai\n");
sleep(1);
abort();
}
}
void handler(int sig)
{
printf("Signal handled\n");
}
输出1:
$ ./a.out
PID: 32235
Hai
Signal handled
Aborted (core dumped)
$
根据参考,中止函数的工作方式类似于raise(SIGABRT)
。 因此, abort()
函数生成的信号为SIGABRT。 因此,我创建了上面的程序。
在该程序中,将处理SIGABRT信号。 执行信号处理程序后,它不会从调用它的位置返回到主函数。 处理程序完成后,为什么不返回主函数?
程式2:
#include<stdio.h>
#include<signal.h>
void handler(int sig);
void main()
{
printf("PID: %d\n",getpid());
signal(SIGABRT,handler);
while(1){
printf("Hai\n");
sleep(1);
}
}
void handler(int sig)
{
printf("Signal handled\n");
}
输出2:
$ ./a.out
PID: 32247
Hai
Hai
Hai
Signal handled
Hai
Signal handled
Hai
Hai
^C
$
与程序1不同,程序2按预期执行。 在上面的程序中,信号通过kill命令通过命令行发送到进程,如下所示。
$ kill -6 32247
$ kill -6 32247
因此,一旦出现信号,便执行处理程序函数,然后返回主函数。 但是它不会在程序1中发生。为什么它会表现为这样? abort
功能和SIGABRT不同吗?
请参阅man 3 abort
此文档:
除非捕获到SIGABRT信号并且信号处理程序不返回,否则这将导致进程异常终止(请参见
longjmp(3)
)。
还有这个:
如果
SIGABRT
信号被忽略,或者被返回的处理程序捕获,则abort()
函数仍将终止该过程。 它通过恢复SIGABRT
的默认配置,然后第二次提高信号来做到这一点。
因此,防止信号abort()
中止程序的唯一方法是通过信号处理程序中的longjmp()
ing。
Libc实现abort()
。 在其实现中, abort()
检查该进程是否仍然存在,因为abort()
在raise(SIGABRT)
之后执行。 如果是,则知道用户已处理SIGABRT
。 根据文档,这无关紧要,因为该过程仍将退出:
您可以在GLIBC源代码( stdlib/abort.c
)中看到确切的实现:
/* Cause an abnormal program termination with core-dump. */
void
abort (void)
{
struct sigaction act;
sigset_t sigs;
/* First acquire the lock. */
__libc_lock_lock_recursive (lock);
/* Now it's for sure we are alone. But recursive calls are possible. */
/* Unlock SIGABRT. */
if (stage == 0)
{
++stage;
if (__sigemptyset (&sigs) == 0 &&
__sigaddset (&sigs, SIGABRT) == 0)
__sigprocmask (SIG_UNBLOCK, &sigs, (sigset_t *) NULL);
}
/* Flush all streams. We cannot close them now because the user
might have registered a handler for SIGABRT. */
if (stage == 1)
{
++stage;
fflush (NULL);
}
/* Send signal which possibly calls a user handler. */
if (stage == 2)
{
/* This stage is special: we must allow repeated calls of
`abort' when a user defined handler for SIGABRT is installed.
This is risky since the `raise' implementation might also
fail but I don't see another possibility. */
int save_stage = stage;
stage = 0;
__libc_lock_unlock_recursive (lock);
raise (SIGABRT);
__libc_lock_lock_recursive (lock);
stage = save_stage + 1;
}
/* There was a handler installed. Now remove it. */
if (stage == 3)
{
++stage;
memset (&act, '\0', sizeof (struct sigaction));
act.sa_handler = SIG_DFL;
__sigfillset (&act.sa_mask);
act.sa_flags = 0;
__sigaction (SIGABRT, &act, NULL);
}
/* Now close the streams which also flushes the output the user
defined handler might has produced. */
if (stage == 4)
{
++stage;
__fcloseall ();
}
/* Try again. */
if (stage == 5)
{
++stage;
raise (SIGABRT);
}
/* Now try to abort using the system specific command. */
if (stage == 6)
{
++stage;
ABORT_INSTRUCTION;
}
/* If we can't signal ourselves and the abort instruction failed, exit. */
if (stage == 7)
{
++stage;
_exit (127);
}
/* If even this fails try to use the provided instruction to crash
or otherwise make sure we never return. */
while (1)
/* Try for ever and ever. */
ABORT_INSTRUCTION;
}
根据标准,并没有完全指定如果处理SIGABRT
会发生什么:
异常终止功能导致程序异常终止,除非捕获到信号SIGABRT并且信号处理程序不返回。 实现定义是清除包含未写入的缓冲数据的打开流,关闭打开流还是删除临时文件。 状态未成功终止的实现定义形式通过函数调用raise(SIGABRT)返回到主机环境。
然而,它的规定什么是不应该的:
中止功能不会返回到其调用方。
因此,正确的行为是确保发生“异常终止”。 这是通过abort
函数来确保的,这是最好的方法,异常终止程序是最好的,它通过尝试以各种方式终止操作来完成此操作,并且如果似乎无济于事,它会进入无限循环(至少要确保它不会返回到呼叫者,召集者)。
它们不一样。 abort
函数两次调用raise(SIGABRT)
。 如果您为SIGABRT
定义了一个处理程序,它将首先调用您的处理程序,然后再调用默认处理程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.