Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

To decide what is defined or not, you need to reference the relevant specification. The specification is not ISO C, but ISO C plus additional guarantees by Fil-C.
 help



I reference C's here because it gives the best idea of what clang/LLVM itself is going to consider UB and the bulk of the optimization semantics (where they haven't been changed by Fil-C), since Fil-C is really a fork with some additional passes and transforms built-in.

Fil-C is a fork of clang that explicitly defines all these things to have bounded behavior, so ignoring exactly this - the whole point of Fil-C - makes no sense.

But what are "all these things"? It does not define away all of the UB that C/LLVM has for sure, nor does it turn all UB into crashes, which I demonstrated above and is the inaccurate description of Fil-C that spawned this. But beyond that, it's my belief in all of this is that leaving some UB behavior while trying to state a global correctness property puts those guarantees at risk.

I spent a few minutes poking just to see if my gut is right here, and already, here's an example of UB being used in an optimization by the compiler that leaves a fil safety check at on -O0 but drops it at higher optimization levels. I find it difficult to believe that all of the complex interactions of every optimization pass in the presence of even this subset of UB are guaranteed not to violate these memory safety promises.

    #include <stdio.h>
    #include <stdlib.h>
    
    __attribute__((noinline)) static void poke(int *p, int k)
    {
        int n = 32 + (k & 15);          /* always >= 32: shifting an int by >= 32 is UB */
        p[(1 << n) * 20] = 0x41414141;  /* on x86 the CPU computes index 40, out of bounds */
    }

    int main(int argc, char **argv)
    {
        int *p = calloc(16, sizeof(int));
        poke(p, argc);
        puts("after poke");
        return 0;
    }

It does not have to fully specify what happens in each case, Fil-C only formulates a bound that guarantees that any memory access is limited to the memory that can legitimately be accessed. That safety checks can be removed, where the optimizer can prove that they are always fulfilled, would be expected. If it is removed and then still allows an out-of-bounds access, then this would be a bug in Fil-C.

I also do not believe that all complex interactions are guaranteed to not violate all safety promises. I also know that this is not true for Rust, so what is your point?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: