Re: [MLton] Crash in GC
"Chris Cannam" <[email protected]> Mon, 07 Nov 2022 13:53:34 +0000
| Newsgroups | gmane.comp.lang.ml.mlton.devel |
|---|---|
| Message-ID | <[email protected]> |
On Sun, 6 Nov 2022, at 20:49, Matthew Fluet wrote:
> Just before this, there must be a
> T(Q, n) = CPointer_add (Frontier, (Word64)(0x8ull));
> T(P, 1) = (Objptr)T(Q, n);
Yes, there was. Thank you - this is all really informative, but I think I actually made a mistake in what I was tracking with the debugger. I realise I had been setting a watchpoint on the address *within the nursery* to tell me when that was modified - not on the address in the old generation that points to the nursery address.
So the code I quoted above - that is setting elements within a sequence of records in nursery allocation. The cards it marks all appear to be for addresses within the nursery, at or around the address that later fails the invariant check (because it has been overlooked in copy collection).
But I guess what we actually need to know (?) is what causes the pointer in old generation to be written, pointing to this nursery address. So I added a second watchpoint, and the order of events is like this:
1. Nursery address (346e00) is initialised to 1 in sequence allocate
2. Nursery address (346e00) and its surroundings are modified in sequence update
3. Old-generation address (27308) is set to point to the nursery address
And (3) occurs not from a sequence update, but within a call to GC_sequenceCopy:
Hardware watchpoint 1: *0x0000080000027308
Old value = 1433506504
New value = 3436032
__memcpy_avx_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:418
418 VMOVU %VEC(5), -(VEC_SIZE * 2)(%rdi, %rdx)
(gdb) where
#0 __memcpy_avx_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:418
#1 0x00005555556d0a5e in GC_memmove (src=0x80000348e80 "(\201\a", dst=0x80000027260 "(\201\a",
size=176) at gc/virtual-memory.c:41
#2 0x00005555556e1fbd in GC_sequenceCopy (s=0x555555719700 <gcState.0>, ad=0x80000027260 "(\201\a",
ds=0, as=0x80000348e80 "(\201\a", ss=0, l=22) at gc/sequence.c:89
#3 0x00005555555c9287 in Chunk_1 (GCState=0x555555719700 <gcState.0>, StackTop=0x80000000238,
Frontier=0x80000348f30, nextBlock=306) at program.0.c:3698
#4 0x00005555555695d0 in MLton_trampoline (s=0x555555719700 <gcState.0>, nextBlock=292,
mayReturnToC=false) at /usr/local/lib/mlton/include/c-main.h:35
#5 0x0000555555569858 in MLton_main (argc=4, argv=0x7fffffffe3c8) at program.2.c:5216
#6 0x000055555556987f in main (argc=4, argv=0x7fffffffe3c8) at program.2.c:5217
In the call to GC_sequenceCopy, the destination address is in the old generation and the source address is in the nursery. But it appears to be called from generated code, not from a GC action - there is no GC occurring at the time. Why is something outside a GC copying directly to the old generation? Am I entirely misunderstanding?
(The program doesn't call any primitives or MLton functions itself, it doesn't use copyArray/copyVector)
There is no sign of any card marking around the call to GC_sequenceCopy:
L_8647:
/* TW32(0): Word32 = WordS64_lt (TW64(1): Word64, 0x5:w64) */
T(W32, 0) = WordS64_lt (T(W64, 1), (Word64)(0x5ull));
/* switch {test = TW32(0): Word32, default = None, expect = None, cases = ((0x0:w32, L_8646), (0x1:w32, L_8644))} */
if (T(W32, 0)) goto L_8644; else goto L_8646;
L_8646:
/* CCall {args = (<GCState>, TP(6): Objptr (opt_98), TW64(2): Word64, Cast (TP(0): Objptr (opt_98), Objptr (opt_13)), 0x0:w64, TW64(1): Word64), func = {args = (CPointer, Objptr (opt_98), Word64, Objptr (opt_13), Word64, Word64), convention = cdecl, inline = false, kind = Runtime {bytesNeeded = None, ensuresBytesFree = None, mayGC = false, maySwitchThreadsFrom = false, maySwitchThreadsTo = false, modifiesFrontier = false, readsStackTop = false, writesStackTop = false}, prototype = {args = (CPointer, Objptr, Word64, Objptr, Word64, Word64), res = None}, return = Bits0, symbolScope = private, target = GC_sequenceCopy}, return = Some {return = L_8645, size = None}} */
GC_sequenceCopy (GCState, T(P, 6), T(W64, 2), (Objptr)T(P, 0), (Word64)(0x0ull), T(W64, 1));
goto L_8645;
L_8645:
/* TW64(0): Word64 = SW64(48): Word64 */
T(W64, 0) = S(Word64, 48);
/* SP(32): Objptr (opt_94) = TP(5): Objptr (opt_94) */
S(Objptr, 32) = T(P, 5);
/* Goto loop_262 */
goto loop_262;
Chris