|
1 | 1 | # Changelog |
2 | 2 |
|
| 3 | +## v0.255.9 — Fix: `(gc!)` During In-Flight Major Mark Use-After-Free |
| 4 | + |
| 5 | +Root cause of the v0.255.6 / .7 / .8 CI hang: `mino_gc_collect(MINO_GC_FULL)` |
| 6 | +(the `(gc!)` primitive) ran the nested minor BEFORE finishing the |
| 7 | +in-flight major. The minor freed a YOUNG header that was still on |
| 8 | +major's mark stack from a prior incremental slice; the subsequent |
| 9 | +`gc_force_finish_major` chased the freed pointer through |
| 10 | +`gc_mark_child_push`. |
| 11 | + |
| 12 | +`gc_tick_during_major` (driver.c:141-147) already documents the |
| 13 | +correct ordering -- "finish-then-minor rather than nest" -- and |
| 14 | +honours it for the auto-tick path; the public-API path simply had |
| 15 | +the calls reversed. Auto-tick is the common case so the bug went |
| 16 | +unnoticed locally; CI's test ordering puts `transient-survives-gc- |
| 17 | +yield` (which explicitly calls `(gc!)`) inside an in-flight major |
| 18 | +on every push, surfacing the bug deterministically. |
| 19 | + |
| 20 | +Symptom shape under each environment: |
| 21 | + |
| 22 | +* GitHub Actions matrix (macos-14 / ubuntu-24.04{,-arm} / |
| 23 | + windows-2022): 8-min timeout in the Test step, identical hang |
| 24 | + point across all four OSes -- the v0.255.8 diagnostic trace |
| 25 | + pinned the hanging deftest to `transient-survives-gc-yield`. |
| 26 | +* Local without sanitizer: intermittent SIGSEGV in |
| 27 | + `tiny_free_no_lock` (sweep double-free) or |
| 28 | + `error[MTY001] inc expects a number` (corrupted value via the |
| 29 | + reused freed header). |
| 30 | +* Local under ASan: clean repro -- |
| 31 | + `heap-use-after-free at gc_mark_child_push driver.c:414` |
| 32 | + with the freer site at `gc_minor_collect minor.c:472` inside the |
| 33 | + same `mino_gc_collect` call. |
| 34 | + |
| 35 | +Fix: reorder `MINO_GC_FULL` to finish the major BEFORE the minor, |
| 36 | +mirroring `gc_tick_during_major`. Behaviour for `MINO_GC_MINOR` and |
| 37 | +`MINO_GC_MAJOR` unchanged. |
| 38 | + |
| 39 | +Regression: `tests/gc_test.clj` gains |
| 40 | +`gc-bang-during-incremental-major` -- warms up enough OLDs to start |
| 41 | +an incremental major, then calls `(gc!)` mid-mark in the transient |
| 42 | +shape that surfaced the bug. Fails (SIGSEGV / inc-error / hang) |
| 43 | +under the old ordering, passes under the fix. Full suite climbs |
| 44 | +from 1273 / 4555 to 1274 / 4557 (one deftest, two assertions). |
| 45 | + |
| 46 | +Local verification: |
| 47 | +* `./mino tests/run.clj`: 1274 / 4557 green in 1.6s. |
| 48 | +* `./mino_asan tests/run.clj`: 1274 / 4557 green, ASan clean. |
| 49 | +* `./mino task release-gate`: 17/17 probes green. |
| 50 | +* 5x consecutive `./mino /tmp/repro.clj` (35 transient deftests): |
| 51 | + all green, no flakiness. |
| 52 | + |
3 | 53 | ## v0.255.8 — Diagnostic: Per-Deftest Trace for CI Hang Investigation |
4 | 54 |
|
5 | 55 | A diagnostic-only release: surfaces which test is running at the |
|
0 commit comments