Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> Just another nail in the long overdue C/C++ coffin

C, f**ing C. By the sake of god. Not C++.

Stop to put both in the same basket, it just show you do not know what you are talking about.

https://github.com/XKCP/XKCP/commit/fdc6fef075f4e81d6b1bc383...

Something like that in modern C++ would have been done using std::span<> and that prevents this kind of out-of-bound access and the party-time that comes with it.




WG21 (the C++ Standards Committee) feels that since idiomatic C++ was unsafe (e.g. array operations don't have bounds checks) it is consistent for new C++ features to also be unsafe by default, even if the whole point of those features in other languages is to provide an idiomatic safe way to do things.

So for example in Rust you have a native slice type reflecting a dynamically sized view into a contiguous sequence, and of course it's safe -- five[20] will either refuse to compile if the compiler can see this slice is too short, or it will panic at runtime. In C++ as others have mentioned actually std::span just isn't safe when used ergonomically. five[20] in C++ is Undefined Behaviour. std::optional has a safe interface for a Maybe / Option type, but is presented with a more ergonomic unsafe behaviour and that's what people use.

This is not an old-fashioned thing the C++ Committee grew out of, std::expected is in C++ 23, that's a Result type and it likewise offers an ergonomic unsafe API. The safe APIs were seen as a nice-to-have which could miss the train because who needs safety anyway? Just don't make any mistakes.


Tragically, what I would call idiomatic C++ with compiler provided frameworks pre-ISO C++98, made use of bounds checking in their collection classes, and then the C++ Committee went completly to the other way.

Naturally we have now ways to enable them on all major compilers, but many still don't.

This is one point I kind of agree with you.


The crucial trick in Rust is not that the index operations are bounds checked, that's easy, as you observed plenty of C++ toolchains can do that.

The crucial trick is providing the unchecked operations (with improved performance) as unergonomic alternatives. *(five.get_unchecked_mut(20)) = k; // looks horrible. Nobody wants to write that, so when they don't need it they won't write it. The fact calling get_unchecked_mut requires unsafe is part of how Rust could achieve its goals, but the choice to not make this ergonomic is why it actually delivers in practice.

What CppFront wants here, and P2687 proposes, and lots of other C++ work has suggested, is roughly:

  [[suppress(bounds_check)]] { five[20] = k; }
Thus imitating what they think Rust does here, rather than what it actually did, and in the process completely missing the point.


Given that on some domains, there is no way around C or C++, unless one wants to be part of building the ecosystem, I was having big hopes on the clang and VC++ static analysis work for those kind of scenarios.

I can't speak for clang, but in what concerns VC++ is mostly useless still, unless one wants to annotate everything with those kind of annotations + SAL, and even then it is only half way there.

Which is not really inspiring.


Mmmhm. Go look in the docs for std::span and see how long it takes to find "The behavior is undefined if idx is out of range" or similar. For example: https://en.cppreference.com/w/cpp/container/span/operator_at


> Mmmhm. Go look in the docs for std::span and see how long it takes to find "The behaviour is undefined if idx is out of range" or similar.

It is regrettable and under fix but:

- You generally do have your own implementation with more advance bound check for safety-critical implementation. - We do have our own where I work right now. - Google has its own in abseil.

- span allows the usage for range-for loop which combined with subspan() makes possible to avoid pointer arithmetic all together.


When you are already in a deep hole, it's a good idea to stop digging.

How much time did it took you to understand all this? What chances does a beginner has to understand these subtle differences and learn the particular way your codebase uses std::span and not footgun themselves? How much productivity is lost to the sheer terror of such footguns - not actual bugs, but time and effort lost that did not move the product forward?

And most importantly, what is the point of accepting that huge cost instead of writing in a language where unsafe data access is impossible?


> And most importantly, what is the point of accepting that huge cost instead of writing in a language where unsafe data access is impossible?

Because the world is a place where billions of lines of code have been written. And these will never be rewritten, but can be modernized.

That the reality, and that's why your web browser right now and most of your OS is still written in unsafe language right now. And will still be for the next 15years at least.


Surely "nails in the coffin of C/C++" does not imply an all out effort to rewrite all this existing and working software from scratch.

The beast will die in the same sense Fortran or Cobol are dead: an outdated language that has no noticeable strengths in the modern world, used by a bunch of (difficult to hire) old timers to fix legacy systems.


> Surely "nails in the coffin of C/C++" does not imply an all out effort to rewrite all this existing and working software from scratch.

Or you use the evolutionary approach: remove the unsafe part from C/C++ bit by bit. And do code migration (Carbon style) when you can do it. This is what some C and C++ committee members try to do and fortunately they are there.

Because that is way more likely to happen in a reasonable time frame (next 15 years) than rewrite Chrome, Linux, OpenSSL, Office and all the other 10 of billions of proprietary code we have around in Rust.


> remove the unsafe part from C/C++ bit by bit.

You cannot do that without breaking backward compatibility. If you maintain compatibility, what results is a sprawling meta-language with a large learning burden that has the theoretical ability to emulate a safe language, and which in practice will be used to mix both safe and unsafe idioms depending on the experience and discipline of the programmer, in an unholy mess that no static analyzer can prove as correct and no programmer can say they really fully understand.

Maybe I'm mistaken, I've last programmed in C++ a good number of years ago, but I have not encountered a (C++ programming paradigm, static linter) doublet that can prove data integrity and thread safety to an extent even close to the Rust compiler. And it would be useless for existing codebases anyhow.


As much as I like C++, std::span<> would only have helped if the build was built with bounds checking turned on.

ISO on their wisdom has turned the safety defaults around in regards to classical C++ frameworks.

So C++ secure code, either has to make use of Microsoft's gsl::span<>, or again turn on bounds checking in release builds, you cannot trust everyone to call .at().


C++ offers safer constructs but they have their own sharp edges and you have to actually use them to get their benefits. In security critical software these can still be enough to cause significant problems.


Code like that in C++ would probably be over-optimized and would skip boundary checks, exposing it to the same problem.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: