HN Debrief

How memory safety CVEs differ between Rust and C/C++

  • Security
  • Programming
  • Rust
  • C++
  • Developer Tools

The post compares memory-safety CVEs in Rust and C or C++ and says the counts are not measuring the same thing. In Rust, a library can get a CVE when safe-looking API usage can reach undefined behavior because an internal `unsafe` block failed to uphold Rust’s safety contract. In C and C++, similar misuse is often dismissed as violating a documented precondition, so it never becomes a CVE even if the outcome is a null dereference, buffer overrun, or other memory error. The curl example in the post is there to show the gap in classification, not to claim Rust has no bugs or that C APIs cannot be hardened.

Do not use CVE totals to compare language security. Look at exploitability, bug class, and reporting norms, and expect Rust ecosystems to surface more issues as CVEs because they treat unsound APIs as security bugs earlier and more aggressively.

Discussion mood

Mostly supportive of the post’s core claim that CVE counts are a poor cross-language metric and that Rust and C or C++ ecosystems classify similar bugs differently. The mood was frustrated with compliance checklists built on CVE totals, broadly favorable to Rust’s stricter safety culture, and skeptical that “modern C++” guidance or optional hardening closes the gap in practice.

Key insights

  1. 01

    CVE totals are breaking security decision making

    Counting CVEs by itself was treated as close to useless because filing behavior, compliance incentives, and disclosure norms vary wildly across ecosystems. The sharp point here is operational, not philosophical. Teams are getting pushed by SOC 2 and similar programs to clear CVE counts as if the number maps cleanly to risk, even when it mostly reflects who bothers to classify bugs formally.

    If you buy software or run compliance reviews, stop using raw CVE counts as a gate. Ask how a vendor triages exploitability and whether the issue is a real attack path or a bookkeeping artifact of stricter reporting.

      Attribution:
    • john_strinlai #1
    • mk89 #1 #2
  2. 02

    Rust safety is partly a reporting culture

    Rust’s advantage is not just the borrow checker. It is a norm that says soundness bugs, unsafe API holes, and even some non-memory safety flaws should be fixed instead of documented away. That changes the denominator. A Rust stdlib TOCTOU bug may become a CVE and get patched quickly, while an equivalent flaw in C++ can sit as accepted background radiation.

    When you compare ecosystems, separate language guarantees from maintainer behavior. Rust’s stricter bug bar can create more short-term vulnerability noise, but it also signals a project that will likely fix sharp edges earlier.

      Attribution:
    • dralley #1
    • afdbcreid #1
  3. 03

    Modern C++ hardening is not a drop-in answer

    The strongest C++ rebuttal in the comments was not that safer patterns exist, but that they are optional, partial, and hard to enforce across real codebases. Hardening flags do not outlaw raw pointer style access, do not comprehensively prevent stale references or iterator invalidation, and do not solve ABI constraints in the standard library. That leaves a large gap between “can write safer C++” and “compiler makes unsafe patterns the exception.”

    If you are deciding between incremental C++ hardening and Rust for new components, price in enforcement cost. Optional safety profiles help, but they do not give you a uniform baseline across a mixed legacy codebase.

      Attribution:
    • okanat #1
    • afdbcreid #1
    • jeffbee #1
  4. 04

    Rust can expose backend compiler bugs more cleanly

    One commenter used an LLVM provenance bug to make a subtle point. Safe Rust can produce a compact reproducer for a miscompile because the frontend rules out a lot of undefined behavior. In C or C++, proving the compiler is wrong is harder because many small test cases are dismissed as UB before the backend bug can even be isolated.

    For teams debugging toolchains, stronger source-level safety rules have a second-order benefit. They narrow the search space when a miscompile appears and make backend defects easier to report convincingly.

      Attribution:
    • tialaramex #1
    • afdbcreid #1
  5. 05

    Rust makes nullability explicit instead of ambient

    The useful distinction was not just “Rust rejects nulls.” It was that Rust forces APIs to opt into absence with `Option`, while C makes nullable pointers the default and leaves non-null intent mostly as documentation or optional annotations like `nonnull` and `static 1`. That changes where bugs show up. In Rust the type signature carries the contract. In C the contract often lives outside the type system.

    When designing APIs in any language, move preconditions into types or machine-checkable annotations wherever possible. Documentation-only contracts are cheap to write and expensive to enforce.

      Attribution:
    • eptcyka #1
    • f33d5173 #1
    • __s #1
    • selfmodruntime #1
  6. 06

    Linux accepted Rust because people did the integration work

    The kernel example was used to puncture a lazy narrative that language choice follows from abstract technical superiority alone. Rust got traction in Linux because the Rust for Linux effort built bindings, documentation, and a process the kernel community could actually adopt. C++ proposals often stop at “the kernel should allow C++” and never clear the practical integration barrier.

    If you want a new language or tool accepted in a conservative codebase, do not lead with theory. Lead with maintained integration, documentation, and a migration path that reduces work for incumbents.

      Attribution:
    • ghosty141 #1
    • tialaramex #1

