Fil-C

Memory SafetyC/C++ CompatibilityModern Tooling

Fil-C Runtime

Programs compiled with Fil-C enjoy comprehensive memory safety thanks to the entire userland stack being compiled with the Fil-C compiler. There is no interoperability with Yolo-C (i.e. classic C). This is both a goal and the outcome of a non goal.

Goal: To prevent memory safety issues arising from code linked into your Fil-C program. Lots of memory safety solutions make it easy to lock down just a small part of your program. While this can be a satisfying thing to do for systems builders as it shows progress towards memory safety, it's also easy for the attackers to work around. Software that's in a perpetually "partly memory safe" state is really in a perpetually unsafe state. It's a goal of Fil-C to take a giant leap towards complete memory safety, rather than slowly inching towards it.

Non-Goal: To support interoperability with Yolo-C. That kind of interoperability is hard to engineer, both from a language design and a language implementation standpoint. Fil-C uses pointers that carry capabilities. It's hard to imagine a satisfactory language design that allows Yolo-C code to pass a pointer to Fil-C while having some kind of meaningful capability associated with that pointer. Even if a design existed, actually making it work is even harder, particularly since Fil-C uses accurate garbage collection and Yolo-C++ has explicitly removed support for garbage collection of any kind. It's a non-goal of Fil-C to try to marry its garbage collected capabilities with languages that disallow garbage collection and lack capabilities.

Building a meaningful product often means accepting what you can and cannot do and then embracing the limitations that fall out. Fil-C proudly embraces comprehensive memory safety.

What does this look like in practice? This document shows the current status.

The libc Sandwich

Fil-C has a runtime (libpizlo.so and filc_crt.o) that is written in Yolo-C and that links to a libc compiled with Yolo-C. Another libc, compiled with Fil-C, lives on top of the runtime. The rest of your software stack then lives on top of that libc.

Fil-C Sandwich Runtime

Let's review the components:

Note that while I'm showing shared libraries (.sos), it's possible to compile a static Fil-C executable, in which case ld-yolo-x86_64 doesn't come into play at all and the rest of the stack is statically linked into your program.

You can see a bit of this architecture by calling the stdfil.h zdump_stack function:

#include <stdfil.h>

int main()
{
    zdump_stack();
    return 0;
}

This program prints:

    <runtime>: zdump_stack
    stack.c:5:5: main
    src/env/__libc_start_main.c:79:7: __libc_start_main
    <runtime>: start_program

Let's examine these frames starting from the bottom:

Memory Safe Linking And Loading

Fil-C relies on ELF. I have also previously demonstrated it working on Mach-O. Fil-C does not require changes to the linker. The only changes to the musl loader are to teach it that from its standpoint, the libc that it cares about is called libyoloc.so not libc.so. Fil-C even supports advanced ELF features like weak symbols, weak or strong aliases, comdats, and even ifuncs. Fil-C ifuncs are just Fil-C functions and they are totally memory safe.

Linking and loading "just works" because of the following three tricks:

Put together, this means that even wild misuse of linker capabilities in your Fil-C program will at worst result in a memory safe outcome (like a Fil-C panic).

To learn more, check out Explanation of Fil-C Disassembly.