• Yes, that’s true, but it’s also unavoidable.

    Fil-C avoids it by forcing folks to use the stdfil allocators.

    I get that Fil-C gets there by making trade-offs that you consider unacceptable. But the allocator problem is not unavoidable.

    A lot of our code is now compiled with sub-object bounds, where taking the address of a struct field gives you a pointer bounded to that specific field.

    I’m curious, how much code can you compile that way?

    An earlier project I did that made C safe in a similar way to Fil-C took that approach by default, but in practice, that thing required even more code changes than Fil-C.

    In Fil-C, you can zrestrict(ptr, type, count), which gives you a ptr restricted to that type and count, with a runtime check to ensure that this is safe. Interestingly, this operation is like gold for an abstract interpreter, so there will be an incentive to use it aggressively if you want to optimize your code for Fil-C. That’s definitely not as good as a compiler mode that gives it to you by default, though!

    This prevents overflow between struct fields (e.g. the Firefox vulnerability from a couple of years ago that used an intra-object overflow to bypass TLS certificate checks).

    Yes, and that’s why it’s useful!

    Fil-C partly addresses this. If the overflow between struct fields trips the wrong type (like you overflow an int array field and the next thing after it is a ptr, then you’ll trap).


    score 3 · canonical

    • Fil-C avoids it by forcing folks to use the stdfil allocators.

      You can only force people to use specific allocators if you can detect things that act like allocators. I’ve seen a lot of code that uses malloc to back another allocator, so you need to spot things that take a void* and then return a void* derived from it. A lot of things that are not allocators also do this.

      I’m curious, how much code can you compile that way?

      It’s very variable. Almost no systems code unmodified, but quite a bit if you add a few annotations in headers. Most kernels (including Linux and NT) have a set of data structures derived from the 4BSD set, which use the container-of idiom, but you can annotate them elsewhere.

      For a lot of userspace applications, it requires no code change, but they typically depend on libraries that do need some annotations. It also depends on the age of the code.


      score 4 · canonical