AxisOps Harbour
Labs

Insights

Rust arrives where C had no competitor

The claim that most security vulnerabilities in large C and C++ codebases are memory-safety issues has been made repeatedly by people who have the data. Microsoft's security response centre put it at around 70% of the CVEs it assigns, measured across twelve years of patched vulnerabilities. Chromium reached the same figure from 912 high and critical bugs in its own codebase since 2015, with use-after-free making up half of the memory-unsafety share.

Those are different populations counted different ways, and the fact that they land on the same number is a coincidence rather than corroboration. Take it as two large C++ codebases independently finding that memory safety dominates, not as a law.

That number was never news. The news is that there is finally somewhere else to go.

Why the previous answers failed

Memory safety without garbage collection was well understood in theory long before Rust turned up. The reason it never displaced C was never the theory:

  • Garbage-collected languages solve safety and hand you a pause. For a kernel, a driver or a hard-real-time path that's not a trade available to you.
  • Static analysers on C catch a fraction and produce false positives at a rate that trains people to ignore the output.
  • Safer C dialects needed everybody to adopt them, which is about the hardest deployment model there is.

Rust's contribution is affine types and a borrow checker packaged with a toolchain, a package manager and error messages good enough that an intermediate programmer gets somewhere. The theory was the easy part; the theory is always the easy part.

What it costs you

The advocacy around this gets tiresome, so here is the bill.

  • The learning curve is real, and the borrow checker is properly difficult for anyone whose instincts come from C. It improves, but "it clicks after a few weeks" understates things badly for a whole team.
  • Compile times are not good.
  • unsafe exists and has to exist. Rust doesn't eliminate memory bugs; it confines the code that can cause them to blocks that are marked as such, which makes them reviewable. That's a large improvement and a different claim from "memory safe".
  • The interface to C is where the bugs go. An FFI boundary is unsafe by construction, and a mixed codebase has rather a lot of boundary.

In the kernel

Rust for Linux is the test case that counts, because the kernel is the least forgiving environment going: no standard library, custom allocators, pervasive C interfaces and a maintainer culture with strong opinions.

The interesting engineering question is where the boundary sits, not "is Rust good": how much C API surface has to be wrapped in safe abstractions before writing a driver in Rust is safer rather than just differently shaped. Every wrapper is itself unsafe code that someone has to get right.

That work is ongoing and it's the thing to watch, rather than the language advocacy going on around it.

What this makes possible

Our bet: within five years, writing a new network-facing parser in C will look like a choice that needs defending in review.

That is a bigger deal than it sounds, and here is where it lands.

A whole class of emergency disappears. The out-of-hours call that starts "there's a remote heap overflow in the thing that parses untrusted input" is the most expensive single category of security work in the industry. Image decoders, font shapers, TLS record layers, video demuxers, DNS resolvers: these are where the CVEs live, they are all small and they are all ideal candidates to rewrite. An engineer who no longer spends a fortnight a year on that gets a fortnight back, permanently.

Safety stops costing performance. Previously the choice was unsafe and fast or safe and paused. A device driver, a hypervisor component or an audio path written this way carries no collector and no pause; the bounds checks that survive to runtime cost what they cost, and in practice that lands close enough to C that the argument stops being about speed. That means the safety argument finally wins on hardware that is cheap and small, not just on servers with headroom to spare: a router, a set-top box, a meter, a car. Embedded firmware is where memory-safety bugs are most common and least likely ever to be patched, and it is where a garbage collector was never an option.

Review gets a usable map. grep -rn unsafe on a Rust codebase tells you where the memory-safety risk is concentrated. On a C codebase of the same size, the answer is "everywhere". For anyone who has to audit code they did not write, under a deadline, that difference is the whole job.

Rust makes the same move as a load-time verifier or a bytecode validator, at a different point in the pipeline: establish a property by construction, check it once, then rely on it. Check at compile time and the runtime gets to be cheap. We expect that pattern to keep spreading, because it is the only one that scales to code you did not write and cannot read.

The safety story ends at crates.io

Now the part that should worry you, and it is not the language.

Rust's adoption story depends on Cargo, and Cargo depends on a single default registry. One organisation runs the index, serves the tarballs and decides what can be published, yanked or kept. Flat dependency trees of three hundred crates are normal, which means an ordinary build pulls code from a hundred-odd maintainers through one distribution point. We have watched what a default public registry does to a container ecosystem. The same shape applies here, and the blast radius for a compromise of the registry or of a widely-depended-on crate is the entire language's output.

Vendoring and lockfiles help with reproducibility. They do nothing about trust: pinning a hash guarantees you keep getting the same code, not that the code was ever any good. There is no meaningful namespacing, no mandatory signing and no practical way for a reviewer to audit a transitive tree of that size. Anyone who has shipped a Node application knows where this goes.

The second chokepoint is the toolchain itself. One production-grade compiler, one package manager, one registry and the funding for all of it coming substantially from a handful of very large companies who now have Rust on their critical path. That alignment is useful right now; the interests of a hyperscaler and the interests of someone running ten machines are not permanently the same. The healthy signs to watch for are an independent governance foundation with real money in it, a second compiler implementation and a specification somebody other than the project could implement against. The absence of a written language specification is the gap that matters most, because without one, "Rust" means "whatever rustc does this week".

Vendor the dependencies, build in a container you control and mirror the crates you depend on: an estate that cannot build without a third party's uptime is not an estate you own. The language is a gift. The distribution model is a single point of trust that the language's own safety guarantees say nothing whatsoever about. It is the half that needs the engineering attention now.