The Rust On Modern C++ Is Beginning To Show

In August of 2019, I appeared on the CppCast podcast hosted by Jason Turner and Rob Irving. Among the topics we discussed was the Rust language and how Mozilla was moving away from C++ to Rust due to safety concerns with C++. Rust is the future, we were told by Mozilla. You can see my comments here: CppCast Episode 209: Secure Coding with Matt Butler starting at the 49:11 mark.

My basic premise was that Rust has become the closest replacement for C++ and that’s something that the C++ Standards Committee needs to take seriously given that Rust:

  • has a similar performance curve to C++,
  • is not garbage collected (like Java),
  • easily interfaces with C++, and
  • is considered to be safer than C++.

I still believe that and the last part of the list is key. Most language decisions are made by the company’s CTO (Chief Technical Officer) with input from the company’s CISO (Chief Information Security Officer). In the modern age, both of these positions are responsible for product security and more than few CTOs and CISOs have lost their jobs when the company was penetrated by hackers. This makes them especially sensitive to language safety issues. And yet, few CTOs are security experts and in my 30 years as an engineer I have never met a CISO that was a software engineer. Neither has the skills necessary to evaluate a language for efficacy AND safety.

This leaves them to rely on articles written by outside sources such as Vice’s Motherboard: The Internet Has a Huge C/C++ Problem and Developers Don’t Want to Deal With It. And even the White House is holding forth with their opinion: Global CISOs, White House, Agree 10-Point Open Source Security Plan.

According to the White House Mobility Plan, the problem is that:

It is common for vulnerabilities to result from a program mismanaging memory. These types of vulnerabilities are called memory safety vulnerabilities. Such vulnerabilities exist because certain unsafe languages, mainly C and C++, allow programmers to easily make memory management mistakes. Memory safe languages such as Rust, Go, and Java, do not allow for programmers to make the kinds of mistakes that result in memory safety vulnerabilities. Microsoft estimates that 70% of vulnerabilities in their products over the past decade are memory safety vulnerabilities. Google estimates that 90% of vulnerabilities in Android are memory safety vulnerabilities. The percentages are similar in open source software, with a constant stream of memory safety vulnerabilities being announced and patched.

And the solution is to:

Move the Internet’s most critical software away from unsafe languages such as C and C++ with an efficient strategy that emphasizes upgrading the most security-sensitive components first.

And their champion of the day is explained as:

Much of the world’s most ubiquitous and critical software is lower-level systems software that underlies almost every computing device in the world (e.g. kernels, basic networking
functionality, timekeeping). It’s in banks, hospitals, and government systems. This software is typically written in an unsafe language called C, because for much of computing history C
was the go-to language for systems software development. Because lower-level software has more operational constraints than higher-level software (e.g. it typically cannot tolerate a runtime or memory management via garbage collection), developing a memory safe language suitable for systems software is particularly challenging. The Rust language has met that challenge, however, and is an excellent candidate for replacing C in many systems applications.

From a CTO or CISO’s point of view, it’s an easy call. Move from C++ to Rust and all your security problems are solved plus they co-exist so you can migrate your C++ code at your leisure. So we’re good?

Not quite.

While all of these articles make lots of good points and the C++ Standard’s Committee has not helped itself with regard to safety, the issue is more complicated than the mobility plan lays out. Is Rust safer? Yes, unless you use the unsafe features, which often times you have to. Is C++ unsafe? Yes, but Modern C++ techniques have gone a long way to eliminating the types or memory vulnerabilites we’ve seen in the wild. Is Rust a simpler language? Maybe, right now. But as time goes by all languages grow more complicated as competing requirements add complexity. And Rust has less than a decade of wide-spread use where as C++ has nearly five decades. It’s not as simple as choosing one language over the other based on a single criteria.

Consider this Rust code, by Andrei Gorine from his article C is Alive and Well, that does an insert into an AVL tree:

