gpt4 book ai didi

c - abort() 在 glibc 版本 < 2.27 中不是异步信号安全的吗?

转载 作者:行者123 更新时间:2023-12-02 15:44:30 25 4
gpt4 key购买 nike

我正在阅读 signal safety在联机帮助页中,abort 是 POSIX 标准要求的异步信号安全功能之一。但是,根据 abort 的联机帮助页, 它说

Up until glibc 2.26, if the abort() function caused processtermination, all open streams were closed and flushed (as withfclose(3)).

fclose 未列为异步信号安全(尽管 close 是)。这是否意味着 abort 在 2.27 之前的 glibc 版本中不是异步信号安全的?

我这么想的另一个原因是 exit(3) 不是异步信号安全的,因为它会刷新 stdio 缓冲区,这正是 abort 使用的做。

最佳答案

fclose is not listed as async-signal-safe (although close is). Does this mean that abort was not async-signal-safe in glibc versions before 2.27?

是的,你是对的。 abort 在早期版本中不是异步信号安全的。在某个阶段,它会[尝试]fclose所有打开的。而且,它将通过它设置的内部信号处理程序执行此操作。

给定的流可能被锁定或处于不确定状态。 TL;DR 是 abort 不是 异步安全的,因为 fclose 是[并且] 不是 异步安全的。

缺乏异步安全的原因之一是 malloc 等。阿尔。 异步安全。尽管它们将访问包装在互斥体中,但它们不会屏蔽信号。进程/线程可以在涉及执行 realloc 的流上执行 set*buf。信号处理程序中的调用可能会损坏堆和/或崩溃。


能够查看较旧的源代码可能会有所帮助。这是 glibc 源代码页面:

https://www.gnu.org/software/libc/sources.html

在该页面上,我们可以克隆 glibc git 存储库:

git clone https://sourceware.org/git/glibc.git
cd glibc
git checkout master

这将为我们提供一个相当现代的版本。

但是,只要稍微改变那里的说明,我们就可以检查早期版本:

git checkout release/2.25/master

然后,如果我们查看 stdlib/abort.c,我们会看到:

  /* Now close the streams which also flushes the output the user
defined handler might has produced. */
if (stage == 4)
{
++stage;
__fcloseall ();
}

在以后的版本中,第 4 阶段缺少 __fcloseall 调用:

  /* Now try to abort using the system specific command.  */
if (stage == 4)
{
++stage;
ABORT_INSTRUCTION;
}

这是 2.25 到当前的 [手动] 差异:

--- abort.c 2022-12-11 22:42:33.064470777 -0500
+++ /tmp/abort.c 2022-12-11 22:42:21.106728443 -0500
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.

The GNU C Library is free software; you can redistribute it and/or
@@ -13,7 +13,7 @@

You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
+ <https://www.gnu.org/licenses/>. */

#include <libc-lock.h>
#include <signal.h>
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <internal-signals.h>

/* Try to get a machine dependent instruction which will make the
program crash. This is used in case everything else fails. */
@@ -30,11 +31,8 @@
# define ABORT_INSTRUCTION
#endif

-#include <libio/libioP.h>
-#define fflush(s) _IO_flush_all_lockp (0)
-
/* Exported variable to locate abort message in core files etc. */
-struct abort_msg_s *__abort_msg __attribute__ ((nocommon));
+struct abort_msg_s *__abort_msg;
libc_hidden_def (__abort_msg)

/* We must avoid to run in circles. Therefore we remember how far we
@@ -50,32 +48,24 @@
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. */
+ /* Unblock 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);
+ internal_sigset_t sigs;
+ internal_sigemptyset (&sigs);
+ internal_sigaddset (&sigs, SIGABRT);
+ internal_sigprocmask (SIG_UNBLOCK, &sigs, NULL);
}

/* Send signal which possibly calls a user handler. */
- if (stage == 2)
+ if (stage == 1)
{
/* This stage is special: we must allow repeated calls of
`abort' when a user defined handler for SIGABRT is installed.
@@ -93,7 +83,7 @@
}

/* There was a handler installed. Now remove it. */
- if (stage == 3)
+ if (stage == 2)
{
++stage;
memset (&act, '\0', sizeof (struct sigaction));
@@ -103,30 +93,22 @@
__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)
+ if (stage == 3)
{
++stage;
raise (SIGABRT);
}

/* Now try to abort using the system specific command. */
- if (stage == 6)
+ if (stage == 4)
{
++stage;
ABORT_INSTRUCTION;
}

/* If we can't signal ourselves and the abort instruction failed, exit. */
- if (stage == 7)
+ if (stage == 5)
{
++stage;
_exit (127);

关于c - abort() 在 glibc 版本 < 2.27 中不是异步信号安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74766327/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com