ludic/examples/modules/alloc_ok_private.ludic
Orkuncakilkaya de6d78bef5 escape (fix): kept memory is HEAP, so what is pushed through an alias of it is kept
render3d's stream_new holds its pool through a local (`let live = s.chunks; push(live, new
Chunk)`): the flow edge from s.chunks to live carried ESC to nothing, the Chunk records were
LOCAL, and the arena reset them under the stream - the row and horse scenarios' crash at
0xdddd... in fn_stream_update. An ESC class is now HEAP too, so every alias of kept memory is,
and a value stored through it is kept. Bidirectional alias edges were tried first and over-kept
through returns (el_place, rim).

- examples/lang/arena_alias.ludic: the stream_new shape; poisoned it read 3 3000, now 3 1518
- examples/modules/alloc_ok_private.ludic: @alloc_ok on a module's private function and on a
  statement in its private generic, declared at run time (it already passes: a guard)
- the game: frame_allocs, frame_keeps, owned_leaks 0; the lab builds under `arena strict`; the row
  scenario poisoned (R3D_ARENA_CHECK=1, 2400 frames) runs clean, bad 0 kept 0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 21:15:32 +03:00

16 lines
571 B
Text

# alloc_ok_private.ludic - 25.1: @alloc_ok on a module's PRIVATE function, and on a statement in its
# private generic, is declared at run time like an exported one's (the module rules rename a private
# name, and the fence once lost the declaration with it). The failing fence lets it through:
# bad 0 kept 0
import "memo"
program AllocOkPrivate {
entry {
let m = new Memo
for f in 0 .. 900 {
if f > 650 and f % 25 == 0 { memo_miss(m, f) }
Mem.frame()
}
let kept_now = Mem.kept()
print(`bad {Mem.bad_frames()} kept {kept_now}`)
}
}