Subject: Re: bug#33014: 26.1.50; 27.0.50; Fatal error after re-evaluating a thread's function

From: Gemini Lasswell <[email-masked]>
Date: Tue, 16 Oct 2018 11:46:36 -0700

Eli Zaretskii <[email-masked]> writes:

> In this case, the function whose bytecode seems to be GC'ed is the
> thread function itself.  That function is also marked, as part of
> marking the thread object itself, although, of course, re-evaluating
> the function will redefine the function.  But, if my reading of
> exec_byte_code is correct, the bytecode should be on the stack and in
> registers while we execute it, so even though the bytecode gets
> disconnected from the function, it is still reachable from the stack,
> and should have been marked...

My knowledge of what gcc does and how the code it generates works is
superficial, but I don't see why an optimizer would find it necessary to
save the following values:

- The value of 'fun' in Ffuncall after it is used as an argument for
  funcall_lambda.

- The value of 'fun' in funcall_lambda after it is used to calculate
  the arguments to exec_byte_code.

- The value of 'vector' in exec_byte_code after the calculation of
  vectorp.

These three are the only variables that I see in Thread 7 from which the
garbage collector could find the constants vector which it's not
finding.  If gcc's optimizer puts them all in registers instead of on
the stack because it knows it won't need them later, those registers
will be overwritten with other values by recursive calls before
flush_stack_call_func is called.  Here's the backtrace of where Thread 7
is stopped while Thread 1 is running garbage collection, in which the
three frames I'm talking about above are 10, 11 and 12:

(gdb) thread apply 7 bt

Thread 7 (Thread 0x7fecdacdd700 (LWP 5509)):
#0  0x00007fecf771f592 in pthread_cond_wait@@GLIBC_2.3.2 () from /nix/store/fg4yq8i8wd08xg3fy58l6q73cjy8hjr2-glibc-2.27/lib/libpthread.so.0
#1  0x0000000000648389 in sys_cond_wait (cond=cond@entry=0x16e9c48 <bss_sbrk_buffer+9921960>, mutex=mutex@entry=0xd73440 <global_lock>) at systhread.c:163
#2  0x0000000000647747 in condition_wait_callback (arg=0x16e9c30 <bss_sbrk_buffer+9921936>) at thread.c:410
#3  0x00000000005a9608 in flush_stack_call_func (func=func@entry=0x647630 <condition_wait_callback>, arg=<optimized out>) at alloc.c:5021
#4  0x0000000000646e1d in Fcondition_wait (cond=<optimized out>) at thread.c:449
#5  0x00000000005cc49e in funcall_subr (subr=0xcdc1c0 <Scondition_wait>, numargs=numargs@entry=1, args=args@entry=0x7fecdacdc1c0) at eval.c:2931
#6  0x00000000005ca661 in Ffuncall (nargs=2, args=args@entry=0x7fecdacdc1b8) at eval.c:2856
#7  0x0000000000611e00 in exec_byte_code (bytestr=<optimized out>, vector=<optimized out>, maxdepth=<optimized out>, args_template=<optimized out>, nargs=nargs@entry=1, 
    args=<optimized out>, args@entry=0x11bde68 <bss_sbrk_buffer+4499400>) at bytecode.c:632
#8  0x00000000005cdd32 in funcall_lambda (fun=XIL(0x7fecdacdc1b8), nargs=nargs@entry=1, arg_vector=0x11bde68 <bss_sbrk_buffer+4499400>, arg_vector@entry=0x7fecdacdc470)
    at eval.c:3057
#9  0x00000000005ca54b in Ffuncall (nargs=2, args=args@entry=0x7fecdacdc468) at eval.c:2870
#10 0x0000000000611e00 in exec_byte_code (bytestr=<optimized out>, vector=<optimized out>, maxdepth=<optimized out>, args_template=<optimized out>, nargs=nargs@entry=0, 
    args=<optimized out>, args@entry=0x16eac38 <bss_sbrk_buffer+9926040>) at bytecode.c:632
#11 0x00000000005cdd32 in funcall_lambda (fun=XIL(0x7fecdacdc468), nargs=nargs@entry=0, arg_vector=0x16eac38 <bss_sbrk_buffer+9926040>, 
    arg_vector@entry=0x1578c58 <bss_sbrk_buffer+8410552>) at eval.c:3057
#12 0x00000000005ca54b in Ffuncall (nargs=nargs@entry=1, args=args@entry=0x1578c50 <bss_sbrk_buffer+8410544>) at eval.c:2870
#13 0x000000000064680b in invoke_thread_function () at thread.c:684
#14 0x00000000005c964f in internal_condition_case (bfun=bfun@entry=0x6467d0 <invoke_thread_function>, handlers=<optimized out>, handlers@entry=XIL(0xc3c0), 
    hfun=hfun@entry=0x6466f0 <record_thread_error>) at eval.c:1373
#15 0x00000000006471a1 in run_thread (state=0x1578c30 <bss_sbrk_buffer+8410512>) at thread.c:723
#16 0x00007fecf77195a7 in start_thread () from /nix/store/fg4yq8i8wd08xg3fy58l6q73cjy8hjr2-glibc-2.27/lib/libpthread.so.0
#17 0x00007fecf6db422f in clone () from
/nix/store/fg4yq8i8wd08xg3fy58l6q73cjy8hjr2-glibc-2.27/lib/libc.so.6

gdb shows a value for fun in frame 11, but when I try to print
XIL(0x7fecdacdc468) it complains about it being an invalid lisp object,
and then the result of "info frame 11" shows some similar values,
so I'm thinking gdb is confused:

(gdb) thread apply 7 info frame 11

Thread 7 (Thread 0x7fecdacdd700 (LWP 5509)):
Stack frame at 0x7fecdacdc7d0:
 rip = 0x5cdd32 in funcall_lambda (eval.c:3057); saved rip = 0x64680b
 tail call frame, caller of frame at 0x7fecdacdc7d0
 source language c.
 Arglist at unknown address.
 Locals at unknown address, Previous frame's sp is 0x7fecdacdc7d0

I haven't figured out how to get gdb to print the Lisp backtrace of one
thread while execution is stopped in a different one.  But I expect
Thread 7's Lisp backtrace looks like this:

condition-wait
thread-queue-get
erb--benchmark-monitor-func