Memory Safety Audit - Vitte Compiler
Date: 2026-05-23 Scope: compiler internals, backend/runtime interfaces, runtime C support, ownership and lifetime analysis.
1. Unsafe Inventory
1.1 Language-level unsafe surface
unsafeis parsed as a block construct in the frontend parser: parser.vit.- AST carries
unsafeflags in items/statements: - proc signatures default to
unsafe: false: item.vit - statements mark
AstStmtKind.Unsafe: stmt.vit - Finding: there is parsing/modeling support, but no explicit end-to-end enforcement boundary in this audit scope that would require unsafe ops to be inside unsafe blocks.
- Risk: Medium (policy drift risk, not immediate memory corruption by itself).
1.2 Raw pointers and deref typing
- Raw pointer kinds are present in AST type system (
RawPointer): type_expr.vit. - Pointer unification exists (
*const,*mut) in typeck: unify.vit. - Finding: pointer type compatibility is handled; lifetime/provenance guarantees for raw pointers are not established by type unification alone.
- Risk: Medium.
1.3 Native/C boundary usage
- Real heap allocation primitives appear in C runtime (
malloc,realloc,calloc): vitte_runtime.c. - Backend declares runtime stubs
vitte_alloc/vitte_free/vitte_print: llvm_emit.vit, c_emit.vit. - Finding: declarations exist, but corresponding implementations are not present in
runtime_cheader/source exported API shown in this audit. - Risk: High (ABI/link mismatch, potential undefined behavior if symbol expectations diverge across paths).
2. Ownership Audit
2.1 Strengths
- Ownership model tracks local states (
Available,Moved, borrow counters): ownership.vit. - Place overlap/prefix checks exist for field/index/deref projections: ownership.vit.
- Borrow checker enforces move-while-borrowed and write-while-borrowed diagnostics: mod.vit, mod.vit.
2.2 Gaps / risks
- Borrow metadata scopes are line-based approximations (
scope_end_line) and sentinel max values: mod.vit, mod.vit. - This can be conservative or imprecise for complex control-flow/lifetime nesting.
- Risk: Medium (false positives/negatives possible at edges).
3. Allocator Audit
3.1 Runtime C allocator behavior
realloc-based push for slices andmallocfor strings: vitte_runtime.c, vitte_runtime.c.- Panic marker set on allocation failure (
vitte_note_panic(3)), but no global ownership/free API for all allocations in this unit. cli_argsallocates withcallocand returns owning slice without matching runtime free primitive exposed here: vitte_runtime.c.- Risk: High for leak accumulation in long-lived processes.
3.2 Core allocator model quality
stdlib/core/memory.vitlprovides a bookkeeping allocator model (good for reasoning/tests): memory.vitl.- But arithmetic is unchecked for underflow/overflow during allocate/release accounting (
free - size,used - block.size): memory.vitl, memory.vitl. - Risk: Medium (model integrity bug; if reused in production-like contexts this becomes high).
4. Pointer Lifetime Audit
4.1 Runtime pointer lifetime issues
VitteStringuses{const char *data, size_t len}and string constructors allocate buffers: vitte_runtime.h, vitte_runtime.c.- No audited destructor/ownership transfer API for
VitteString/VitteSliceStringheap buffers. - Risk: High (lifetime leaks and ambiguous ownership).
4.2 Compile IR-level lifetime validation
- MIR validation checks CFG integrity and terminator consistency: validate.vit.
- IR verification checks structural validity of instructions/blocks/modules: ir.vit, ir.vit.
- Finding: structural checks are strong, but they do not prove pointer provenance/liveness at machine boundary.
- Risk: Medium.
5. Backend Memory Safety Review
5.1 LLVM backend
- Emits intrinsic declarations including lifetime intrinsics: llvm_emit.vit.
- Current emission body is placeholder-oriented (
; statement, simplistic terminator mapping): llvm_emit.vit. - Risk: Medium now (limited feature implementation), High once codegen becomes complete without deeper safety contracts.
5.2 C backend
- Runtime declarations in generated C do not currently align with runtime header signatures (
vitte_printtype mismatch: declared withvitte_string_tin emitter vs absent in runtime header): c_emit.vit, vitte_runtime.h. - Risk: High (ABI mismatch and call-site UB risk).
5.3 Linker/object pipeline
- Linker/object code is largely pseudo-model text assembly, reducing direct memory corruption surface in these modules: linker.vit, object.vit.
- Risk: Low in current form.
6. Runtime Memory Review
6.1 Panic boundary semantics
- Thread-local panic state with boundary depth is clean and bounded in logic: vitte_runtime.c.
vitte_builtin_trapaborts outside boundary, otherwise marks panic state: vitte_runtime.c.- Risk: Low for memory safety; mostly control-flow behavior.
6.2 Memory ownership API incompleteness
- No explicit exported free/destroy functions for heap-backed string/slice values created by runtime helpers in this audit scope.
- Combined with repeated concat/push patterns, this is leak-prone.
- Risk: High.
7. Priority Findings (Top)
- High: Backend/runtime ABI mismatch for allocation/print symbols (
vitte_alloc/vitte_free/vitte_print) across emitters vs runtime C exports. - High: Runtime heap objects (
VitteString,VitteSliceString) lack explicit destruction/ownership-release API in audited surface. - High:
cli_argsheap allocation lifecycle is unpaired with teardown function. - Medium: Borrow/lifetime metadata is line/scope heuristic based, not full CFG region model.
- Medium: Core allocator bookkeeping performs unchecked arithmetic underflow/overflow.
8. Recommended Remediation Plan
Phase A (blocking, immediate)
- Define and implement canonical runtime ABI in one place:
- Add concrete
vitte_alloc,vitte_free,vitte_printimplementations inruntime_c(or remove declarations from emitters if unused). - Ensure signatures are identical across:
- llvm_emit.vit
- c_emit.vit
- vitte_runtime.h
- Add destructors:
vitte_string_free(VitteString)vitte_slice_string_free(VitteSliceString, bool free_elements)vitte_slice_i32_free(VitteSliceI32)
Phase B (short term)
- Add overflow guards before allocations:
next_len > SIZE_MAX / sizeof(T)checks beforerealloc.a.len + b.lenoverflow checks beforemalloc(total + 1).- Add runtime fuzz/ASan/UBSan jobs for
runtime_c. - Add negative tests for ABI mismatch detection during build.
Phase C (medium term)
- Tighten unsafe policy:
- Require explicit unsafe context for raw pointer deref operations.
- Emit diagnostics when unsafe operations appear outside unsafe scope.
- Evolve borrow/lifetime analysis toward CFG/region precision rather than line-end heuristics only.
9. Audit Conclusion
Current compiler core (HIR/MIR/IR validation + borrow machinery) has solid structural safety foundations, but memory safety risk is concentrated at the backend/runtime native boundary. The most urgent issues are ABI consistency and explicit deallocation ownership APIs in runtime_c.