我的理解是,一般来说,如果从信号处理程序调用非异步信号安全函数,行为是不确定的,但我听说linux允许你安全地调用任何系统调用.这是真的?此外,SIGSEGV处理程序的唯一可移植行为是中止或退出,但我知道如果你返回,linux实际上会恢复执行,是吗?
小智 20
根据第2节signal手册:
请参阅signal(7)以获取可从信号处理程序内部安全调用的异步信号安全函数列表.
和第7 signals手册列出了以下的功能和/或系统调用连同非常清楚的说明:
异步信号安全功能
A signal handler function must be very careful, since processing elsewhere may
be interrupted at some arbitrary point in the execution of the program. POSIX
has the concept of "safe function". If a signal interrupts the execution of
an unsafe function, and handler calls an unsafe function, then the behavior of
the program is undefined.
POSIX.1-2004 (also known as POSIX.1-2001 Technical Corrigendum 2) requires an
implementation to guarantee that the following functions can be safely called
inside a signal handler:
_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()
execle()
execve()
fchmod()
fchown()
fcntl()
fdatasync()
fork()
fpathconf()
fstat()
fsync()
ftruncate()
getegid()
geteuid()
getgid()
getgroups()
getpeername()
getpgrp()
getpid()
getppid()
getsockname()
getsockopt()
getuid()
kill()
link()
listen()
lseek()
lstat()
mkdir()
mkfifo()
open()
pathconf()
pause()
pipe()
poll()
posix_trace_event()
pselect()
raise()
read()
readlink()
recv()
recvfrom()
recvmsg()
rename()
rmdir()
select()
sem_post()
send()
sendmsg()
sendto()
setgid()
setpgid()
setsid()
setsockopt()
setuid()
shutdown()
sigaction()
sigaddset()
sigdelset()
sigemptyset()
sigfillset()
sigismember()
signal()
sigpause()
sigpending()
sigprocmask()
sigqueue()
sigset()
sigsuspend()
sleep()
sockatmark()
socket()
socketpair()
stat()
symlink()
sysconf()
tcdrain()
tcflow()
tcflush()
tcgetattr()
tcgetpgrp()
tcsendbreak()
tcsetattr()
tcsetpgrp()
time()
timer_getoverrun()
timer_gettime()
timer_settime()
times()
umask()
uname()
unlink()
utime()
wait()
waitpid()
write()
POSIX.1-2008 removes fpathconf(), pathconf(), and sysconf() from the above
list, and adds the following functions:
execl()
execv()
faccessat()
fchmodat()
fchownat()
fexecve()
fstatat()
futimens()
linkat()
mkdirat()
mkfifoat()
mknod()
mknodat()
openat()
readlinkat()
renameat()
symlinkat()
unlinkat()
utimensat()
utimes()
Run Code Online (Sandbox Code Playgroud)
我相信这些信息比我们有时听到的某些信息更可靠.所以Linux确实只允许一些系统调用,但不是全部.所以你的问题的答案很简单 - 不.
是的,没有
是:
您可以在信号处理程序中调用任何实际/原始系统调用.内核有责任确保它是安全的(在内核的视图中).
1)内核不知道用户空间的上下文,或者说内核在传递信号后将状态保存到用户空间后故意忘记它.(注意:执行恢复是由用户通过系统调用在保存状态的帮助下完成的,而不是由内核完成,内核已经忘记了)
2)一些线程lib是通过单一实现的,因此线程已经在"信号处理程序"中,但这些线程可以调用任何系统调用.
没有:
但用户空间功能有其自身的目的和副作用.有些不能重新进入安全,这些功能无法从信号处理程序调用.man 7 signal将帮助您找出哪些是重新入口安全.
举个例子,你可以sys_futex()在包括信号处理程序在内的任何地方调用,但如果你sys_futex()用来实现互斥锁,sys_futex()当信号中断互斥锁的关键部分时,内部信号处理程序可能永远被阻塞.
此外,SIGSEGV处理程序的唯一可移植行为是中止或退出,但我知道如果你返回,linux实际上会恢复执行,是吗?
是的,如果你找不到原因.有些用户可能会将SIGSEGV用于他们自己的地图 - 当需要时(例如,在JIT中,您可以将SIGSEGV信号处理程序中的代码翻译并将已翻译的代码mmap到内存然后返回),他们可以调用mmap()或mprotect ()......等.
我相信任何真正的系统调用都可以从信号处理程序调用.真正的系统调用在<asm/unistd.h>(或<asm/unistd_64.h>)中有一个数字.
手册页第2节中的一些posix函数是通过"多路复用"系统调用来实现的,所以它们不是我认为的"真正的系统调用"
从应用程序的角度来看,系统调用是一种原子操作; 它几乎就像一台机器指令(来自应用程序内部).看到这个答案.
如果您的问题是:处理程序是否可以SIGSEGV通过mprotect或更改故障地址映射mmap?那么我相信答案是肯定的(至少在X86-64和X86-32架构),因为在这里说你引用了一个问题,但我没有尝试.我读过,这样做是非常低效的(SIGSEGV处理不是非常快,mprotect或者mmap也有点慢).特别是,这样模仿Hurd/Mach外部寻呼机可能效率低下.
| 归档时间: |
|
| 查看次数: |
8060 次 |
| 最近记录: |