What attempts have been made to bring memory safety to C++?

C++ is a powerful and widely used programming language known for its flexibility and performance. However, one of its historical drawbacks has been the lack of built-in memory safety features, which can lead to various types of memory-related bugs such as buffer overflows, dangling pointers, and memory leaks.

This is a known issue that has persisted for decades, and numerous attempts have been made to find a solution. Unfortunately, none have succeeded.

What has been done in the past to enhance memory safety within the language?

Garbage Collector

A Garbage Collector (GC) is a mechanism used in programming languages and runtime environments to automatically reclaim memory that is no longer in use by the program. Its primary purpose is to manage memory allocation and deallocation, relieving developers from the burden of manual memory management and helping to prevent common memory-related errors such as memory leaks and dangling pointers.

For C++, in 2008 a minimal support for garbage collection and reachability-based leak detection was added to C++0x. And since then, many propositions have been suggested. Unfortunately, none of them have resolved all cases, and the garbage collector was definitively removed in C++23

Borrow Chekers

The borrow checker is a key feature of the Rust programming language that enforces memory safety and prevents data races by statically analyzing the ownership and borrowing of references in a program at compile time. It is one of Rust’s core innovations and a fundamental aspect of its ownership model.

So the question is: Why not bring this mechanism to C++?

In 2021, a google chromium team tried to answer this question, and in its conclusion paper, they conclude

It would seem at first glance that we have successfully written C++ borrow checking, with the types defined above. Unfortunately, we have not.

Indeed, many unresolved challenges remain as described in their paper, and the borrow checkers ultimately could not be added to C++.

Runtime Checkers

C++ runtime checks refer to various mechanisms and techniques used to validate program behavior and detect errors during program execution. In C++ there are called sanitizers. They are part of the Clang and GCC compilers and provide runtime instrumentation to catch errors during program execution. These sanitizers are generally used during development and testing phases to identify and fix issues. However, there are not used in production, and unfortunately many cases in production can’t be handled in development phase.

And even in development phase the sanitizers are not very popular and therefore not widely used.

What next?

Currently Stroustrup try to find finally a good solution to this safety problem, it’s called C++ profiles(That is, a set of rules which, when followed, achieve specific safety guarantees.) They’d be defined by the ISO C++ standard, addressing common safety issues like pointers and array ranges.

He’s created a GitHub repository, where people can put suggestions, and where he will put his drafts , so that we can create a community working on getting this kind of stuff done in a reasonable time.

Conclusion:

C++ continues to resist to any attempt to enhance memory safety within the language. However, finding a definitive solution to this significant issue has become increasingly urgent. Perhaps we should consider adding this problem to the Millennium Prize problems 🙂

Make your C++ code more safer by enabling the native compiler Runtime Checks.

Runtime checks in C++ refer to mechanisms or tools used to detect errors, vulnerabilities, or unexpected behavior in a program while it is executing. These checks are performed dynamically during runtime rather than at compile-time and can help identify issues that may not be apparent during static analysis or code review.

In the context of software development the term “sanitizer” refers to this kind of runtime checks. Sanitizers operate by instrumenting code with additional checks or tracking mechanisms to detect common programming mistakes or security vulnerabilities. When an issue is detected, the sanitizer typically provides feedback or generates diagnostic information to assist developers in understanding and resolving the problem.

However, not all C++ developers are aware that almost all C++ compilers provide native runtime checks. Clang, GCC, and the Microsoft compiler offer advanced sanitizers to enhance the safety of your C++ code.

The Microsoft compiler enable by default these runtime cheks in debug mode. However, for clang and gcc you have to enable them manually.

Here are a list of the most popular sanitizers:

  1. AddressSanitizer (ASan): AddressSanitizer detects memory corruption errors such as buffer overflows, use-after-free, and out-of-bounds accesses. It works by allocating a shadow memory region alongside the program’s memory and checking memory accesses against this shadow memory to detect violations.
  2. MemorySanitizer (MSan): MemorySanitizer detects the use of uninitialized memory, which can lead to undefined behavior and security vulnerabilities. It tracks the initialization status of memory locations at runtime and reports any attempts to use uninitialized memory.
  3. UndefinedBehaviorSanitizer (UBSan): UndefinedBehaviorSanitizer detects undefined behavior in C and C++ code, such as integer overflows, null pointer dereferences, and signed integer overflow. It instruments the code to detect and report instances of undefined behavior at runtime.
  4. ThreadSanitizer (TSan): ThreadSanitizer detects data races and other concurrency-related bugs in multithreaded C and C++ code. It works by analyzing the program’s execution to identify conflicting accesses to shared memory by different threads.
  5. DataFlowSanitizer (DFSan): DataFlowSanitizer detects taint-style vulnerabilities by tracking the flow of data through the program and identifying potentially dangerous operations involving tainted data, such as SQL injection or command injection.

