As I've been learning Rust through browser-based books, I wanted to test whether it's possible to intentionally crash programs like in C. The result demonstrates that Rust's compiler is remarkably robust.
MacBook Air M2 arm64
docker run -it --rm -v $(pwd):/mnt rust:latest bash
apt update && apt install -y gcc make vim build-essential
We'll systematically test the following aspects:
Test Case | C Language | Rust |
---|---|---|
Access to freed memory | ❌ Crashes/undefined behavior | ✅ Compile-time prevention |
Null pointer dereference | ❌ Segmentation fault | ✅ Option<T> system |
Invalid references | ❌ Undefined behavior | ✅ Borrow checker |
Buffer overflow | ❌ Memory corruption | ✅ Bounds checking |
#include <stdlib.h>
#include <stdio.h>
int main() {
int* p = malloc(sizeof(int));
*p = 10;
free(p);
printf("%d\n", *p); // Undefined behavior!
return 0;
}
fn main() {
let p = Box::new(10);
drop(p);
// println!("{}", *p); // Compile error!
}
Result: Rust prevents this at compile time with ownership rules.
int* p = NULL;
*p = 42; // Segmentation fault
let p: Option<i32> = None;
match p {
Some(value) => println!("{}", value),
None => println!("No value"),
}
Result: Rust's Option type eliminates null pointer dereferences entirely.
int* create_dangling() {
int x = 42;
return &x; // Returns address of local variable
}
fn create_dangling() -> &i32 {
let x = 42;
&x // Compile error: borrowed value does not live long enough
}
Result: Rust's borrow checker prevents dangling references at compile time.
char buffer[10];
strcpy(buffer, "This string is way too long!"); // Buffer overflow
let mut buffer = [0u8; 10];
let data = b"This string is way too long!";
// buffer.copy_from_slice(data); // Panic with bounds check
Result: Rust performs bounds checking and panics safely instead of corrupting memory.
Rust does provide an unsafe
keyword for scenarios requiring low-level control:
unsafe {
let p = 0x12345678 as *const i32;
println!("{}", *p); // This CAN crash
}
However, unsafe blocks are:
Rust's compiler demonstrates remarkable robustness in preventing common memory safety issues that plague C programs. Through its ownership system, borrow checker, and strong type system, Rust eliminates entire classes of bugs at compile time rather than allowing them to manifest as runtime crashes.
While it's possible to write unsafe code in Rust, it requires explicit opt-in and is designed to be rare and auditable. This makes Rust an excellent choice for systems programming where both performance and safety are critical.