4 ms·
All of it. But especially anything added after C89 that was not already there implicitly. Edit: okay, not all of it. I was hyperbolic. Race conditions and data
by gavinhoward 2y ago
All of it. But especially anything added after C89 that was not already there implicitly.
Edit: okay, not all of it. I was hyperbolic. Race conditions and data races should be UB. But anything that can be implementation-defined should be.
- dzaima 2y agoSo your issue is not at all any specific thing or action anyone took, but just in general having UB in places not strictly necessary. And "Especially anything [different from The Golden Days]", besides being extremely cliche, is a completely arbitrary cutoff point. A given compiler is free to define specific behavior for UB (and indeed you can add compiler flags to do that for many things); the standard explicitly acknowledges that with "Possible undefined behavior ranges from […], to behaving during translation or program execution in a documented manner characteristic of the environment".
- gavinhoward 2y agoSigh...yes, I don't want any UB where it's not necessary. But if you must have a concrete example, how about realloc? In C89 [1] (page 155), realloc with a 0 size and a non-NULL pointer was defined as free: > If size is zero and ptr is not a null pointer, the object it points to is freed. In C99 [2] (page 314), that sentence was removed, making it undefined behavior when it wasn't before. This is a pure example of behavior becoming undefined when it was not before. In C11 [3] (page 349), that sentence remains gone. In C17 [4] (page 254), we get an interesting addition: > If size is zero and memory for the new object is not allocated, it is implementation-defined whether the old object is deallocated. If the old object is not deallocated, its value shall be unchanged. So the behavior switches from undefined to implementation-defined. In C23 [5] (page 357), the wording completely changes to: > ...or if the size is zero, the behavior is undefined. So WG14 made it UB again after making implementation-defined. SQLite targets C89, but people compile it with modern compilers all the time, and those modern compilers generally default to at least C99, where the behavior is UB. I don't know if SQLite uses realloc that way, but if it does, are you going to call it buggy just because the authors stick to C89 and their users use later standards? [1]: https://web.archive.org/web/20200909074736if_/https://www.pdf-archive.com/2014/10/02/ansi-iso-9899-1990-1/ansi-iso-9899-1990-1.pdf https://web.archive.org/web/20200909074736if_/https://www.pd... [2]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf [3]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf [4]: https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf https://web.archive.org/web/20181230041359if_/http://www.ope... [5]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf
- dzaima 2y agoIf SQLite wants exactly C89, it can just require -std=c89, and then people compiling it with a different standard target are to blame. This is just standard backwards incompatibility, nothing about UB (in other languages requiring specific compiler/language versions is routine). Problems would arise even if it was changed from being a defined 'free(x)' to being a defined 'printf("here's the thing you realloc(x,0)'d: %p",x)'. (whether the C standard should always be backwards compatible is a more interesting question, but is orthogonal to UB) I do remember reading somewhere that a real platform in fact not handling size 0 properly (or having explicitly-defined behavior going against what the standard allowed?) being an argument for changing the standard requirement. It's certainly not because compiler developers had big plans for optimizing around it, given that both gcc and clang don't: https://godbolt.org/z/jjcGYsE7W https://godbolt.org/z/jjcGYsE7W. and I'm pretty sure there's no way this could amount to any optimization on non-extremely-contrived examples anyway. I had edited one of my parent comments to mention realloc, so if we both landed on the same example, there's probably not that many significant other cases.
- gavinhoward 2y ago> If SQLite wants exactly C89, it can just require -std=c89, and then people compiling it with a different standard target are to blame. Backwards compatibility? I thought that was a target for WG14. > This is just standard backwards incompatibility, nothing about UB But UB is insidious and can bite you with implicit compiler settings, like the default to C99 or C11. > whether the C standard should always be backwards compatible is more interesting, but is a question orthogonal to UB If it's a target, then it should be. And on the contrary, UB is not orthogonal to backwards compatibility. Any UB could have been made implementation-defined and still be backwards compatible. But it's backwards-incompatible to make anything UB that wasn't UB. These count as examples of WG14 screwing over its users. > I do remember some mention somewhere of a real platform in fact not handling size 0 properly being an argument for reducing the standard requirement. So WG14 just decides to screw over users from other platforms? Just keep it implementation-defined! It already was! And that's still a concession from the pure defined behavior of C89! > I had edited one of my parent comments to mention realloc, so if we both landed on the same example, there's probably not that many significant other cases. I beg to differ. Any case where UB was implicit just because it wasn't defined in the standard could have easily been made implementation-defined instead. Anytime WG14 adds UB that doesn't need to be UB, it is screwing over users.