3 ms·
I completely agree that C and C++ become more manageable with modern tooling. The problem is that better doesn't fundamentally change the situation. How UB is d
by AlotOfReading 2y ago
I completely agree that C and C++ become more manageable with modern tooling. The problem is that better doesn't fundamentally change the situation. How UB is defined in the standards means semantics are an all or nothing situation. Either there's no UB and you have the semantics specified by the standard, or you have UB and no semantics (past the point of UB in C23 thanks to your proposal). We've had a solid 30 years of history demonstrating that exhaustive static detection is impossible and every nontrivial program has UB of some kind.
You can't fix this with minor changes in the language or improved tooling. You need a complete overhaul of how the standards and implementations deal with UB.
- uecker 2y agoBut Rust shows that static detection is possible if you add constraints to the language, and this is exactly what one can do it C too. Rust was inspired by a C dialect after all. The situation with UB is not actually as bad as it sounds (I analyzed all UB in the core language).
- AlotOfReading 2y agoIgnoring memory safety where rust's solution is more obvious, the lack of UB in Rust is mainly the result of consciously deciding to eliminate it. Signed overflow is implementation defined for example. The parsing UB that takes up half of annex J is eliminated by simply expecting that implementations write proper parsers and having a better macro system. Invalid enum values were solved by a stronger type system. If there were actually an appetite to eliminate it, I suspect we could probably eliminate 70% of J.2 with a few straightforward changes. Many of these aren't completely amenable to static analysis, like signed/shift bounds, but they're workable at the language level. The members of the C++ committee I've talked to were skeptical about the actual chances here though. The rest of annex J is at least partially addressed with existing efforts like checked C and Coral ("constraints"), so at least there's a path forward with tooling.
- uecker 2y agoThe things you mention are already ongoing. We eliminated 15 items in J.2 in last meeting and will remove more in the next. Not that I agree that the UB is really the that much of a problem, only very specific cases of UB actually cause real safety problems.
- AlotOfReading 2y agoIn my domain (safety critical), I'm interested in taking a piece of code I didn't necessarily write and making statements about the state of the system at various points in the execution. It doesn't matter whether the UB that exists doesn't result in observable misbehavior of the system as it exists today, I also need to ensure that the system will continue behaving in 10-50 years with a different compiler on a different architecture that may not even be designed yet. Currently, all of that work has to come with a little asterisk saying "except for undefined behavior". I can't constrain where UB might be in the system, or how it might violate the safety model. In short, if I do my job properly I shouldn't assume C/C++ semantics at all. Obviously that's not reasonable, so everyone goes around pretending this isn't an issue to their safety models and their regulatory filings and so on. Obviously I think that's wrong, but there haven't been ways to address it in C and C++. It's possible in Rust.
- uecker 2y agoThe thing with UB in C is that it was traditionally seen also as a possible extensions point, so someone else can come in and define the behavior, e.g. POSIX does it for some. But yes, we understood that this is not how people look at this anymore, and hence we will remove it. But I do not see how Rust helps? Rust has no standard and its reference implementation is subject to change. How did you convince yourself that what ISO C leaves not-standardized is any worse than what is not being standardized in the first place? There seems to be a double-standard here.
- AlotOfReading 2y agoThe comparison isn't with rust today, but the long term differences between the languages. Rust has a straightforward path to rectifying the standardization issue and enough community momentum to succeed. For example, Rust has an in-progress specification, here's the (currently empty) repo: https://github.com/rust-lang/spec https://github.com/rust-lang/spec. There's also MIR, a de-sugared internal representation that's sufficiently well specified to build formal models of (see https://github.com/rust-lang/a-mir-formality https://github.com/rust-lang/a-mir-formality and https://github.com/rust-lang/miri https://github.com/rust-lang/miri), as well as the ferrocene spec (https://spec.ferrocene.dev/general.html https://spec.ferrocene.dev/general.html) that's suitable for certification authorities (if not actually useful) and of course the rust reference/RFCs that are actually usable by people. Plus, the fact that everyone in the rust community has standardized on one compiler and one package manager (for better or worse) means that the language team has a much better insight into specification breakages than the ISO process of languages like C and C++. I can start writing stuff today and be confident that any changes will be minor if necessary when the language catches up. I'm more than happy to have this discussion over email if you want to move it off HN, too.