Against the grain

  1. 01

    Overclassifying bugs as CVEs creates noise

    Treating every type invariant failure or possible panic as a vulnerability can swamp maintainers and consumers with issues that have little standalone security meaning. A library bug is not automatically a security flaw in isolation. Impact depends on whether applications can realistically trigger it, whether it changes attack surface, and whether some larger failure already makes the extra bug irrelevant.

    Build your internal triage around exploitability and deployment context, not the presence of a CVE label. Otherwise you will spend scarce engineering time clearing findings that do not change real-world risk.

      Attribution:
    • fweimer #1
  2. 02

    Rust may trade some memory risk for dependency risk

    A skeptical line of argument said Rust’s thin standard library pushes developers toward deep crate graphs, `build.rs` execution at compile time, and package ownership concerns on crates.io. Others pushed back that this is not uniquely Rust and that actual supply-chain compromise in Rust has been limited so far. The point still lands as a practical warning. Rust’s safety story does not remove the need to govern dependencies aggressively.

    If you adopt Rust, pair it with dependency controls from day one. Audit `build.rs`, cap transitive sprawl, and treat package provenance as part of the security model rather than an unrelated procurement problem.

      Attribution:
    • bitbasher #1 #2
    • galangalalgol #1
    • selfmodruntime #1
  3. 03

    Memory safety is not the whole vulnerability picture

    One commenter argued that most ordinary software is more likely to fail through auth mistakes, exposed secrets, and application logic bugs than through use-after-free exploits. The pushback was that memory safety dominates exploited zero-days in places like browsers and operating systems. Both points can be true. Memory safety matters most where attackers value the target and the code runs close to the machine.

    Match the mitigation to the threat model. Rust has the clearest payoff in parsers, network-facing infrastructure, browsers, kernels, and embedded code. It is not a substitute for fixing auth, secrets handling, or supply-chain hygiene in higher-level application stacks.

      Attribution:
    • jurschreuder #1
    • khuey #1
    • kalaksi #1
    • wahern #1

In plain english

ABI
Application Binary Interface, the low-level rules that let compiled code from different components work together.
API
Application programming interface, the exposed behavior or contract that other code depends on.
borrow checker
Rust’s compile-time system for enforcing ownership and lifetime rules to prevent many memory and concurrency bugs.
build.rs
A Rust build script that can run arbitrary code during compilation to generate code or configure builds.
crates.io
The main public package registry for Rust libraries, which are called crates.
CVE
Common Vulnerabilities and Exposures, a standard identifier for publicly known security flaws.
LLVM
Low Level Virtual Machine, a widely used compiler infrastructure that languages like Rust and Clang build on.
nonnull
A compiler annotation that marks a pointer parameter as not allowed to be null.
Option
A Rust type that explicitly represents either a present value or no value at all.
SOC 2
Service Organization Control 2, a compliance framework used to assess how companies handle security and related controls.
static 1
A C array-parameter annotation that promises the argument points to at least one element, enabling some compile-time checks.
stdlib
Standard library, the built-in library that ships with a programming language.
TOCTOU
Time-of-check to time-of-use, a bug where a condition is checked and then changes before the program uses the result.
UB
Undefined behavior, code whose effects the language standard does not define, letting compilers produce unpredictable and sometimes dangerous results.
unsafe
In Rust, a language feature that allows operations the compiler cannot fully prove safe, placing extra correctness obligations on the programmer.

Reference links

Original post and primary references

Security metrics and memory safety data

Rust safety and soundness references

C++ safety and ecosystem debates

Adoption and package ecosystem references