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}