Clang

Clang provides a list of options to customize the runtime checks as described here.

For example:

% clang++ -fsanitize=signed-integer-overflow,null,alignment -fno-sanitize-recover=null -fsanitize-trap=alignment a.cc

The program will continue execution after signed integer overflows, exit after the first invalid use of a null pointer, and trap after the first use of misaligned pointer.

Using Clang sanitizers can help identify bugs and vulnerabilities early in the development process, before they manifest as runtime errors or security vulnerabilities in production code. They are particularly valuable for finding difficult-to-diagnose issues that may not be caught by traditional testing methods.

Microsoft C++ Compiler

The microsoft compiler provides also many runtime checks as described here.

When you debug a program that has run-time checks enabled, the default action is for the program to stop and break to the debugger when a run-time error occurs. You can change this default behavior for any run-time check. For more information, see Managing Exceptions with the Debugger.

GCC:

GCC supports a number of command-line options that control adding run-time instrumentation to the code it normally generates. For example, one purpose of instrumentation is collect profiling statistics for use in finding program hot spots, code coverage analysis, or profile-guided optimizations. Another class of program instrumentation is adding run-time checking to detect programming errors like invalid pointer dereferences or out-of-bounds array accesses, as well as deliberately hostile attacks such as stack smashing or C++ vtable hijacking. A complete list of sanitizers are available here.

How we can establish a habit of utilizing C++ sanitizers?

  1. Learn about Sanitizers: Educate yourself and your team about the different types of sanitizers available in C++, such as AddressSanitizer (ASan), UndefinedBehaviorSanitizer (UBSan), and ThreadSanitizer (TSan). Understand how each sanitizer detects specific types of bugs and vulnerabilities in your code.
  2. Integrate Sanitizers into Your Build Process: Make it a standard practice to enable sanitizers during the build process of your C++ projects. Modify your build scripts or configuration files (e.g., CMakeLists.txt) to include compiler flags that enable the desired sanitizers.
  3. Start with a Small Project: Begin by incorporating sanitizers into a small, non-critical project or module within your codebase. This allows you to become familiar with the process without overwhelming yourself or your team.
  4. Enable Sanitizers for Testing and Debugging: Make it a habit to run your tests and debug builds with sanitizers enabled. This helps catch bugs early in the development cycle, making them easier and cheaper to fix.
  5. Review Sanitizer Output Regularly: Pay attention to the output generated by the sanitizers during the build process. Take time to understand the detected issues and their root causes. Use this feedback to improve your code and prevent similar issues in the future.
  6. Incorporate Sanitizers into Code Reviews: Encourage team members to enable sanitizers during code reviews. Discuss any issues detected by the sanitizers and work together to address them.
  7. Provide Training and Support: Offer training sessions or workshops to help team members understand how to use sanitizers effectively. Provide support and guidance as needed, especially for those who are new to using sanitizers.
  8. Document Best Practices: Document best practices for using sanitizers within your organization. Include guidelines on when and how to enable sanitizers, how to interpret sanitizer output, and how to address common issues detected by sanitizers.
  9. Set Goals and Track Progress: Set goals for increasing the usage of sanitizers within your team or organization. Track progress regularly and celebrate milestones to reinforce the habit of using sanitizers.
  10. Continuous Improvement: Continuously evaluate and improve your processes for using sanitizers. Solicit feedback from team members and adapt your approach based on lessons learned.

By following these steps and making the use of sanitizers a standard practice within your team, you can develop a habit of using C++ sanitizers effectively to improve the quality and safety of your code.

What about our emotional relationship with a specific programming language? C++ as example.

The emotional relationship between a developer and a programming language can be quite profound and personal, like to the relationship between a musician and his instrument. This relationship is shaped by various factors and experiences, leading to a complex mix of feelings and attachments.

Developers often feel a sense of comfort and familiarity with a programming language they have been using for a long time. They develop an intimate understanding of its syntax, semantics, and quirks, which can create a feeling of being “at home” when writing code. Emotional attachment to a programming language can fuel passion and motivation in developers. However, it can introduce some risks, like :

Continue reading “What about our emotional relationship with a specific programming language? C++ as example.”

Even the White House wants you to abandon C and C++, It’s time to focus on C++ safety and join the Bjarne initiative.

