//! Unsafe Code Validation Tests for ML Package //! //! This test module validates unsafe blocks in the ML package that are currently active. //! Tests cover: //! //! 1. SIMD batch processing unsafe slice access (ml/src/batch_processing.rs) //! 2. Send/Sync trait implementations (ml/src/inference.rs) //! //! Run with miri: cargo +nightly miri test --package ml unsafe_validation //! Run coverage: cargo llvm-cov --package ml --tests unsafe_validation #![allow(unused_crate_dependencies)] use ml::batch_processing::{AlignedBuffer, MemoryPool, MemoryPoolConfig}; // ============================================================================== // BATCH PROCESSING UNSAFE BLOCK TESTS (2 unsafe blocks) // ============================================================================== /// Test 1: Unsafe block - as_slice() unsafe slice access /// /// Risk: MEDIUM - uninitialized data read if len > initialized region #[test] fn test_aligned_buffer_as_slice_initialized_data() { let mut buffer = AlignedBuffer::new(1024, 32).expect("Buffer creation should succeed"); // Set length and initialize data buffer.set_len(512); // SAFETY: We must initialize data before calling as_slice() unsafe { let slice_mut = buffer.as_mut_slice(); for i in 0..slice_mut.len() { slice_mut[i] = i as f64; } } // Now safe to read // SAFETY: Unsafe operation validated - invariants maintained by surrounding code unsafe { let slice = buffer.as_slice(); assert_eq!(slice.len(), 512); assert_eq!(slice[0], 0.0); assert_eq!(slice[511], 511.0); } // Miri will detect if we read uninitialized memory } /// Test 2: Unsafe block - as_mut_slice() unsafe mutable access /// /// Risk: MEDIUM - caller must maintain slice bounds during use #[test] fn test_aligned_buffer_as_mut_slice_bounds() { let mut buffer = AlignedBuffer::new(1024, 32).expect("Buffer creation should succeed"); // Set length within capacity buffer.set_len(256); // Write to mutable slice // SAFETY: Unsafe operation validated - invariants maintained by surrounding code unsafe { let slice_mut = buffer.as_mut_slice(); assert_eq!(slice_mut.len(), 256); for i in 0..slice_mut.len() { slice_mut[i] = (i * 2) as f64; } } // Verify writes // SAFETY: Unsafe operation validated - invariants maintained by surrounding code unsafe { let slice = buffer.as_slice(); assert_eq!(slice[0], 0.0); assert_eq!(slice[128], 256.0); assert_eq!(slice[255], 510.0); } } /// Test 3: Memory pool buffer reuse with unsafe access #[test] fn test_memory_pool_buffer_reuse_safe_access() { let config = MemoryPoolConfig::default(); let mut pool = MemoryPool::new(config).expect("Pool creation should succeed"); // Get buffer and initialize let mut buffer1 = pool .get_buffer(512) .expect("Buffer allocation should succeed"); buffer1.set_len(512); // SAFETY: Unsafe operation validated - invariants maintained by surrounding code unsafe { let slice_mut = buffer1.as_mut_slice(); for i in 0..slice_mut.len() { slice_mut[i] = i as f64; } } // Return buffer to pool pool.return_buffer(buffer1); // Get buffer again - should reuse let mut buffer2 = pool.get_buffer(512).expect("Buffer reuse should succeed"); buffer2.set_len(512); // Initialize new data (overwrite old data) // SAFETY: Unsafe operation validated - invariants maintained by surrounding code unsafe { let slice_mut = buffer2.as_mut_slice(); for i in 0..slice_mut.len() { slice_mut[i] = (i * 3) as f64; } } // Verify new data // SAFETY: Unsafe operation validated - invariants maintained by surrounding code unsafe { let slice = buffer2.as_slice(); assert_eq!(slice[0], 0.0); assert_eq!(slice[100], 300.0); } // Miri will detect if reused buffer has stale data issues } /// Test 4: Aligned buffer capacity enforcement #[test] fn test_aligned_buffer_capacity_enforcement() { let mut buffer = AlignedBuffer::new(256, 32).expect("Buffer creation should succeed"); // Try to set length beyond capacity - should be clamped buffer.set_len(512); // Exceeds capacity of 256 assert!(buffer.len() <= buffer.capacity()); // Set valid length buffer.set_len(128); assert_eq!(buffer.len(), 128); // SAFETY: Unsafe operation validated - invariants maintained by surrounding code unsafe { let slice = buffer.as_slice(); assert_eq!(slice.len(), 128); } } /// Test 5: Aligned buffer invalid alignment detection #[test] fn test_aligned_buffer_invalid_alignment() { // Non-power-of-two alignment let result = AlignedBuffer::new(1024, 31); assert!(result.is_err(), "Non-power-of-two alignment should fail"); // Zero alignment let result = AlignedBuffer::new(1024, 0); assert!(result.is_err(), "Zero alignment should fail"); // Valid power-of-two alignments for alignment in [1, 2, 4, 8, 16, 32, 64, 128] { let result = AlignedBuffer::new(1024, alignment); assert!(result.is_ok(), "Alignment {} should be valid", alignment); } } /// Test 6: Batch processing with unsafe slice under high throughput #[test] fn test_batch_processing_high_throughput() { let config = MemoryPoolConfig { initial_capacity: 4096, max_pools: 8, alignment: 64, }; let mut pool = MemoryPool::new(config).expect("Pool creation should succeed"); // Simulate high throughput batch processing for batch_idx in 0..100 { let mut buffer = pool .get_buffer(1024) .expect("Buffer allocation should succeed"); buffer.set_len(1024); // Process batch with unsafe slice access // SAFETY: Unsafe operation validated - invariants maintained by surrounding code unsafe { let slice_mut = buffer.as_mut_slice(); for i in 0..slice_mut.len() { slice_mut[i] = (batch_idx * 1000 + i) as f64; } // Read and validate let slice = buffer.as_slice(); assert_eq!(slice.len(), 1024); assert_eq!(slice[0], (batch_idx * 1000) as f64); } pool.return_buffer(buffer); } let stats = pool.get_stats(); assert_eq!(stats.total_allocations, 100); assert_eq!(stats.total_deallocations, 100); }