3 ms·
Some kinds of UB can easily be handled that way. GCC offers a flag to guarantee wrapping on signed arithmetic overflow, for instance. [0] It wouldn't be easy to
by MaxBarraclough 5y ago
Some kinds of UB can easily be handled that way. GCC offers a flag to guarantee wrapping on signed arithmetic overflow, for instance. [0] It wouldn't be easy to nicely handle every instance of UB though. The current state-of-the-art for that kind of thing would be something like Valgrind, an extremely 'intrusive' runtime system.
This is because of the particulars of the C language. For instance, the way it handles arrays and pointer arithmetic make it difficult to detect every instance of out-of-bounds access.
[0] -fwrapv, see https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html
- ChuckMcM 5y agoI think we're talking about different things, but maybe not. Using out of bounds references in arrays and pointer arithmetic are unsafe but they can be defined. The definition of "array accesses using indexes that are outside the range of 0 - the declared array size will access memory in the data segment. The compiler will treat that access as if the addressed memory had the type specified for the array." The behavior is defined, it is unsafe, but it is defined. Not like "the compiler may or may not choose to optimize out loads and stores, or re-order them." which especially on embedded systems creates bugs where the things like "read the status register THEN read the data register (which clears the status register when read)" those get re-ordered and suddenly your loop never exits because your status bit is never set. That kind of UB needs to die in a fire IMHO.
- pjmlp 5y agoOut of bounds is only defined for length + 1, for anything else anything goes.
- MaxBarraclough 5y agoThat doesn't sound right. C (and C++) permit you to do pointer arithmetic to derive a pointer value pointing to one element beyond the final element of an array. This special treatment doesn't extend to dereferencing though - if you deference that pointer, that's UB. If you do pointer arithmetic to derive a pointer value pointing 2 or more elements beyond the final element of an array, that's undefined behaviour, even if you never dereference that pointer.
- pjmlp 5y agoSure, I just didn't want to spend too much time explaining all details, my failure.
- tialaramex 5y agoIt's downright perverse to insist that you should be able to assume all accesses are volatile reads/ stores just because that was momentarily convenient. C lacks the intrinsics you'd actually want for this (explicit load/ store of various machine sizes) but it does provide the "volatile" storage qualifier which is what you should be using to do what you apparently wanted in C today. It makes no sense to demand everybody else writes some sort of "not-volatile" qualifier in front of every variable to tell the compiler that actually this is just a variable and it's OK to optimise.
- Thiez 5y ago> which especially on embedded systems creates bugs where the things like "read the status register THEN read the data register (which clears the status register when read)" those get re-ordered and suddenly your loop never exits because your status bit is never set. Why are the embedded systems programmers not using `volatile`, which exists for this exact reason?
- compiler-guy 5y ago"volatile" is not a synchronization primitive and doesn't forbid reordering amongst access to different memory locations. All it does is forbid reordering or removing accesses to a particular memory location. Historically, many compilers implemented it as a hard memory barrier, but that isn't how the standard defines it.
- Thiez 5y agoVolatile operations are considered a side effect and as such may not be reordered with other volatile operations. How is that not literally sufficient for the operations that GGP described?
- compiler-guy 5y agoI spoke perhaps a little strongly. But that said: The compiler is free to reorder accesses to multiple volatile variables if they happen prior to the same sequence point. So (roughly) expressions involving two volatile variables do not have those accesses sequenced. But you are right that the usage described earlier is OK, as long as both variables are marked volatile, and the accesses straddle a sequence point. The more common mistake with volatiles is to use the for multithreading primitives.
- MaxBarraclough 5y ago> "[...] The compiler will treat that access as if the addressed memory had the type specified for the array." The behavior is defined, it is unsafe, but it is defined. I believe performance (compiler optimisation) is the reason the language isn't defined that way. Permitting the compiler to assume that the runtime error will never arise, opens the door to all sorts of optimisations. (At least, that's the idea.) C permits the 'union trick' to (roughly speaking) access the bit-pattern of a value as another type, which is to say an escape-hatch is offered in the language. Similarly the strict aliasing rule is surprising to people who are new to C, but the C standard committee seem to be committed to keeping it, presumably for performance reasons. > Not like "the compiler may or may not choose to optimize out loads and stores, or re-order them." which especially on embedded systems creates bugs Right, but it's defined that way to enable compiler optimizations, not to spite the programmer. As others have mentioned, C has features like volatile specifically to address this kind of thing. If the C standard required memory fences to be inserted everywhere, performance would be ruined. > That kind of UB needs to die in a fire IMHO. C cannot easily be made into a safe language, and I think the committee is doing the right thing in declining to try to make C into something it isn't. On the plus side, there are plenty of other languages around, many of them with compelling advantages over C. Ada, Rust, and Zig, for instance.
- pjmlp 5y agoWG14 could perfectly add proper string and vector types, even if library based structs, they didn't had any qualms to add complex numbers in C99. Then again, just use C++ alongside std::vector, std::array and std::string with FORTIFY turned on (or equivalent) and be done with it.