首先很抱歉在信号处理程序里面调用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 ..
我在https://access.redhat.com/solutions/48701报告了类似的核心。
操作系统:RHEL
答案 0 :(得分:6)
malloc()
不是可以从信号处理程序安全调用的函数。它不是异步信号安全功能。
所以,你永远不应该从信号处理程序调用malloc()。您只能从信号处理程序中调用一组有限的功能。
有关可以从信号处理程序安全调用的函数列表,请参阅man signal-safety。
查看您的GDB输出,看来当malloc()
持有锁时,您再次调用malloc()
会导致死锁。
答案 1 :(得分:4)
只能从信号处理程序中安全地调用异步信号安全函数。
以上[在下面复制]表格中的任何功能都可能不安全 信号。实现可以使其他接口异步信号安全。 在存在信号的情况下,由此卷定义的所有函数 POSIX.1-2008在调用或中断时应按行为定义 通过信号捕捉功能,除了当一个信号 中断不安全的功能或等效功能(如处理 相当于从初始调用返回后执行的
exit()
到main())和信号捕获函数调用一个不安全的函数, 行为未定义。其他例外情况在 各个功能的描述,例如longjmp()
。
如果从信号处理程序中调用“不安全的函数”,则“行为未定义”。
异步信号安全功能
自处理以来,信号处理函数必须非常小心 其他地方可能会在执行中的某个任意点中断 该计划。 POSIX具有“安全功能”的概念。如果一个 信号中断执行不安全的函数和处理程序 要么调用不安全的函数,要么通过调用来终止处理程序 longjmp()或siglongjmp(),程序随后调用 不安全的函数,那么程序的行为是不确定的。
Linux手册页提供了Linux上的async-signal-safe函数列表。它们可能与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()
答案 2 :(得分:0)
malloc
的实现可能会抓住内部glibc锁定。我们知道信号处理程序是异步调用的。如果正常执行期间的线程有malloc
&d;并且被中断以处理信号,那么如果信号处理函数使用malloc
则会出现问题。信号处理程序malloc
会尝试获取锁,但它不可用,因为同一个线程在正常执行期间获得了它。你有僵局。因此,信号处理程序应该是精简的,不应该调用非AS安全功能。
答案 3 :(得分:0)
直接回答OP的问题。一些glibc包装器(例如malloc arenas和printf文件访问)使用低级锁定来实现并发。信号处理程序进入函数调用,抓取" lll _",中断,重新进入函数调用和死锁。
可能的解决方案: 1)上面已经讨论过第一个 2)不要使用glibc包装器 - 直接进入内核系统调用。例如。不要使用printf,请使用write。不要使用glibc malloc,使用系统调用(sbrk ...) - 可能不是一个好主意,除非你真的不得不...... 3)不要在处理程序中进行任何动态内存分配,在主任务中分配它并在处理程序中访问它