Cygwin: sigtimedwait: Fix segfault when timeout is used
Previously, two bugs exist in sigtimedwait(). One is, that since
_my_tls.sigwait_mask was left non-zero if the signal arrives after
the timeout, sigpacket::process() would wrongly try to handle it.
The other is if a timeout occurs after sigpacket::process() is
called, but not completed yet, the signal handler can be called
accidentally. If the signal handler is set to SIG_DFL or SIG_IGN,
access violation will occur in both cases.
With this patch, in sigwait_common(), check if sigwait_mask == 0
to confirm that sigpacket::process() cleared it. In this case,
do not treat WAIT_TIMEOUT, but call cygwait() again to retrieve
the signal. Furthermore, sigpacket::process() checks whether
timeout occurs in sigwait_common() and if timeout already happens,
do not treat the signal as waited. In both cases, to avoid race
issues, the code is guarded by cygtls::lock().
Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256762.html
Fixes: 24ff42d79a
("Cygwin: Implement sigtimedwait")
Reported-by: Christian Franke <Christian.Franke@t-online.de>
Reviewed-by: Corinna Vinschen <corinna@vinschen.de>
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
This commit is contained in:
parent
21a2c9db69
commit
26144e4008
|
@ -1527,11 +1527,14 @@ sigpacket::process ()
|
|||
if ((HANDLE) *tls)
|
||||
tls->signal_debugger (si);
|
||||
|
||||
if (issig_wait)
|
||||
tls->lock ();
|
||||
if (issig_wait && tls->sigwait_mask != 0)
|
||||
{
|
||||
tls->sigwait_mask = 0;
|
||||
tls->unlock ();
|
||||
goto dosig;
|
||||
}
|
||||
tls->unlock ();
|
||||
|
||||
if (handler == SIG_IGN)
|
||||
{
|
||||
|
|
|
@ -42,3 +42,6 @@ Fixes:
|
|||
|
||||
- Fix NtCreateEvent() error in create_lock_ob() called from flock().
|
||||
Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html
|
||||
|
||||
- Fix segfault in sigtimedwait() when using timeout.
|
||||
Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256762.html
|
||||
|
|
|
@ -615,6 +615,7 @@ sigwait_common (const sigset_t *set, siginfo_t *info, PLARGE_INTEGER waittime)
|
|||
set_signal_mask (_my_tls.sigwait_mask, *set);
|
||||
sig_dispatch_pending (true);
|
||||
|
||||
do_wait:
|
||||
switch (cygwait (NULL, waittime,
|
||||
cw_sig_eintr | cw_cancel | cw_cancel_self))
|
||||
{
|
||||
|
@ -640,6 +641,17 @@ sigwait_common (const sigset_t *set, siginfo_t *info, PLARGE_INTEGER waittime)
|
|||
}
|
||||
break;
|
||||
case WAIT_TIMEOUT:
|
||||
_my_tls.lock ();
|
||||
if (_my_tls.sigwait_mask == 0)
|
||||
{
|
||||
/* sigpacket::process() already started.
|
||||
Will surely be signalled soon. */
|
||||
waittime = cw_infinite;
|
||||
_my_tls.unlock ();
|
||||
goto do_wait;
|
||||
}
|
||||
_my_tls.sigwait_mask = 0;
|
||||
_my_tls.unlock ();
|
||||
set_errno (EAGAIN);
|
||||
break;
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue