3 ms·
> That is not accurate. If I have a single-threaded program sitting around a ppoll(2) loop and a signal can arrive only inside my main loop ppoll(), then I know
by arghwhat 3y ago
> That is not accurate. If I have a single-threaded program sitting around a ppoll(2) loop and a signal can arrive only inside my main loop ppoll(), then I know a priori that my signal handler can't be interrupting non-reentrant code and so I can call whatever I want inside it.
If you have a single-threaded program sitting in ppoll, you cannot ever receive a SIGSEGV during said ppoll unless you passed it bugus fds, timeout or sigmask pointers. A sleeping process cannot segfault.
If you register a SIGSEGV handler, you have zero guarantees that it will only fire at a particular time in your code as it is delivered on any pagefault from any code accidentally generating it. This is why the async-signal-safe rules apply.
If you try handling such fault, what needs to be reentrant is the full call stack that lead to the fault, and every call made from the handler. If, for example, the fault is generated from an event loop handler (in case of a single-threaded example, most things run off event loop handlers), the signal handler must in turn not touch the event loop (no adding/removing/adjusting events, no dispatch) unless the event loop is fully reentrant.
- quotemstr 3y ago> you cannot ever receive a SIGSEGV during said ppoll Unless someone sends one with kill(2). Also, I was talking about signals in general, not SIGSEGV in particular. Who uses SIGSEGV as an async work dispatch mechanism? > unless you passed it bugus fds, timeout or sigmask pointers. A sleeping process cannot segfault. No, you get EFAULT. System calls don't work that way. > If you register a SIGSEGV handler, you have zero guarantees that it will only fire at a particular time in your code as it is delivered on any pagefault from any code accidentally generating it That's why you use sigaction(2) to register signal handlers --- your callback gets both a siginfo_t and a ucontext_t you can use to figure out whether your segfault came from a region of code you know about or some other random thing going wrong in your process. In principle, you can do the non-reentrant thing after having checked that the signal came from the context you expect, and you can do this checking in an async-signal-safe manner. > If, for example, the fault is generated from an event loop handler (in case of a single-threaded example, most things run off event loop handlers), the signal handler must in turn not touch the event loop (no adding/removing/adjusting events, no dispatch) unless the event loop is fully reentrant. Of course. That's a matter of program design.
- arghwhat 3y ago> No, you get EFAULT. System calls don't work that way. `ppoll(2)` is a C library function you call. On glibc, depending on which implementation you hit on your architecture, the `ppoll` call will segfault before the syscall if you call it with bogus timeout or sigmask pointers, as glibc is dereferencing them. > That's why you use sigaction(2) to register signal handlers --- your callback gets both a siginfo_t and a ucontext_t you can use to figure out whether your segfault came from a region of code you know about or some other random thing going wrong in your process. It is true that you could try to figure out whether the faulting address is within a range you thought belonged to a particular thing, but I don't see any reason or benefit. However, this is fragile: Distinguishing between a page fault from a corrupt program state and a page fault in a valid program depends on the program state (specifically, inspecting memory that is likely foo), which in turn makes the output undefined. You won't get false negatives, but will get false positives. You could also try to establish a list of all program counter values (PIE/PIC caveats), and check if the signal originated from near those, but... Ugh. Now, any other signal I could level with you, but not SIGSEGV. Not until I see some code where it's truly justified: a real, tangible benefit that can only be obtained in this fashion, justifying all the gymnastics and (in my opinion) nastiness of trying to handle a signal that should never be handled in the first place (not even for crash dumps, they're always worse than a proper core).
- quotemstr 3y ago> `ppoll(2)` is a C library function you call. ppoll is a real system call on all Linux systems and has been for over a decade. > It is true that you could try to figure out whether the faulting address is within a range you thought belonged to a particular thing, Which programs do, reliably, all the time. > You won't get false negatives, but will get false positives. No, you won't. Once a program wanders into la-la land of memory corruption, all bets are off anyway.