4 ms·
Despite what the other commenters are saying, it is bizarre. 1. There is very little you can safely do in a signal handler. For a threaded application, that pr
by arghwhat 3y ago
Despite what the other commenters are saying, it is bizarre.
1. There is very little you can safely do in a signal handler. For a threaded application, that pretty much boils entirely down to setting a bit and leaving it at that. If they did anything more, the behavior is undefined.
2. The memory state that a program receiving a SIGSEGV in is often undefined/garbage, and attempting to execute further at this point is at best unsafe, at worst trampling on state further, continuing execution in a broken state and destroying all evidence that would be useful for debugging - whereas a coredump preserves the state at the time the issue occurs.
There are cases where you need to catch SIGBUS, such as if an anonymous file has been truncated after you mmap'ed it.
- fweimer 3y agoThe signal comes from a safe fetch, which is just a read that allows ignoring the fault as if it never happened. Such a signal is deliver synchronously, so the usual restrictions for asynchronous signal handlers do not apply. The code in question takes into account that the value read might be garbage. See the big comment here: https://github.com/openjdk/jdk/commit/29397d29baac3b29083b1b5d6b2cb06e456af0c3 https://github.com/openjdk/jdk/commit/29397d29baac3b29083b1b... On current CPUs and operating systems, this is not an optimization, so the code was removed earlier this year: https://bugs.openjdk.org/browse/JDK-8320317 https://bugs.openjdk.org/browse/JDK-8320317
- arghwhat 3y agoThe "safe fetch" code relies on a signal handler (either here https://github.com/openjdk/jdk/blob/48717d63cc58f693f0917e61eafd672cd6af02ed/src/hotspot/os/posix/vmError_posix.cpp#L80 https://github.com/openjdk/jdk/blob/48717d63cc58f693f0917e61... or here https://github.com/openjdk/jdk/blob/3c70f26b2f3fa9bc143e2506af30f9b1daf20022/src/hotspot/os/posix/signals_posix.cpp#L557C5-L557C26 https://github.com/openjdk/jdk/blob/3c70f26b2f3fa9bc143e2506...), which is considered asynchronous delivery (i.e., delivered mid-execution, see `man 7 signal`) - which is why the `async-signal-safe` manpage simply states that it is functions that can safely be called within a signal handler. This is opposed to calling `sigwait` or similar to actively suspend and wait for a signal, which is not possible to do here. Granted, it may be that the stars align and their implementation works in practice, but that does not make it any less bizarre.
- quotemstr 3y agoIt's not "bizarre" at all. It's a direct translation of hardware CPU traps to userspace API. That's what signal handers are: virtualized interrupts! There's nothing wrong with using signals to achieve performance levels otherwise not possible.
- zozbot234 3y agoBut this also means that signal handlers are running in what's effectively a separate thread of execution - even in otherwise single-threaded code! So the things you're allowed to do safely in your signal handler are very limited, they boil down to atomically tweaking some lightweight data structure (or even just setting a flag) that the main code will look at later and behave accordingly.
- quotemstr 3y agoWhile it's true that async-signal-safe programming bears some similarities to multi-threaded programming, an interrupt really isn't the same as a thread. Also, there's a lot more you can do in a signal handler than just set a flag: you can longjmp or even make calls to regular functions. For example, one kind of program organization that used to be more common in Unix but that remains legal involves keeping signals masked all the time except around certain blocking system calls, e.g. ppoll, that atomically unblock signals and wait. In such a program, a signal can arrive only inside the blocking system call and so the handler can call regular functions without the usual strictures of asynchronous signal safety. (Consider responding to SIGWINCH, which tells you about changing terminal size.) Synchronous signals are also special in that they're, well, synchronous. That means that in the signal handler you can examine the target memory address or instruction pointer and take action specific to a given spot in your program --- e.g. longjmp to an error handler. All of this is useful, safe, and legal under POSIX. The main problems with POSIX signals are that, 1) as this thread underscores, most people don't understand them, and 2) signal handlers are process global and hard to share. (Consider if you're running two VMs in a process and each wants to use a SIGSEGV GC safe point trick.) (userfaultfd, sadly, requires more system calls than a synchronous signal handler to handle anomalous memory access.) We should be enhancing POSIX signals to make them easier to share, not casting aspersions on them.
- PhilipRoman 3y ago>There is very little you can safely do in a signal handler You can actually do pretty much anything you want, it's just the C library that uses a lot of global state and internal memory allocations, which messes things up. The core syscall API and any reentrant code you write yourself are not affected. >The memory state that a program receiving a SIGSEGV in is often undefined/garbage That may be true for arbitrary segfaults caused by bugs, but the JIT has 100% control over what instructions to emit, it is not restricted by ABIs or platform-specific issues, so there is no problem to use SEGV as a signaling mechanism.
- zozbot234 3y agoYou can "do pretty much anything you want" as long as you carefully avoid doing anything non thread-safe (even indirectly) in both the main app and the handler itself? How reassuring!
- dwattttt 3y agoThe HotSpot JVM is already multithreaded, they understand how to write thread-safe code (I'm not sure which JVM(s?) are reported to be impacted, HotSpot was the first I found a result for).