Why The US Government Wants You To Dump C/C++
Understanding the Memory-Safe Programming Stance of the US Government and Why it Matters
For the past few years, the US Cybersecurity and Infrastructure Security Agency (CISA) has been pushing federal agencies to patch known exploited vulnerabilities, with a strong emphasis on prioritising those stemming from memory-safe language deficiencies. You can read a recently published news article in this regard.
This recent directive from CISA is one of many signs of a brewing development in the software world. For years, I've built systems with C and C++, drawn to their raw power and the granular control they offer. But that power is a double-edged sword. One memory allocation error, one unchecked buffer, and what seemed like a solid foundation can collapse, inviting a world of hurt in the form of breaches and exploited vulnerabilities.
The numbers don't lie. That relentless 70% of vulnerabilities Microsoft and Google attribute to memory mismanagement? That’s real! And I feel it. It's a constant cause for concern in my day to day work as an engineer.Â
It's increasingly clear that while C and C++ will always have a place in my toolbox, the landscape is shifting. Memory-safe languages are no longer a futuristic concept– the US government is placing its bets on them for a more secure future.
I can't help but sense that we're at a crossroads. The old ways, while exhilarating, feel increasingly precarious when building the systems our society depends on. Especially in the backdrop of AI and the immense advancements in chip making and the cloud boom.
The Problem with C and C++
Okay, first up, let me make it very clear - I am NOT a C/C++ hater. The first programming language that I learnt was C. The first project that I worked on, used C++. These languages have always had a special place in my heart. C and C++ are undeniably powerful. They provide the kind of fine-grained control over hardware that's essential for certain applications.Â
Having said that, this power does come at a steep price. Let's delve deeper into the issues.
No Bounds Checking
Think of your program's memory like a series of bookshelves. In C and C++, I can freely place a book (data) on any shelf, regardless of whether it's the right size or if it even belongs there. There's no librarian telling me if I'm about to shove a giant encyclopaedia onto a shelf meant for paperbacks. This means I can easily overwrite crucial data in neighbouring memory locations, or worse, corrupt the very instructions that tell my program what to do.
Manual Memory ManagementÂ
Not only do I decide where to put those books, but I'm also the one who has to remember to remove them when I'm done and mark the shelf as empty. If I forget, shelves remain occupied yet useless (memory leak). Even worse, what if I remove a book and later try to reference it, unaware that a completely different book has been placed there? These are dangling pointers, and they lead to wildly unpredictable behaviour.
Hacker's Toolkit
Vulnerabilities like buffer overflows are classic examples of these issues in action. A buffer overflow occurs when I stuff too much data into a 'bookshelf' meant for a smaller amount. The excess data spills over, potentially overwriting critical control structures. Hackers know how to manipulate this to redirect program execution, essentially forcing the program to run their code instead of mine.
A Simple Buffer Overflow Example
Here's a simplified C code snippet to illustrate:
#include <stdio.h>
int main() {
char name[10]; // A 'shelf' with space for 10 characters
printf("Enter your name: ");
gets(name); // Uh oh! 'gets' doesn't check how much data the user enters
printf("Hello, %s!\n", name);
return 0;
}
If I enter a name longer than 10 characters, the excess spills over, potentially wreaking havoc depending on what was stored in the adjacent memory.
The unsettling truth is that even experienced C and C++ programmers can inadvertently introduce these flaws, and their consequences are devastating for cybersecurity.
Why It Matters for National Security
The memory-related shortcomings of C and C++ aren't just theoretical programming headaches; they have far-reaching, real-world consequences that directly impact national security. Let's break down the dangers.
Critical InfrastructureÂ
Our modern society relies on a complex web of interconnected systems – power grids, transportation networks, financial institutions, and many more. The software underpinning this critical infrastructure is often a mix of legacy code built in C and C++. Any memory-related vulnerability becomes a potential entry point for a malicious actor to disrupt, disable, or even gain control over these vital systems. Imagine the chaos of a widespread power outage caused not by a storm, but a hacker exploiting a buffer overflow.
Espionage and Data Exfiltration
Government agencies, defence contractors, and research institutions handle vast troves of sensitive information, some of which could shift the balance of global power if compromised. When systems safeguarding this data are built using C and C++, attackers have a proven toolkit to exploit. A dangling pointer could become the backdoor through which classified documents, military plans, or groundbreaking research is syphoned away.
Eroding Trust, Elevating Risk
Even in the absence of a successful breach, the mere necessity of constant vigilance against vulnerabilities in C/C++ code erodes trust in the security of our digital infrastructure. Every patch, every alert is a reminder that the foundation could crumble. Nation-states and sophisticated cyber threat actors are acutely aware of these weaknesses, making systems built on this foundation tempting targets.
The Hidden Cost of Insecurity
Securing C/C++ based systems demands enormous resources. This includes continuous code audits to root out potential flaws, expensive penetration testing, and the perpetual scramble to patch newly discovered vulnerabilities. These costs divert money and personnel away from other essential priorities and create a relentless treadmill where organisations always feel a step behind.
History Speaks for Itself
Unfortunately, we don't need hypothetical scenarios to illustrate the risks. There have been plenty of devastating cyber attacks with origins in C/C++ vulnerabilities. Below are two famous examples.
Heartbleed: This infamous bug in OpenSSL (used for internet encryption) stemmed from a simple memory mishandling error in C code, leaving millions of supposedly secure servers open to data theft.
Stuxnet: A piece of highly sophisticated malware, likely state-sponsored, used multiple zero-day exploits (including those stemming from C/C++ weaknesses) to physically damage Iranian nuclear centrifuges.
The choice to rely heavily on C and C++ for mission-critical systems is like constructing a state-of-the-art fortress with a foundation plagued by sinkholes. Yes, you can try to shore it up, but the fundamental instability remains – a constant source of worry and a drain on resources that could be better used elsewhere.
The Government’s Recommendations for Memory-Safe Languages
Recognizing the inherent risks of C and C++, the US government is making a calculated shift. Agencies like the NSA and the Office of the National Cyber Director are strongly advocating for a future where new, critical systems are built with a focus on memory-safe languages. I am listing below some of the key players.
Rust
If you are a seasoned programmer, you may have already heard of Rust. It is not only one of the most upcoming programming languages but also one in most demand right now. Rust offers C-like performance without the burdens of manual memory management. Its compiler employs a rigorous ownership and borrowing system, preventing errors like dangling pointers and buffer overflows at compile-time, drastically reducing the chances of them lurking in released code.
Java and C#
These established languages use garbage collection. They automatically reclaim memory when it's no longer needed, eliminating entire classes of memory errors. While carrying some performance overhead, they're proven for building large-scale, secure systems, making them suitable for many government and enterprise applications. I am personally not a big fan of Java. It’s the one language that I am openly biassed against and I have received plenty of flak for sharing my opinions about it in the past. But that’s just me. If you are a Java lover, go for it! More power to you. Â
Go
Speaking of ‘going’ for it (pun intended), I cannot skip Go in this conversation. There are two things that Google developed in the recent years that I absolutely love - Dart (for Flutter) and Go. I think these programming languages have contributed immensely in their respective fields and have been a great contribution to the programming field.Â
Go prioritises simplicity, readability, and safety. Its garbage collection system and built-in bounds checking offer significant protection against common memory-related pitfalls. I think Go is the best option after Rust for developing modern day system infrastructures, especially for handling complex and computationally heavy systems such as those used for running large scale AI models.
Python and Swift
While these languages are technically in the list, they would personally be a measure of last resort for me. I have reasons to say that, but perhaps those reasons are better shared in a separate article.Â
But having said that, Python and Swift also include memory management safeguards. They're excellent for rapid development and less performance-critical scenarios.
Recommending a Holistic Approach
It's crucial to note that the government isn't suggesting we simply abandon C and C++ overnight. Many critical systems have a vast C/C++ codebase. Rewriting them is often impractical and introduces its own risks. For specific embedded systems or when absolute peak performance is essential, C and C++ might remain the best tool for the job. There are workarounds for their vulnerabilities that might be a better fix rather than doing a ground-up rebuild of the entire system.
Even with safer languages, meticulous testing and code analysis tools are essential. Using safer subsets of C and C++ when they're absolutely necessary. Implementing multiple layers of protection, so even if one safeguard fails, others remain in place.
So it is safe to say that while the US Government (and possibly other governments around the world) are making a push for shifting their codebases away from C/C++, it is very much possible that some of their systems might always remain on C/C++.
The Challenging albeit Necessary Path Forward
While the move towards memory-safe languages is a crucial step for improved cybersecurity, it doesn't come without its fair share of obstacles. Here's what we need to contend with.
The Power of C and C++
These languages aren't going away. Their low-level control and ability to squeeze maximum performance out of hardware make them indispensable in certain domains. Operating systems, device drivers, and embedded systems often still necessitate their use.
Legacy Codebases
Rewriting the vast amount of existing critical software built on C and C++ is a monumental undertaking. It's expensive, time-consuming, and risks introducing new bugs during the conversion process. We'll need strategies for maintaining and securing this code while transitioning to safer alternatives for new projects.
The Learning Curve
Memory-safe languages, especially Rust, introduce new concepts like ownership and borrowing. Even experienced developers will need time to retrain and adjust their thinking. Organisations will need to invest in training and upskilling their workforce.
Talent Pool
While interest in memory-safe languages is growing, the pool of developers highly proficient in them is smaller compared to the abundance of C and C++ programmers. Building a workforce ready for this shift will take time and a targeted effort to nurture expertise.
Ecosystem Maturity
Some memory-safe languages have less comprehensive libraries and tooling support compared to the decades-long development surrounding C and C++. Addressing these gaps is essential for wider adoption.
Acknowledging these challenges isn't about pessimism, but about setting realistic expectations. Organisations need tailored plans to identify where new projects can prioritise memory safety and where existing systems absolutely require C/C++. Increased funding for training, research, and tooling will smooth the transition. Government, industry, and the open-source community must work together to build resources and incentives promoting this move.