Re: [MLton] Crash in GC
Matthew Fluet <[email protected]> Sat, 5 Nov 2022 22:43:04 -0400
| Newsgroups | gmane.comp.lang.ml.mlton.devel |
|---|---|
| Message-ID | <CAMrhFL5cHiU_F7NFxpB5OY923znqPTLAUOdNknGGGtpWSA=qTQ@mail.gmail.com> |
--===============1202340204324177820== Content-Type: multipart/alternative; boundary="000000000000d745a305ecc444d6" --000000000000d745a305ecc444d6 Content-Type: text/plain; charset="UTF-8" On Sat, Nov 5, 2022 at 11:45 AM Chris Cannam <[email protected]> wrote: > A few (not very clever) questions about the GC state here - > > * The frontier pointer, stored in gc_state rather than in heap - does > this represent the end of live allocation in the nursery? In this case it > appears to be equal to the nursery pointer. Does that mean all live objects > have been (or should have been) copied from nursery to old generation by > the copying GC that just finished, and so the nursery is (should be) empty? > The frontier pointer is where the mutator (SML code) will allocate new objects. The frontier pointer should always be between `heap.nursery` and `heap.start + heap.size`. Just before a GC, the frontier pointer should be close to (but still less than) `heap.start + heap.size`; immediately after a GC (minor or major), the frontier pointer should be equal to `heap.nursery`, because all live objects of the nursery should have been copied to the old generation. Note that the nursery size is not fixed. Given a heap, the nursery starts at `heap.start + ((heap.size - heap.oldGenSize) / 2)` and has size `((heap.size - heap.oldGenSize) / 2)`. That is, the size of the nursery is the upper-half of the space not used by the old gen. Using half that space ensures that any future minor gc of the nursery can, in worst case, copy all of its data into the lower-half of the space not used by the old gen. > * The gc-messages output says the nursery had size 1,093,424. My > offending pointer was beyond the nursery pointer, but not by as much as > that - so it was a valid pointer within the nursery before the last copying > GC? > Yes, that would make sense. > * The error comes from the invariant scan performed at invariant.c:116 > following the remark "Checking old generation" (see stack trace below). I > think this is going through every object pointer it can find in the old > generation heap to make sure the thing it points to is also in some valid > space? So this pointer that was in the nursery, and has been overlooked by > the copying GC, is pointed to by something that either already was in the > old generation or has just been copied to it, hence the problem. > Yes, the old generation check makes sure that every object in the old generation's pointers are "correct", at least in the sense of pointing to a valid object. > I am struggling slightly with the philosophical question of how the GC can > see that the pointer is pointed to by something in the old generation, > while also having been unable to spot that the object existed when > performing the copying GC. > That's the classic example of an intergenerational pointer being missed. In a functional language, newly allocated and initialized objects can only point to previously allocated objects. In the absence of mutation, the object graph is always a DAG. So, the objects in the nursery, composed of the most recently allocated objects, can be pointed to by stack variables (roots) or by other nursery objects, but not by old gen objects. So, a minor GC need only trace the stack variables that point to nursery objects. However, in the presence of mutation, an update can cause an old gen object to point to a nursery object. It would be expensive to walk the entire old gen looking for pointers to nursery objects, so a generational GC typically uses some mechanism to know when and where an old-gen to nursery pointer was created. In MLton, this is a card map; essentially, a boolean array that is 1/256 the size of the heap. Each boolean of this array indicates whether or not an object in the corresponding 256byte card of the heap has been the target of an update (in SML, either an `Array.update` or a reference `:=`); at the next minor GC, the card map is walked (much faster than walking the entire old gen) and whenever a true element is found, the corresponding card of the heap is traced (looking for pointers into the nursery to be marked live). See https://github.com/MLton/mlton/blob/master/runtime/gc/generational.h#L30 for some more comments. We should be checking that intergenerational pointers have their corresponding card marked, but that test is currently disabled: https://github.com/MLton/mlton/blob/master/runtime/gc/invariant.c#L23 I'm guessing that if we enabled/fixed that, then we would trip the invariant at the beginning of the GC (rather than at the end), where it would clearly indicate that between the last GC and this GC, there was an update to an old gen object and the corresponding card was not property marked. -Matthew > #0 assertIsObjptrInFromSpaceOrImmutableMutableOrRootStaticHeap > (s=0x555555602b80 <gcState>, opp=0x80000027308, env=0x0) > at gc/invariant.c:17 > #1 0x00005555555c4082 in callIfIsObjptr (s=0x555555602b80 <gcState>, > f=0x7fffffffe220, opp=0x80000027308) at gc/foreach.c:12 > #2 0x00005555555c443c in foreachObjptrInObject (s=0x555555602b80 > <gcState>, p=0x80000027308 "", f=0x7fffffffe220, > skipWeaks=false) at gc/foreach.c:95 > #3 0x00005555555c48b8 in foreachObjptrInRange (s=0x555555602b80 > <gcState>, front=0x80000027248 "", back=0x7fffffffe1f0, > f=0x7fffffffe220, skipWeaks=false) at gc/foreach.c:190 > #4 0x00005555555ce988 in invariantForGC (s=0x555555602b80 <gcState>) at > gc/invariant.c:116 > #5 0x00005555555c66ef in performGC (s=0x555555602b80 <gcState>, > oldGenBytesRequested=0, nurseryBytesRequested=32808, > forceMajor=false, mayResize=true) at gc/garbage-collection.c:194 > #6 0x00005555555d2352 in GC_sequenceAllocate (s=0x555555602b80 <gcState>, > ensureBytesFree=0, numElements=4098, header=211) > at gc/sequence-allocate.c:65 > #7 0x00005555555772d0 in L_nonZeroLen_135 () at /tmp/fileM2oB33.3.s:18345 > #8 0x00007fffffffe470 in ?? () > #9 0x00005555555d4afe in MLton_init (argc=2048, argv=0x8000000d078, > s=0x800003d5648) at platform.c:20 > > On Thu, 3 Nov 2022, at 16:45, Chris Cannam wrote: > > Thanks! Trying again with some more debug output, the failure is > > > > gc.c: assertIsObjptrInFromSpace opp = 0x0000080000027308 *opp = > > 0x0000080000346e00 > > > > at a time when > > > > 0x0000080000000000 - start of heap > > 0x00000800001da1a0 - end of old generation > > 0x00000800002e50d0 - start of nursery > > 0x00000800002e50d0 - frontier pointer in gc_state > > 0x00000800003f0000 - end of heap > > > > and so the test that fails must be "p <= s->frontier" in > isPointerInNursery(). > > > > The last output from gc-messages was > > > > [GC: Finished minor Cheney-copy; copied 66,808 bytes.] > > [GC: Finished gc #34; time 18 ms,] > > [GC: heap at 0x0000080000000000 of size 4,128,768 bytes (+ 32,768 bytes > > card/cross map),] > > [GC: with old-gen of size 1,941,920 bytes (47.0% of heap),] > > [GC: and nursery of size 1,093,424 bytes (26.5% of heap).] > > > > Does that suggest anything obvious? I think I would have to learn more > > about GCs to get really into this. > > > > I've uploaded the offending program at > > https://all-day-breakfast.com/m/program.sml.gz (as it's pretty much a > > concatenation of publicly-available code; it just isn't something > > currently managed in a public repo). > > > > > > Chris > > > > On Thu, 3 Nov 2022, at 01:28, Matthew Fluet wrote: > >> Agreed that, while non-default, your GC options aren't particularly > >> unusual and there is a true GC bug there. > >> > >> You can automate compiling with `-g` and linking to the debug runtime > >> by compiling with `-debug true`. > >> > >> The https://github.com/MLton/mlton/blob/master/runtime/gc/debug.h has > a > >> number of enums/constants that can be switched from `FALSE` to `TRUE` > >> to turn on additional assertions and logging. `DEBUG_GENERATIONAL` > >> would seem to be a good candidate to enable. It can also be helpful to > >> simply run the program with `@MLton gc-messages`, which will print out > >> information at the start and end of each GC, especially about the > >> address and sizes of the heaps (including generational boundary). That > >> might help to understand if the bad pointer is "near" the FromSpace or > >> in an old heap or something similar. > >> > >> Feel free to follow up with more information or to share the > >> bug-triggering program if its still hard to track down. > >> > >> -Matthew > >> > >> On Wed, Nov 2, 2022 at 11:58 AM Chris Cannam > >> <[email protected]> wrote: > >>> Hello! > >>> > >>> I have a pure SML program (no FFI) which compiles and runs when > compiled with the default MLton options, but crashes with a segfault when > compiled with certain GC flags. > >>> > >>> For example, > >>> > >>> $ mlton program.sml > >>> $ ./program > >>> > >>> runs to completion, while > >>> > >>> $ mlton -runtime 'copy-generational-ratio 10.0' program.sml > >>> $ ./program > >>> > >>> runs for a second or so and then crashes. The crash is a segfault in > (according to gdb) forwardObjptr within performGC. > >>> > >>> I tried emitting C and compiling that with -g linked against > libmlton-dbg.a, and in this mode I get an assertion failure:: > >>> > >>> gc/invariant.c:13: > assertIsObjptrInFromSpaceOrImmutableMutableOrRootStaticHeap: Assertion > `isObjptrInFromSpace (s, *opp) || > isObjptrInImmutableMutableOrRootStaticHeap (s, *opp)' failed. > >>> > >>> The failure is within the invariant check made at the end of performGC > just before leaveGC is called, and is within the "checking old generation" > part of invariantForGC. > >>> > >>> The same behaviour happens with the Arch Linux package of 20210117 and > with a clean build from the current MLton repo, and it doesn't appear to > matter which codegen I use. > >>> > >>> Any tips or ideas for how to debug this? Besides that it seems a bug, > I am afraid that a failure in GC with unusual options now has the potential > to become a failure with default options in the future under different > memory pressure or allocation patterns. > >>> > >>> I can provide a test program off-list if that would help anyone get to > grips with it, but although it's just a single SML file, it is quite large > - the result of concatenating about 38k lines from other files - and I > haven't identified a nice small test case. > >>> > >>> > >>> Chris > >>> > >>> > >>> _______________________________________________ > >>> MLton-devel mailing list > >>> [email protected]; [email protected] > >>> https://lists.sourceforge.net/lists/listinfo/mlton-devel > >> > >> _______________________________________________ > >> MLton-devel mailing list > >> [email protected]; [email protected] > >> https://lists.sourceforge.net/lists/listinfo/mlton-devel > > > > > > _______________________________________________ > > MLton-devel mailing list > > [email protected]; [email protected] > > https://lists.sourceforge.net/lists/listinfo/mlton-devel > > > _______________________________________________ > MLton-devel mailing list > [email protected]; [email protected] > https://lists.sourceforge.net/lists/listinfo/mlton-devel > --000000000000d745a305ecc444d6 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail= _attr">On Sat, Nov 5, 2022 at 11:45 AM Chris Cannam <<a href=3D"mailto:c= [email protected]">[email protected]</a>> wrote:<br= ></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;= border-left:1px solid rgb(204,204,204);padding-left:1ex">A few (not very cl= ever) questions about the GC state here -<br> <br> =C2=A0* The frontier pointer, stored in gc_state rather than in heap - does= this represent the end of live allocation in the nursery? In this case it = appears to be equal to the nursery pointer. Does that mean all live objects= have been (or should have been) copied from nursery to old generation by t= he copying GC that just finished, and so the nursery is (should be) empty?<= br></blockquote><div><br></div><div><div style=3D"font-family:arial,sans-se= rif;font-size:large" class=3D"gmail_default">The frontier pointer is where = the mutator (SML code) will allocate new objects.=C2=A0 The frontier pointe= r should always be between `heap.nursery` and `heap.start + heap.size`.=C2= =A0 Just before a GC, the frontier pointer should be close to (but still le= ss than) `heap.start + heap.size`; immediately after a GC (minor or major),= the frontier pointer should be equal to `heap.nursery`, because all live o= bjects of the nursery should have been copied to the old generation.<br></d= iv></div><div></div><div><br></div><div><div style=3D"font-family:arial,san= s-serif;font-size:large" class=3D"gmail_default">Note that the nursery size= is not fixed.=C2=A0 Given a heap, the nursery starts at `heap.start + ((he= ap.size - heap.oldGenSize) / 2)` and has size `((heap.size - heap.oldGenSiz= e) / 2)`.=C2=A0 That is, the size of the nursery is the upper-half of the s= pace not used by the old gen.=C2=A0 Using half that space ensures that any = future minor gc of the nursery can, in worst case, copy all of its data int= o the lower-half of the space not used by the old gen.<br></div></div><div>= =C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0= .8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"> =C2=A0* The gc-messages output says the nursery had size 1,093,424. My offe= nding pointer was beyond the nursery pointer, but not by as much as that - = so it was a valid pointer within the nursery before the last copying GC?<br= ></blockquote><div><br></div><div><div style=3D"font-family:arial,sans-seri= f;font-size:large" class=3D"gmail_default">Yes, that would make sense.<br><= /div></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"marg= in:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1e= x"> =C2=A0* The error comes from the invariant scan performed at invariant.c:11= 6 following the remark "Checking old generation" (see stack trace= below). I think this is going through every object pointer it can find in = the old generation heap to make sure the thing it points to is also in some= valid space? So this pointer that was in the nursery, and has been overloo= ked by the copying GC, is pointed to by something that either already was i= n the old generation or has just been copied to it, hence the problem.<br><= /blockquote><div><br></div><div><div style=3D"font-family:arial,sans-serif;= font-size:large" class=3D"gmail_default">Yes, the old generation check make= s sure that every object in the old generation's pointers are "cor= rect", at least in the sense of pointing to a valid object.</div></div= ><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px= 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"> I am struggling slightly with the philosophical question of how the GC can = see that the pointer is pointed to by something in the old generation, whil= e also having been unable to spot that the object existed when performing t= he copying GC.<br></blockquote><div><br></div><div><div style=3D"font-famil= y:arial,sans-serif;font-size:large" class=3D"gmail_default">That's the = classic example of an intergenerational pointer being missed.<br></div><div= style=3D"font-family:arial,sans-serif;font-size:large" class=3D"gmail_defa= ult"><br></div><div style=3D"font-family:arial,sans-serif;font-size:large" = class=3D"gmail_default">In a functional language, newly allocated and initi= alized objects can only point to previously allocated objects.=C2=A0 In the= absence of mutation, the object graph is always a DAG.=C2=A0 So, the objec= ts in the nursery, composed of the most recently allocated objects, can be = pointed to by stack variables (roots) or by other nursery objects, but not = by old gen objects.=C2=A0 So, a minor GC need only trace the stack variable= s that point to nursery objects.</div><div style=3D"font-family:arial,sans-= serif;font-size:large" class=3D"gmail_default"><br></div><div style=3D"font= -family:arial,sans-serif;font-size:large" class=3D"gmail_default">However, = in the presence of mutation, an update can cause an old gen object to point= to a nursery object.=C2=A0 It would be expensive to walk the entire old ge= n looking for pointers to nursery objects, so a generational GC typically u= ses some mechanism to know when and where an old-gen to nursery pointer was= created.=C2=A0 In MLton, this is a card map; essentially, a boolean array = that is 1/256 the size of the heap.=C2=A0 Each boolean of this array indica= tes whether or not an object in the corresponding 256byte card of the heap = has been the target of an update (in SML, either an `Array.update` or a ref= erence `:=3D`); at the next minor GC, the card map is walked (much faster t= han walking the entire old gen) and whenever a true element is found, the c= orresponding card of the heap is traced (looking for pointers into the nurs= ery to be marked live).=C2=A0 See <a href=3D"https://github.com/MLton/mlton= /blob/master/runtime/gc/generational.h#L30">https://github.com/MLton/mlton/= blob/master/runtime/gc/generational.h#L30</a> for some more comments.</div>= <div style=3D"font-family:arial,sans-serif;font-size:large" class=3D"gmail_= default"><br></div><div style=3D"font-family:arial,sans-serif;font-size:lar= ge" class=3D"gmail_default">We should be checking that intergenerational po= inters have their corresponding card marked, but that test is currently dis= abled:</div><div style=3D"font-family:arial,sans-serif;font-size:large" cla= ss=3D"gmail_default"><a href=3D"https://github.com/MLton/mlton/blob/master/= runtime/gc/invariant.c#L23">https://github.com/MLton/mlton/blob/master/runt= ime/gc/invariant.c#L23</a></div><div style=3D"font-family:arial,sans-serif;= font-size:large" class=3D"gmail_default">I'm guessing that if we enable= d/fixed that, then we would trip the invariant at the beginning of the GC (= rather than at the end), where it would clearly indicate that between the l= ast GC and this GC, there was an update to an old gen object and the corres= ponding card was not property marked.</div><div style=3D"font-family:arial,= sans-serif;font-size:large" class=3D"gmail_default"><br></div><div style=3D= "font-family:arial,sans-serif;font-size:large" class=3D"gmail_default">-Mat= thew<br></div></div><div>=C2=A0</div><div><br></div><blockquote class=3D"gm= ail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,= 204,204);padding-left:1ex"> <br> #0=C2=A0 assertIsObjptrInFromSpaceOrImmutableMutableOrRootStaticHeap (s=3D0= x555555602b80 <gcState>, opp=3D0x80000027308, env=3D0x0)<br> =C2=A0 =C2=A0 at gc/invariant.c:17<br> #1=C2=A0 0x00005555555c4082 in callIfIsObjptr (s=3D0x555555602b80 <gcSta= te>, f=3D0x7fffffffe220, opp=3D0x80000027308) at gc/foreach.c:12<br> #2=C2=A0 0x00005555555c443c in foreachObjptrInObject (s=3D0x555555602b80 &l= t;gcState>, p=3D0x80000027308 "", f=3D0x7fffffffe220, <br> =C2=A0 =C2=A0 skipWeaks=3Dfalse) at gc/foreach.c:95<br> #3=C2=A0 0x00005555555c48b8 in foreachObjptrInRange (s=3D0x555555602b80 <= ;gcState>, front=3D0x80000027248 "", back=3D0x7fffffffe1f0, <b= r> =C2=A0 =C2=A0 f=3D0x7fffffffe220, skipWeaks=3Dfalse) at gc/foreach.c:190<br= > #4=C2=A0 0x00005555555ce988 in invariantForGC (s=3D0x555555602b80 <gcSta= te>) at gc/invariant.c:116<br> #5=C2=A0 0x00005555555c66ef in performGC (s=3D0x555555602b80 <gcState>= ;, oldGenBytesRequested=3D0, nurseryBytesRequested=3D32808, <br> =C2=A0 =C2=A0 forceMajor=3Dfalse, mayResize=3Dtrue) at gc/garbage-collectio= n.c:194<br> #6=C2=A0 0x00005555555d2352 in GC_sequenceAllocate (s=3D0x555555602b80 <= gcState>, ensureBytesFree=3D0, numElements=3D4098, header=3D211)<br> =C2=A0 =C2=A0 at gc/sequence-allocate.c:65<br> #7=C2=A0 0x00005555555772d0 in L_nonZeroLen_135 () at /tmp/fileM2oB33.3.s:1= 8345<br> #8=C2=A0 0x00007fffffffe470 in ?? ()<br> #9=C2=A0 0x00005555555d4afe in MLton_init (argc=3D2048, argv=3D0x8000000d07= 8, s=3D0x800003d5648) at platform.c:20<br> <br> On Thu, 3 Nov 2022, at 16:45, Chris Cannam wrote:<br> > Thanks! Trying again with some more debug output, the failure is<br> ><br> > gc.c: assertIsObjptrInFromSpace opp =3D 0x0000080000027308=C2=A0 *opp = =3D <br> > 0x0000080000346e00<br> ><br> > at a time when <br> ><br> > 0x0000080000000000 - start of heap<br> > 0x00000800001da1a0 - end of old generation<br> > 0x00000800002e50d0 - start of nursery<br> > 0x00000800002e50d0 - frontier pointer in gc_state<br> > 0x00000800003f0000 - end of heap<br> ><br> > and so the test that fails must be "p <=3D s->frontier"= ; in isPointerInNursery().<br> ><br> > The last output from gc-messages was<br> ><br> > [GC: Finished minor Cheney-copy; copied 66,808 bytes.]<br> > [GC: Finished gc #34; time 18 ms,]<br> > [GC:=C2=A0 heap at 0x0000080000000000 of size 4,128,768 bytes (+ 32,76= 8 bytes <br> > card/cross map),]<br> > [GC:=C2=A0 with old-gen of size 1,941,920 bytes (47.0% of heap),]<br> > [GC:=C2=A0 and nursery of size 1,093,424 bytes (26.5% of heap).]<br> ><br> > Does that suggest anything obvious? I think I would have to learn more= <br> > about GCs to get really into this.<br> ><br> > I've uploaded the offending program at <br> > <a href=3D"https://all-day-breakfast.com/m/program.sml.gz" rel=3D"nore= ferrer" target=3D"_blank">https://all-day-breakfast.com/m/program.sml.gz</a= > (as it's pretty much a <br> > concatenation of publicly-available code; it just isn't something = <br> > currently managed in a public repo).<br> ><br> ><br> > Chris<br> ><br> > On Thu, 3 Nov 2022, at 01:28, Matthew Fluet wrote:<br> >> Agreed that, while non-default, your GC options aren't particu= larly <br> >> unusual and there is a true GC bug there.<br> >><br> >> You can automate compiling with `-g` and linking to the debug runt= ime <br> >> by compiling with `-debug true`.<br> >><br> >> The <a href=3D"https://github.com/MLton/mlton/blob/master/runtime/= gc/debug.h" rel=3D"noreferrer" target=3D"_blank">https://github.com/MLton/m= lton/blob/master/runtime/gc/debug.h</a> has a <br> >> number of enums/constants that can be switched from `FALSE` to `TR= UE` <br> >> to turn on additional assertions and logging.=C2=A0 `DEBUG_GENERAT= IONAL` <br> >> would seem to be a good candidate to enable.=C2=A0 It can also be = helpful to <br> >> simply run the program with `@MLton gc-messages`, which will print= out <br> >> information at the start and end of each GC, especially about the = <br> >> address and sizes of the heaps (including generational boundary).= =C2=A0 That <br> >> might help to understand if the bad pointer is "near" th= e FromSpace or <br> >> in an old heap or something similar.<br> >><br> >> Feel free to follow up with more information or to share the <br> >> bug-triggering program if its still hard to track down.<br> >><br> >> -Matthew<br> >><br> >> On Wed, Nov 2, 2022 at 11:58 AM Chris Cannam <br> >> <<a href=3D"mailto:[email protected]" target=3D"_bla= nk">[email protected]</a>> wrote:<br> >>> Hello!<br> >>> <br> >>> I have a pure SML program (no FFI) which compiles and runs whe= n compiled with the default MLton options, but crashes with a segfault when= compiled with certain GC flags.<br> >>> <br> >>> For example,<br> >>> <br> >>> $ mlton program.sml<br> >>> $ ./program<br> >>> <br> >>> runs to completion, while<br> >>> <br> >>> $ mlton -runtime 'copy-generational-ratio 10.0' progra= m.sml<br> >>> $ ./program<br> >>> <br> >>> runs for a second or so and then crashes. The crash is a segfa= ult in (according to gdb) forwardObjptr within performGC.<br> >>> <br> >>> I tried emitting C and compiling that with -g linked against l= ibmlton-dbg.a, and in this mode I get an assertion failure::<br> >>> <br> >>> gc/invariant.c:13: assertIsObjptrInFromSpaceOrImmutableMutable= OrRootStaticHeap: Assertion `isObjptrInFromSpace (s, *opp) || isObjptrInImm= utableMutableOrRootStaticHeap (s, *opp)' failed.<br> >>> <br> >>> The failure is within the invariant check made at the end of p= erformGC just before leaveGC is called, and is within the "checking ol= d generation" part of invariantForGC.<br> >>> <br> >>> The same behaviour happens with the Arch Linux package of 2021= 0117 and with a clean build from the current MLton repo, and it doesn't= appear to matter which codegen I use.<br> >>> <br> >>> Any tips or ideas for how to debug this? Besides that it seems= a bug, I am afraid that a failure in GC with unusual options now has the p= otential to become a failure with default options in the future under diffe= rent memory pressure or allocation patterns.<br> >>> <br> >>> I can provide a test program off-list if that would help anyon= e get to grips with it, but although it's just a single SML file, it is= quite large - the result of concatenating about 38k lines from other files= - and I haven't identified a nice small test case.<br> >>> <br> >>> <br> >>> Chris<br> >>> <br> >>> <br> >>> _______________________________________________<br> >>> MLton-devel mailing list<br> >>> <a href=3D"mailto:[email protected]" target=3D= "_blank">[email protected]</a>; <a href=3D"mailto:mlton-dev= [email protected]" target=3D"_blank">[email protected]</a><br> >>> <a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-= devel" rel=3D"noreferrer" target=3D"_blank">https://lists.sourceforge.net/l= ists/listinfo/mlton-devel</a><br> >><br> >> _______________________________________________<br> >> MLton-devel mailing list<br> >> <a href=3D"mailto:[email protected]" target=3D"_bl= ank">[email protected]</a>; <a href=3D"mailto:mlton-devel@m= lton.org" target=3D"_blank">[email protected]</a><br> >> <a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-deve= l" rel=3D"noreferrer" target=3D"_blank">https://lists.sourceforge.net/lists= /listinfo/mlton-devel</a><br> ><br> ><br> > _______________________________________________<br> > MLton-devel mailing list<br> > <a href=3D"mailto:[email protected]" target=3D"_blank"= >[email protected]</a>; <a href=3D"mailto:mlton-devel@mlton= .org" target=3D"_blank">[email protected]</a><br> > <a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-devel" r= el=3D"noreferrer" target=3D"_blank">https://lists.sourceforge.net/lists/lis= tinfo/mlton-devel</a><br> <br> <br> _______________________________________________<br> MLton-devel mailing list<br> <a href=3D"mailto:[email protected]" target=3D"_blank">MLto= [email protected]</a>; <a href=3D"mailto:[email protected]"= target=3D"_blank">[email protected]</a><br> <a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-devel" rel=3D= "noreferrer" target=3D"_blank">https://lists.sourceforge.net/lists/listinfo= /mlton-devel</a><br> </blockquote></div></div> --000000000000d745a305ecc444d6-- --===============1202340204324177820== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline --===============1202340204324177820== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ MLton-devel mailing list [email protected]; [email protected] https://lists.sourceforge.net/lists/listinfo/mlton-devel --===============1202340204324177820==--