bug#28211: Stack marking issue in multi-threaded code, 2020 edition

Ludovic Courtès <[email protected]>
Newsgroups gmane.lisp.guile.bugs
Message-ID <[email protected]>
Hi!

Andy Wingo <[email protected]> skribis:

> On Thu 12 Mar 2020 22:59, Ludovic Courtès <[email protected]> writes:
>
>> I think I’ve found another race condition involving stack marking, as a
>> followup to <https://issues.guix.gnu.org/issue/28211> (this time on
>> 3.0.1+, but the code is almost the same.)
>>
>> ‘abort_to_prompt’ does this:
>>
>>   fp = vp->stack_top - fp_offset;
>>   sp = vp->stack_top - sp_offset;
>>
>>   /* Continuation gets nargs+1 values: the one more is for the cont.  */
>>   sp = sp - nargs - 1;
>>
>>   /* Shuffle abort arguments down to the prompt continuation.  We have
>>      to be jumping to an older part of the stack.  */
>>   if (sp < vp->sp)
>>     abort ();
>>   sp[nargs].as_scm = cont;
>>   while (nargs--)
>>     sp[nargs] = vp->sp[nargs];
>>
>>   /* Restore VM regs */
>>   vp->fp = fp;
>>   vp->sp = sp;
>>   vp->ip = vra;
>>
>>
>> What if ‘scm_i_vm_mark_stack’ walks the stack right before the ‘vp->fp’
>> assignment?  It can determine that one of the just-assigned ‘sp[nargs]’
>> is a dead slot, and thus set it to SCM_UNSPECIFIED.
>
> I think you're right here.
>
> Given that the most-recently-pushed frame is marked conservatively, I
> think it would be sufficient to reset vp->fp before shuffling stack
> args; that would make it so that the frame includes the values to
> shuffle, their target locations, and probably some other crap in
> between.  Given that marking the crap is harmless, I think that would be
> enough.  WDYT?

Sounds good.  Following our discussion on IRC, I pushed what you
proposed as 89edd1bc2dcff50fb05c3598a846d6b51b172f7c.  \o/

I confirmed with and without rr that it no longer triggers the dreaded
crash.

BTW, pro tip: to run ./meta/guile under rr, I do:

  sed -i libguile/guile \
      -e 's/exec /exec rr record -n --syscall-buffer-sig=SIGUSR1 /g'

where ‘-n’ disables stack switching.

> In a more perfect world, initiating GC should tell threads to reach a
> safepoint and mark their own stacks -- preserves thread locality and
> prevents this class of bug.  But given that libgc uses signals to stop
> threads, we have to be less precise.

Yup, agreed.

Thanks,
Ludo’.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.