That's not true.
Rust behaviour avoids UB by not compiling with invalid reference deref because it checks life time.
Clang's behaviour is likely a crash but anything can still happen. It is literally undefined.
You act as if clang itself is random. Clang will do and handful of things none of them which will melt your computer.
A given implementation may choose to do anything. Clang and gcc on major operating systems do reasonable things.
> It is literally undefined.
Ok but I’m explaining why undefined is the right thing.
Ok, clang will not directly melt my computer because clang just generates code, but imagine this:
if (temperature_too_high)
lower_temperature();
if somewhere else the code access invalid pointer, clang may decide to remove this condition altogether because it thinks it must be dead code, for example. And running this code will melt the computer even though the programmer thought this wouldn't be possible.A conforming implementation may chose to melt your computer - and you can choose to not use that implementation. But clang and gcc will never melt your Linux.
Once again, a real life example where that is relevant is an embedded device with no memory protection. If you overwrite a buffer you can overwrite the OS code - breaking your computer and requiring you to flash the memory.
It seems there is a lot of misguided accusations going around about who misunderstands UB.
If you use gcc or clang to compile your kernel, they will happily melt your Linux.
You could still define what happens.
Eg you could define that whatever error might happen because of invalid pointer deref can't travel back in time. (UB famously can travel back in time: UB at any time during the execution makes the whole execution UB.)
This is now clearly standardized, but even without that it's pretty trivial to see how compilers would generally abide by this - if you call an external function that does arbitrary things, it may exit(), so the call can't be optimized even if it's followed by UB. (printf & co are effectively arbitrary calls for these purposes for multiple reasons). And all other behavior is just writing things to memory, which can be undone by happening to write what was there before. (ok there's also volatile, and a bug in clang (not gcc though): https://github.com/llvm/llvm-project/issues/102237)
(and singron's mention of SIGSEGV handling is entirely irrelevant; the C standard only cares about the abstract machine; in general real memory state can temporarily appear in arbitrarily weird states in practice if interrupted by a signal even without UB, e.g. https://godbolt.org/z/91ModhbEY will have all a[0..15] written even if there's a handled trap on the write to b[0] (or otherwise an interrupt between the two SIMD writes) (using restrict for simplicity, but taking an 'int n' argument and using that for the loop bound will result in ~the same thing without restrict, just with less direct assembly); the same applies even to Rust, though of course with Rust you shouldn't be able to have a situation where you trap on a safe write; could still have a random interrupt happen in the middle though)
In embedded systems without virtual memory there is no validity checking at all. Or it could periodically check (random sampling).
So the standard makes the reasonable choice to leave it undefined. If you can detect it and crash, that’s great. If not and you accidentally overwrite your programs instructions, anything can happen.
Rust only avoids UB in so far as it relies on default clang behavior on modern hardware.