3 ms·
> remove some of the undefined behaviors, There was a great talk from a C/C++ compiler writer about why you can't remove undefined behaviors while at the same
by lhweroiuwer 7y ago
> remove some of the undefined behaviors,
There was a great talk from a C/C++ compiler writer about why you can't remove undefined behaviors while at the same time keeping C like speed.
Simple example: accessing an array past it's end it's undefined behaviour. If you want to remove this, you need to add bounds checking (either to raise an error or to just return 0).
- tynorf 7y agoI haven't actually watched it in a while, but are you referencing this talk by Chandler Carruth? https://youtu.be/yG1OZ69H_-o https://youtu.be/yG1OZ69H_-o
- T-hawk 7y ago> you can't remove undefined behaviors while at the same time keeping C like speed. This is absolutely correct. The specs of C allow so much undefined behavior in order to let the compiler just emit the instructions for the arithmetic operation or memory access or whatever. For edge cases like overflow and bounds, C deliberately says "not my problem" and you just get whatever that hardware architecture happens to do with that instruction. It's a deliberately leaky abstraction.
- juped 7y agoIt's more that things were left undefined for portability and compiler authors (ab)used them for optimization enough for that to become de facto true (especially now that portability is easier).
- favorited 7y agoAnd if all C users decided that, now that portability is much easier, it was time to define some of that behavior, it would happen. But, as much as people want to blame optimizing compilers for their behavior around UB, absolutely no one is going to sacrifice C's performance for safety.
- tylerhou 7y agoPortability is still nontrivial. It’s still difficult to target all of x86, ARM, Power, RISC-V at once.
- dooglius 7y agoOnly if you define it to be something dumb like an error or returning 0. It should instead be defined as the hardware behavior: a load to the resulting linearly-calculated address which enters an implementation-defined exceptional state (e.g. SIGSEGV/SIGBUS) if that address does not represent readable memory.
- audunw 7y ago> There was a great talk from a C/C++ compiler writer about why you can't remove undefined behaviors while at the same time keeping C like speed. I don't think this is true. Look at Zig, they don't seem to have a problem removing a lot of C's undefined behaviour, while still being able to surpass C in speed in many cases. > Simple example: accessing an array past it's end it's undefined behaviour. If you want to remove this, you need to add bounds checking Zig does indeed do bounds checking. I think the way it can still compete with C is: - Zig should be better at propagating constants (Better module system, Link-Time Optimization by default, and I think avoiding undefined behaviour helps here too). Arrays/slices do often have constant bounds. - You can choose to build with or without bounds checks (--release-safe, --release-fast). This means you're more likely to discover out of bounds problems during debugging, since you'll always get errors in those cases. But you have the option to release a fast version. Julia has another interesting solution to bounds checking, where you can mark a piece of code with @inbounds to declare that you assume array access is within bounds. I think some undefined behaviour can also be detrimental to performance. If you pass two pointers to a function, and it's undefined whether they alias or not, there are optimisations you can't do.
- slrz 7y ago> I think some undefined behaviour can also be detrimental to performance. If you pass two pointers to a function, and it's undefined whether they alias or not, there are optimisations you can't do. I think this results from a misunderstanding of how undefined behaviour works in C. When a program exhibits undefined behaviour it is not a valid C program. The compiler may just assume (instead of having to prove) that it doesn't happen. Example: the memcpy(3) standard library function. C says the behaviour is undefined if the given areas overlap. That means the implementation can perform optimizations "knowing" that there is no overlap. A valid C program can't possible invoke memcpy with buffers aliasing each other (because then, the program would be invalid). The compiler is not required to issue a diagnostic about these kinds of incorrect programs and just compiles your code assuming they don't exist.
- Dylan16807 7y agoThere are a lot of undefined behaviors that only exist out of inertia and laziness. For example there's a bunch of things that should be syntax errors that are instead UB. > Simple example: accessing an array past it's end it's undefined behaviour. If you want to remove this, you need to add bounds checking (either to raise an error or to just return 0). What's wrong with saying "it will either return an unspecified value or trap"?