Aussie AI

Chapter 3. The Safe C++ Proposal

  • Book Excerpt from "Safe C++: Fixing Memory Safety Issues"
  • by David Spuler

Introducing Safe C++

The movement to address safety issues in the C++ programming language has been spearheaded by major software vendors, notably Microsoft and Google, over many years. However, the issue went mainstream when the U.S. federal government, specifically the White House, went public with policies aimed at addressing memory safety issues in software.

This led to work on extending C++ so that it has full memory-safety with a view to creating an ISO standard for a language called Safe C++. The draft proposal for Safe C++ is available online here:

    https://safecpp.org/draft.html

This is an immense body of work that has been completed over the prior 18 months. The results are not only the proposed standard for Safe C++, but also a compiler that implements the proposal. The expected timeframe for full completion is another 18 months after this announced draft in September, 2024, which puts final completion into early 2026 by my calculations.

Note that there have been several other initiatives in regard to a "Safe C" language, and also "Safe C Standard Library" versions.

However, this is the first initiative for C++ safety that attempts to address memory safety with a Rust-like model of borrows and lifetimes. The main advantages of this policy are:

  • Memory safety guarantees (at compile-time!)
  • Low performance cost (no garbage collection needed)

Note that the performance benefit is not only the lack of garbage collection overhead, but also that the compile-time guarantee of memory safety means that there is not a runtime cost to enforcing pointer safety. For example, pointers and arrays would not need a costly validation of their address at runtime.

The way of achieving this is quite involved, and the draft standard also provides some advice for compiler implementers. The main features of the Safe C++ proposal are examined below.

Goals of Safe C++

In a word: safety. But in a way that extends C++ with features similar to Rust's memory safety guarantees, while maintaining backward compatibility with all the existing C++ code. The over-arching goals are therefore:

  • Reducing memory errors and their consequent failures.
  • Increased security from the absence of memory errors.

The Safe C++ proposal aims to prevent memory errors rather than detecting them. It does so via an intrinsic modification to the memory management model. Some of the memory errors that should be prevented inside the safe sections of code include:

  • Buffer overflows
  • Null pointer dereferences
  • Dangling pointers
  • Array out-of-bounds errors
  • Use-after-free memory errors
  • Double-free errors
  • Memory leaks

Note that memory leaks are resolved by effectively guaranteeing automatic de-allocation of memory. The borrow-based method of managing allocated memory does not require garbage collection, which is an inherent advantage of Rust that is being added to Safe C++.

Safe C++ Extensions

The main methods used for safety in the Safe C++ proposal include:

  • Safe contexts — code is split into safe and unsafe areas.
  • Memory safety — prevention of buffer overflows, array bounds errors, and null pointer derefences.
  • Explicit mutation — clarification of when memory is modified.
  • Borrow checking — guarantees about memory addresses and de-allocation automation.

Note that Safe C++ is inspired by the borrow-lifetimes model in Rust for memory safety, but does not adopt the Rust language syntax. Rather, Safe C++ maintains the C++ style of syntax, while adding various safety-related extensions to the language. Safe C++ also does not adopt other neat features of Rust that are unrelated to safety, such as algebraic data types or pattern matching. Instead, Safe C++ limits its focus to safety-related additions, which is probably more than enough to start with!

Safe C++ Syntax

The Safe C++ syntax builds on standard C++ syntax, so that existing developers only need to learn the extensions. Some of the more interesting features of Rust are not added to Safe C++.

Safe C++ introduces a number of new keywords to the language, such as:

  • safe — mark safe contexts for statements or functions.
  • unsafe — unsafe contexts and also a specifier.
  • mut — explicit mutation contexts indicating memory modification.
  • borrow — use of an object without transferring owernship.
  • owned — marks objects as being "owned" rather than transferred.
  • checked — marks risky areas that are checked at compile-time.

The features of Safe C++ are initially enabled by this line at the top of the C++ code:

    #feature on safety

Blocks of code can be declared as "safe" using that as a keyword:

    safe {
        // code block
    }

In a safe code block, all of the code must follow additional rules in relation to memory safety, such as for pointers and arrays.

Various safe versions of the standard C++ library are available via "std2::" rather than "std::" prefixes. Thus, the Safe C++ proposal requires significant additional changes to the standard C++ libraries.

The safe keyword is not only for code blocks, but can be used as a specifier in declarations. You can declare a function as being "safe" via a special specifier keyword that is part of its type (like "noexcept"):

    void myfunc() safe;

A special keyword "mut" specifies a mutable context, whereby C++ memory allocation is changed to Rust-like semantics with borrows and lifetimes.

Unsafe blocks can be explicitly created inside Safe C++ functions using the "unsafe" keyword. Here's an exmaple: using:

    unsafe {
        // Block of horrible code
    }

The unsafe keyword can also be used in other contexts, such as types or array-deference operators.

Supporting Safe C++

The draft proposal for Safe C++ needs support from the overall C++ community. The intention is to develop the standard and then attempt to ratify it as an official ISO standard. Please take the time to review the draft proposal and give it the full attention that it deserves.

This proposal needs additional support from industry and feedback to make its way through the standards process. It already represents over 18 months of work on both the standards document and a Circle compiler that implements the proposal. This plan is expected to take another 18 months to complete the proposal and to implement a compiler and standard library for Safe C++.

Unfortunately, the Safe C++ language is not here already for businesses to use, and will take some time to come to fruition, with the current estimate putting project completion in early 2026. I'm not recommending a switch to Rust programming in the interim. That would be a massive dislocation in software development efforts, although I'm sure some organizations will make that choice.

Personally, I am recommending a strategy for memory safety that involves doing some short-term pragmatic actions toward C++ quality improvements. There are numerous ways to address memory safety and other areas of weakness in the C++ language, while retaining acceptance performance cost. However, the main problem with this approach is that, although pragmatic in many ways, fully resolving some of the intractible memory safety issues are too compute-expensive to achieve in the current C++ language model. Hence, the long-term goal has to be the compile-time memory safety guarantees, with zero runtime cost, that are achieved in the Safe C++ proposal.

 

Online: Table of Contents

PDF: Free PDF book download

Buy: Safe C++: Fixing Memory Safety Issues

Safe C++ Safe C++: Fixing Memory Safety Issues:
  • The memory safety debate
  • Memory and non-memory safety
  • Pragmatic approach to safe C++
  • Rust versus C++
  • DIY memory safety methods
  • Safe standard C++ library

Get it from Amazon: Safe C++: Fixing Memory Safety Issues