ctst->sig_mask = ptst->sig_mask;
ctst->tmp_sig_mask = ptst->sig_mask;
+ /* Start the child with its threadgroup being the same as the
+ parent's. This is so that any exit_group calls that happen
+ after the child is created but before it sets its
+ os_state.threadgroup field for real (in thread_wrapper in
+ syswrap-linux.c), really kill the new thread. a.k.a this avoids
+ a race condition in which the thread is unkillable (via
+ exit_group) because its threadgroup is not set. The race window
+ is probably only a few hundred or a few thousand cycles long.
+ See #226116. */
+ ctst->os_state.threadgroup = ptst->os_state.threadgroup;
+
/* We don't really know where the client stack is, because its
allocated by the client. The best we can do is look at the
memory mappings and try to derive some useful information. We
ctst->sig_mask = ptst->sig_mask;
ctst->tmp_sig_mask = ptst->sig_mask;
+ /* Start the child with its threadgroup being the same as the
+ parent's. This is so that any exit_group calls that happen
+ after the child is created but before it sets its
+ os_state.threadgroup field for real (in thread_wrapper in
+ syswrap-linux.c), really kill the new thread. a.k.a this avoids
+ a race condition in which the thread is unkillable (via
+ exit_group) because its threadgroup is not set. The race window
+ is probably only a few hundred or a few thousand cycles long.
+ See #226116. */
+ ctst->os_state.threadgroup = ptst->os_state.threadgroup;
+
seg = VG_(am_find_nsegment)((Addr)sp);
if (seg && seg->kind != SkResvn) {
ctst->client_stack_highest_word = (Addr)VG_PGROUNDUP(sp);
VG_TRACK(pre_thread_first_insn, tid);
tst->os_state.lwpid = VG_(gettid)();
+ /* Set the threadgroup for real. This overwrites the provisional
+ value set in do_clone() syswrap-*-linux.c. See comments in
+ do_clone for background, also #226116. */
tst->os_state.threadgroup = VG_(getpid)();
/* Thread created with all signals blocked; scheduler will set the
ctst->sig_mask = ptst->sig_mask;
ctst->tmp_sig_mask = ptst->sig_mask;
+ /* Start the child with its threadgroup being the same as the
+ parent's. This is so that any exit_group calls that happen
+ after the child is created but before it sets its
+ os_state.threadgroup field for real (in thread_wrapper in
+ syswrap-linux.c), really kill the new thread. a.k.a this avoids
+ a race condition in which the thread is unkillable (via
+ exit_group) because its threadgroup is not set. The race window
+ is probably only a few hundred or a few thousand cycles long.
+ See #226116. */
+ ctst->os_state.threadgroup = ptst->os_state.threadgroup;
+
/* We don't really know where the client stack is, because its
allocated by the client. The best we can do is look at the
memory mappings and try to derive some useful information. We
ctst->sig_mask = ptst->sig_mask;
ctst->tmp_sig_mask = ptst->sig_mask;
+ /* Start the child with its threadgroup being the same as the
+ parent's. This is so that any exit_group calls that happen
+ after the child is created but before it sets its
+ os_state.threadgroup field for real (in thread_wrapper in
+ syswrap-linux.c), really kill the new thread. a.k.a this avoids
+ a race condition in which the thread is unkillable (via
+ exit_group) because its threadgroup is not set. The race window
+ is probably only a few hundred or a few thousand cycles long.
+ See #226116. */
+ ctst->os_state.threadgroup = ptst->os_state.threadgroup;
+
/* We don't really know where the client stack is, because its
allocated by the client. The best we can do is look at the
memory mappings and try to derive some useful information. We
ctst->sig_mask = ptst->sig_mask;
ctst->tmp_sig_mask = ptst->sig_mask;
+ /* Start the child with its threadgroup being the same as the
+ parent's. This is so that any exit_group calls that happen
+ after the child is created but before it sets its
+ os_state.threadgroup field for real (in thread_wrapper in
+ syswrap-linux.c), really kill the new thread. a.k.a this avoids
+ a race condition in which the thread is unkillable (via
+ exit_group) because its threadgroup is not set. The race window
+ is probably only a few hundred or a few thousand cycles long.
+ See #226116. */
+ ctst->os_state.threadgroup = ptst->os_state.threadgroup;
+
/* We don't really know where the client stack is, because its
allocated by the client. The best we can do is look at the
memory mappings and try to derive some useful information. We