Live data from Hacker News

Undefined Behavior in C and C++ (2024)

russellw.github.io

151–160 of 234 posts

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

#151
post #131
post #80

Earlier quoted context omitted.

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…

It is important to understand why undefined behaviour has proliferated over the past ~25 years. Compiler developers are (like the rest of us) under pressure to improve metrics like the performance of compiled code. Often enough that's because a CPU vendor is the one paying for the work and has a particular target they need to reach at time of product launch, or there's a new optimization being implemented that has to…

Language standards have much less power than people think and compiler-vendors are of course present in the standard working groups. Ultimately, the users need to put pressure on the compiler vendors. Please file bugs - even if this often has no effect, it takes away the argument "this is what our users want". Also please support compilers based on how they deal with UB and not on the latest benchmark posted somewhere.

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

#152

Earlier quoted context omitted.

There is no C or C++ ways. It's widely known that every codebase is its own dialect.

There are lots of C and particularly C++ ways, but you're still restricted. Want to use methods in C: nope, you can't. Want language-level tagged unions and pattern matching in either language: nope. Same for guaranteed tail call optimisation and a bunch of other things. This is especially true for C which supports almost nothing (it doesn't even have a sensible array type!). But is also true for C++: while it suppor…

The funny part is that all of these things are easy to achieve as libraries/paradigms.

Methods in C, just have function pointers as members. Common in many codebases.

Guaranteed tail calls, all the compilers guarantee that function calls that are a return expression are tail calls.

Tagged union in C++, it's trivial as a library, see std::variant for a bad example of it, and all the various monadic/pattern-matching variants (pun intended) people have written. C is at a disadvantage here due to lack of lambdas, but I'm sure people have built stuff using some GCC extensions.

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

#153

Earlier quoted context omitted.

There are lots of C and particularly C++ ways, but you're still restricted. Want to use methods in C: nope, you can't. Want language-level tagged unions and pattern matching in either language: nope. Same for guaranteed tail call optimisation and a bunch of other things. This is especially true for C which supports almost nothing (it doesn't even have a sensible array type!). But is also true for C++: while it suppor…

what changes, in your opinion, would need to be made to the C array type to make it "sensible"? C's array is simplistic, but I don't think it's not "sensible"...

consider the C++ std::array, which exists to make arrays behave like normal objects.

You can do the same in C by wrapping your array in a struct.

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

#154

Earlier quoted context omitted.

I litterally have no idea what are you trying to say. Do you mean that bar should be allowed to access *ptr with impunity or not?

I'm not trying to say anything. I said and meant exactly what I said. No more, no less. Your logic is obviously flawed. There is nothing preventing that optimization in the presence of a forged pointer in bar().

Either there is no provenance, forging is allowed and the optimization is disallowed; or there is provenance and forging the pointer and attempting to inspect (or modify) the value of *ptr in bar() is UB.

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

#155

Earlier quoted context omitted.

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.

> But it's good to see Rust is finally paying attention to binary sizes.

Just to be clear, this isn't a recent development, it has been this way for many years at this point.

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

#156

We switched to Rust. Generally, are there specific domains or applications where C/C++ remain preferable? Many exist—but are there tasks Rust fundamentally cannot handle or is a weak choice?

Rust encourages a rather different "high-level" programming style that doesn't suit the domains where C excels. Pattern matching, traits, annotations, generics and functional idioms make the language verbose and semantically-complex. When you follow their best practices, the code ends up more complex than it really needs to be. C is a different kind of animal that encourages terseness and economy of expression. When…

> When you know what you are doing with C pointers, the compiler just doesn't get in the way.

Tell me you use -fno-strict-aliasing without telling me.

Fwiw, I agree with you and we're in good[citation needed] company: https://www.mail-archive.com/linux-btrfs@vger.kernel.org/msg...

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

#157
post #86

Earlier quoted context omitted.

Safer languages manage similar optimizations without having to rely on UB.

Well, yes, safer languages prevent pointer forging statically, so provenance is trivially enforced. And I believe that provenance is an issue in unsafe rust.

Unlike C++ and (until Martin's work is moved to the actual language ISO document rather than separate) C the Rust language actually has a definition for how provenance is supposed to work.

https://doc.rust-lang.org/std/ptr/index.html#provenance

The definition isn't deemed complete because of aliasing. AIUI The definition we have is adequate if you're OK with treating all edge cases for "Is this an alias?" as "Yes" but eventually Rust will also need to carefully nail down all those edge cases so that you can tread closer without falling off.

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

#158
post #145

Earlier quoted context omitted.

So it's something that exists in some hardware. Are you claiming that it exists in all hardware, and we only realized that because of CHERI? Or are you claiming that it exists in CHERI hardware, but not in others. If it only exists in some hardware, how should the standard deal with that?

> If it only exists in some hardware, how should the standard deal with that? Generally seems to me the C standard makes things like that UB. Signed integer overflow, for example. Implemented as wrapping two's-complement on modern architectures, defined as such in many modern languages, but UB in C due to ongoing support for niche architectures. The issues around pointer provenance are inherent to the C abstract mach…

Historically, the reason was was often niche architectures. But sometimes certain behavior dies out and we can make semantics more strict. For example, two's complement is now a requirement for C. Still, we did not make signed overflow defined. The reasons are optimization and - maybe surprising for some - safety. UB can be used to insert the compile-time checks we need to make things safe, but often we can not currently require everyone to do this. At the same time, making things defined may make things worse. For example, finding wraparound bugs in unsigned arithmetic - though well-defined - is a difficult and serious problem. For signed overflow, you use a compiler flag and this is not exploitable anymore (could still be a DoS).

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

#159
post #122

Earlier quoted context omitted.

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…

> I find C compilation extremely fast exactly because of headers.

The header model is one of the parts that makes compiling C slower than it could be. This doesn't mean that it is slow, but it's fast in spite of headers, not because of them.

> In C you can split interface and implementation cleanly between header and c-file and this enables efficient incremental builds.

That's not what does, it is the ability to produce individual translation units as intermediary files.

> Rust also does not seem to have proper separate compilation.

Rust does separate compilation, and also has efficient incremental builds. Header files are not a hard requirement for this.

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

#160
post #55

Earlier quoted context omitted.

Prototyping in any domain. It's nice to do some quick&dirty way to rapidly evaluate ideas and solutions.

I don't think C nor C++ were ever great languages for prototyping? (And definitely not better than Rust.)

Please try not to be obnoxious and turn this into a language war.
Post reply on HN