rust_memory_safety_examples/
lib.rs

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