Live data from Hacker News

Undefined Behavior in C and C++ (2024)

russellw.github.io

121–130 of 234 posts

Re: Undefined Behavior in C and C++ (2024)

#121

I don’t buy the “it’s because of optimization argument”. And I especially don’t buy that UB is there for register allocation. First of all, that argument only explains UB of OOB memory accesses at best. Second, you could define the meaning of OOB by just saying “pointers are integers” and then further state that nonescaping locals don’t get addresses. Many ways you could specify that, if you cared badly enough. My fa…

> Second, you could define the meaning of OOB by just saying “pointers are integers" This means losing a lot of optimisations, so in fact when you say you "don't buy" this argument you only mean that you don't care about optimisation. Which is fine, but this does mean the "improved" C isn't very useful in a lot of applications, might as well choose Java.

> This means losing a lot of optimisations

You won’t lose “a lot” of optimizations and you certainly won’t lose enough for it to make a noticeable difference in any workload that isn’t SPEC

Re: Undefined Behavior in C and C++ (2024)

#122
post #67

Earlier quoted context omitted.

I do not understand what you are tying to say, but it seems to be some hostile rambling.

Never meant to be hostile (if I indeed were, I would have question every single word), but sorry for that. I mean to say that best practices do help much but learning those best practices take much time as well. So short compilation time is easily offseted by learning time, and C was not even designed to optimize compilation time anyway (C headers can take a lot to parse and discard even when unused!). Your other poi…

Sorry, maybe I misread your comment. There are certainly languages easier to learn than C, but I would not say C++ or Rust fall into this category. At the same time, I find C compilation extremely fast exactly because of headers. In C you can split interface and implementation cleanly between header and c-file and this enables efficient incremental builds. In C++ most of the implementation is in headers, and all the template processing is order of magnitude more expensive than parsing C headers. Rust also does not seem to have proper separate compilation.

Re: Undefined Behavior in C and C++ (2024)

#123
post #33

Earlier quoted context omitted.

Unfortunely it also means that when the programmer fails to understand what undefined behaviour is exposed on their code, the compiler is free to take advantage of that to do the ultimate performance optimizations as means to beat compiler benchmarks. The code change might come in something as innocent as a bug fix to the compiler.

Ah yes, the good old "compiler writers only care about benchmarks and are out to hurt everyone else" nonsense. I for one am glad that compilers can assume that things that can't happen according to the language do in fact not happen and don't bloat my programs with code to handle them.

Moral hazard here. The rest of us, and all of society, now rests on a huge pile of code written by incorrigible misers who imagined themselves able to write perfect, bug-free code that would go infinitely fast because bad things never happen. But see, there's bugs in your code and other people pay the cost.

Re: Undefined Behavior in C and C++ (2024)

#124
post #80

Earlier quoted context omitted.

Pointer provenance already existed before, but the standards were contradictory and incomplete. This is an effort to more rigorously nail down the semantics. i.e., the UB already existed, but it was not explicit had to be inferred from the whole text and the boundaries were fuzzy. Remember that anything not explicitly defined by the standard, is implicitly undefined. Also remember, just because you can legally constr…

The current standard still says integer-to-pointer conversions are implementation defined ( not undefined) and furthermore "intended to be consistent with the addressing structure of the execution environment" (that's a direct quote). I have an execution environment, Wasm, where doing this is pretty well defined, in fact. So if I want to read the memory at address 12345, which is within bounds of the linear memory (a…

I fully agree with your analysis but compilers writers did think the could bend the rules, hence it was necessary to clarify that pointer-to-integer casts do work as intended. This still not in ISO C 23 btw because some compiler vendors did argue against it. But it is a TS now. If you are, please file bugs against your compilers.

Re: Undefined Behavior in C and C++ (2024)

#125

Earlier quoted context omitted.

Not the GP, but the biggest one is dependency management. Cargo is just extremely good. As for the language tooling itself, static and runtime analyzers in C and C++ (and these are table stakes at this point) do not come close to the level of accuracy of the Rust compiler. If you care about writing unsafe code, Miri is orders of magnitude better at detecting UB than any runtime analyzer I've seen for C and C++.

Pacman is extremely good, too, for C. :)

Pacman solves a different problem. Cargo manages your project's dependencies, not system packages.

Re: Undefined Behavior in C and C++ (2024)

#126

Earlier quoted context omitted.

This is a pet peeve, so forgive me: C is not portable in practice. Almost every C program and library that does anything interesting has to be manually ported to every platform. C is portable in the least interesting way, namely that compilers exist for all architectures. But that's where it stops.

> C is not portable in practice. Almost every C program and library that does anything interesting has to be manually ported to every platform. I'm guessing you mean that every cross-platform C codebase ends up being plastered in cascading preprocessor code to deal with OS and architecture differences. Sure that's true, you still have to do some porting work regardless of the language you chose. But honestly, is ther…

If "portability" to you has to include incredibly esoteric architectures in 2025, then what C has to offer is probably the best you can do, but my point is it doesn't do any better on mainstream platforms either.

If you are targeting any recent platform, both Rust and Zig do what you want.

Re: Undefined Behavior in C and C++ (2024)

#127
post #65

Earlier quoted context omitted.

This is a pet peeve, so forgive me: C is not portable in practice. Almost every C program and library that does anything interesting has to be manually ported to every platform. C is portable in the least interesting way, namely that compilers exist for all architectures. But that's where it stops.

Compilers existing is essential and not trivial (and also usually then what other languages build on). The conformance model of C also allows you to write programs that are portable without change to different platforms. This is possible, my software runs on 20 different architectures without change. That one can then also adopt it to make use of specific features of different platforms is quite natural in my opinion…

It is essential and nontrivial, but it's also the extremely bare minimum.

You cannot write portable code without platform-specific and even environment-specific adaptations, like handling the presence of certain headers (looking at you, stdint.h and stddef.h), and let's not even start about interacting with the OS in any way.

Re: Undefined Behavior in C and C++ (2024)

#128

Earlier quoted context omitted.

embedded hardware, any processor Rust doesn't support (there are many), and any place where code size is critical. Rust has a BIG base size for an application, uselessly so at this time. I'd also love to see if it offered anything that could be any use in those spaces - especially where no memory allocation takes place at all. C (and to a lesser extent C++) are both very good in those spaces.

You can absolutely make small rust programs, you just have to actually configure things the right way. Additionally, the Rust language doesn’t have allocation at all, it’s purely a library concern. If you don’t want heap allocations, then don’t include them. It works well. The smallest binary rustc has produced is like ~145 bytes.

That is far from my only concern. But it's good to see Rust is finally paying attention to binary sizes. And the overwhelming complexity of rust code is definitely not a gain when one is working in embedded spaces anyway. I am however really REALLY annoyed with the aggressive sales tactics of the rust community.

Re: Undefined Behavior in C and C++ (2024)

#129
post #98

Earlier quoted context omitted.

A lot of that work is basically fixing documentation bugs, labelled "ghosts" in your text. Places where the ISO document is so bad as a description of C that you would think there's Undefined Behaviour but it's actually just poorly written. Fixing the document is worthwhile, and certainly a reminder that WG21's equivalent effort needs to make the list before it can even begin that process on its even longer document,…

> practical C programmers don't read the document and since this UB was a "ghost" they weren't tripped by it I would strongly suspect that C compiler implementers very much do read the document, though. Which, as far as I can see, means "ghosts" could easily become actual UB (and worse, sneaky UB that you wouldn't expect.)

If I understand correctly, the "ghosts" are vacuously UB. As in, the standard specifies that if X, then UB, but X can in fact never be true according to the standard.

Re: Undefined Behavior in C and C++ (2024)

#130
post #98

Earlier quoted context omitted.

> practical C programmers don't read the document and since this UB was a "ghost" they weren't tripped by it I would strongly suspect that C compiler implementers very much do read the document, though. Which, as far as I can see, means "ghosts" could easily become actual UB (and worse, sneaky UB that you wouldn't expect.)

The previous language might cause a C compiler developer to get very confused because it seems as though they can choose something else but what it is isn't specified, but almost invariably eventually they'll realise oh, it's just badly worded and didn't mean "should" there. It's like one of those tricky self-referential parlor box statements. "The statement on this box is not true"? Thanks I guess. But that's a game…

Most of the "ghosts" are indeed just cleaning up the wording. But compiler writers historically often used any excuse that the standard is not clear to justify aggressive optimization. This starts with an overreaching interpretation of UB itself, to wacky concepts such as time-travel, wobbly numbers, incorrect implementation of aliasing (e.g. still in clang), and pointer-to-integer round trips.
Post reply on HN