From c048886458ce68280ba32647a93a04902c929988 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson <sverker@erlang.org>
Date: Fri, 1 Apr 2016 20:11:34 +0200
Subject: erts: Fix race for process_flag(trap_exit,true)

and a concurrent exit signal.

We now actually guarantee that the process will not die
from exit signal *after* the call to process_flag(trap_exit,true)
has returned.

The race is narrow and probably quite hard to observe even if you
manage to provoke it. Has only been confirmed with the help of
return trace and a sleep in send_exit_signal().

Solution:
Seize status lock to prevent send_exit_signal() from reading
an old status (without TRAP_EXIT) and then writing PENDING_EXIT
after TRAP_EXIT has been set by process_flag_2().
---
 erts/emulator/beam/bif.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

(limited to 'erts')

diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index b43137597e..11c694233f 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -1566,14 +1566,17 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2)
 	*       true. For more info, see implementation of
 	*       erts_send_exit_signal().
 	*/
+       erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCKS_XSIG_SEND);
        if (trap_exit)
 	   state = erts_smp_atomic32_read_bor_mb(&BIF_P->state,
 						 ERTS_PSFLG_TRAP_EXIT);
        else
 	   state = erts_smp_atomic32_read_band_mb(&BIF_P->state,
 						  ~ERTS_PSFLG_TRAP_EXIT);
+       erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCKS_XSIG_SEND);
+
 #ifdef ERTS_SMP
-       if (ERTS_PROC_PENDING_EXIT(BIF_P)) {
+       if (state & ERTS_PSFLG_PENDING_EXIT) {
 	   erts_handle_pending_exit(BIF_P, ERTS_PROC_LOCK_MAIN);
 	   ERTS_BIF_EXITED(BIF_P);
        }
-- 
cgit v1.2.3