commit eee2c95b91b2fdcb36c0b1a2ab15df4a44ee2986 Author: philippe Date: Sat Nov 19 13:51:41 2016 +0000 Fix Bug 372600 - process loops forever when fatal signals are arriving quickly git-svn-id: svn://svn.valgrind.org/valgrind/trunk@16140 a5019735-40e9-0310-863c-91ae7b9d1cf9 diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c index 168b681..b398882 100644 --- a/coregrind/m_signals.c +++ b/coregrind/m_signals.c @@ -2430,8 +2430,14 @@ void async_signalhandler ( Int sigNo, info->si_code = sanitize_si_code(info->si_code); if (VG_(clo_trace_signals)) - VG_(dmsg)("async signal handler: signal=%d, tid=%u, si_code=%d\n", - sigNo, tid, info->si_code); + VG_(dmsg)("async signal handler: signal=%d, tid=%u, si_code=%d, " + "exitreason %s\n", + sigNo, tid, info->si_code, + VG_(name_of_VgSchedReturnCode)(tst->exitreason)); + + /* */ + if (tst->exitreason == VgSrc_FatalSig) + resume_scheduler(tid); /* Update thread state properly. The signal can only have been delivered whilst we were in @@ -2479,8 +2485,16 @@ void async_signalhandler ( Int sigNo, ); /* (2) */ - /* Set up the thread's state to deliver a signal */ - if (!is_sig_ign(info, tid)) + /* Set up the thread's state to deliver a signal. + However, if exitreason is VgSrc_FatalSig, then thread tid was + taken out of a syscall by VG_(nuke_all_threads_except). + But after the emission of VKI_SIGKILL, another (fatal) async + signal might be sent. In such a case, we must not handle this + signal, as the thread is supposed to die first. + => resume the scheduler for such a thread, so that the scheduler + can let the thread die. */ + if (tst->exitreason != VgSrc_FatalSig + && !is_sig_ign(info, tid)) deliver_signal(tid, info, uc); /* It's crucial that (1) and (2) happen in the order (1) then (2) @@ -2946,6 +2960,20 @@ void VG_(poll_signals)(ThreadId tid) ThreadState *tst = VG_(get_ThreadState)(tid); vki_sigset_t saved_mask; + if (tst->exitreason == VgSrc_FatalSig) { + /* This task has been requested to die due to a fatal signal + received by the process. So, we cannot poll new signals, + as we are supposed to die asap. If we would poll and deliver + a new (maybe fatal) signal, this could cause a deadlock, as + this thread would believe it has to terminate the other threads + and wait for them to die, while we already have a thread doing + that. */ + if (VG_(clo_trace_signals)) + VG_(dmsg)("poll_signals: not polling as thread %u is exitreason %s\n", + tid, VG_(name_of_VgSchedReturnCode)(tst->exitreason)); + return; + } + /* look for all the signals this thread isn't blocking */ /* pollset = ~tst->sig_mask */ VG_(sigcomplementset)( &pollset, &tst->sig_mask ); @@ -2961,15 +2989,18 @@ void VG_(poll_signals)(ThreadId tid) /* If there was nothing queued, ask the kernel for a pending signal */ if (sip == NULL && VG_(sigtimedwait_zero)(&pollset, &si) > 0) { if (VG_(clo_trace_signals)) - VG_(dmsg)("poll_signals: got signal %d for thread %u\n", - si.si_signo, tid); + VG_(dmsg)("poll_signals: got signal %d for thread %u exitreason %s\n", + si.si_signo, tid, + VG_(name_of_VgSchedReturnCode)(tst->exitreason)); sip = &si; } if (sip != NULL) { /* OK, something to do; deliver it */ if (VG_(clo_trace_signals)) - VG_(dmsg)("Polling found signal %d for tid %u\n", sip->si_signo, tid); + VG_(dmsg)("Polling found signal %d for tid %u exitreason %s\n", + sip->si_signo, tid, + VG_(name_of_VgSchedReturnCode)(tst->exitreason)); if (!is_sig_ign(sip, tid)) deliver_signal(tid, sip, NULL); else if (VG_(clo_trace_signals)) @@ -3073,7 +3104,8 @@ void VG_(sigstartup_actions) ( void ) } if (VG_(clo_trace_signals)) - VG_(dmsg)("Max kernel-supported signal is %d\n", VG_(max_signal)); + VG_(dmsg)("Max kernel-supported signal is %d, VG_SIGVGKILL is %d\n", + VG_(max_signal), VG_SIGVGKILL); /* Our private internal signals are treated as ignored */ scss.scss_per_sig[VG_SIGVGKILL].scss_handler = VKI_SIG_IGN;