"Going past the end of the array results in addressing arbitrary values" I can live with. "Going past the end of an array results in anything happening" is a hard sell.
Once you are addressing arbitrary values you are firmly in the realm of "anything happening" in practice, but you've now given up optimization opportunities. As has been repeatedly demonstrated over the years, once memory safety breaks it is practically impossible to make any guarantees about program behavior.
Your compiler emitting a load operation and it failing isn't "anything". The failure being handled by code that the compiler authors can't predict doesn't make it "anything".
And if you lose optimization opportunities because of this it's because your optimization is broken. By the way, if you lose optimization opportunities because of this, that means both codes are meaningfully different and you knew it all the time.
https://daniel.haxx.se/blog/2016/10/14/a-single-byte-write-o...
And if you get code execution, then you by definition have "anything".
Documenting that the instructions to access will always be eliminated makes it easier to predict what will happen.
For example, a dynamically linked library that takes in a pointer, and then writes to the 10 ints after it—whether or not this behavior is defined is determined after that library is compiled, right?
But just because those forms are common, doesn't mean the behavior is actually defined.
Ex - I might be using a vendor specific compiler for custom embedded devices where dynamic linking isn't available at all, and which might have complicated storage mechanisms that look nothing like standard memory pages.
You're already deep into the bowels of implementation specific behavior by the time we talk about dynamic linking. The C standard doesn't have anything to say about it at all.
My read on the above conversation is basically a discussion about asking/requiring vendors to properly document their implementation, as opposed to leaving it undocumented (the default - given my experience with hardware manufacturers...).
I don't think the real takeaway is that "instructions should be eliminated in case [blah blah blah]" it's that "Something is going to happen, please tell me what that is on your system, instead of leaving it as UB" (Basically - make UB in the standard implementation defined behavior from the vendor).
My read is that this won't happen because it's genuinely incredibly difficult to do, and this isn't a space overflowing with capital to allocate to the problem. But I do think there's merit to the idea of pushing vendors to provide coverage in this space AT SOME POINT.
"Can't always be detected" is jut a different way of saying "Can sometimes be detected".
Upon detection, I'd rather that the compiler still emit the instructions, not elide the code altogether.
That does not seem like an improvement if your goal is predictable, consistent behavior.
> That does not seem like an improvement if your goal is predictable, consistent behavior.
Getting unpredictable outcomes only on some items is better than getting unpredictable outcomes on every item. This is what I meant when I said moving UB to IB might not fix everything, but it is certainly a solid start!
For the former, I kinda get it. It may need to be there for cases like with segmented address space where p+10 could actually be a value less than p, for the eventually generated assembly. Maybe it should be fine to create such a pointer, but have it be "indeterminate value" or whatever, if you try to compare that pointer to anything? I don't know enough about compiler internals to say one way or the other.
Dereferencing, though, can only be UB. There may not be a "value" behind that address. There may be a motor that's been I/O mapped, or a self destruct button.
Right now, if a dereference results in UB, the compiler may omit it entirely.
I know what you mean, but I'm just not sure you're describing something that fits what C "is". We program C to the abstract machine specified in the standard (5.1.2), and the compiler's job is to translate that into something with identical behavior on particular hardware. Piercing the layers down to actual hardware or assembly isn't really done.
Even "volatile" just says (basically) "touching this object has side effects". It implies no double-loading, speculative store, etc, but doesn't say "don't emit assembly instructions to load this unless the program logic path takes the route where the C program does load it".
The standard is not using ancient language when it refers to "objects with static storage duration" instead of "heap" or ".data segment". It is the true class of objects in the abstract machine.