Skip to content

First Encounter: Running Safe Code: Code Companion

Reference code for the First Encounter: Running Safe Code lecture. Sections correspond to the lecture document.


Section 1: The Anatomy of a Rust Entry Point

fn main() {
    // The simplest entry point: no arguments, returns unit type ()
    // Rust's runtime has already initialized safely before this runs

    println!("=== Buffer Overflow Prevention in Rust ===\n");

    // ... demonstration code follows
}

The implicit return type is () (unit). For error-handling entry points, you could use fn main() -> Result<(), E> or fn main() -> ExitCode.


Section 2: Module Imports and the Crate Ecosystem

// Import the buffer_overflow module from our crate
use rust_memory_safety_examples::buffer_overflow;

fn main() {
    // Call functions using the module path
    buffer_overflow::safe_array_access();
    //     ^-- module      ^-- function

    buffer_overflow::safe_string_handling();

    buffer_overflow::compare_c_vs_rust();
}

The :: path separator navigates the module hierarchy. The use statement brings the module into scope, allowing buffer_overflow::function() instead of the full path rust_memory_safety_examples::buffer_overflow::function().


Section 3: Documentation Comments and Intent

//! Buffer overflow prevention example
//  ^-- The `!` makes this an INNER doc comment
//      It documents the containing item (the whole file)

// Regular comments use just //
// Doc comments for items below them use ///

use rust_memory_safety_examples::buffer_overflow;

Inner doc comments (//!) become module-level documentation when you run cargo doc. Outer doc comments (///) document the item that follows them.


Section 4: Sequential Demonstration Structure

fn main() {
    // Header with visual separator
    println!("=== Buffer Overflow Prevention in Rust ===\n");
    //                                              ^-- \n adds newline

    // Section 1: Basic array safety
    println!("1. Safe Array Access");
    buffer_overflow::safe_array_access();

    // Section 2: Heap-allocated string safety  
    println!("\n2. Safe String Handling");
    //        ^-- leading newline separates from previous output
    buffer_overflow::safe_string_handling();

    // Section 3: Cross-language comparison
    println!("\n3. C vs Rust Comparison");
    buffer_overflow::compare_c_vs_rust();

    // ... summary follows
}

The println! macro (note the !) accepts format strings with escape sequences. The numbered progression creates a teachable output structure.


Section 5: Function Calls as Safety Boundaries

// These functions return () - they exist for side effects
buffer_overflow::safe_array_access();      // -> ()
buffer_overflow::safe_string_handling();   // -> ()
buffer_overflow::compare_c_vs_rust();      // -> ()

// Each call is a contained experiment:
// - If bounds are violated, Rust panics safely
// - No memory corruption can occur
// - No undefined behavior possible

Functions returning () are common in example code. Production code typically returns Result<T, E> for testability and error propagation via the ? operator.


Section 6: The Summary Output Pattern

    println!("\n=== Key Takeaways ===");

    // Unicode works without imports - Rust strings are UTF-8 by default
    println!("✓ Rust prevents buffer overflows at compile time and runtime");
    //        ^-- Unicode checkmark: U+2713

    println!("✓ Bounds checking is automatic and cannot be bypassed");
    println!("✓ No undefined behavior - panics are safe and recoverable");
    println!("✓ Strings automatically resize - no fixed buffer vulnerabilities");

Rust's String and &str types guarantee valid UTF-8 encoding. The compiler enforces this invariant, making string handling both safe and Unicode-aware by default.


Section 7: Connecting to the Library

Project structure:

rust-memory-safety-examples/
├── Cargo.toml
├── src/
│   ├── lib.rs              <- Library root, exports modules
│   └── buffer_overflow.rs  <- Contains the actual demonstrations
└── examples/
    └── buffer_overflow_prevention.rs  <- THIS FILE (you are here)
// In lib.rs (not shown), something like:
pub mod buffer_overflow;

// This example links against the library via Cargo:
// $ cargo run --example buffer_overflow_prevention

The examples/ directory has special meaning to Cargo. Files here compile as separate binaries that depend on the main library crate.


Section 8: What Running This Code Teaches

// The complete file - notice what's ABSENT:
//! Buffer overflow prevention example

use rust_memory_safety_examples::buffer_overflow;

fn main() {
    println!("=== Buffer Overflow Prevention in Rust ===\n");

    println!("1. Safe Array Access");
    buffer_overflow::safe_array_access();

    println!("\n2. Safe String Handling");
    buffer_overflow::safe_string_handling();

    println!("\n3. C vs Rust Comparison");
    buffer_overflow::compare_c_vs_rust();

    println!("\n=== Key Takeaways ===");
    println!("✓ Rust prevents buffer overflows at compile time and runtime");
    println!("✓ Bounds checking is automatic and cannot be bypassed");
    println!("✓ No undefined behavior - panics are safe and recoverable");
    println!("✓ Strings automatically resize - no fixed buffer vulnerabilities");
}

// What you DON'T see:
// - No manual memory allocation
// - No null checks
// - No buffer size tracking
// - No cleanup code
// - No error-prone pointer arithmetic

The absence of defensive code is the point. Rust's type system and ownership model handle these concerns, letting you focus on logic rather than memory management.


Quick Reference

Element Syntax Purpose
Entry point fn main() Program execution starts here
Module import use crate::module Brings module into scope
Path separator :: Navigates module hierarchy
Inner doc comment //! Documents containing item
Outer doc comment /// Documents following item
Macro call name!() Compile-time code expansion
Unit type () Empty return / no value

Common Entry Point Signatures

fn main() { }                           // Simple, no error handling
fn main() -> Result<(), Error> { }      // Can use ? operator
fn main() -> ExitCode { }               // Explicit exit codes (Rust 1.61+)

Running Examples with Cargo

# Run this specific example
cargo run --example buffer_overflow_prevention

# Run with release optimizations
cargo run --example buffer_overflow_prevention --release

# List all available examples
cargo run --example