TNS
VOXPOP
As a JavaScript developer, what non-React tools do you use most often?
Angular
0%
Astro
0%
Svelte
0%
Vue.js
0%
Other
0%
I only use React
0%
I don't use JavaScript
0%
NEW! Try Stackie AI
Operations / Programming Languages / Security

Secure Coding in C++: Avoid Buffer Overflows and Memory Leaks

The same features that make C++ powerful, like direct memory access, also introduce security risks if not meticulously managed.
Feb 26th, 2025 9:15am by
Featued image for: Secure Coding in C++: Avoid Buffer Overflows and Memory Leaks

Software vulnerabilities can pose serious threats, from data breaches to total system compromises. Writing secure code is essential to reducing these risks and ensuring that applications remain protected against attacks.

Among programming languages, C++ stands out for its performance advantages, driven by low-level memory management. However, this feature makes it inherently vulnerable to buffer overflows and memory leaks. If left unaddressed, these vulnerabilities can lead to application crashes, data exposure and even unauthorized code execution.

Before exploring the pitfalls of buffer overflows and memory leaks, it’s critical to understand what secure coding entails and why it’s particularly vital in C++.

Secure coding minimizes software vulnerabilities while preserving systems’ confidentiality, integrity and availability. Secure coding isn’t optional for a language like C++, which is frequently used in high-performance applications such as system software, embedded systems, game development and AI. It’s essential.

The same features that make C++ powerful, like direct memory access, also introduce security risks if not meticulously managed. These capabilities can lead to memory corruption and open doors to exploitation without strict safeguards. Understanding these risks and adopting secure coding practices is crucial to leveraging C++’s strengths without compromising system security.

For instance, if direct memory access is not handled carefully, this can lead to memory corruption, buffer overflows and leaks.


Take a look at the code above. If the input exceeds the allocated buffer size, it overwrites adjacent memory, potentially allowing attackers to execute malicious code.

Whereas languages like Java and Python have automatic garbage collection that prevents memory leaks, in C++, developers must manually free memory by deleting data. If forgotten, memory accumulates, leading to crashes and degraded performance. In long-running applications such as web servers or embedded systems, memory leaks (like the one below) can gradually consume all available system memory and lead to failure.


Since C++ prioritizes performance over safety, many of its standard library functions (strcpy, sprintf) do not include built-in security mechanisms. Developers must explicitly implement security best practices to prevent vulnerabilities.

Now that we have a general understanding of C++’s security vulnerabilities, let’s examine buffer overflows and memory leaks in detail.

A buffer overflow occurs when more data is written to a buffer (array or memory block) than it can hold, causing adjacent memory to be overwritten. This results in unexpected crashes, data corruption and malicious code execution if an attacker injects code into memory.

To understand this better, look at the code below.


The above code’s input string is longer than the buffer’s size (10 bytes). Since strcpy() doesn’t check boundaries, it writes beyond the buffer, corrupting adjacent memory. This can crash the program or allow attackers to inject malicious code.

Some real-world examples of buffer overflows include the 1988 Morris worm. This was one of the earliest internet worms, and it exploited a buffer overflow vulnerability in the gets() function in Unix. By repeatedly infecting machines, it caused widespread network slowdowns.

The other scenario is the 2014 Heartbleed bug. This vulnerability in OpenSSL’s Heartbeat extension allowed attackers to read sensitive data from memory. An unchecked buffer size caused this flaw, resulting in the leak of passwords, private keys and sensitive user data.

So, how do we mitigate the buffer overflow vulnerability? There are several ways to protect our systems from this mega-flaw.

One of them is using safer string functions. Instead of strcpy(), use strncpy() to specify buffer limits. Refer to the code below.


We can also use bounded input functions. Avoid gets() — use fgets() instead.


The other option is to use modern C++ features such as std::string. Instead of raw character arrays, std::string automatically manages memory.


You can also enable compiler protections, as modern compilers provide protection against buffer overflows.


Lastly, AddressSanitizer can be used to detect buffer overflows.


The above code will detect the overflows during runtime.

Next, let’s look at memory leaks.

A memory leak occurs when a program allocates memory dynamically but never releases it. Over time, the program consumes increasing amounts of memory, leading to performance degradation, system slowdowns and application crashes.

This is normally caused when a developer forgets to free allocated memory. Remember, C++ does not have automatic garbage collection like Python or Java, so forgetting to delete dynamically allocated memory leads to a leak. Refer to the code below.


So to give you context of what is happening, every call to memoryLeak() allocates new memory. Since delete ptr; is missing, the program keeps consuming memory indefinitely as the pointer is not deleted, resulting in memory exhaustion and an eventual system slowdown or crash.

To fix this issue, all we have to do is delete the pointer.


The other common cause is allocating memory inside a loop without freeing it before the next iteration.


To fix this, the array has to be deleted before the next iteration.


In other cases, memory leaks are common in functions returning pointers. When functions return dynamically allocated memory, the caller is responsible for deallocating it.


Lastly, classes that dynamically allocate memory but don’t release it in the destructor are likely to cause memory leaks.


To fix this, add a destructor.


To overcome this, there are a few techniques we can use to safeguard our applications from memory leaks. Let’s explore some of them.

1. Always free dynamically allocated memory. Every “new” must have a corresponding “delete.”


2. Prefer std::vector instead of raw arrays. Instead of new int[100], use a std::vector, which automatically manages memory.


3. Use std::unique_ptr for single objects. A std::unique_ptr automatically frees memory when it goes out of scope.


4.When multiple objects share ownership of dynamically allocated memory, use
std::shared_ptr`.


And lastly, use the RAII idiom (“resource acquisition is initialization”), which ensures memory is allocated and freed within an object’s lifetime.


On top of using these preventative methods, detecting leaks during development is important.

For Mac/Linux users, use Valgrind during execution.


For Windows users, use Visual Studio memory leak detection.


The strengths of C++ are a double-edged sword that might turn fatal if not managed well. Buffer overflows and memory leaks are serious security vulnerabilities that can lead to system crashes, degraded performance and even security breaches. Attackers can exploit buffer overflows to execute arbitrary code, while memory leaks gradually consume system resources, leading to instability. By following secure coding practices — such as bounds checking, using smart pointers and applying RAII principles — developers can harness the power of C++ safely and efficiently. Writing secure C++ code is not just about avoiding bugs, but about building resilient and high-performance software that stands the test of time.

Discover the critical role of caching for developers by exploring Zzwia’s blog post on cutting-edge backend optimization.

Created with Sketch.
TNS DAILY NEWSLETTER Receive a free roundup of the most recent TNS articles in your inbox each day.