Summary: | [timer_create / SIGEV_THREAD] signalmask of timer_sigev_thread dangerous | ||
---|---|---|---|
Product: | glibc | Reporter: | Roland Lezuo <roland.lezuo> |
Component: | librt | Assignee: | Adhemerval Zanella <adhemerval.zanella> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | adhemerval.zanella, bugdal, glibc-bugs, tpiepho |
Priority: | P2 | Flags: | fweimer:
security-
|
Version: | 2.9 | ||
Target Milestone: | 2.32 | ||
Host: | Target: | ||
Build: | Last reconfirmed: |
Description
Roland Lezuo
2009-10-20 10:11:43 UTC
The behavior is correct. You're relying on undefined behavior. Just don't do it. (In reply to comment #1) > The behavior is correct. You're relying on undefined behavior. Just don't do > it. This means it's impossible to use sigwait()/sigwaitinfo()/sigtimedwait() in the same process with a POSIX timer using SIGEV_THREAD. It would be much more useful if the helper thread had the same signal mask as the thread that originally called timer_create. That signal mask is already retrieved when the timer thread is created. If it were simply stored somewhere, then the helper thread could set its mask to that instead of an empty set. Drepper's comment is technically incorrect; the behavior is implementation-defined, not undefined. And in this case, glibc is actively providing detrimental behavior. I think this should be fixed. As Trent suggested, it may be convenient to have the signal mask match the mask at the time of the call to timer_create, but storing this and restoring it would be extra work. I think the most-correct behavior is for the timer thread always to start with all signals blocked. If the applications wants some signals unblocked, it can always unblock them as part of the timer handling code. But if any of them start out unblocked, it's impossible to block them without race conditions. Basically, this just comes down to common-sense about signal masking and race conditions. A library function (whether in the standard library or a third-party library) should NEVER unblock a signal unless that signal is only used for its own internal purposes (like the timer or cancellation signals). The only operations libraries ever perform on the signal mask should be blocking signals and restoring to a previously-saved mask. The signal mask is already stored by code in the timer_create() call, so using that mask in the timer thread doesn't actually take any more work that is done now. It's just as matter of changing two existing rt_sigprocmask calls to use a global rather than a local variable. But thinking about it more, I agree with Rich that blocking all signals is the only sensible way. The sigprocmask call in the timer thread can be removed. The user code can always add it back and unblock whatever it wants unblocked if it cares. If it doesn't, then the call is avoided. Restoring the mask used when calling timer_create() wouldn't work if the process has since blocked a signal. For instance, if it needs to modify a data structure also used by a signal handler, it's necessary to block the signal while doing so to avoid racing with the handler. If a completely unrelated timer goes off and creates a new thread with unblocked signals.... Using a global is definitely not viable; the sigset_t would have to be added to the structure allocated for the particular timer. There's no reason this couldn't be done, but I think we're both in agreement that starting SIGEV_TIMER threads with all signals blocked is the most desirable (and most flexible) behavior anyway. Fixed on 2.32. |