35 ms·
Unlike Rust and Cs before C23, C23's signed arithmetic is fully specified to wrap around. edit - nevermind, I'm wrong lol
by pillmillipedes 1mo ago
Unlike Rust and Cs before C23, C23's signed arithmetic is fully specified to wrap around.
edit - nevermind, I'm wrong lol
- deleted 1mo ago[deleted]
- dzaima 1mo agoC23 specifies that signed integers must be two's complement, but still leaves signed arithmetic overflow as undefined behavior.
- pillmillipedes 1mo agoyeah, turns out you're right. god dammit. maybe one day
- wavemode 1mo agoProbably never. This has been debated to death by both C and C++ standards committees. The consensus is that, since signed overflow is almost always a sign of a bug in the program, keeping it undefined enables compilers to optimize by assuming it never happens, and also allows sanitizers to continue to flag it to developers so that they fix their bugs (though it could be argued that, a sanitizer doesn't really have to strictly adhere to the standard, the committee apparently didn't feel that way).
- aw1621107 1mo ago> and also allows sanitizers to continue to flag it to developers so that they fix their bugs I've never really found this argument particularly convincing; as you say, sanitizers don't have to strictly adhere to the standard, and they do in fact take advantage of this flexibility to check behaviors that "are not undefined behavior, but are often unintentional" (e.g., -fsanitize=unsigned-integer-overflow). Makes me wonder whether "sanitizers can't flag defined behavior" is meant to be shorthand for some more nuanced position ("the false positive rate for signed overflow sanitizer checks would be too high", maybe?) or something else.
- dzaima 1mo ago> -fsanitize=unsigned-integer-overflow Of course, -fsanitize=unsigned-integer-overflow isn't enabled by default, and few people use it (github code search gives 6K results for that, compared to 175K for "-fsanitize=undefined"; which to be fair is a lot higher than I expected, but still not a lot). > Makes me wonder whether "sanitizers can't flag defined behavior" is meant to be shorthand for some more nuanced position And signed overflow checking would have to be off-by-default too, if people were allowed to start relying on it. It'd be less "false positive rate too high", more "it disallows you to use a genuine language feature that is actually useful", defeating the point of defining signed overflow in the first place. (imo defining signed overflow specifically for reducing attack surface from exploitable UB is a mostly-separate discussion, which should not affect core language semantics, and certainly not what users would be suggested to do)
- aw1621107 1mo ago> Of course, -fsanitize=unsigned-integer-overflow isn't enabled by default, and few people use it Sure, but it's still a counterexample for "you can't define it because it means sanitizers can't warn for it". Sanitizers can warn for it; you "just" get a worse signal-to-noise ratio. > It'd be less "false positive rate too high", more "it disallows you to use a genuine language feature that is actually useful" I'm not sure I see the distinction? Flagging a correct use of a language feature as incorrect is more or less the definition of a false positive, so if intentional signed overflows get a reasonable amount of use then that'd presumably result in an unacceptably noisy check to be enabled by default. > defeating the point of defining signed overflow in the first place. As for unsigned overflow checks I'd imagine the intent is that one would enable that particular check if you think that the corresponding overflow is more likely to be unintentional than not, and in the cases where it actually is intentional you can suppress the check.
- dzaima 1mo ago> it's still a counterexample for "you can't define it because it means sanitizers can't warn for it" Sure, technically you can write a sanitizer for anything. It just becomes less a "sanitizer" you can always recommend everyone everywhere use, and more of just a heuristic thing that only really works if you design your code for its arbitrary desires. > and in the cases where it actually is intentional you can suppress the check. imo it'd be nice to have separate types for wrapping and non-wrapping integers for that, so that you have actual language-level semantics and an easy way to mix things (e.g. wrapping arith for hashing, mixed with non-wrapping arith for loop index or whatever) instead of suppressions.
- rictic 1mo agoYeah, it's my favorite bit of C lore, a program that reads two integers, adds them, and reports the sum isn't well defined.