Skip to content
Natalia Kazankova

Memory safety bugs: an in-depth look at critical issues

Memory safety vulnerabilities remain among the most widespread and exploited security issues. They occur in C and C++ projects, which are widely used across embedded systems, including automotive, medical devices, and avionics. Read on to learn why they can happen and how to prevent them.

Content

    • What Are Memory Safety Issues
    • Why Memory Safety Matters
    • Real-World Examples of Memory Corruption
    • Example of a Memory Safety Bug
    • How to Detect Memory Corruption

What Are Memory Safety Issues?

Memory safety issues arise when a program accesses memory in an unintended or unsafe way, such as reading from or writing to the wrong location in memory or accessing memory that has already been freed.

These issues commonly arise in languages like C and C++, where manual memory management is required. 

Some common types of memory safety bugs include:

  • Buffer overflows: Writing more data than a buffer can hold. There are three types of buffer overflows: global, stack-based, and heap buffer overflow. Learn the difference here.
  • Use-after-free: Accessing memory after it has been freed.
  • Out-of-bounds access: Reading or writing outside the limits of an array.
  • Double free: Freeing the same memory location twice.
  • Null pointer dereference: Attempting to access memory through a null reference.

During code execution, various factors, including buffer overflows, use-after-free errors, or dangling pointers, can lead to memory corruption, making it a pervasive issue in embedded software.

Why Memory Safety Matters

Embedded systems, often constrained by memory and processing power, are especially susceptible to these problems. Unlike desktop applications, a failure in embedded software can impact physical devices, posing serious risks to users and infrastructure alike.

Memory safety issues aren’t just bugs — they’re often security vulnerabilities. Attackers can exploit these flaws to:

  • Crash programs (Denial of Service)
  • Leak sensitive data (e.g., from adjacent memory)
  • Execute arbitrary code (Remote Code Execution)

According to the 2024 CWE Top 10 KEV Weaknesses List Insights, memory safety remains the #1 type of exploited vulnerability in 2024. 

Memory Safety is the Top Known Exploited Vulnerabilities Category in 2024

 

Real-World Examples of Memory Corruption 

Let’s look at a few real-life examples of memory corruption's impact.

In Industrial Control Systems, the Stuxnet worm is a well-known example of memory corruption exploitation.

  • Discovered in 2010, Stuxnet targeted industrial control systems, particularly in Iran's nuclear program.
  • It exploited multiple zero-day vulnerabilities, including memory corruption issues.
  • The worm caused significant damage by manipulating centrifuge speeds in nuclear facilities.

The Toyota Unintended Acceleration case is one of the most significant and well-documented cases of memory corruption impacting safety-critical systems. 

  • In 2013, a jury found Toyota liable for a fatal crash involving a 2005 Camry with unintended acceleration.
  • Expert testimony revealed serious defects in the Electronic Throttle Control System (ETCS).
  • Software expert Michael Barr testified that the death of a critical task (“Task X”) due to memory corruption was likely the root cause of the incident.

In 2014, the Heartbleed bug happened in the widely used OpenSSL.

  • Allowed attackers to read sensitive memory contents from affected servers.
  • Exposed passwords, encryption keys, and private user data.
  • Impacted numerous financial institutions, tech companies, and online services.

In 2017, a buffer overflow in Cloudflare’s code led to sensitive user data being leaked. This incident was later dubbed Cloudbleed

  • Caused accidental leakage of memory containing sensitive user data, including passwords and API keys.
  • Triggered by a flaw in the code responsible for parsing web pages.
  • Though not maliciously exploited, the bug underscored the severity of buffer overflows in cloud infrastructure.
    Named “Cloudbleed” due to its similarity to the Heartbleed incident.

Example of a Memory Safety Bug

Let’s take a use-after-free bug as an example. This error happens when a program continues to use memory after it has been freed, leading to memory corruption. Attackers can exploit this to execute arbitrary code or compromise system stability. It’s one of the most severe exploitable vulnerabilities. 

#include <iostream>

int main() {
   int *ptr = new int(10);  // Dynamically allocate memory and assign a value
   std::cout << "Value: " << *ptr << std::endl;  // Print the value

    delete ptr;  // Free the allocated memory

   // Use-after-free: trying to access memory after it's freed
   std::cout << "Accessing freed memory: " << *ptr << std::endl;

   return 0;
}

Explanation

  1. int *ptr = new int(10); allocates memory and initializes it with the value 10.
  2. delete ptr; deallocates that memory.
  3. Attempting to use ptr afterward causes undefined behavior.

To avoid use-after-free errors, always set the pointer to nullptr after freeing it:

delete ptr;

ptr = nullptr;  // Prevents accidental access

Setting the pointer to nullptr ensures that any further access attempts will result in a detectable error, making it easier to debug.

How to Detect Memory Corruption

  • Fuzz Testing

Fuzz testing is the most effective in uncovering memory corruption vulnerabilities. By inputting random or unexpected data, fuzz tests reveal unexpected behavior, improving code resilience against memory corruption. Learn how you can secure C and C++ with fuzz testing here. 

  • Static and Dynamic Analysis

These methods examine code both statically (before execution) and dynamically (at runtime), detecting potential memory corruption issues. Static analysis identifies vulnerabilities before code is executed, while dynamic analysis checks for issues during runtime.

  • C++ Debug Memory Corruption Tools

Debugging tools specifically for C++ help identify memory corruption issues, particularly useful in embedded systems where corrupted memory is a common concern.

  • Memory-Safe Coding Practices

Employing memory-safe practices, like careful bounds checking and using safer memory allocation libraries, is essential to mitigate memory corruption risks.

Secure Your C/C++ Code Against Memory Safety Bugs

If you develop critical products using C/C++, ensure that you uncover all memory safety issues early in the testing process. Read more about fuzz testing here or book a call with Code Intelligence’s experts to see AI-automated fuzzing in action.