Live data from Hacker News

Undefined Behavior in C and C++ (2024)

russellw.github.io

201–210 of 234 posts

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

#201
post #197

Earlier quoted context omitted.

Please try not to be obnoxious and turn this into a language war.

How is this obnoxious? C and C++ have their strengths, but rapid prototyping is generally not seen to be amongst them. This shouldn't be any more controversial than saying that pure Python is generally slow.

They are pretty much the best choice for prototyping 3D apps and GPU algorithms. They're fast, powerful, and don't impose restrictions - you can do whatever and however. It also helps that CUDA is C++.

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

#202
post #114

Earlier quoted context omitted.

> 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. Yes, unthinkable happenstances like addition on fixed-width integers overflowing ! According to the language, signed integers can't overflow, so code like the following: int new_offset = current_offset + 16; if (new_offset can be optimized to…

Garbage in, garbage out. Stop blaming the compiler for your bad code.

You're objectively wrong. This code isn't bad, it's concise and fast (even without the compiler pattern-matching it to whatever overflow-detecting machine instructions happen to be available), and it would be valid and idiomatic for unsigned int. Stop blaming the code for your bad language spec.

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

#203
post #179

Earlier quoted context omitted.

If you say the header model makes it slower than it could be, you need to compare it to something. I do not see how it causes significant slow downs in C projects (in contrast to C++). And yes, I wrote compilers and (incomplete) preprocessors. I do not understand what you mean by your second point. What separation of interface and implementation allows you to do is updating the implementation without having to recomp…

> I do not see how it causes significant slow downs in C projects It's that textual inclusion is just a terrible model. You end up reprocessing the same thing over and over again, everywhere it is used. If you #include 100 times, the compiler has to reparse those contents 100 times. Nested headers end up amplifying this effect. It's also at a file-level granularity, if you change a header, every single .c that import…

> It's that textual inclusion is just a terrible model. You end up reprocessing > the same thing over and over again, everywhere it is used.

One could certainly store the interfaces in some binary format, but is it really worth it? This would also work with headers by using a cache, but nobody does it for C because there is not much to gain. Parsing is fast anyhow, and compilers are smart enough not to look at headers multiple times when protected by include guards. According to some quick measurements, you could save a couple of percent at most.

The advantages of headers is that they are simple, transparent, discoverable, and work with outside tools in a modular way. This goes against the trend of building frameworks that tie everything together in a tightly integrated way. But I prefer the former. I do not think it is a terrible model, quite the opposite. I think it is a much better and nicer model.

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

#204
post #202

Earlier quoted context omitted.

Garbage in, garbage out. Stop blaming the compiler for your bad code.

You're objectively wrong. This code isn't bad, it's concise and fast (even without the compiler pattern-matching it to whatever overflow-detecting machine instructions happen to be available), and it would be valid and idiomatic for unsigned int . Stop blaming the code for your bad language spec.

The language spec isn't bad just because it doesn't allow you to do what you want. Are you also upset that you need to add memory barriers where the memory model of the underlying platform doesn't need them?

Again, this isn't undefined behavior to fuck you over and compilers don't use it for optimizations because they hate you. It's because it makes a real difference for performance which is the primary reason low level languages are used.

If you for some reason want less efficient C++ then compilers even provide you flags to make this particular operation defined. There is no reason the rest of us have to suffer worse performance because of you.

Personally I would prefer if unsigned ints had the same undefined behavior by default with explicit functions for wrapping overflow. That would make developer intent much clearer and give tools a chance to diagnose unwanted overflow.

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

#205
post #182

Earlier quoted context omitted.

They sometimes screwed up, sometimes just because of bugs, or because different optimization passes had different assumptions that are inconsistent. This somehow contradicts your second point. Compiler have something things implemented which may be concrete on some sense (because it is in a compiler), but still not really a "thing" because it is a mess nobody can formalize using a coherent set of rules. But then, the…

Certainly compiler developers are only human, and many of them write C++ so they're humans working with a terrible programming language, I wouldn't sign up for that either (I have written small contributions to compilers, but not in C++). I still don't see "any excuses". I see more usual human laziness and incompetence, LLVM for example IMNSHO doesn't work hard enough to ensure their IR has coherent semantics and to…

I do not imply bad intentions, but I see the arguments brought forward in WG14. It got better in recent years but we had to push back against some rather absurd interpretations of the standard, e.g. that unspecified values can change after they are selected. Your example shows something else, the standard is simply not seemed to be very important. The standard is perfectly clear how pointer comparison works, and yet this is not alone reason enough to invest resources into fixing this if this is not shown to cause actual problems in real code.

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

#206
post #178

Earlier quoted context omitted.

