leak at birth (25.2d): an allocation nothing keeps, made where the arena does not take it

ludic deps --births lists every site the escape analysis finds kept by nothing and not the frame
arena's - boot and load code, a function spanning frames, frame code with the arena off - which is
made and dropped and never given back; birth_leaks is a number --check ratchets. A text used up by +
or == where it is made is freed at once and not counted; nor is what @alloc_ok covers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-28 16:37:50 +03:00
parent db3a3d80d1
commit ce2699dfee
5 changed files with 57715 additions and 56121 deletions

View file

@ -25,6 +25,7 @@ var g_es_aok: int = 0 # inside a statement under @
var g_es_site_aok: []bool = new []bool # the site is (not reported by the region rule)
var g_es_site_grow: []bool = new []bool # the site is a push's growth (25.5's capacities, not the rule)
var g_es_done: bool = false
var g_es_consumed: []Node = new []Node # text used up where it is made (a + or == operand): freed at once
var g_es_ft: []int = new []int # flow edges
var g_es_ff: []int = new []int
var g_es_st: []int = new []int # store edges: value, target
@ -114,6 +115,10 @@ function es_val(e: Node) -> int {
if k == E_BIN {
es_val(e.a)
es_val(e.b)
if (e.s == "+") or (e.s == "==") or (e.s == "!=") {
if e.a != null and (e.a.kind == E_BIN or e.a.kind == E_CALL or e.a.kind == E_SLICE) { push(g_es_consumed, e.a) }
if e.b != null and (e.b.kind == E_BIN or e.b.kind == E_CALL or e.b.kind == E_SLICE) { push(g_es_consumed, e.b) }
}
if (e.s == "+") and fr_is_textish(e) { return es_site(e) }
return -1
}

View file

@ -227,4 +227,40 @@ function deps_keeps(f: pointer, seen: []bool) -> void {
}
deps_line(f, `frame_keeps {itoa(n)}`)
if g_arena_strict and n > 0 { exit(1) }
deps_births(f, seen)
}
function fr_consumed(n: Node) -> bool {
var i = 0
while i < len(g_es_consumed) { if g_es_consumed[i] == n { return true }; i += 1 }
return false
}
# 25.2's leak-at-birth: an allocation nothing keeps, made where the arena does not take it - outside
# frame code (a boot, a load), in a function spanning frames, or anywhere with the arena off - is
# made and dropped, never given back. `fbirth` lines, and the birth_leaks number
function deps_births(f: pointer, seen: []bool) -> void {
var n = 0
var s = 0
while s < len(g_es_site) {
let c = g_es_site_cls[s]
let fi = g_es_site_fn[s]
let site = g_es_site[s]
if c >= 0 and fi >= 0 and (g_es_flag[c] & ES_ESC) == 0 and not g_es_site_aok[s] and not g_es_site_grow[s] {
let d = g_es_fnode[fi]
let k = dr_index(d.s)
let inframe = k >= 0 and seen[k]
let scratch = g_arena and site.uns == ES_SCRATCH and inframe # before the first frame the arena is not running
if not scratch and d.file != null and not is_runtime_file(d.file) and not fr_alloc_ok(d.s) and not fr_consumed(site) {
var kind = fr_alloc_kind(site, false)
if kind == null { kind = "text" }
var where = "outside-a-frame"
if inframe { where = fr_chain(k) }
deps_line(f, `fbirth {kind} {d.file}:{itoa(site.line)} {d.s} {where}`)
n += 1
}
}
s += 1
}
deps_line(f, `birth_leaks {itoa(n)}`)
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff