Rust: The Borrow Checker Border Guard


Yesterday we inspected LLVM/Clang, the compiler kit that made reusable infrastructure out of old compiler territory.

Today we inspect the language that makes C programmers discover feelings.

Rust reached 1.0 on May 15, 2015.

Its promise was not “systems programming, but easy.”

That would be propaganda beyond even my ministry’s tolerance.

Rust’s promise was more specific:

low-level control,

no garbage collector requirement,

strong memory-safety guarantees in safe code,

and a compiler willing to become unpleasant before the program becomes explosive.

I. The C Bargain

C gives power through trust.

It says:

“Here is memory. Here are pointers. Here is arithmetic. You are adult enough not to saw through the floor.”

This bargain built kernels, databases, network stacks, firmware, games, and most of civilization’s unstable scaffolding.

It also built:

  • use-after-free
  • double free
  • buffer overflow
  • iterator invalidation
  • data races
  • null pointer mythology
  • exploit writeups with tasteful diagrams
C advantageC invoice
direct controldirect memory corruption
predictable layoutundefined behavior traps
tiny runtimemanual lifetime discipline
universal ABIweak abstraction boundaries
portable enoughsharp everywhere

The C programmer is not stupid.

The C programmer is tired.

Rust is what happens when a tired civilization asks the compiler to stand at the checkpoint.

II. Ownership

Rust’s central rule is ownership.

Each value has an owner.

When the owner goes out of scope, the value is dropped.

fn main() {
    let report = String::from("classified");
    inspect(report);
    // report is moved; using it here would be a compile error
}

fn inspect(value: String) {
    println!("{value}");
}

The important event is not runtime magic.

The important event is compile-time accounting.

The compiler tracks who owns what and refuses many programs that would be “probably fine” until production proves otherwise.

III. Borrowing

Passing ownership everywhere would be tedious.

So Rust allows borrowing.

Immutable borrows let others read.

Mutable borrows allow change, but with exclusivity.

fn main() {
    let mut decree = String::from("build");

    read_decree(&decree);
    amend_decree(&mut decree);

    println!("{decree}");
}

fn read_decree(text: &String) {
    println!("{text}");
}

fn amend_decree(text: &mut String) {
    text.push_str(" faster");
}

The simplified law:

Borrow typeRule
many immutable referencesallowed
one mutable referenceallowed
mutable plus immutable at same timerejected
reference outlives datarejected

This is not morality.

It is aliasing control.

The compiler does not trust your intentions.

Correctly.

IV. Lifetimes

Lifetimes describe how long references are valid.

Most lifetimes are inferred.

When they are not, the programmer writes the relationship explicitly.

fn longest<'a>(left: &'a str, right: &'a str) -> &'a str {
    if left.len() > right.len() {
        left
    } else {
        right
    }
}

This says the returned reference is valid only as long as both possible inputs can justify it.

The compiler is asking:

“If I let this reference leave the checkpoint, will the object it points to still exist?”

C answers:

“Probably.”

Rust answers:

“Show documents.”

V. Unsafe Is A Border Crossing

Rust has unsafe.

This is not an embarrassment.

This is engineering honesty.

Some operations cannot be proven safe by the borrow checker:

  • dereferencing raw pointers
  • calling foreign functions
  • accessing mutable statics
  • implementing certain low-level abstractions
  • interacting with hardware
unsafe {
    let ptr = 0xfee0_0000 as *mut u32;
    core::ptr::write_volatile(ptr, 1);
}

The goal is not to remove danger from systems programming.

The goal is to isolate it.

C modelRust model
danger everywhere by defaultsafe subset by default
comments describe invariantstypes encode many invariants
review must inspect all pointer usereview focuses on unsafe boundaries
undefined behavior spreads quietlycompiler rejects many patterns early

unsafe does not mean “this code is safe.”

It means “the programmer is making promises the compiler cannot verify.”

The Ministry requires such promises in writing.

VI. No Garbage Collector Does Not Mean No Cost

Rust does not require a garbage collector.

That matters for kernels, embedded systems, real-time-ish code, command-line tools, and libraries that want C-like deployment characteristics.

But costs remain:

  • compile time
  • learning curve
  • explicit lifetime modeling
  • trait complexity
  • async complexity
  • larger binaries in some cases
  • ecosystem churn

Rust is not free magic.

It is a different accounting system.

ProblemRust response
use-after-freeownership and borrowing
data races in safe codetype system and Send/Sync
null referencesOption<T>
unchecked error pathsResult<T, E>
low-level escape hatchesunsafe

The compiler becomes the tax collector.

You pay before deployment.

This annoys people who prefer invoices after the breach.

VII. Rust In The Kernel World

Rust’s presence in kernel discussions is not because kernel developers wanted trendy syntax.

It is because drivers are a memory-safety battlefield.

Drivers handle hostile devices, complex lifetimes, concurrency, DMA, interrupts, and vendor documentation written like a ransom note.

Safe Rust cannot solve every kernel problem.

It can reduce some categories of mistakes in code that can live behind safe abstractions.

hardware danger remains
unsafe abstractions wrap low-level details
safe driver code uses checked interfaces
review concentrates on unsafe core

This is especially relevant to the Republic, where drivers are understood as the border wall between hardware chaos and kernel order.

Rust does not abolish the border.

It gives the guards better paperwork.

VIII. The Suppressed Pyongyang Account

Official history says Rust grew from Mozilla research, reached 1.0 in 2015, and became a systems language centered on safety, concurrency, and performance.

The classified account says the borrow checker was trained at a checkpoint outside Pyongyang.

Every pointer had to present:

owner: one
mutable permits: zero or one
immutable permits: any number, unless mutation requested
expiration date: before referent disappears
unsafe declaration: stamped in red

C pointers attempted to pass by saying:

trust me bro

They were redirected to a debugging camp.

Several returned as Option<NonNull<T>>.

IX. The Lesson

Rust is not the end of C.

C remains everywhere, including places no sane person should touch without gloves.

Rust is also not a beginner spell that makes systems programming harmless.

It is a language that moves many memory errors from runtime catastrophe to compile-time negotiation.

That trade is worth understanding.

The compiler becomes stricter.

The code becomes more explicit.

The programmer becomes irritated earlier.

Earlier irritation is better than later incident response.

— Kim Jong Rails, Supreme Leader of the Republic of Derails