Three coupled changes that unblock the ecdsa quantum-circuit
simulator's run on the C tier from neoblanka.
1. c/Makefile autodetects libgc-dev — if /usr/include/gc.h is
present, the build links Boehm and defines USE_BOEHM_GC. Without
GC, ul_free is a no-op (lumbda.h:35) and every allocation leaks;
small REPL snippets work but workloads with thousands of envs
OOM the process. Override with USE_GC=0 to force the malloc-only
path for diagnostics.
2. c/main.c calls GC_INIT before init_symbols, then GC_disable.
GC_INIT registers the stack base for conservative scan — without
it some Linux configs miss roots. GC_disable is a deliberate
stopgap: lumbda Values are NaN-boxed pointers that conservative
Boehm cannot recognize as pointers, so live targets get reclaimed
(env binding symbol payloads, SymbolEntry strings) and lookups
fail with "undefined: <sym>". Reproducing this without GC_disable
on the GC build: any sim.lsp call chain triggers the corruption
after ~100 named-let iterations. Until tracing is precise,
growing the heap is safer than wrong results. Long-running
workloads run under ulimit -v.
3. c/builtins.c gains rename-file and delete-file matching the
Python tier (lumbda.py:3468). sim.lsp's write-portal! pattern
(write to .tmp, rename) needs rename-file to land cross-tier
identical results.
4. tests/regression-named-let-leak.lsp + .sh pin four shapes that
blew up ecdsa: the c/TODO-named-let-bytecode.md repro, the F1
shape from foxhop.net's lumbda-c-tier-leak-SP.md (12-line
minimum), a 200-iter scaled variant, and a sim.lsp run-ops!
mirror. Wired into root Makefile as regression-named-let-leak;
added to test-all. Wrapper caps memory at 256 MB virt and 15s
per tier so a leak regression fails the run instead of consuming
host RAM.
Known limits:
- --fast JIT still has the named-let + inner user-fn call hang
(separate TODO; tree-walker handles this fine).
- GC_disable means the heap grows; workloads must bound their work
budget. ecdsa's sim runs comfortably in 5 MB.
Verified inside a 2G/2vCPU QEMU guest (foxhop.net ecdsa/vm-runner.sh):
- test-c (tree-walker) — 35/35 PASS
- bench-c (tree-walker) — score 18 matches Python tier byte-identical
- F1 probe (tree-walker) — all four steps PASS