News for hackers. Stuff that matters.
Re:C and C++ Prioritize Performance over Correctness by pogopop77 on Friday August 18, 2023 @01:27PM (#37179073)
C and C++ are most often used when performance is the highest priority. Undefined behavior is basically the standards committee allowing the compiler developers maximum flexibility to optimize for performance over error checking/handling/reporting. The penalty is that errors can become harder to detect.

It appears the author is a Go advocate. I assume they are valuing clearly defined error checking/handling/reporting (the authors definition of correctness) over performance. If that's what you are looking for, consider Go.

Re:C and C++ Prioritize Performance over Correctness by kelnos on Friday August 18, 2023 @01:31PM (#37179146)
I think this allowance is a mistake.

I suspect that there is some huge number of developer hours that have been wasted, and huge amount of money wasted, on cleaning up after security breaches and finding and fixing security issues. I suspect that those numbers dwarf any losses that might have arisen due to reduced developer productivity or reduced performance when using a (hypothetical) C-like language that doesn't allow the compiler to do these sorts of things.

Re:C and C++ Prioritize Performance over Correctness by PaulDavisThe1st on Friday August 18, 2023 @02:06PM (#37179710)
The allowance wasn't "tradeoff performance time with developer time".

The point of undefined behavior is "if we specify this, we cause problems for some of the compile targets for this language".

Re:C and C++ Prioritize Performance over Correctness by patmorgan23 on Friday August 18, 2023 @02:47PM (#37180303)
Yes, but then complier vendors started abusing UB to increase performance and while silently decreasing safety/correctness. If the compiler creates a security bug by optimizing away a bounds check the programmer explicitly put there, that's a problem.

https://thephd.dev/c-undefined-behavior-and-the-sledgehammer...

Re:C and C++ Prioritize Performance over Correctness by jerf on Friday August 18, 2023 @02:25PM (#37179983)
"a (hypothetical) C-like language that doesn't allow the compiler to do these sorts of things."

It's not very hypothetical in 2023. There are plenty of languages whose compilers don't do this sort of thing and attain C-like performance. There isn't necessarily a single language that exactly and precisely replaces C right now, but for any given task where you would reach for C or C++ there's a viable choice, and one likely to be better in significant ways.

I also feel like this is missed by some people who defend this or that particularly treatment of a particular undefined behavior. Yeah, sure, I concede that given the history of where C is and how it got there and in your particular case it may make sense. But the thing is, my entire point is we shouldn't be here in the first place. I don't care about why your way of tapping a cactus for water is justifiable after all if you consider the full desert context you're living in, I moved out of the desert a long time ago. Stop using C. To a perhaps lesser but still real extent, stop using C++. Whenever you can. They're not the best option for very many tasks anymore, and if we discount "well my codebase is already in that language and in the real world I need to take switching costs into account" they may already not be the best option for anything anymore.

Re:C and C++ Prioritize Performance over Correctness by spookie on Friday August 18, 2023 @02:44PM (#37180251)
I'm sorry, but the world doesn't really align with these ideas, sometimes that is. It's understandable, but at the same time it really isn't.
Re:C and C++ Prioritize Performance over Correctness by jerf on Friday August 18, 2023 @04:43PM (#37181843)
I assume you're referring to "my codebase is already in C/C++"? Which I did acknowledge?

Because otherwise, what the world is increasingly not aligning with is using C when you shouldn't be. Security isn't getting any less important and C isn't getting any better at it.

Re:C and C++ Prioritize Performance over Correctness by dahfizz on Friday August 18, 2023 @02:46PM (#37180293)
I'll stop using C when there is a faster alternative. When nanoseconds count, there is no competition.
Re:C and C++ Prioritize Performance over Correctness by jerf on Friday August 18, 2023 @04:42PM (#37181827)
You don't need one faster. You need one as fast. These options generally exist. Rust seems to have crept its way right up to "fast as C"; it isn't really a distinct event, but https://benchmarksgame-team.pages.debian.net/benchmarksgame/... (it tends to better on the lower ones so scroll a bit). There are some other more exotic options.

C isn't the undisputed speed king any more. It hasn't necessarily been "roundly trounced", there isn't enough slack in its performance for that most likely, but it is not the undisputed speed king. It turns out the corners it cuts are just corners being cut; they aren't actually necessary for performance, and in some cases they can actually inhibit performance. See the well-known aliasing issues with C optimizations for an example. In general I expect Rust performance advantages to actually get larger as the programs scale up in size and Rust affords a style that involves less copying just to be safe; benchmarks may actually undersell Rust's advantages in real code on that front. I actually wouldn't be surprised that Rust is in practice a straight-up faster language than C on non-trivial code bases being developed in normal ways; it is unfortunately a very hard assertion to test because pretty much by definition I'm talking about things much larger than a "benchmark".

Re:C and C++ Prioritize Performance over Correctness by optymizer on Friday August 18, 2023 @03:27PM (#37180827)
This reasoning is why software keeps getting slower and more bloated, build times increase, and latency goes up despite having orders of magnitude more compute power.
Re:C and C++ Prioritize Performance over Correctness by jerf on Friday August 18, 2023 @04:38PM (#37181774)
If whatever language you're thinking of does that, it isn't one of the ones I'm talking about. I sure as heck aren't talking about Python here. Think Rust, D, Nim, in general the things floating along at the top of the benchmarks (that's not a complete list either).
Re:C and C++ Prioritize Performance over Correctness by nmz on Friday August 18, 2023 @07:48PM (#37183695)
I don't see how this solves anything, Nim's backend is C, which means it should suffer from the same pitfalls. They probably clean it up and eliminate UB, but it should still exist.
Re:C and C++ Prioritize Performance over Correctness by Pet_Ant on Saturday August 19, 2023 @05:36AM (#37187059)
Yeah, but with less bugs, more features, and faster development. I mean I hate Electron with a passion but it means everybody gets a client. Let’s not pretend that it’s all worse rather than a set of tradeoffs.
Re:C and C++ Prioritize Performance over Correctness by wheelerof4te on Friday August 18, 2023 @01:43PM (#37179359)

  res, err := InterceptNuke(enemyNuke)
  if err != nil {
    fmt.Println("NUCLEAR LAUNCH DETECTED!")
    log.Fatal(err)
  } else {
   fmt.Printf("Phew, we're safe. Nuke intercepted after %d seconds.\n", res)
  }
Very clearly defined errors indeed.
Re:C and C++ Prioritize Performance over Correctness by mxmlnkn on Friday August 18, 2023 @01:57PM (#37179556)
The undefined behavior I struggle with keeps me from better performance though. I have something like [(uint32_t value) >> (32 - nbits)] & (lowest nbits set). For the case of nbits=0, I would expect it to always return 0, even if the right shift of a 32-bit value by 32 bits is undefined behavior, then bit-wise and with 0 should make it always result in 0. But I cannot leave it that way because the compiler thinks that undefined behavior may not happen and might optimize out everything.
Re:C and C++ Prioritize Performance over Correctness by titzer on Friday August 18, 2023 @02:39PM (#37180166)
Exactly. The irony in all of this is that C is not a portable assembler. If you want the exact semantics of a hardware instruction, you cannot get it, because the compiler reasons with C's abstract machine that assumes your program doesn't have undefined behavior, like signed wraparound, when in some situations you in fact do want signed wraparound, since that's what literally every modern CPU does.
Re:C and C++ Prioritize Performance over Correctness by zzo38computer on Friday August 18, 2023 @02:08PM (#37179744)
I think that the undefinde behaviour should be partially specified. In the case you describe, it should require that it must do one of the following:

1. Return any 32-bit answer for the right shift. (The final result will be zero due to the bitwise AND, though, regardless of the intermediate answer.) The intermediate answer must be "frozen" so that if it is assigned to a variable and then used multiple times without writing to that variable again then you will get the same answer each time.

2. Result in a run-time error when that code is reached.

3. Result in a compile-time error (only valid if the compiler can determine for sure that the program would run with a shift amount out of range, e.g. if the shift amount is a constant).

4. Have a behaviour which depends on the underlying instruction set (whatever the right shift instruction does in that instruction set when given a shift amount which is out of range), if it is defined. (A compiler switch may be provided to switch between this and other behaviours.) In this case, if optimization is enabled then there may be some strange cases with some instruction sets where the optimizer makes an assumption which is not valid, but bad assumptions such as this should be reduced if possible and reasonable to do so.

In all cases, a compiler warning may be given (if enabled and detected by the compiler), in addition to the effects above.

Re:C and C++ Prioritize Performance over Correctness by mxmlnkn on Friday August 18, 2023 @02:28PM (#37180021)
I wanted to reply that your point 3 should already be possible with C++ constexpr functions because it doesn't allow undefined behavior. But I it seems I was wrong about that or maybe I'm doing it wrong:

    [[nodiscard]] constexpr uint64_t
    getBits( uint8_t nBits )
    {
        return BITBUFFER >> ( 64 - nBits ) & ( ( 1ULL << nBits ) - 1U );
    }
 
    int main()
    {
        std::cerr << getBits( 0 ) << "\n";
        std::cerr << getBits( 1 ) << "\n";
        return 0;
    }
The first output will print a random number, 140728069214376 in my case, while the second line will always print 1. However, when I put the ( ( 1ULL << nBits ) - 1U ) part into a separate function and print the values for that, then getBits( 0 ) suddenly always returns 0 as if the compiler understands suddenly that it will and with 0.

    template<uint8_t nBits>
    [[nodiscard]] constexpr uint64_t
    getBits2()
    {
        return BITBUFFER >> ( 64 - nBits ) & ( ( 1ULL << nBits ) - 1U );
    }
In this case, the compiler will only print a warning when trying to call it with getBits2<0>. And here I kinda thought that constexpr would lead to errors on undefined behavior, partly because it always complains about uninitialized std::array local variables being an error. That seems inconsistent to me. Well, I guess that's what -Werror is for ...

Compiled with -std=c++17 and clang 16.0.0 on godbolt: https://godbolt.org/z/qxxWW93Tx

Re:C and C++ Prioritize Performance over Correctness by gpderetta on Friday August 18, 2023 @03:50PM (#37181155)
Unfortunately constexpr doesn't imply constant evaluation. Your function can still potentially be executed at runtime.

If you use the result in an expression that requires a constant (an array bound, a non-type template parameter, a static_assert, or, in c++20, to initialize a constinit variable), then that will force constant evaluation and you'll see the error.

Having said that, compilers have bugs (or simply not fully implemented features), so it is certainly possible that both GCC and clang will fail to correctly catch constant time evaluation UB in some circumstances.

Re:C and C++ Prioritize Performance over Correctness by mxmlnkn on Friday August 18, 2023 @04:02PM (#37181317)
Ah thanks, I was not aware that these compile-time checks are only done when it is evaluated in a compile-time evaluating context.

To add to your list, using C++20 consteval instead of constexpr also triggers the error.

Re:C and C++ Prioritize Performance over Correctness by pjmlp on Friday August 18, 2023 @02:11PM (#37179778)
Nowadays, in 1980's....

"Oh, it was quite a while ago. I kind of stopped when C came out. That was a big blow. We were making so much good progress on optimizations and transformations. We were getting rid of just one nice problem after another. When C came out, at one of the SIGPLAN compiler conferences, there was a debate between Steve Johnson from Bell Labs, who was supporting C, and one of our people, Bill Harrison, who was working on a project that I had at that time supporting automatic optimization...The nubbin of the debate was Steve's defense of not having to build optimizers anymore because the programmer would take care of it. That it was really a programmer's issue.... Seibel: Do you think C is a reasonable language if they had restricted its use to operating-system kernels? Allen: Oh, yeah. That would have been fine. And, in fact, you need to have something like that, something where experts can really fine-tune without big bottlenecks because those are key problems to solve. By 1960, we had a long list of amazing languages: Lisp, APL, Fortran, COBOL, Algol 60. These are higher-level than C. We have seriously regressed, since C developed. C has destroyed our ability to advance the state of the art in automatic optimization, automatic parallelization, automatic mapping of a high-level language to the machine. This is one of the reasons compilers are ... basically not taught much anymore in the colleges and universities."

-- Fran Allen interview, Excerpted from: Peter Seibel. Coders at Work: Reflections on the Craft of Programming

Re:C and C++ Prioritize Performance over Correctness by titzer on Friday August 18, 2023 @02:50PM (#37180348)
A great quote. She's absolutely right. C has absolutely polluted people's understanding of what compiler optimizations should be. Compilers should make a program go faster, invisibly. C makes optimization everyone's problem because the language is so absolutely terrible at defining its own semantics and catching program errors.
Re:C and C++ Prioritize Performance over Correctness by marcosdumay on Friday August 18, 2023 @04:25PM (#37181608)
Hum... We have to move further than this citation. The 1980s C was much more secure than our current one.

The undefined behavior paradoxes were only added by the 90s, when optimizing compilers became a logic inference engine, feed with the unquestionable truth that the developer never exercises UB.

Just because it was a sane language for kernel development at the 1980s, it doesn't mean it is one now.

Re:C and C++ Prioritize Performance over Correctness by pjmlp on Friday August 18, 2023 @05:06PM (#37182102)
Yeah, because the only way to achieve performance in 1980's C on 16 bit platforms was to litter it with inline Assembly, thus UB based optimisation was born to win all those SPEC benchmarks in computer magazines.
Re:C and C++ Prioritize Performance over Correctness by marcosdumay on Friday August 18, 2023 @05:15PM (#37182218)
Funny thing in that the same thing stopping people to write those crazy¹ optimizers at the 1980s was exactly the lack of capacity of the computers to run them.

What means that they appeared exactly at the time the need for them became niche. And yet everybody adopted them due to the strong voodoo bias we all have at computer-related tasks.

1 - They are crazy. They believe the code has no UB even though they can prove it has.

Re:C and C++ Prioritize Performance over Correctness by btilly on Friday August 18, 2023 @02:12PM (#37179790)
Given who invented it, Go can be thought of as, "What C might have been if we could have done it."

Go really is in many ways more similar to early C in spirit than modern C is.

Re:C and C++ Prioritize Performance over Correctness by anthk on Friday August 18, 2023 @03:52PM (#37181183)
Go it's modelled after plan9'C [1-9]c = go cross compiling, and Limbo so it has a lot of sense. Both come from the same people after all. Unix->Unix8 -> Plan9 -> Go.
Re:C and C++ Prioritize Performance over Correctness by akshayshah on Friday August 18, 2023 @03:55PM (#37181215)
Expanding this for those not familiar with Go's history: Ken Thompson, formerly of Bell Labs and co-creator of B and Unix, was deeply involved in Go's early days. Rob Pike, also ex-Bell Labs, was also one of Go's principal designers.

I can't find a source now, but I believe Rob described Russ Cox as "the only programmer I've met as gifted as Ken." High praise indeed.

Re:C and C++ Prioritize Performance over Correctness by TwentyPosts on Friday August 18, 2023 @02:14PM (#37179828)
Eh. The existence of Rust (and Zig, to a lesser extent) prove that you can, in fact, have both: Highest performance and safe, properly error checked code without any sort of UB.

UB is used for performance optimizations, yes, but all of these difficult to diagnose UB issues and bugs happen because C++ makes it laughably easy to write incorrect code, and (as shown by Rust) this is by no means a requirement for fast code.

Re:C and C++ Prioritize Performance over Correctness by alphanullmeric on Friday August 18, 2023 @02:26PM (#37180004)
You can do any rust optimization yourself in C++ (ie. aliasing assumptions), whereas rust makes the other way around very difficult, often forcing you to use multiple layers of indirection where c++ would allow a raw pointer, or forcing an unwrap on something you know is infallible when exceptions would add no overhead, etc. Rust programmers want people to believe that whatever appeases the supposedly zero cost borrow checker is the fastest thing to do even though it has proven to be wrong time and time again. I can’t tell you how many times I’ve seen r/rust pull the “well why do you want to do that” or “are you sure it even matters” card every time rust doesn’t allow you to write optimized code.
Re:C and C++ Prioritize Performance over Correctness by cortesoft on Friday August 18, 2023 @02:49PM (#37180330)
Isn't that the point of unsafe blocks in rust? So you can write optimized code when you need to and the rust borrow checker won't let you?
Re:C and C++ Prioritize Performance over Correctness by gmueckl on Friday August 18, 2023 @03:15PM (#37180683)
Unsafe blocks are subject to the same borrow checking that the rest of the language is.
Re:C and C++ Prioritize Performance over Correctness by tialaramex on Friday August 18, 2023 @03:31PM (#37180908)
That is correct. However, raw pointers are not borrow checked, in safe Rust they're largely useless, but in unsafe Rust you can use raw pointers if that's what you need to do to get stuff done.

As an example inside a String is just a Vec<u8> and inside the Vec<u8> is a RawVec<u8> and that is just a pointer, either to nothing in particular or to the bytes inside the String if the String has allocated space for one or more bytes - plus a size and a capacity.

Re:C and C++ Prioritize Performance over Correctness by celeritascelery on Friday August 18, 2023 @03:40PM (#37181032)
> You can do any rust optimization yourself in C++ (ie. aliasing assumptions)

I don’t think that is entirely true. C++ doesn’t have any aliasing requirements around pointers, so if the compiler sees two pointers it has to assume they might alias (unless the block is so simple it can determine aliasing itself, which is usually not the case), but in Rust mutable references are guaranteed to not alias.

This was part of the reason it took so long to land the “noalias” LLVM attribute in Rust. That optimization was rarely used in C/C++ land so it had not been battle tested. Rust found a host of LLVM bugs because it enables the optimization everywhere.

Re:C and C++ Prioritize Performance over Correctness by LegionMammal978 on Friday August 18, 2023 @04:23PM (#37181590)
While standard C++ has no equivalent of a noalias annotation, it's wrong to say that it has no aliasing requirements. To access an object behind a pointer (or a glvalue in general), the type of the pointer must be (with a few exceptions) similar to the type of the pointee in memory, which is generally the object previously initialized at that pointer's address. This enables type-based alias analysis (TBAA) in the compiler, where if a pointer is accessed as one type, and another pointer is accessed as a dissimilar type, then the compiler can assume that the pointers don't alias.

Meanwhile, Rust ditches TBAA entirely, retaining only initialization state and pointer provenance in its memory model. It uses its noalias-based model to make up for the lack of type-based rules. I'd say that this is the right call from the user's standpoint, but it can definitely be seen as a tradeoff rather than an unqualified gain.

Re:C and C++ Prioritize Performance over Correctness by celeritascelery on Friday August 18, 2023 @08:21PM (#37184017)
Why couldn’t the Rust compiler also assume that dissimilar types don’t alias?
Re:C and C++ Prioritize Performance over Correctness by LegionMammal978 on Saturday August 19, 2023 @01:10PM (#37190859)
Because existing unsafe code written in stable Rust depends on the ability to convert raw pointers and references from one type to another, as long as their memory layouts match. That's the whole premise of the bytemuck crate [0], and it's the basis for things like the &str-to-&[u8] or &[u8]-to-&str conversions in the standard library.

[0] https://docs.rs/bytemuck/latest/bytemuck/

Re:C and C++ Prioritize Performance over Correctness by thedracle on Friday August 18, 2023 @04:18PM (#37181529)
> when exceptions would add no overhead

Isn't the overhead for C++ exceptions quite significant, especially if an exception is thrown?

Exception handling can also increase the size of the binary because of the additional data needed to handle stack unwinding and exception dispatch.

I think a number of optimizations are made quite a bit more complex by exception handling as well.

Re:C and C++ Prioritize Performance over Correctness by tialaramex on Friday August 18, 2023 @04:35PM (#37181746)
The argument for the Exception price is that we told you Exceptions were for Exceptional situations. This argument feels reasonable until you see it in context as a library author.

Suppose I'm writing a Clown Redemption library. It's possible to Dingle a Clown during redemption, but if the Clown has already dingled that's a problem so... should I raise an exception? Alice thinks obviously I should raise an exception for that, she uses a lot of Clowns, the Clown Redemption library helps her deliver high quality Clown software and it's very fast, she has never dingled a Clown and she never plans to, the use of exceptions suits Alice well because she can completely ignore the problem.

Unfortunately Bob's software handles primarily dingling Clowns, for Bob it's unacceptable to eat an exception every single damn time one of the Clowns has already been dingled, he demands an API in which there's just a return value from the dingling function which tells you if this clown was already dingled, so he can handle that appropriately - an exception is not OK because it's expensive.

Alice and Bob disagree about how "exceptional" the situation is, and I'm caught in the middle, but I have to choose whether to use exceptions. I can't possibly win here.

Re:C and C++ Prioritize Performance over Correctness by alphanullmeric on Friday August 18, 2023 @05:18PM (#37182267)
Like I said, this argument doesn’t work because you can use options in c++ but you can’t use exceptions in rust. So when there’s an occasion where you want to avoid the overhead of an option or result in rust - well too bad.
Re:C and C++ Prioritize Performance over Correctness by dureuill on Sunday August 20, 2023 @04:24AM (#37197197)
Yes you can. They're called panics
Re:C and C++ Prioritize Performance over Correctness by kllrnohj on Friday August 18, 2023 @04:52PM (#37181945)
Exceptions cost performance when thrown whereas return values always cost performance.

If all you care about is outright performance, having the option for exceptions is easily the superior choice. The binary does get bigger but those are cold pages so who cares (since exceptions are exceptional, right?)

Re:C and C++ Prioritize Performance over Correctness by adamdegas on Friday August 18, 2023 @03:31PM (#37180914)
The Computer Language Benchmarks Game has C++ outperforming Rust by around 10% for most benchmarks. Binary trees is 13% faster in C++, and it's not the best C++ binary tree implementation I've seen. k-nucleotide is 32% faster in C++. Rust wins on a few benchmarks like regex-redux, which is a pointless benchmark as they're both just benchmarking the PCRE2 C library, so it's really a C benchmark.

> because C++ makes it laughably easy to write incorrect code

I was going to ask how much you actually program in C++, but I found a past comment of yours:

> I frankly don't understand C++ well enough to fully judge about all of this

Re:C and C++ Prioritize Performance over Correctness by thedracle on Friday August 18, 2023 @04:09PM (#37181405)
I mean, it's outperforming C as well in that particular benchmark.

Lies, damn lies, and benchmarks?

I can at least say, the performance difference between C, C++, and Rust, is splitting hairs.

If you want to write something performant, low level, with predictable timing, all three will work.

I'm spending a lot of time building projects with Rust & C++ these days. The issue/tradoff isn't performance with C++, but that C++ is better for writing unsafe code than Rust.

https://www.p99conf.io/2022/09/07/uninitialized-memory-unsaf...

Re:C and C++ Prioritize Performance over Correctness by estebank on Friday August 18, 2023 @04:38PM (#37181768)
> Rust wins on a few benchmarks like regex-redux, which is a pointless benchmark as they're both just benchmarking the PCRE2 C library, so it's really a C benchmark.

The Rust #1 through #6 entries use the regex crate, which is pure-Rust. Rust #7[rust7] (which is not shown in the main table or in the summary, only in the "unsafe" table[detail]) uses PCRE2, and it is interestingly also faster than the C impl that uses PCRE2[c-regex] as well (by a tiny amount). C++ #6[cpp6], which appears ahead of Rust #6 in the summary table (but isn't shown in the comparison page)[comp], also uses PCRE2 and is closer to Rust #7.

[comp]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

[detail]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

[rust7]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

[c-regex]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

[cpp6]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

Re:C and C++ Prioritize Performance over Correctness by overgard on Friday August 18, 2023 @04:07PM (#37181388)
> C++ makes it laughably easy to write incorrect code

It also provides a lot of mechanisms and tools to produce correct safe code, especially modern C++. Most codebases you're not seeing a lot of pointer arithmetic or void pointer or anything of that nature. You hardly even see raw pointers anymore, instead a unique_ptr or a shared_ptr. So yes, you can write incorrect code because it's an explicit design goal of C++ not to treat you like a baby, but that doesn't mean that writing C++ is inherently like building a house of cards.*

Re:C and C++ Prioritize Performance over Correctness by tylerhou on Friday August 18, 2023 @02:51PM (#37180370)
The author, Russ Cox, was one of the inventors of Go.
Re:C and C++ Prioritize Performance over Correctness by jeremyloy_wt on Friday August 18, 2023 @03:23PM (#37180781)
> It appears the author is a Go advocate

A bit of an understatement. The author is the current Golang project lead and a member since it’s inception

Re:C and C++ Prioritize Performance over Correctness by barsonme on Saturday August 19, 2023 @02:05AM (#37186017)
He’s more like the BDFL.