You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: trace enums by active variant so a scalar payload is not a GC root
An enum's GC pointer descriptor was the union of every variant's pointer
slots. When two variants store different kinds of value in the same slot, one
a scalar (a `Float`) and another a GC pointer (a `String`), the union marked
that slot as a pointer. A collection then followed the scalar variant's raw
bits as if they were an object pointer, writing GC bits to an arbitrary
address: a segfault, or the `suspend_current` scheduler assertion when the
corrupted memory was a coroutine. JSON values (a `Number(Float)` sharing a
slot with `Str(String)`) and any `Result<Int, String>`-shaped enum hit this
under collection pressure, which is why an allocation-heavy concurrent server
crashed within seconds.
The back end now registers a per-variant pointer mask via a new
`raven_enum_register(type_id, variant, mask)` intrinsic, and the collector
selects the mask by the value's discriminant (slot 0) instead of tracing the
union. A plain struct still uses its single per-type mask.
Adds a runtime unit test for discriminant-aware tracing and an end-to-end
golden example (`gc_enum_scalar_payload`) that forces collections while
`Float`-payload enums are live; it crashes on the old union mask and passes on
the fix. Version 2.18.121.
Fixes#601
Copy file name to clipboardExpand all lines: CHANGELOG.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,12 @@
2
2
3
3
All notable changes to Raven are documented in this file.
4
4
5
+
## [2.18.121] - 2026-06-16
6
+
7
+
### Fixed
8
+
9
+
- The garbage collector traces an enum value by its active variant rather than the union of every variant's pointer slots. An enum whose variants store a scalar (for example a `Float`) and a GC pointer (for example a `String`) in the same slot, such as a JSON value, previously had the scalar's bits followed as a pointer during a collection, corrupting the heap and crashing the program (a `SIGSEGV`, or a scheduler assertion under concurrency). The back end now registers a per-variant pointer mask and the collector selects it by the discriminant (#601).
10
+
5
11
## [2.18.120] - 2026-06-16
6
12
7
13
Continuing the codex-review fix batch (one patch per issue).
0 commit comments