rust_memory_safety_examples/
lib.rs

1//! # Rust Memory Safety Examples v2.0
2//!
3//! Comprehensive educational examples demonstrating memory-safe programming patterns
4//! in Rust for financial systems, critical infrastructure, and security-sensitive applications.
5//!
6//! ## Purpose
7//!
8//! This library provides clear, documented examples of how Rust's ownership system
9//! prevents common memory safety vulnerabilities that affect C/C++ systems. Version 2.0
10//! adds CVE case studies, secure programming patterns, and performance benchmarks.
11//!
12//! ## What's New in v2.0
13//!
14//! - **CVE Case Studies**: Real-world vulnerability analysis (Heartbleed, Baron Samedit, etc.)
15//! - **Secure Patterns**: Type-state, capability-based security, secret wrappers
16//! - **Performance Benchmarks**: Measure safety overhead with criterion benchmarks
17//! - **Enhanced Documentation**: Comprehensive explanations with industry references
18//!
19//! ## Comparative Examples
20//!
21//! Each module includes:
22//! - Vulnerable C/C++ code patterns (commented examples)
23//! - Safe Rust equivalents
24//! - Explanations of how Rust prevents the vulnerability
25//! - Real-world CVE references
26//!
27//! ## Running Examples
28//!
29//! ```bash
30//! # Run CVE case studies
31//! cargo run --example cve_case_studies
32//!
33//! # Run secure patterns demonstration
34//! cargo run --example secure_patterns
35//!
36//! # Run benchmarks
37//! cargo bench
38//! ```
39//!
40//! ## Alignment with Federal Guidance
41//!
42//! These examples align with 2024-2025 CISA/FBI/NSA guidance recommending memory-safe
43//! languages for critical infrastructure to eliminate 70% of security vulnerabilities.
44//!
45//! ## Industry Research References
46//!
47//! - Microsoft Security: ~70% of CVEs are memory safety issues
48//! - Google Chrome: ~70% of high-severity bugs are memory safety issues
49//! - CISA: Memory safety roadmap for critical infrastructure (2024)
50//! - NSA: Software Memory Safety Cybersecurity Information Sheet
51
52#![allow(clippy::empty_line_after_doc_comments)]
53#![allow(clippy::mixed_attributes_style)]
54#![allow(dead_code)]
55#![allow(clippy::vec_init_then_push)]
56#![allow(clippy::approx_constant)]
57#![allow(clippy::useless_vec)]
58
59pub mod buffer_overflow_prevention;
60pub mod data_race_prevention;
61pub mod use_after_free_prevention;
62
63/// Module demonstrating buffer overflow prevention
64pub mod buffer_overflow {
65    //! Buffer overflow prevention through bounds checking
66    //!
67    //! In C/C++, buffer overflows are a major security vulnerability.
68    //! Rust prevents these at compile time and runtime.
69
70    /// Safe array access - Rust prevents buffer overflows
71    pub fn safe_array_access() {
72        let data = vec![1, 2, 3, 4, 5];
73
74        // Safe access with bounds checking
75        if let Some(&value) = data.get(10) {
76            println!("Value: {}", value);
77        } else {
78            println!("Index out of bounds - safely handled!");
79        }
80
81        // Panics instead of undefined behavior (can be caught)
82        // let value = data[10]; // Would panic with clear error message
83    }
84
85    /// Safe string handling - no buffer overflows
86    pub fn safe_string_handling() {
87        let mut buffer = String::new();
88
89        // Rust automatically resizes, no fixed buffer overflow
90        for i in 0..1000 {
91            buffer.push_str(&format!("Item {}, ", i));
92        }
93
94        println!("Buffer safely holds {} bytes", buffer.len());
95    }
96
97    /// Comparing C vs Rust buffer handling
98    pub fn compare_c_vs_rust() {
99        // C code (UNSAFE):
100        // char buffer[10];
101        // strcpy(buffer, "This is way too long"); // Buffer overflow!
102
103        // Rust equivalent (SAFE):
104        let buffer = "This is way too long".to_string();
105        let truncated: String = buffer.chars().take(10).collect();
106
107        println!("C: Buffer overflow vulnerability");
108        println!("Rust: Safe truncation - {}", truncated);
109    }
110}
111
112/// Module demonstrating use-after-free prevention
113pub mod use_after_free {
114    //! Use-after-free prevention through ownership
115    //!
116    //! Use-after-free is impossible in safe Rust due to the ownership system.
117
118    /// Ownership prevents use-after-free
119    pub fn ownership_prevents_uaf() {
120        let data = vec![1, 2, 3, 4, 5];
121
122        // Transfer ownership
123        let owned_data = data;
124        // data is now invalid
125
126        // This would not compile:
127        // println!("{:?}", data); // ERROR: value used after move
128
129        println!("Rust prevents use-after-free at compile time");
130        println!("Data safely owned: {:?}", owned_data);
131    }
132
133    /// Borrowing prevents dangling references
134    pub fn borrowing_prevents_dangling() {
135        let data = vec![1, 2, 3, 4, 5];
136
137        // Borrow the data
138        let reference = &data;
139
140        // Can't drop data while reference exists
141        // drop(data); // ERROR: cannot move out of `data` because it is borrowed
142
143        println!("Reference is valid: {:?}", reference);
144        // data dropped here, after reference is done
145    }
146
147    /// Comparing C vs Rust lifetime management
148    pub fn compare_c_vs_rust() {
149        // C code (UNSAFE):
150        // int* ptr;
151        // {
152        //     int x = 42;
153        //     ptr = &x;
154        // }
155        // printf("%d", *ptr); // Use-after-free!
156
157        // Rust equivalent (SAFE - won't compile):
158        /*
159        let ptr: &i32;
160        {
161            let x = 42;
162            ptr = &x; // ERROR: `x` does not live long enough
163        }
164        */
165
166        println!("C: Use-after-free vulnerability");
167        println!("Rust: Compile-time prevention of dangling pointers");
168    }
169}
170
171/// Module demonstrating data race prevention
172///
173/// Data race prevention through ownership and type system
174///
175/// Rust prevents data races at compile time through the type system.
176pub mod data_race {
177    use std::sync::{Arc, Mutex};
178    use std::thread;
179
180    /// Arc and Mutex for safe concurrent access
181    pub fn safe_concurrent_access() {
182        let counter = Arc::new(Mutex::new(0));
183        let mut handles = vec![];
184
185        for _ in 0..10 {
186            let counter_clone = Arc::clone(&counter);
187            let handle = thread::spawn(move || {
188                let mut num = counter_clone.lock().unwrap();
189                *num += 1;
190            });
191            handles.push(handle);
192        }
193
194        for handle in handles {
195            handle.join().unwrap();
196        }
197
198        println!("Final count (safe): {}", *counter.lock().unwrap());
199        println!("No data races possible!");
200    }
201
202    /// Send and Sync traits prevent data races
203    pub fn type_system_prevents_races() {
204        // This would not compile (Rc is not Send):
205        // use std::rc::Rc;
206        // let data = Rc::new(vec![1, 2, 3]);
207        // thread::spawn(move || {
208        //     println!("{:?}", data); // ERROR: Rc cannot be sent between threads
209        // });
210
211        println!("Rust's type system prevents data races at compile time");
212    }
213
214    /// Comparing C vs Rust concurrency
215    pub fn compare_c_vs_rust() {
216        // C code (UNSAFE):
217        // int counter = 0;
218        // // Multiple threads incrementing counter without synchronization
219        // // Result: Data race, undefined behavior
220
221        // Rust equivalent (SAFE):
222        safe_concurrent_access();
223
224        println!("\nC: Data races cause undefined behavior");
225        println!("Rust: Compile-time prevention of data races");
226    }
227}
228
229/// Module demonstrating integer overflow protection
230pub mod integer_overflow {
231    //! Integer overflow detection and prevention
232
233    /// Checked arithmetic prevents silent overflows
234    pub fn checked_arithmetic() {
235        let a: u32 = 4_000_000_000;
236        let b: u32 = 1_000_000_000;
237
238        // Silent overflow in C (undefined behavior)
239        // In Rust debug mode: panics
240        // In Rust release mode with checked_add: returns None
241
242        match a.checked_add(b) {
243            Some(result) => println!("Result: {}", result),
244            None => println!("Overflow detected and handled safely!"),
245        }
246    }
247
248    /// Saturating arithmetic for financial calculations
249    pub fn saturating_arithmetic() {
250        let balance: u32 = 1000;
251        let withdrawal: u32 = 2000;
252
253        // Saturating subtraction (clamps at 0)
254        let new_balance = balance.saturating_sub(withdrawal);
255
256        println!("Balance after withdrawal: {} (saturated)", new_balance);
257    }
258}
259
260/// Module demonstrating null pointer dereference prevention
261pub mod null_pointer {
262    //! Null pointer prevention through Option<T>
263
264    /// Option<T> eliminates null pointer dereferences
265    pub fn option_prevents_null() {
266        fn find_user(id: u32) -> Option<String> {
267            if id == 1 {
268                Some("Alice".to_string())
269            } else {
270                None
271            }
272        }
273
274        // Must explicitly handle None case
275        match find_user(1) {
276            Some(name) => println!("Found user: {}", name),
277            None => println!("User not found"),
278        }
279
280        // Can't accidentally dereference null
281        // let name = find_user(99); // Type is Option<String>
282        // println!("{}", name); // ERROR: can't print Option directly
283    }
284
285    /// Comparing C vs Rust null handling
286    pub fn compare_c_vs_rust() {
287        // C code (UNSAFE):
288        // char* ptr = find_user(99); // Returns NULL
289        // printf("%s", ptr); // Null pointer dereference!
290
291        // Rust equivalent (SAFE):
292        option_prevents_null();
293
294        println!("\nC: Null pointer dereferences cause crashes");
295        println!("Rust: Option<T> forces handling of null cases");
296    }
297}
298
299/// Module demonstrating double-free prevention
300pub mod double_free {
301    //! Double-free prevention through ownership
302    //!
303    //! Double-free errors (freeing the same memory twice) are impossible in Rust
304    //! because the ownership system ensures memory is freed exactly once.
305
306    /// Ownership ensures single free
307    pub fn ownership_prevents_double_free() {
308        let data = vec![1, 2, 3, 4, 5];
309
310        // Data is automatically freed when it goes out of scope
311        // Trying to manually free twice would not compile:
312        // drop(data);
313        // drop(data); // ERROR: use of moved value
314
315        println!("Rust prevents double-free through ownership");
316        println!("Data will be freed exactly once: {:?}", data);
317    } // data freed here automatically
318
319    /// Box demonstrates single ownership
320    pub fn box_single_ownership() {
321        let boxed_value = Box::new(42);
322
323        // Transfer ownership
324        let moved_box = boxed_value;
325
326        // This would not compile:
327        // drop(boxed_value); // ERROR: value used after move
328
329        println!("Boxed value freed exactly once: {}", moved_box);
330    } // moved_box freed here
331
332    /// Comparing C vs Rust memory management
333    pub fn compare_c_vs_rust() {
334        // C code (UNSAFE):
335        // int* ptr = malloc(sizeof(int));
336        // free(ptr);
337        // free(ptr); // Double-free!
338
339        // Rust equivalent (SAFE - won't compile):
340        ownership_prevents_double_free();
341
342        println!("\nC: Double-free vulnerabilities");
343        println!("Rust: Compile-time prevention of double-free");
344    }
345}
346
347/// Module demonstrating uninitialized memory prevention
348pub mod uninitialized_memory {
349    //! Uninitialized memory prevention through initialization requirements
350
351    /// All variables must be initialized
352    pub fn initialization_required() {
353        // This would not compile:
354        // let x: i32;
355        // println!("{}", x); // ERROR: use of possibly uninitialized variable
356
357        // Must initialize
358        let x: i32 = 42;
359        println!("Value is always initialized: {}", x);
360    }
361
362    /// Uninitialized array prevention
363    pub fn array_initialization() {
364        // C code (UNSAFE):
365        // int arr[100];
366        // printf("%d", arr[0]); // Reading uninitialized memory!
367
368        // Rust equivalent (SAFE):
369        let arr = vec![0; 100]; // Initialized to zero
370        println!("Array element (initialized): {}", arr[0]);
371
372        // Or must explicitly initialize each element
373        let arr2: Vec<i32> = (0..100).map(|i| i * 2).collect();
374        println!("Array with values: {} elements", arr2.len());
375    }
376
377    /// Struct initialization must be complete
378    pub fn struct_initialization() {
379        struct User {
380            id: u32,
381            name: String,
382            email: String,
383        }
384
385        // This would not compile:
386        // let user = User {
387        //     id: 1,
388        //     name: "Alice".to_string(),
389        //     // ERROR: missing field `email`
390        // };
391
392        // Must initialize all fields
393        let user = User {
394            id: 1,
395            name: "Alice".to_string(),
396            email: "alice@example.com".to_string(),
397        };
398
399        println!("User struct fully initialized: {}", user.name);
400    }
401
402    /// Comparing C vs Rust initialization
403    pub fn compare_c_vs_rust() {
404        println!("C: Uninitialized memory contains garbage values");
405        println!("Rust: Compiler enforces initialization before use");
406
407        initialization_required();
408        array_initialization();
409        struct_initialization();
410    }
411}
412
413/// Module demonstrating memory leak prevention with RAII
414///
415/// Memory leak prevention through RAII (Resource Acquisition Is Initialization)
416pub mod memory_leak {
417    use std::fs::File;
418    use std::io::Write;
419
420    /// RAII ensures resources are cleaned up
421    pub fn raii_file_handling() {
422        // File automatically closed when it goes out of scope
423        {
424            let mut file = File::create("/tmp/test.txt").ok();
425            if let Some(ref mut f) = file {
426                let _ = f.write_all(b"Hello, RAII!");
427            }
428            // File automatically closed here
429        }
430
431        println!("File handle automatically closed (RAII)");
432    }
433
434    /// Drop trait for custom cleanup
435    pub fn drop_trait_cleanup() {
436        struct DatabaseConnection {
437            id: u32,
438        }
439
440        impl Drop for DatabaseConnection {
441            fn drop(&mut self) {
442                println!("Closing database connection: {}", self.id);
443            }
444        }
445
446        {
447            let _conn = DatabaseConnection { id: 1 };
448            println!("Database connection open");
449            // Automatically cleaned up at end of scope
450        }
451
452        println!("Connection automatically closed via Drop trait");
453    }
454
455    /// Comparing C vs Rust resource management
456    pub fn compare_c_vs_rust() {
457        // C code (RISK):
458        // FILE* f = fopen("test.txt", "w");
459        // // Forgot to call fclose(f) - memory/resource leak!
460
461        // Rust equivalent (SAFE):
462        raii_file_handling();
463
464        println!("\nC: Easy to forget resource cleanup (leaks)");
465        println!("Rust: RAII ensures automatic cleanup");
466    }
467}
468
469/// Module demonstrating type confusion prevention
470pub mod type_confusion {
471    //! Type confusion prevention through strong typing
472
473    /// Strong typing prevents type confusion
474    pub fn strong_typing_prevents_confusion() {
475        let integer: i32 = 42;
476        let float: f64 = 3.14;
477
478        // This would not compile:
479        // let result = integer + float; // ERROR: mismatched types
480
481        // Must explicitly convert
482        let result = integer as f64 + float;
483        println!("Explicit conversion required: {}", result);
484    }
485
486    /// Newtype pattern for type safety
487    pub fn newtype_pattern() {
488        struct UserId(u32);
489        struct ProductId(u32);
490
491        let user = UserId(123);
492        let product = ProductId(456);
493
494        // This would not compile:
495        // if user == product { } // ERROR: mismatched types
496
497        println!("NewType pattern prevents mixing different ID types");
498        println!("User ID: {}, Product ID: {}", user.0, product.0);
499    }
500
501    /// Enum prevents invalid states
502    pub fn enum_prevents_invalid_states() {
503        enum ConnectionState {
504            Disconnected,
505            Connecting,
506            Connected { session_id: String },
507            Error { message: String },
508        }
509
510        let state = ConnectionState::Connected {
511            session_id: "abc123".to_string(),
512        };
513
514        // Can't access session_id unless in Connected state
515        match state {
516            ConnectionState::Connected { session_id } => {
517                println!("Connected with session: {}", session_id);
518            }
519            _ => println!("Not connected"),
520        }
521    }
522
523    /// Comparing C vs Rust type safety
524    pub fn compare_c_vs_rust() {
525        println!("C: Type confusion through casting and unions");
526        println!("Rust: Strong type system prevents confusion at compile time");
527
528        strong_typing_prevents_confusion();
529        newtype_pattern();
530    }
531}
532
533#[cfg(test)]
534mod tests {
535    use super::*;
536
537    #[test]
538    fn test_buffer_overflow_examples() {
539        buffer_overflow::safe_array_access();
540        buffer_overflow::safe_string_handling();
541        buffer_overflow::compare_c_vs_rust();
542    }
543
544    #[test]
545    fn test_use_after_free_examples() {
546        use_after_free::ownership_prevents_uaf();
547        use_after_free::borrowing_prevents_dangling();
548        use_after_free::compare_c_vs_rust();
549    }
550
551    #[test]
552    fn test_data_race_examples() {
553        data_race::safe_concurrent_access();
554        data_race::type_system_prevents_races();
555        data_race::compare_c_vs_rust();
556    }
557
558    #[test]
559    fn test_integer_overflow_examples() {
560        integer_overflow::checked_arithmetic();
561        integer_overflow::saturating_arithmetic();
562    }
563
564    #[test]
565    fn test_null_pointer_examples() {
566        null_pointer::option_prevents_null();
567        null_pointer::compare_c_vs_rust();
568    }
569
570    #[test]
571    fn test_double_free_examples() {
572        double_free::ownership_prevents_double_free();
573        double_free::box_single_ownership();
574        double_free::compare_c_vs_rust();
575    }
576
577    #[test]
578    fn test_uninitialized_memory_examples() {
579        uninitialized_memory::initialization_required();
580        uninitialized_memory::array_initialization();
581        uninitialized_memory::struct_initialization();
582        uninitialized_memory::compare_c_vs_rust();
583    }
584
585    #[test]
586    fn test_memory_leak_examples() {
587        memory_leak::raii_file_handling();
588        memory_leak::drop_trait_cleanup();
589        memory_leak::compare_c_vs_rust();
590    }
591
592    #[test]
593    fn test_type_confusion_examples() {
594        type_confusion::strong_typing_prevents_confusion();
595        type_confusion::newtype_pattern();
596        type_confusion::enum_prevents_invalid_states();
597        type_confusion::compare_c_vs_rust();
598    }
599}