Subject: Re: bug#76237: 31.0.50; feature/igc: crash #1, 2025-02-12

From: Pip Cet <[email-masked]>
Date: Fri, 14 Feb 2025 12:24:51 +0000

"Oliver Reiter" <[email-masked]> writes:

> Pip Cet <[email-masked]> writes:
>
>> "Oliver Reiter" <[email-masked]> writes:
>>
>>> Pip Cet <[email-masked]> writes:
>>>
>>>> "Oliver Reiter" <[email-masked]> writes:
>>>>
>>>>> Pip Cet <[email-masked]> writes:
>>>>>
>>>>>> (gdb) p main_thread.s.bc
>>>>>>
>>>>>> then
>>>>>>
>>>>>> (gdb) p bc_next_frame (main_thread.s.bc.fp)
>>>>>>
>>>>>
>>>>> (gdb) p main_thread.s.bc
>>>>> $1 = {fp = 0x7fffdf3ff710, stack = 0x7fffdf3ff010 "", stack_end = 0x7fffdf7ff010 ""}
>>>>> (gdb) p bc_next_frame (main_thread.s.bc.fp)
>>>>> You can't do that without a process to debug.
>>>>
>>>> (gdb) p main_thread.s.bc.fp->next_stack
>>>>
>>>> might work.
>>>>
>>>
>>> It does:
>>>
>>> (gdb) p main_thread.s.bc.fp->next_stack
>>> $4 = 0x7fffdf3ff730
>>
>> Oh.  I was confused, sorry, I meant
>>
>> (gdb) p main_thread.s.bc.fp->saved_fp
>> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp
>> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp->saved_fp
>>
>> and so on for a few iterations.  We want to know whether any of the
>> stack frames exceed 1024 bytes :-)
>>
>> Thanks, and sorry for the confusion!
>
> Don't worry. I count 14 iterations until we hit 0x0:
>
> (gdb) p main_thread.s.bc.fp
> $1 = (struct bc_frame *) 0x7fffdf3ff710
> (gdb) p main_thread.s.bc.fp->saved_fp
> $2 = (struct bc_frame *) 0x7fffdf3ff640
> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp
> $3 = (struct bc_frame *) 0x7fffdf3ff5d8
> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp->saved_fp
> $4 = (struct bc_frame *) 0x7fffdf3ff578
> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp->saved_fp->saved_fp
> $5 = (struct bc_frame *) 0x7fffdf3ff4a8
> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp
> $6 = (struct bc_frame *) 0x7fffdf3ff3d8
> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp
> $7 = (struct bc_frame *) 0x7fffdf3ff370
> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp
> $8 = (struct bc_frame *) 0x7fffdf3ff2a0
> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp
> $9 = (struct bc_frame *) 0x7fffdf3ff238
> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp
> $10 = (struct bc_frame *) 0x7fffdf3ff1d8
> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp
> $11 = (struct bc_frame *) 0x7fffdf3ff108
> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp
> $12 = (struct bc_frame *) 0x7fffdf3ff0c8
> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp
> $13 = (struct bc_frame *) 0x7fffdf3ff050
> (gdb) p main_thread.s.bc.fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp
> $14 = (struct bc_frame *) 0x7fffdf3ff010
> (gdb) p
> main_thread.s.bc.fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp->saved_fp
> $15 = (struct bc_frame *) 0x0

Thanks.  None of these are very large, so something else must be
happening.

While it's not likely to be the other two issues I'm aware of
(nativecomp option and allocating sys_jmp buffers in a way that scans
them conservatively), I'll fix those, and hope that a clearer backtrace
emerges.

Unless someone else has an idea, that is?

I do have some code which forks just before GC inspects the global
roots, and keeps the forked process around for a while.  My hope was
that this would be a relatively cheap way of (very limited) time travel
to before a GC overwrote an object, so we can go back and see what that
object was and why GC (incorrectly) decided it wasn't reachable.

But this is not yet ready for general deployment, and it comes at a
price: we can't run pthread_atfork handlers because we're forking in the
middle of GC, and that may break other subprocesses.

Pip