← Back to AILP Home

Memory FAQ

Short answers to recurring questions. For longer-form treatment see the chapter linked at the end of each entry.


What region does a bare local declaration use?

The stack region, same as the explicit stack keyword. The earlier "non-primitives are GC by default" lore was wrong; only the explicit gc keyword routes through npk_gc_alloc. See regions.md.


When should I pick gc over stack?

When the value's lifetime needs to outlast the current frame: returning it, storing it in another gc structure, putting it in a queue, or participating in a cyclic graph. Otherwise, prefer stack. See gc.md.


Is gc safe across npk_gc_safepoint() calls?

Yes. Every gc binding is auto-pinned and shadow-stack rooted at allocation (v0.26.3.2+). You don't need to add a # pin yourself for this case; the binding name keeps the object reachable and the auto-pin keeps its address stable. See gc.md and pinning.md.


Why does the borrow checker reject pass $$m local;?

That's ARIA-028 STACK_ESCAPE. The host's stack frame is destroyed when the function returns, so the borrow would dangle. Return by value, take ownership in the caller, or accept a borrow parameter and return that. See diagnostics.md.


Can a borrow into a gc binding escape the function?

No — ARIA-028 is conservative and rejects this even though the underlying object survives on the heap. The named binding goes out of scope, and the borrow path is rooted in the binding name. The path-sensitive relaxation that would allow this is deferred. See stack.md.


Does the GC follow wild pointers?

No. The GC heap and the libc-malloc-backed wild heap are disjoint — verified end-to-end by bug230 against npk_gc_is_heap_pointer_i32. A wild slot does not root anything the GC can see, either; if you need that, use npk_shadow_stack_add_root as documented in interop.md.


How do I tune the GC?

Three env-vars read at GC init: NPK_GC_NURSERY_SIZE, NPK_GC_OLD_GEN_THRESHOLD, NPK_GC_MODE. Resolution order: explicit arg → env-var → compiled-in default. Full table and verification recipe in tuning.md.


Is there a way to opt out of the borrow checker?

wild does that for the contents of the allocation (the leak/UAF guards ARIA-014 / ARIA-015 still apply at the allocation site). wild is intended for FFI buffers and interop with C-style APIs, not as a general escape hatch. For owned values that need to outlive the frame, use gc. See wild.md.


Does #x extend lifetime?

No. #x only promises address stability — the underlying storage will not move for the lifetime of the alias. Lifetime is a separate concern handled by the borrow checker (and the GC reachability graph for gc bindings). See pinning.md.


What does npk_shadow_stack_add_root do, and when do I need it?

It registers an arbitrary memory location as a GC root, so the marker will trace whatever pointer lives at that address. The narrow case it exists for: a wild slot must hold a gc reference that the GC needs to see. Almost no user code should need this; the auto-pin + auto-root behaviour for gc bindings handles the common cases. See interop.md.


Why ARIA-028 and not ARIA-017 or ARIA-027?

History. The compiler tagged stack-escape errors as ARIA-017 from v0.26.1 through v0.26.5; the docs promised ARIA-027 for the same concept but the code never used that tag. v0.26.6 unified everything under ARIA-028 STACK_ESCAPE with polished message text. See diagnostics.md.