5

At my tiny org, the core engine is C++ due to a compute heavy workload. I need to internally react to NSA's recommendation about replacing C++ with a memory safe language.

They're highlighting the fact that C++ (or C) allows the code to read from or write to any memory address (i.e. pointers). That can lead to bugs like read / write out of bounds, or read / write after delete (dangling pointers). These bugs can then be exploited in production by malicious actors.

I don't think my org can afford to rewrite the codebase in another language in near to medium term, and I am not even sure we need to. As long as we do the following in our codebase, can we claim memory safety? (for the purpose of this question, I want to ignore any other kinds of safety or good coding practices).

  • No heap allocation ourselves. No new / delete
  • No char* for string variables, only std::string
  • Replace static arrays with std::array, dynamic arrays with std::vector
  • No pointers. Pass objects by reference where needed

Anything else?

Edits based on comments received

6/14/24: The code is not running in a highly resource constrained environment like an embedded system. Nor is it super sensitive where failure could harm someone's health or well being

6/14/24: We use Visual Studio and GCC as our compilers. To the extent the compilers would catch something, I don't want to repeat it in our internal guidelines

6/17/24: Safety seems to mean different things to different people. In the context of this question (and NSA's paper), a bug introduced by lack of memory safety is harmful because it can be exploited by malicious actors. Think heart bleed or Morris worm where buffer overflow had a role to play. A program crashing is not the same thing as a program being tricked to do something it wasn't supposed to do (using heart bleed as an example, I would rather have it crash than leak credentials)

6/17/24: The fact that this question is about memory safety, doesn't mean that we don't care about other kinds of safety

6/17/24: Google's Safer Usage of C++ comes quite close to describing both the problems and potential solutions that I am grappling with.

15
  • 1
    This question requires probably a much longer answer than you thought, and some of our hardliners will surely downvote and close-vote it ("needs more focus"). Still, I like it.
    – Doc Brown
    Commented Jun 14 at 14:42
  • 7
    Of course its possible to write memory-safe C++ code, you just can't prove that the code is safe using the type system. You can use the type system + linters + sanitizers + fuzzing to reduce the likelihood of memory safety issues. One thing that you're missing is that the smart pointers can still be nullptr, and that vector doesn't do bounds checks. I wouldn't think about rewriting, but about adopting security-conscious modern C++ practices, and about investigating safer languages for future components.
    – amon
    Commented Jun 14 at 15:51
  • 3
    @JimmyJames. You're right, the remediation needs to make sense to a non-technical audience. There is no immediate consequence of non-compliance, but it can be at some point in future.
    – Dr Phil
    Commented Jun 14 at 16:50
  • 4
    If someone nontechnical is feeling alarmed or worried about this report and nobody has identified any specific risks to the business/customers/etc, then it sounds like the most important thing is reassurance, stakeholder management and communication. You could counter this by pointing out that having a system built around unsafe code doesn't necessarily mean any imminent risk to the business - especially if that code has already proven itself over years. Commented Jun 14 at 19:48
  • 3
    The key think I would make sure the non-technical stakeholders understand is how disastrously bad it will likely go if you attempted to rewrite the entire application in one shot using another language/platform. If it's decided that a rewrite is needed, the first thing to figure out is how you can do it one piece at a time. Otherwise, you need a mitigation strategy. It might need to be someone's job to implement software security practices. There's a lot of information about the things to look out for with C and C++. Largely because there's a lot to look out for.
    – JimmyJames
    Commented Jun 14 at 21:58

4 Answers 4

10

Whether statements like "our C++ codebase is memory safe" are useful is a discussion for itself. Independent of that, your measures to make C++ memory safe are far from sufficient. Many out-of-bound accesses are hard to prevent by simple rules.

For a std container like a vector or a string v, v[i] may refer to pretty arbitrary memory if i is out of bounds. Such accesses cannot be avoided easily. Is the following code safe?

for (auto& x : v)
{
  foo();
  bar(x);
}

It is not, because foo may access a reference of v and resize it such that it moves in memory. Then, using x afterwards is not safe anymore.

You could route all memory accesses through custom containers where each operation includes a bounds check. Even then, you are not safe if you need to account for multithreading and race conditions. Adding locks everywhere may help with that, but it's probably not worth the cost. It may then be cheaper to switch languages. C++ has many strengths, but they come at a price.

You may want to ask yourself (and the stakeholders) whether 100% memory safety is actually necessary. There are more kinds of attacks that can achieve bad results, so focussing on memory safety is a little bit narrow-sighted.

If you want to stick with C++, I'd recommend to follow best practices and coding guidelines like, for example, the CppCoreGuidelines. Additionally, make use of sanitizers and static code analyzers and add a good test suite. Most importantly, educate your team.

1

Before you go in deep, look at what “memory safe” in other languages means. A[i] = 0 with out of range i can overwrite a random memory location. Or it can instantly crash your software. Or it can throw an exception that you can catch (and then how are you going to handle that?). The “badness” of what happens is different, but in either case the assignment should have never happened, and the real problem is the assignment.

Comments: Amon seems to be missing the point. Some code is unacceptable. And in a “memory safe” language most of it is just as unacceptable. Discussing which is worse is pointless when it is unacceptable either way.

9
  • 5
    I don't think this is a helpful take. Memory-safe languages don't magically make code correct, you're right on that. But "the program is guaranteed to crash" is much safer than UB, and at least gives you a decent chance to notice the problem.
    – amon
    Commented Jun 15 at 8:31
  • 4
    “Guaranteed to crash” is in many situations unacceptable. Just like undefined behaviour, which in many cases is exactly the same.
    – gnasher729
    Commented Jun 16 at 23:43
  • 1
    @amon is correct to point out, that UB is less acceptable than crash. UB is much more dangerous specifically because it sometimes does not lead to crash. In other words, there are a lot of situations where crash is acceptable while UB is not.
    – Basilevs
    Commented Jun 17 at 10:10
  • 1
    If safety is so important for OP, UB and crash are probably equally bad
    – Ccm
    Commented Jun 17 at 16:33
  • 1
    UB is much worse than crash. Consider reading data out of an array's range by mistake. Typically it won't crash, since there is some data there, often accessible to the process. This might even pass tests, and yet it may have a very unexpected and unwanted behaviour in production. And this particular example is a source of insane number of security vulnerabilities.
    – freakish
    Commented Sep 14 at 17:51
1

changing the language to make execution "safer" is probably starting in the wrong place.

(Dumbo the elephant held a feather in his trunk and could fly. What if the Ringmaster got feathers for all the big elephants so they could fly too? Wouldn't work.)

the team should agree on a common understanding of what "safety" is for their environment and product, and make a plan to provide the safety. that plan could say that programs have to work differently, and programmers have to pay attention to certain failure modes, and maybe use an existing language differently, or use a new language. then the team can start evaluating how to implement the plan.

New contributor
THVV is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
1

Memory safety in C++

You can easily write memory safe code in C++ if using some recommended practices such as:

  • avoiding raw arrays and prefering vectors
  • avoid raw pointers and prefer smart pointers
  • if using const and const references whenever possible
  • and a few more, like the enforcement of the rule of 3.

The NSA's prudent position is that nothing would prevent someone from using a rogue pointer, or use a reference to an object that lifetime has passed away (for example using it in some lambda, or threaded code). But good and simple coding standards, such as the C++ core guidelines, prevent most of issues here.

Safety is made by people and requires some discipline

My whole point here is that languages are only a part of the system safety. Of course, they can facilitate some practices or give visibility to insecure constructs. But ultimately, people are at the core of safety, and some discipline is required.

For example, there are several standards to strengthen further code written by large teams when developing mission critical systems in C++, such as:

As a counter example, the nicest languages are not exempt of vulnerabilities in the language implementation or from supply-chain attacks via vulnerable popular components that hide insecure features:

24
  • 3
    @Basilevs as long time practitioner having worked with C++ since before templates even existed, and having witnessed the emergence of cleaner ways to do things since modern c++11, I simply do not agree. The main risk with C++ is caused by a lot of teachers around the world who still teach C idioms and malloc() in C++, have not inderstood the C*+ object model and perpetuate UB behaviors and use of raw pointers because they feel powerful in doing so. Such a way of teaching should be considered as a crime.
    – Christophe
    Commented Jun 18 at 7:07
  • 3
    I have 10 years of experience with C++ and worked professionally with it for 6 years I've hit the UB @pschill describes multiple times and there was nothing I could do to predict it. There are NO raw pointers in his example. The UB is very well hidden. The reference to a vector being updated or iterator over it may be obtained indirectly. I perfectly understand the nature of this particular UB and it does not help a bit.
    – Basilevs
    Commented Jun 18 at 8:48
  • 1
    @Basilev but doesn't everybody do tests, whatever the language? Don't we mix here very different problems ? I mean, you can have a similar code like pschils in lemory safe languages like Swift. You wouldn't have UB but you would not iterate on the latest version of v. If this loops would be to calculate insulin dosage, it could mean life or death even if it's not UB in swift. On the other side you can by design prevent these situations in C++ as well. I use for example a lot copies when there is a risk of conflict.
    – Christophe
    Commented Jun 18 at 18:40
  • 1
    At the same time C++ offers const functions to prevent accidental changes of an object's state, which is a very common issue in other languages. What I want to say here is that you cannot generalise your own experience. There are a lot of C++ developments that are not al all driven by SEGV. (but hopefully test driven).
    – Christophe
    Commented Jun 18 at 18:44
  • 1
    @Christophe most critical systems in spacecrafts, rockets and powerplants are written in Ada, not C++. Precisely because of Ada's safety. C++ is s**t language for masochists. Yes, you can write safe code in it. Except the language itself taunts you to do otherwise. Safe pointers? Sure, except most libs still use raw pointers. Good luck with that, or write everything from scratch.
    – freakish
    Commented Sep 14 at 7:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.