We already have a thread discussing this topic here: New Proposal by Andrew: introduce an actually memory safe (unlike Rust) compilation mode inspired by Fil-C
But I feel like it has way too much off-topic emotion mixed in.
So I want to start a purely technical topic to discuss this new compilation mode:
- Is it actually memory safe?
- How big is the performance hit? In some cases, will it degrade to the level of languages with GC?
- Most importantly, from a coding perspective, will it have a major impact — to the point where it splits into “safe Zig” and “unsafe Zig”?
Personally, I also have one more question: In a complex real-world project made up of Zig code plus C/C++ libraries, could the library code cause my Fil-C mode build to fail? And would I then have to go in and modify those libraries myself?
Chaz July 21, 2026, 2:40am 2
First, thanks for beginning a purely technical discussion.
My understanding of what I read earlier today is that Andrew’s goal is clearly that 1 = yes, it is actually memory safe, 2 = 1-6x perf hit based on Fil-C measurement of Fil-C implementation, though this would absolutely be a new implementation, and 3 = no, it does not change your code.
But with more certainty than any of the other answers, I would say that the new issue describes a goal and not an implementation and that makes measurement very difficult.
Edit: I realized I had something to add re your last question as well.
Fil-C has a list of programs that work that should give a clearer idea of its progress so far. It’s not zero changes required for all programs ever, but it’s small enough that one person (I think) has updated sqlite/rsync/tmux/python/openssl/openssh and a few dozen other projects.
Read through the list, the nuances are interesting: rsync and tmux and sqlite worked out of the box, but the SQLite test suite needed changes. A note on Python mentions a lot of pointer-as-int usages that had to change to an actual pointer type.
The Linux Sandboxes And Fil-C page describes some specific details of their threading/seccomp changes.
Again, that is all from Fil-C’s testing of Fil-C’s implementation and not a hypothetical Zig implementation, but it can give us some idea what issues exist. A hypothetical new Zig-specific implementation (maybe one shared with Aro or zig libc?) could end up adding other limitations or avoiding some of these limitations.
IceGuye July 21, 2026, 3:18am 3
I think right now there is another concern I would like to know too:
Most people here just run their programs forever in ReleaseSafe right now… And they accept the performance downgrade… I think people expect a safe language that runs fast enough forever, so they concern about the performance. But few people talk about the actual debugging first, then back to release fast method.
I would like to know that in C community, how do the people feel when they run their programs in Fil-C for debug, and eventually released in normal C compiling, and are they still safe? Did they fix all the memory safety issues before going back to normal C? How was their codes run in normal C?
Same here, how many people did successfully use debug mode or releasesafe mode, and in the future, they will use the “very safe Fil-C whatever mode”, then change back to ReleaseFast. Is the program still safe? How long does it take for the debugging? How good was their ReleaseFast build after Debug build?
Anyone have the experience and want to share?
Chaz July 21, 2026, 3:23am 4
I have a question: is this inherently a whole-program abi change or could it be scoped to only some allocators or an @optimizeFor(.filc) scoped? I’d love to have only my most interesting allocations be checked and have my task-specific tight loops of allocations just use trivial arenas (as long as I use another mechanism to make sure those pointers are gone before the arena).
There are some gaps depending on your definition of “memory-safe”. Strictly speaking, all pointers are checked… but to what granularity?
AFAIK – and forgive me for not actually trying this but I don’t really want to install the Fil-C compiler – intra-object overflows are not checked. For example:
struct User {
char name[16];
int is_admin;
};
struct User user = {0};
strcpy(user.name, attacker_input);
This would not trap.
This is outlined in the “Gep” section of his “Garbage In, Memory Safety Out” (GIMSO) doc. It’s some technical jargon with LLVM semantics but if understood correctly, the pointer to name carries the capabilities of its parent – the User.
Once the read/write crosses outside of the parent container (in this case the User struct into adjacent memory) it would be flagged. IF you corrupt a pointer field, you’re likely to corrupt its capabilities which would cause a trap later down the road.
This issue is tracked upstream here: Consider subobject and encapsulated capabilities · Issue #133 · pizlonator/fil-c · GitHub
This is also a gap with ASAN that’s solved with poisoned gaps in the struct: AddressSanitizerIntraObjectOverflow · google/sanitizers Wiki · GitHub
Hardware-based solutions like MTE and I think CHERI also share this gap.
I think this would need to be all-or-nothing, otherwise your “safe” code could not reasonably touch data from “unsafe” code since there’d be no capabilities to check. Likewise, your “unsafe” code would need some way of knowing it’s interacting with pointers carrying provenance. This can probably be expressed via some fancy types but at that point you’re making code changes to facilitate something that desires to require no code changes according to Andrew.
From an exploitation perspective if your safe world CAN suddenly start stripping capabilities from pointers that could probably be used as a bridge to attack the unsafe world. You could probably use something like an LFI sandbox to further isolate these, but that’s adding yet another layer of complexity
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.