use std::mem::{replace, swap};
impl<'a, T: 'a + Ord> AvlNode<T> {
   fn rotate_right(&mut self) -> bool {
      if self.left.is_none() {
         return false;

      let left_node = self.left.as_mut().unwrap();
      let left_right_tree = left_node.right.take();
      let left_left_tree = left_node.left.take();

      let mut new_right_tree = replace(&mut self.left, left_left_tree);
      swap(&mut self.value, &mut new_right_tree.as_mut().unwrap().value);
      let right_tree = self.right.take();

      let new_right_node = new_right_tree.as_mut().unwrap();
      new_right_node.left = left_right_tree;
      new_right_node.right = right_tree;
      self.right = new_right_tree;

      if let Some(node) = self.right.as_mut() {


Now, the same implementation in C:

node* rotate_right(node* x)
    if (x == NULL)
        return NULL;

    node* y;
    y = x->left;
    x->left = y->right;
    y->right = x;
    x->ht = height(x);
    y->ht = height(y);

    return y;

I personally prefer the C/C++ implementation, given that Rust’s implementation of pointers is just a train wreck, but it is safer?

Yes. More readable code is, by default, safer.

Before we go further and in the interests of full disclosure: I am an active member of the ISO C++ Standards Committee and was one of the founders of the committee’s Safety and Security Review Group (SSRG). The SSRG consults with the different study groups on areas of safety and security in the language. I am also an active member of the Programming Language Vulnerabilities ISO committee which helps document language vulnerabilities in various languages, including C++. I have used C++ and Modern C++ as my primary development language for more than 30 years.

With that out of the way, let’s look deeper into the issue.

We have to be honest, C++ has a poor safety record and the Standards Committee has done little to help that reputation. Between the ever present Undefined Behavior and the relatively new Ill-Defined, No Diagnostic Required (more later on that), the C++ Standard is a dry river bed filled with shards of broken class, rusty razors and punji sticks. It’s an immensely complicated language designed by experts for experts. And at nearly fifty years old, it requires an immense amount of work just to keep it from collapsing under its own weight.

If you stop there, the deal is done.

But one of the major movements in C++ is the move to Modern C++. Starting with C++11, the committee began building in Zero Overhead Abstractions and safer constructs, including:

  • adding unique and shared pointers that automatically control memory lifetime,
  • adding Concepts that allow for compile time validation of template arguments which make interfaces safer,
  • adding atomic locking to easily protect shared variables,
  • adding variadic templates that are a safer alternative to variadic functions,
  • adding strongly-typed enumerations that are safer than standard enumerations,
  • adding ranges that provide zero overhead abstractions that eliminates direct memory access, iterators, et al,
  • adding a new concurrency library that is safer than hand-rolled libraries, and
  • adding designated initializer lists that make variable initialization compile-time enforced.

On the downside, the C++ Standard Committee has:

  • not reigned in the exploding complexity of the language standard,
  • not reigned in the use of Undefined Behavior (which it inherited from C), and
  • added Ill-Formed, No Diagnostic Required.

Undefined Behavior is when the compiler can change code, eliminate code or simply crash under specific, often highly opaque, circumstances. Ill-Formed, No Diagnostic Required is just a train wreck. When a program is ill-formed, you get a compiler error. With Ill-Formed, NDR you have an ill-formed program but the compiler doesn’t emit an error. The program compiles but the compiled code is invalid and will likely crash when you get to that point.

It’s easy to claim that Rust is THE future and everyone that works with C++ needs to move over immediately. But, right now Rust is in its infancy and before your rush out and jump on the Rust bandwagon (like we all did with Java), consider:

  • Rust has only been around for a decade,
  • There is considerable uncertainty in the future of Rust given the turbulence on the driving committee,
  • All languages start simple – and start safe, but they rarely stay that way as competing requirements add complexity,
  • Rust still allows developers to make unsafe choices,
  • Rust’s ecosystem is not all Rust – OpenSSL, for example, is written in C and Rust has no other FIPS certified option, and
  • Rust has significant gaps in its security tooling – VeraCode and SonacQube are two examples.

The good news is that the C++ Standards Committee seems to have gotten the message and there are a lot of conversations going on today on this issue. The creation of the Safety and Security Review Group is one positive step as is the movement towards value semantics and a larger role for Modern C++ which is safer. As long as the committee continues to improve safety and security in the language, Modern C++ is a long way from dead. If not, the complexity of the language and the perception that it is unsafe is just going to hasten its obsolescence.

And at that point, Rust really will be the future.