My Reaction to Dr. Stroustrup’s Recent Memory Safety Comments
thecodedmessage.com
thecodedmessage.com
I think just the concept of classes, and new, help with memory safety. It's harder to screw with memory with new Foo() then doing a malloc and memcpying bits into a buffer. Sure it's far cry from real memory safety, but i do think c++ has a bunch of improvements over c in memory safety. Sure you can do all the nasty bits in c++ that you could do in c, but you are carrotted out of doing them most of the time.
Yes if you have a statically sized array you can make a pointer to an array of that length, but those are generally not relevant outside of specific cases (arrays in structs or on the stack where the size impacts offsets in codegen). More over the desire of C and C++ to drop those annotations is such that even using your proposal of a pointer to an array rather than just an array, is of questionable value. Take an extension of your example:
int(*y)[3] = ...;
int(*y2)[3] = ...;
You can't do *y2 = *y;
Because C doesn't let you assign arrays by value, even fixed size ones \o/I think "novel" means that they were Greenfield languages. They certainly took concepts from preexisting languages (like Java's "interfaces" being inspired by Objective-C's "protocols"), but they didn't start their lives as "existing-language-with-X," the way C++ was "C, with classes."
A lot of business oriented people may find my delineation here offensive, but it really isn't meant to be. While a business' job is to make money, and employees work for the business, they may still disagree on how to evaluate a given action - because the business making money and being financially optimised may not be the main reason they work there.
Knowing some Rust and how it works, then going back to C++ can help you recognize where to use safer idioms and what's potentially dangerous.
I am a bit rusty (no pun intended) at the moment, but I have decades-long experience with C++, but not all people do, and all people ,even experienced developers make mistakes or get lazy and take the easy way out from time to time.
I think one lesson C++ could take from rust, if nothing else, is that clearly demarking unsafe code sections is beneficial in and of itself.
If Strostrup makes the claim that developers using old C features is the main security problem of modern C++ , then an unsafe keyword would guide behavior towards safe usage.
#No "old unsafe C" here
UNSAFE{
#Full C++, including "old unsafe C" here
...
}
#No "old unsafe C" here
>c++ / treat code as "New Safe C++ only", except for UNSAFE sections
>c++ --no-unsafe / treat all code as "New safe C++ only" UNSAFE not allowed
>c++ --allow-unsafe / current behavior, allow all C++ including "old unsafe C" in all sectionshttps://www.youtube.com/watch?v=ml4t-6bg9-M
However, this is only one compiler, not ISO C++.
See Yaml safe load vs load. Since default method is unsafe due to Yaml bugs there were wide ranging consequence across most of ecosystem.
If default was safe load, and you could opt-in to features of Yaml that caused unsafety it would be a much lesser problem.
Do you think Stroustrup is not aware of Rust? Do you seriously think he wasn't thinking about Rust when he wrote this? Even if he wasn't, don't you think he should've been? Do you not think the existence of Rust is relevant to the conversation?
Is this discourse bound by some lawyer-like rules where if someone doesn't bring up something that everyone knows is relevant, it's off the table to mention? Should I have filed a form with you asking for permission to bring up a topic not mentioned in the document I was responding to, even though everyone thinking through it with good faith knows it's on topic?
If he was, then why didn't he mention it? You seem to know what Stroustrup's inner thoughts are, so tell me, why didn't he mention it?
Maybe he wants to avoid the ten million reply guy Rust evangelists out there (ahem), maybe he doesn't think it's relevant to the discussion for other reasons. Please enlighten me.
Obviously, anyone can blog about anything they want to but likewise I can ask questions too. You seem very upset that I asked such a simple question.
You might have heard of this phenomenon called "click bait" where people inject themselves into only very tangential discussions to get clicks. Or, in this case, I suspect to preach to the choir.
Now, let me ask you: do you have an opinion about what Stroustrup wrote or are you just making sure no one says anything bad about [your_favorite_lang].
As I say immediately afterwards, if he wasn't, he should've been. If Stroustrup thinks Rust is irrelevant to this conversation, he's simply mistaken. It's relevant for bringing memory safety into C++'s last remaining niche, after it's been chased out of most domains already.
> Now, let me ask you: do you have an opinion about what Stroustrup wrote or are you just making sure no one says anything bad about [your_favorite_lang].
Let me answer you: Most of my post still works if you replace Rust with Java. That's why I conclude that the time for Stroustrup to start talking about adding memory safety to C++ is 1995, before Rust was even thought of. If you had read and understood my post, you would've realized it has way more to do with what Stroustrup wrote than Rust in particular. Rust didn't invent memory safety, and Rust didn't make C++ behind the times for not pursuing it.
> You seem very upset that I asked such a simple question.
You didn't ask a question. You made an objection. You started out with a false claim that the NSA document didn't mention Rust, and then you implied that since Stroustrup's document didn't mention Rust, it was inappropriate for me to mention Rust. That's absurd, because Rust is extremely relevant to this conversation, for reasons I explain in the post and here. It's also infuriating, because you're holding me to a standard that sounds like it should be reasonable, but in fact isn't -- this ludicrous idea that replies should be limited strictly to the original topics, even if they can explain why a new topic is relevant, as I do with Rust. So I'm explaining why it's not reasonable, so that the casual reader doesn't mistakenly get the impression that you had a good point.
> very tangential discussions
I've explained (1) why Rust is relevant and (2) why my post would be mostly relevant even if Rust didn't exist, so it's not tangential.
> Or, in this case, I suspect to preach to the choir.
I don't see why this is a bad thing, really. Sometimes, the choir wants someone to explain elegantly to them what they already knew, and help them solidify their thought processes.
Well, he doesn't get to. If he's going to imply that one of the major selling points of Rust over C++ barely matters, he's going to get a response.
Although you did, by your definition, "reply guy" my blog post with your ill-explained and ultimately unjustifiable objection to it.
It doesn’t help though that there’s no way to distinguish a pointer from an array, nor get the length of an array (because you aren’t guaranteed an array is a c++ array with a prefix header or a c style array with a separate size), and given a lot of c++ is still pointers - for example the semantics of iterators makes it hard to be both bounds safe and fast, which means c++ iterators can easily go out of bounds or into random memory in the face of mutation. Now obviously we generally agree mutating something while iterating it is bad, but the c++ iterators semantics makes detecting and stopping that extremely expensive because it’s fundamentally designed around reusing old code that was just incrementing pointers.
C with VLAs can actually express the length of a pointed to array, with the following example:
#include <stdio.h>
// See the linux kernel for a version that verifies
// `x` is actually an array.
#define arrlen(x) (sizeof(x)/sizeof(x[0]))
void foo(const int x, int(*y)[x]){
printf("%zu\n", arrlen(*y));
}
int main(){
int a[3];
foo(arrlen(a), &a);
return 0;
}
If you compile and run the above code, you will see that it correctly prints the length of the array - 3. Unfortunately, the syntax is awkward and most C/C++ programmers would be stumped by the actual syntax for a pointer to an array. There is also no help that the correct length is passed.In C this will probably work, but only because VLAs in C are broken by design - VLAs are not part of the type system, which means there is no actual required relationship between the size of the array - even when statically known as in your example - and the parameters to the function. So yes your example will print 3, but that's because it will print whatever you pass in for x. So I can equally do:
foo(500, &a);
and that's valid, and I would put money on not producing even a warning. Again because VLAs aren't part of the type system I could also do: foo(5, malloc(1));
and that should work fine as well, because VLAs are again not real.Moreover this is also kind of missing the point: I said there is no way to distinguish a pointer from an array allocation, and your example is not using a pointer or an array, it is using a pointer and an additional length value - and yes, the correct thing to do is to have a struct containing both of those, or probably better a struct with trailing storage. Either way the C or C++ type system does not distinguish between a pointer to an object, or a pointer to an array of N (including potentially 1) objects, and you, the programmer need to do this yourself without language support.
I will add that I'm in my mid-50s and have been programming since childhood and so I've had a chance to observe the evolution of C++ since the not-quite-C++ implementations such as those in THINK C (Object Extensions to C) and TCL (Think Class Library). I've used quite a few C++ frameworks and libraries that existed pre-STL including Borland's OWL 2.0 and the old Turbo Vision framework, as well as the first version of MFC (Microsoft Foundation Classes - I still have nightmares), and later worked extensively with the massively useful and very nicely designed Metrowerks PowerPlant class library. I used to subscribe to the old C++ Report magazine and read them cover-to-cover. The best of these articles are still available if you can track down old copies of the books _C++ Gems_ and _More C++ Gems_. (One of the fascinating things to be learned from those articles is how practitioners discovered that the exception mechanism in C++ really could only _theoretically_ be made to ensure safe and easy error-handling and recovery, but in practice made it impossible, because the total state of the program and its resources had to be considered at every point in the program in which an exception could occur; at one job, I tried unsuccessfully to convince my co-workers not to use exceptions for error-handling in embedded multi-threaded client/server code in vehicle infotainment devices.)
I have owned every edition of Stroustrup's _The C++ Programming Language_ and read his _The Design and Evolution of C++_. I used to buy, print out, and bind, copies of the C and C++ standards so that I could try to answer hard questions about whether compilers were broken, or the code was broken. If I had kept every book I've ever owned on C++ programming, I estimate it would be about 12 feet of shelf space. It is probably a blessing that I have only kept about 2 feet, which now has books on C++17 and C++20 for those times when I have to read some modern C++. At one point (about 1999) I considered myself to be a pretty expert C++ programmer, but because of language churn, those days are gone. (How many times can one re-learn the proper way to write a managed pointer class, or what methods should go into a "standard" kind of class to make it useful and safe? For me, the turning point probably came when I bought a brand new book on STL programming and tried to run the chapter 1 examples. Every compiler I had access to at the time on several platforms crashed when trying to compile the programs, which was a really vivid illustration of just how far the cutting edge was from the reality of working programmers.) I also once went to a talk by Stroustrup on the campus of the University of Michigan, and left frustrated and bored.
Given all that, I don't believe Stroustrup's ever been quite the thinker and visionary that some might think he is. He will not be remembered as a great language designer but more a formalizer, implementer, and promoter of ideas mainly borrowed from other languages and other people. He's certainly not a great writer or a great speaker, as I learned at his talk.
That itself is not my real criticism of him and his work; there are a lot of great ideas in language design to borrow from. My real criticism of him and his work is that along the way he has not been able to maintain a coherent vision of how language features would work together in real programs. To be fair to him, I think a lot of the people behind incredibly useful and active real-world computer languages such as Guido van Rossum and Yukihiro Matsumoto find themselves in similar positions, but Stroustrup seems to have a particular lack of self-awareness of the limits of his contributions and role in the design and evolution of a language which is now an irredeemable mess filled with too many Ph.D. theses. C++'s metastatic growth began with the early incorporation of Stepanov's Standard Template Library, a very nice design that, initially at least, was grafted into a language not well-suited to implement it. And things have continued from there, with massive, widespread adoption, and many successful projects, but insufficient attention paid to the unsuccessful ones. Meanwhile I have watched so many better languages fail to gain momentum. People choosing languages for implementing important pieces of software would be wise to look at the minority reports of the most experienced engineers - for example, see Torvalds' comments on C++ over the years - rather than the propaganda from the language promoters.