Mixing safe and unsafe
Mixing safe and unsafe
Posted Oct 29, 2025 11:42 UTC (Wed) by matthias (subscriber, #94967)In reply to: Mixing safe and unsafe by epa
Parent article: Fil-C: A memory-safe C implementation
This is not the only problem. Once you have unsafe blocks, you have a contract between safe and unsafe code, as an unsafe block will for sure rely on invariants that are hard to impossible to check at the boundary. Say you have an unsafe block that traverses a linked list. If you turn of the runtime checks inside the block, you rely on the promise that all pointers in the linked list are valid. Otherwise you immediately have undefined behaviour.
Even in rust this is an issue and if you have unsafe blocks you have to be very careful that the unsafety is contained, usually at the module boundary. Changing an integer is usually considered safe, but if the integer encodes the length of a Vec, than this is very unsafe, as the unsafe code that implements indexing into the Vec relies on this integer to be correct. This is solved by not providing any (safe) functions that can change this integer directly. The situation is that safe code that interacts with Vec cannot cause undefined behaviour. However, safe code within the Vec module most definitely can. You do not need an unsafe block to change the integer encoding the length. This is described quite nicely in the first chapter of the nomicon[1] (the guide to unsafe rust). You can read this introductory chapter even if you do not know rust.
With Fil-C this containment of unsafe is just impossible. In C you can always change the contents of a variable by casting it to an array of bytes. So you cannot rel on any invariants and have to check when you use a pointer. Or you have to verify that the unsafe block is never called with violated invariants, which basically forces you to verify all the code, not only the usnafe block.
[1] https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html