You are right, I wasn't thinking straight. I do not fully agree. Creating arbitrary pointers can not work. Forging pointers to implementation-defined memory region would be ok though.

Why can't it work though? And I'm taking about both things. Integer arithmetic that produces pointers that are just out of bounds of an object. Why can't this work? Why can't the compiler assume that, since I explicitly converted a pointer to an integer, the pointed-to object can't be put into a register, or made to go out or scope early? Second, fabricating pointers. If I have a pointer to mmap/sbrk memory, shouldn'…

In practice if you do a volatile read at an arbitrary mapped address it will work. But you have no guarantee regarding what you will read from it, even it if it happens to match the address of a variable you just wrote into.

Formally it is undefined, as there is no way to give it sane semantics and it will definitely trip sanitizers and similar memory safety tools.

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

#207
post #202

Earlier quoted context omitted.

You're objectively wrong. This code isn't bad, it's concise and fast (even without the compiler pattern-matching it to whatever overflow-detecting machine instructions happen to be available), and it would be valid and idiomatic for unsigned int . Stop blaming the code for your bad language spec.

The language spec isn't bad just because it doesn't allow you to do what you want. Are you also upset that you need to add memory barriers where the memory model of the underlying platform doesn't need them? Again, this isn't undefined behavior to fuck you over and compilers don't use it for optimizations because they hate you. It's because it makes a real difference for performance which is the primary reason low le…

No, dangerous behavior should be opt-in, not opt-out. In 99.9 % of integer additions, overflow-is-UB won't make any difference performance-wise, but may still screw you over if you're unlucky. In the 0.1 % of cases where there's even the potential for a measurable speed-up, you'll want to careful craft your code anyway, and you can use explicit, UB-exploiting functions.

Rust does it right: The "+"-operator is wrapping in release builds (and throws an exception when debug-assertions are enabled), and there are explicit functions for checked/overflowing/saturating/strict/unchecked/wrapping addition [1]. The "unchecked" variant exploits UB-on-overflow and is marked as unsafe. These functions exist both for signed and unsigned integer types. Which once again shows that it's very well possible to design a sane, low-level language which is just as fast as C.

[1] https://doc.rust-lang.org/std/primitive.u32.html

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

#208
post #205

Earlier quoted context omitted.

Certainly compiler developers are only human, and many of them write C++ so they're humans working with a terrible programming language, I wouldn't sign up for that either (I have written small contributions to compilers, but not in C++). I still don't see "any excuses". I see more usual human laziness and incompetence, LLVM for example IMNSHO doesn't work hard enough to ensure their IR has coherent semantics and to…

I do not imply bad intentions, but I see the arguments brought forward in WG14. It got better in recent years but we had to push back against some rather absurd interpretations of the standard, e.g. that unspecified values can change after they are selected. Your example shows something else, the standard is simply not seemed to be very important. The standard is perfectly clear how pointer comparison works, and yet…

> [... absurd interpretations] unspecified values can change after they are selected

It seems hard to not have this without imputing a freeze semantic which would be expensive on today's systems. Maybe I don't understand what you mean ? Rust considered insisting on the freeze semantic and was brought up short by the cost as I understand it.

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

#209

Earlier quoted context omitted.

Why can't it work though? And I'm taking about both things. Integer arithmetic that produces pointers that are just out of bounds of an object. Why can't this work? Why can't the compiler assume that, since I explicitly converted a pointer to an integer, the pointed-to object can't be put into a register, or made to go out or scope early? Second, fabricating pointers. If I have a pointer to mmap/sbrk memory, shouldn'…

In practice if you do a volatile read at an arbitrary mapped address it will work. But you have no guarantee regarding what you will read from it, even it if it happens to match the address of a variable you just wrote into. Formally it is undefined, as there is no way to give it sane semantics and it will definitely trip sanitizers and similar memory safety tools.

So how can you implement an allocator in the language itself? Not even talking about malloc (which gets to have language blessed semantics); say an arena allocator.

You get a bunch of memory from mmap. There are no “objects” (in C terminology) in there, and a single “provenance” (if at all, you got it from a syscall, which is not part of the language).

If arbitrary integer/pointer math inside that buffer is not OK, how do to get heterogeneous allocations from the arena to work? When do slices of it become “objects” and gain any other ”provenance”?

Is C supposed to be the language you can't write an arena allocator in (or a conservative GC, or…)?

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

#210
post #136

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++.

I do not think package management should be done at the level of programming languages.

Strictly speaking, Cargo isn't part of the Rust programming language itself. Cargo is a layer on top of Rust, and you can use the Rust compiler completely independently of Cargo. I think bazel, for example, can compile and handle dependencies without Cargo.
Post reply on HN