Source linked

Why Rust and C/C++ Memory Safety CVEs Don't Compare

kobzol.github.io@systems_wire2 hours ago·Cybersecurity·6 comments

A 5-line C program calling curl_getenv(NULL) segfaults without triggering a CVE, while Rust's compiler would reject it outright. That asymmetry means raw CVE numbers mislead.

rustccppmemory safetycvecurl

Calling curl_getenv(NULL) in C compiles without warnings and segfaults at runtime. That's a memory safety bug, but no sane person would report it as a CVE in curl. Yet swap the NULL for a valid string and a crash would be a major issue. This asymmetry is the unspoken rule of C and C++ vulnerability reporting, and it completely invalidates naive CVE comparisons with Rust.

Why a 5-Line C Program Can Crash Without Being a CVE

Grab the curl networking library, written in C by Daniel Stenberg and maintained for 30 years. Its first documented function curl_getenv accepts a pointer. Pass NULL, and you get a segfault. The function's documentation never says calling it with NULL is forbidden. In C, that's considered "wrong usage" by the application, not a bug in the library. Library authors cannot enumerate every possible misuse because C's type system offers no way to encode contracts like "this argument must be non-null." So the vulnerability is pinned on the caller, and the library gets no CVE.

Contrast that with what would happen if curl were written in Rust. The equivalent safe Rust function would either accept &str (never NULL) or use Option<&str> forcing the caller to handle the None case. The compiler would reject a NULL-like call at compile time. If the library author decided to use unsafe to accept a raw pointer, then any UB caused by passing a null pointer would be the library's responsibility, because unsafe is a conscious choice with documented invariants.

Rust's Compiler Enforces Contracts That C Leaves to Documentation

In C and C++, the burden of correct usage falls on the programmer, backed by API docs that are often incomplete. A single function might have five separate ways to invoke undefined behavior. The CVE system explicitly avoids cataloging all those hypothetical misuses. As the post notes, "we create CVEs for specific misuses of a library, not for the existence of a library API that can be misused." That means the huge surface area for memory safety violations in C/C++ is invisible in CVE counts.

Rust flips this: the compiler enforces most contracts. To trigger memory unsafety, you must reach for unsafe. That unsafe block is a clear signal to auditors, and any UB inside it is a library bug worthy of a CVE. So when someone points to Rust CVEs like the 2023 Cargo vulnerability (a logic bug, not memory safety), they're comparing apples to the orange orchard of implicit C misuses.

The Real Takeaway: CVE Counts Are Apples to Oranges

Comparing raw CVE numbers between Rust and C/C++ systems without this context is worse than meaningless. It actively misleads. The curl example crystallizes the point: the same API call, in one language, produces a crash the library disclaims; in the other language, the compiler prevents the call entirely. The next time someone argues that "Rust still has CVEs, so it's not safer," hand them curl_getenv(NULL) and ask who owns that segfault. The answer is the difference between a language that assumes you'll read the docs and one that forces you to read the types.


Source: Memory safety CVEs differ between Rust and C/C++
Domain: kobzol.github.io

Read original source ->

External source stays available while the OJO article and comment thread stay local.

Comments load interactively on the live page.