Fil-C
- title
- Fil-C
- type
- toolbox
- summary
- Memory-safe C/C++ compiler giving every pointer a bounds-checked capability and a GC, no rewrites
- tags
- c, cpp, memory-safety, compiler, llvm
- language
- C/C++
- license
- Apache-2.0
- created
- 2026-04-18
- updated
- 2026-04-18
A memory-safe implementation of C/C++. Fil-C adds an LLVM IR pass that rewrites pointer operations to carry a shadow "capability" (an AllocationRecord*) alongside every pointer, performs bounds checks on every dereference, and runs a garbage collector to manage the lifetime of the capability records. The result is C/C++ that survives bounds violations, use-after-free, and type confusion without rewriting source code.
How it works
Three ideas, in layers:
- Shadow capability per pointer. Every pointer is paired with an
AllocationRecord*tracking its allocation's bounds (visible_bytes,length). Dereferences check bounds against this record. See simplified-model-of-fil-c for the full walkthrough. - Parallel shadow heap for stored pointers. Each allocation has a
visible_bytesarray (user data) and aninvisible_bytesarray (same size, element typeAllocationRecord*). When user code loads or stores a pointer in memory, Fil-C also loads/stores the capability from the parallel index. This is how capabilities survive being written through memory. - Parallel concurrent incremental GC (FUGC). AllocationRecord objects are never freed explicitly; the GC handles them. This means forgetting
freeis not a leak, and use-after-free is safe (freed records get canonicalised to a single length-0 sentinel).
Additional production features: escape-analyzed locals get heap-promoted automatically, function pointers carry a distinct capability flag with a uniform ABI, and atomic pointer ops use custom lowering to preserve atomicity across the paired load.
See pointer-provenance โ Fil-C is a concrete system that makes provenance semantics observable, because equal pointers can carry different AllocationRecord* values.
Use cases
- Legacy C/C++ you want memory-safe without a full rewrite, typically as a bridge to eventual migration.
- A stronger alternative to ASan for finding memory bugs.
- Safe compile-time evaluation in languages like Zig where compile-time and runtime share a language.
- A teaching example for memory-model concepts like provenance.
Limitations
- Performance cost is large. Every dereference is a bounds check; every pointer load/store is doubled. Optimisations claw some of this back but not all.
- Forces a GC into C/C++. For systems where GC pauses are unacceptable, Fil-C isn't the right fit.
- ABI changes. Functions take paired
(pointer, AllocationRecord*)arguments; interop with unmodified C code needs wrappers. memmovesemantics quirk. Aligned multi-bytememmovemoves shadow memory along with user bytes; misaligned or byte-wise copies don't. This can silently lose capabilities if code relies on unaligned memory layouts.
Related
- simplified-model-of-fil-c โ the step-by-step introduction this toolbox entry is based on
- pointer-provenance โ the memory-model concept Fil-C demonstrates
- win32-stable-abi, abi-stability โ contrast: ABI stability as a lack of enforced safety
- yk โ another LLVM-IR-rewriting project, for JIT rather than safety
Homepage: fil-c.org. Technical deep dive: Invisicaps. Collector: FUGC.