Rustaceans

Exploring Rust: Insights and Expertise from Rustaceans

A Brief History of Rust. Part 1

--

Photo by Ekaterina: https://www.pexels.com/photo/fungus-on-a-leaf-20223372/

It was an ordinary Saturday morning on January 25, 2003, until security expert Aryeh Goretsky received a frantic call from a client. Upon arriving at the company, he found himself amidst a scene of chaos — employees pacing nervously, the IT department in disarray, and phones ringing off the hook.

In the server room, red lights flashed like a disco party gone wrong, and hard disk indicators blinked rapidly, signaling massive amounts of data being read and written. The task manager showed CPU and memory usage maxed out at 100%, while network bandwidth was being devoured faster than a hungry beast. Goretsky quickly realized this was the handiwork of the notorious SQL Slammer worm, exploiting a vulnerability Microsoft had warned about six months earlier.

Acting swiftly, Goretsky instructed the IT staff to pull the plug on all external network connections to contain the spread. What followed was the longest day of his career, as they painstakingly shut down each server, installed the critical patch, and brought them back to life. Although tedious, the cleanup process was surprisingly straightforward since the worm didn’t leave any nasty files behind. By the time the moon rose, all systems were back in action.

The SQL Slammer worm, a digital menace, took advantage of a buffer overflow vulnerability (CVE-2002–0649) in Microsoft SQL Server and Desktop Engine database products, which were written in C++. In a buffer overflow, a program tries to stuff more data into a memory buffer than it can handle. This can lead to all sorts of crazy behavior and even allow malicious code to run amok.

Imagine a medieval castle where each guard has a small notebook to record orders from the king. Each page can hold exactly one order. These pages are like buffers in a computer, with a fixed size (memory capacity).

A buffer overflow is like trying to cram an entire epic poem onto a single page of this notebook. Normally, you’d stop writing when the page is full. But without proper checks, excess content “overflows” onto the next page, potentially overwriting other crucial orders.

In the digital realm, this overflow can crash programs faster than a jester can juggle flaming torches. Worse yet, crafty attackers might intentionally cause an overflow, sneaking in their own “orders” (malicious code) where they don’t belong. It’s as if a spy replaced the guard’s notes with fake orders, leading to chaos in the castle.

This vulnerability is the digital equivalent of leaving your castle drawbridge down, allowing any rogue code to march right in and take over your system. And that’s exactly what the SQL Slammer worm did, turning this simple overflow bug into a kingdom-wide catastrophe.

The worm, like an overzealous partygoer, sent data that was way too big for the target server to handle, causing memory to go haywire and allowing its malicious instructions to take over. It then generated random IP addresses and spread its code to unpatched SQL Servers, which in turn continued the cycle, infecting systems worldwide faster than a viral TikTok video and wreaking havoc on network services.

The SQL Slammer worm unleashed a digital tsunami, triggering widespread Denial of Service (DoS) attacks, crippling thousands of networks, and dramatically throttling global internet traffic. This digital plague spread with breathtaking speed, infecting a staggering 75,000 victims in a mere ten minutes. The worm’s devastation was felt most acutely across Europe, North America, and Asia, with East Asia and India bearing the brunt of its onslaught.

1

The SQL Slammer worm incident in 2003 is like a déjà vu of the Morris worm from 15 years earlier. On November 2, 1988, Robert Tappan Morris unleashed a digital creature that spread like wildfire by exploiting Unix system vulnerabilities, especially the buffer overflow vulnerability in the Finger service, which was written in C. Although Morris didn’t mean to cause chaos, his worm replicated so aggressively that it crippled infected machines, causing widespread disruption and reportedly crashing about 10% of Internet-connected systems. This incident not only highlighted the potential dangers of self-replicating code but also led to the first conviction under the US Computer Fraud and Abuse Act — a legal milestone in the digital age.

Buffer overflow and other memory safety vulnerabilities have been the bane of software written in C and C++. These languages, often chosen for their high-performance capabilities, offer optional memory safety mechanisms rather than mandatory ones, leaving room for potential mishaps.

Mandatory memory safety is like a strict, automated factory safety system. It sets up checkpoints, stops production when hazards are detected, and requires resolution before restart.

Optional memory safety in C/C++ is like a lax, manual system where management allows continuation despite potential hazards, safety tool use is voluntary, and guidelines are scattered like confetti.

From the 1970s to the early 2000s, C and C++ not only dominated the development of system software (including operating systems, device drivers, embedded systems, database engines, and network protocol stacks), but also maintained a leading position in high-performance software development (including web browsers, graphics rendering engines, video processing software, game engines, high-frequency trading systems, and scientific computing tools). These languages offered unparalleled performance, fine-grained resource control, and extensive ecosystem support, including rich libraries, frameworks, and compiler optimizations that catered to diverse application domains. However, their lack of built-in memory safety guarantees, relying instead on manual memory management(such as coding best practices and external static analysis tools), has been a persistent thorn in the side of developers, leading to countless vulnerabilities and security issues throughout the years.

While C and C++ developers can employ best practices and auxiliary tools to enhance memory safety, these measures are optional and not fully enforceable at compile-time. This approach has been a major contributor to memory-related vulnerabilities and crashes in high-performance software, presenting an ongoing challenge for developers and users alike, like a never-ending game of whack-a-mole.

The industry’s struggle with C and C++’s memory safety challenges persisted for decades, like a lingering bad habit. However, the 2000s saw the emergence of new programming languages and tools designed to address these issues while maintaining high performance, gradually shifting the landscape of systems and high-performance programming, like a long-awaited breath of fresh air.

2

One day in 2006, Graydon Hoare, a Canadian C/C++ programmer living in Vancouver, was shocked to find the elevator in his building out of service due to a software crash. As he climbed the 21 flights of stairs to his apartment, Hoare pondered the memory safety issues plaguing C/C++ that likely caused the crash.

C/C++ programmers! Users of system and high-performance software! Is there truly no programming language that can offer us the peace of mind we crave?

He resolved to use his spare time to develop a new programming language that would make memory safety mandatory for the benefit of C/C++ programmers and system and high-performance software users.

Hoare named the language Rust, inspired by rust fungi. These plant pathogens have a complex lifecycle involving multiple hosts, enhancing their ability to survive in diverse environments. Similarly, Rust’s “overengineering” through enforced memory safety rules, though strict, ensures software stability.

Over the next three years, Hoare carefully designed Rust’s key features: memory safety, a strong type system, immutable variables by default, support for multiple paradigms, and different abstractions for different problems. By 2009, Rust was largely feature-complete. To build the Rust compiler, Hoare wrote 38,000 lines of code in OCaml.

Hoare, who worked at Mozilla, demonstrated Rust to the company’s leadership. Impressed, they invested significantly in the project over the next decade. This was motivated by the fact that a large portion of severe vulnerabilities in Mozilla’s Firefox browser were memory-related, something Rust aimed to prevent.

It’s worth noting that Mozilla’s Firefox browser comprised approximately 4.5 million lines of C/C++ code. More significantly, a security vulnerability analysis report released by Mozilla on February 28, 2019, revealed that out of 34 critical or high-risk vulnerabilities, a whopping 32 were memory-related. Hoare’s design of Rust, which made memory safety mandatory, undoubtedly struck a chord with the company’s leadership.

As Rust’s creator, Hoare became the BDFL (Benevolent Dictator For Life) of the language. This title, common in open-source communities, denotes a project leader who retains final decision-making power while striving for consensus to prevent volunteer contributors from splintering off due to disagreements.

3

In 2010, the Rust team embarked on an exciting journey to migrate the compiler from OCaml to a self-hosted version based on LLVM, written entirely in Rust. This ambitious “bootstrapping” milestone was triumphantly achieved in 2011, marking a significant leap forward for the language.

That same year, a Rust team member with a passion for cycling put their creativity in high gear and designed the language’s logo, drawing inspiration from the mesmerizing mechanics of bicycle chainring. The logo beautifully symbolizes Rust’s unwavering commitment to powerful, reliable, and efficient engineering.

Despite his role as the “BDFL,” Hoare found himself in a frustrating tug-of-war with the core team, often losing design debates. In his 2023 blog post, he candidly shared a list of 18 key discussions where his views were overruled, including the following:

Regarding the status of the & symbol, Hoare advocated for making it a “second-class citizen,” used only for parameter passing patterns and not allowed to be returned from functions or placed in structs. He believed this restriction would reduce cognitive load. However, the team decided to elevate the & symbol to a “first-class citizen” — a choice that, while increasing complexity, greatly enhanced Rust’s expressiveness.

Regarding lifetimes, Hoare advocated for fully automated inference without explicit declarations. He believed the complexity of explicit lifetimes outweighed their benefits. Despite this, the team kept explicit lifetimes as a core Rust feature, even though it fell short of achieving fully automatic inference.

Hoare contended that Rust’s grammar had grown excessively complex — a matter he deemed critically important. Despite his initial efforts to maintain a simple, LL(1) grammar, Rust became notoriously difficult to parse. Tasks such as pretty-printing and auto-formatting proved even more challenging. Hoare saw this complexity as a persistent source of issues, rendering Rust only slightly more manageable than C++. He lamented losing pivotal debates on various syntactical elements, including type parameter angle brackets, pattern-binding ambiguities, and rules for semicolons and braces.

Hoare, ever the advocate for simplicity, preferred sacrificing a bit of performance and expressiveness to reduce the cognitive burden on programmers. However, the team’s pursuit of C++-like high performance and “zero-cost abstractions” proved to be an unstoppable force, leaving Hoare strongly opposed but ultimately outnumbered.

Between the action-packed releases of versions 0.2 and 0.4 in 2012, Rust’s type system underwent a thrilling metamorphosis.

Version 0.2, released in March 2012, introduced the concept of classes for the first time.

Merely 4 months later, version 0.3 added support for destructors and polymorphism by introducing interfaces.

Just 3 months after that, version 0.4 introduced traits as the inheritance mechanism. Interfaces were integrated into traits, ceasing to exist as separate entities. Classes were replaced by structs and their implementations.

In 2012, Mozilla and Samsung joined forces to launch Servo, an experimental web browser rendering engine project that showcased Rust’s prowess. Meanwhile, the C/C++ community continued to evolve with the release of C++11 and C11, although their memory safety features remained optional, leaving Rust to shine as the safer alternative.

What did the disagreements between Hoare and the Rust core team portend? How did the global pandemic affect the Rust team’s fate? And what’s the programmer community’s take on Rust? These questions and more will be answered in the next part.

--

--

Rustaceans
Rustaceans

Published in Rustaceans

Exploring Rust: Insights and Expertise from Rustaceans

Bin Wu
Bin Wu

Written by Bin Wu

Craft compelling narratives, design code that resonates with humanity.

No responses yet