The C and C++ languages are no longer favored by the highest American authorities. Indeed, the White House wishes for developers to use memory-safe languages. In this report published on Monday, the Office of the National Cyber Director (ONCD) of the White House invites developers to reduce the risk of cyberattacks by using languages without memory vulnerabilities. IT companies “can prevent the introduction of multiple vulnerabilities into the digital ecosystem by adopting secure languages,” the presidency said in a statement. It refers to those that are protected against buffer overflow, out-of-bounds reads, and memory leaks.

Continue reading “Even the White House wants you to abandon C and C++, It’s time to focus on C++ safety and join the Bjarne initiative.”

Top 7 most used C++ idioms (Part1).

Idioms and design patterns are both common solutions to recurring problems in software development, but they differ in scope, granularity, and formality:

  1. Scope:
    • Idioms: Idioms are small, language-specific coding techniques or patterns that address specific programming challenges within a particular programming language. They often involve leveraging language features or conventions to achieve a desired outcome efficiently and effectively.
    • Design Patterns: Design patterns are higher-level, language-agnostic architectural solutions to common design problems in software engineering. They provide general reusable templates for solving design issues and promoting best practices in software design.
  2. Granularity:
    • Idioms: Idioms tend to be more granular and focused on specific coding constructs or techniques within a single programming language. They often involve manipulating language features or syntax to achieve particular goals.
    • Design Patterns: Design patterns are more comprehensive and deal with broader design concepts and relationships between components within a software system. They provide templates for organizing and structuring code at a higher level of abstraction.
  3. Formality:
    • Idioms: Idioms are typically informal and are commonly passed down through experience, code reviews, or programming literature within a specific programming community. They may not always have formal names or documentation.
    • Design Patterns: Design patterns are more formalized and well-documented solutions to common design problems. They often have recognized names, descriptions, and implementation guidelines outlined in literature such as the Gang of Four (GoF) book “Design Patterns: Elements of Reusable Object-Oriented Software.”
Continue reading “Top 7 most used C++ idioms (Part1).”

Are you curious to know where the move feature is used in your C++ projects, on your behalf?

Move semantics is a feature introduced in C++11 that allows more efficient transfer of resources (such as dynamic memory) from one object to another. It addresses the inefficiencies associated with deep copying objects, especially large ones, by allowing objects to “steal” the resources of other objects when possible, rather than duplicating them.

Before C++11, when you assigned one object to another, a copy constructor or assignment operator would be invoked, resulting in a deep copy of the object’s data. This process could be expensive, particularly for large objects or those containing dynamic memory allocations. This feature is particularly useful in scenarios where performance optimization is critical, such as in high-performance computing, game development, and resource-constrained environments.

Move semantics introduces the notion of “rvalue references” and a new concept called “move constructors” and “move assignment operators”.

Here’s how it works:

Continue reading “Are you curious to know where the move feature is used in your C++ projects, on your behalf?”

C++ is now a feature-rich language, Be aware of OverEngeniering

Being aware of overengineering is crucial when working with a feature-rich language like C++. Overengineering occurs when developers introduce overly complex or unnecessary solutions to a problem.

C++ developers could be attempted to use as possible the new features introduced by the new standards. which makes the code finally more complicated than it must be.

Here’s an example to show how C++ metaprogramming can be used to create a type-erased container with arithmetic operations that are evaluated at compile time. While this example show the power and flexibility of C++ metaprogramming techniques. it might seem complicated due to the use of templates, concepts and constexpr functions:

Continue reading “C++ is now a feature-rich language, Be aware of OverEngeniering”

Proposal for the next C++ standards

Modern C++ refers to the evolution of the C++ programming language beyond its original design principles, incorporating newer features, idioms, and best practices that have emerged since the language’s inception.

C++ is standardized by the International Organization for Standardization (ISO). C++ standards are typically released every few years, bringing new features and improvements to the language.

Continue reading “Proposal for the next C++ standards”

Average experience of active C++ development Poll

C++ has a steep learning curve compared to some other programming languages. Its syntax and concepts can be complex, especially for beginners or those transitioning from higher-level languages. C++ may not be as beginner-friendly as some other languages, it offers unparalleled power, flexibility, and opportunities for those willing to invest in learning and mastering its intricacies. 

The level of experience, particularly with active development spanning more than five years, often correlates with a deeper understanding of C++ and its capabilities. Developers who have been actively working with C++ for an extended period tend to have a comprehensive knowledge of the language’s features, nuances, and ecosystem, enabling them to leverage its power effectively in various applications.

Continue reading “Average experience of active C++ development Poll”