linux信号处理程序中的malloc导致死锁

Nav*_*mar 4 c linux signals rhel

首先很抱歉在信号处理程序内部调用malloc :).我也明白我们不应该在信号处理程序中做任何耗费任务/这种讨厌的事情.

但我很想知道它崩溃的原因?

 #0  0x00006e3ff2b60dce in _lll_lock_wait_private () from /lib64/libc.so.6
 #1  0x00006e3ff2aec138 in _L_lock_9164 () from /lib64/libc.so.6
 #2  0x00006e3ff2ae9a32 in malloc () from /lib64/libc.so.6
 #3  0x00006e3ff1f691ad in ?? () from ..
Run Code Online (Sandbox Code Playgroud)

我在https://access.redhat.com/solutions/48701中报告了类似的核心.

操作系统:RHEL

P.P*_*.P. 7

malloc()不是可以从信号处理程序安全调用的函数.它不是异步信号安全功能.所以,你永远不应该从信号处理程序调用malloc().您只能从信号处理程序中调用一组有限的功能.有关可以从信号处理程序安全调用的函数列表,请参阅man signal-safety.

查看您的GDB输出,看起来在malloc()持有锁时,您malloc()再次调用会导致死锁.


And*_*nle 5

只有异步信号安全函数才能从信号处理程序中安全地调用。

根据POSIX 标准

任何不在上面[复制如下]表中的函数对于信号来说可能是不安全的。实现可以使其他接口异步信号安全。在存在信号的情况下,POSIX.1-2008 本卷定义的所有函数在从信号捕获函数调用或被信号捕获函数中断时,其行为应与所定义的一样,但当信号中断不安全函数或等效函数时(例如相当于exit()从初始调用 main() 返回后执行的处理,并且信号捕获函数调用了不安全函数,该行为是未定义的。其他例外在各个函数的描述中指定,例如longjmp()

如果您从信号处理程序中调用“不安全函数”,则“行为未定义”。

Linux手册signal.7指出:

异步信号安全函数

信号处理函数必须非常小心,因为其他地方的处理可能会在程序执行过程中的某个任意点被中断。POSIX有“安全函数”的概念。如果信号中断不安全函数的执行,并且处理程序调用不安全函数,或者处理程序通过调用 longjmp() 或 siglongjmp() 终止,并且程序随后调用不安全函数,则程序的行为是未定义的。

Linux 手册页提供了 Linux 上异步信号安全函数的列表。它们可能与 POSIX 规范中列出的不同 - 我没有对它们进行比较,并且标准和实现确实会随着时间的推移而发生变化。上面第一个引用中的 POSIX“上表”中的“安全函数”仅包含以下函数:

_Exit()
_exit()
abort()
accept()
access()
aio_error()
aio_return()
aio_suspend()
alarm()
bind()
cfgetispeed()
cfgetospeed()
cfsetispeed()
cfsetospeed()
chdir()
chmod()
chown()
clock_gettime()
close()
connect()
creat()
dup()
dup2()
execl()
execle()
execv()
execve()
faccessat()
fchdir()
fchmod()
fchmodat()
fchown()
fchownat()
fcntl()
fdatasync()
fexecve()
ffs()
fork()
fstat()
fstatat()
fsync()
ftruncate()
futimens()
getegid()
geteuid()
getgid()
getgroups()
getpeername()
getpgrp()
getpid()
getppid()
getsockname()
getsockopt()
getuid()
htonl()
htons()
kill()
link()
linkat()
listen()
longjmp()
lseek()
lstat()
memccpy()
memchr()
memcmp()
memcpy()
memmove()
memset()
mkdir()
mkdirat()
mkfifo()
mkfifoat()
mknod()
mknodat()
ntohl()
ntohs()
open()
openat()
pause()
pipe()
poll()
posix_trace_event()
pselect()
pthread_kill()
pthread_self()
pthread_sigmask()
raise()
read()
readlink()
readlinkat()
recv()
recvfrom()
recvmsg()
rename()
renameat()
rmdir()
select()
sem_post()
send()
sendmsg()
sendto()
setgid()
setpgid()
setsid()
setsockopt()
setuid()
shutdown()
sigaction()
sigaddset()
sigdelset()
sigemptyset()
sigfillset()
sigismember()
siglongjmp()
signal()
sigpause()
sigpending()
sigprocmask()
sigqueue()
sigset()
sigsuspend()
sleep()
sockatmark()
socket()
socketpair()
stat()
stpcpy()
stpncpy()
strcat()
strchr()
strcmp()
strcpy()
strcspn()
strlen()
strncat()
strncmp()
strncpy()
strnlen()
strpbrk()
strrchr()
strspn()
strstr()
strtok_r()
symlink()
symlinkat()
tcdrain()
tcflow()
tcflush()
tcgetattr()
tcgetpgrp()
tcsendbreak()
tcsetattr()
tcsetpgrp()
time()
timer_getoverrun()
timer_gettime()
timer_settime()
times()
umask()
uname()
unlink()
unlinkat()
utime()
utimensat()
utimes()
wait()
waitpid()
wcpcpy()
wcpncpy()
wcscat()
wcschr()
wcscmp()
wcscpy()
wcscspn()
wcslen()
wcsncat()
wcsncmp()
wcsncpy()
wcsnlen()
wcspbrk()
wcsrchr()
wcsspn()
wcsstr()
wcstok()
wmemchr()
wmemcmp()
wmemcpy()
wmemmove()
wmemset()
write()
Run Code Online (Sandbox Code Playgroud)