The book “Writing Secure Code, 2nd Edition” written by David LeBlanc and Michael Howard, published by Microsoft Press in 2002, was once required reading at Microsoft, following Bill Gates’ “Trustworthy Computing” memo. The fifth chapter of said book is titled “Public Enemy #1: The Buffer Overrun” and it starts with a very interesting historical perspective on the problem, referring to the Morris Worm in 1986 as precedent, and even finding occurrences as far back as the 1960s.
Know Thy Enemy
The C programming language, often referred to as “portable assembly”, provides no guards whatsoever against this enemy. Should you mistakenly (or purposedly) allocate
N bytes of memory, but then write
N + k (where
k is an
unsigned int strictly bigger than zero), you might as well be rewriting the very software you are running, for good or, as it is often the case, for bad.
Each generation of computer scientists has brought new ideas to the table to solve this problem, which arguably has cost the industry more than Sir Tony Hoare’s Billion Dollar Mistake. At the end of the 90s, the emergence of managed execution environments seemed to have provided a final blow to buffer overruns.
Indeed, at the beginning of chapter 18 of the aforementioned book, the author (which one?) begins with an anecdote:
While creating slides for two secure software papers at the November 2001 Microsoft Professional Developer’s Conference, a friend told me that I would soon by (sic) out of a job because once managed code and the .NET Framework shipped, all security issues would go away.. This made me convert the SQL injection demonstration code from C++ to C# to make the point that he was wrong.
Ah, software developers.
Neither Java nor C# brought us fully secure software, even though millions of apps and billions of lines of code were rewritten, once and again, in those modern programming languages. Rewriting software is a widely derided activity: Joel Spolsky, Steve Blank, and Peter Seibel all explained its foolishness. It remains, however, a very popular sport in our industry.
Looking backwards, each decade has had its chosen modern language, the one where the world has been rewritten into, once and again.
- 1960s: Fortran (because IBM!)
- 1970s: BASIC (because Byte Magazine!)
- 1980s: Pascal (because structured programming!)
- 1990s: C++ (because object orientation!)
- 2000s: Java (because World Wide Web!)
Let us play the game of predictions. What is the true modern programming language of the 2020s, that is, the one in which the world will be rewritten into?
It is not C# or Java, who have earned the degree of “boring” even though they have solved the buffer overrun issue with runtime checks. Java is trying to make a comeback these days, and even though for a short while there was an operating system written in Java, people have become too wary of Oracle’s legal team by now.
Les Nouvelles Années Folles
After careful analysis, the language of the 2020s might as well be (and maybe already is) Rust, a language that achieves the rare feat of satisfying both high- and low-level programmers alike.
Rust shows many, if not all, signs of modernity:
It does not feature inheritance, instead relying on composition.
Likewise, it does not rely on exceptions for error handling, proposing a handy
Result generic type instead.
It does not have a garbage collector, instead controlling reference lifecycles and ownership during compilation.
Even though it uses type inference to make code look like scripts, it has such a strong type system it can fight buffer overruns at compile time.
It can be installed in the terminal by piping a script downloaded with
curl from the trusty interwebz.
It includes a ready-to-use library of algorithms and abstractions, appealing to both system and app developers as well, in a “batteries included” kind of approach. And if you do not find what you need, just use its own package manager called
cargo and access to a large array of contributed code; for example, an ORM, a GUI, or an image processing library.
It features built-in unit testing.
Its variables are immutable by default.
It has macros, an intelligent evolution of C macros mixed with C++ template metaprogramming.
Primitive arrays include the length as part of their type, and can be easily initialized in the same line.
Its compiler generates blazingly-fast code, and it can do cross-compilation. It can even generate standalone statically-linked binaries, ready for use in Docker containers. Heck, it can even generate WebAssembly out-of-the-box. With a bit of luck, it might generate climate change-friendly binaries.
It uses curly brackets, and anyway, the
rustfmt tool removes the risk of conflicts around code formatting style preferences.
It does not feature a
goto keyword, respecting Dijkstra’s commandment.
In short, Rust ticks many checkboxes in the modern category.
Let us take a closer look at what the industry is doing with it.
Mozilla (the original creators of Rust) have been busy rewriting parts of their flagship browser in Rust.
Linus Torvalds is convinced Rust will take over the Linux Kernel. In the meantime, one can alias
exa, and run them inside alacritty, all written in Rust. And coreutils in Rust is coming soon, and somebody is even rewriting LaTeX in it, too.
Microsoft, almost 20 years after the “Trustworthy Computing” demo, says memory safety issues (still) are 70% of all security bugs, and therefore argues that Rust is the current best chance for safe systems programming. Such is their interest in Rust that they are a member of the recently created Rust Foundation, and they promote it as a solid alternative for apps running on Kubernetes.
Dropbox is rewriting its sync engine with Rust.
Apple is hiring Rust engineers.
IBM is teaching Rust in their developer website.
Discord is switching from Go to Rust.
Figma runs a Rust-powered backend in production.
The Cloud Native world is steadily favoring Linkerd (written in Rust) over Istio (written in Go) as the service mesh of choice.
Andrew Binstock mentioned Rust in a Dr. Dobb’s magazine article back in 2014, shortly before it shut down.
Rust will invariably solve some issues in today’s programming, including security-related trouble such as Heartbleed or the
goto fail fiasco of 2014. But Rust will invariably introduce new issues, completely unforeseen as of now. And a new, modern programming language will appear in 2050 or 2060 solving those issues, and the rewrite cycle will begin all over again. And people will wonder how come anyone could get anything done in C.
Everybody is raving about Swift, but in reality what I pay more attention to these days is LLVM itself.
I think LLVM is the most important software project today, as measured in its long-term impact. Objective-C blocks, Rust & Swift (…) all of these things were born out or powered by LLVM.
Time will tell if this prediction was right. In the meantime, KubeCon + CloudNativeCon Europe 2021, the main conference of the Kubernetes world, opens up online the same day this article hits the press, featuring this time… a one-day special Cloud Native Rust Day.