1use crate::core::safe_operations::SafeLock;
11use crate::core::types::TrackingResult;
12use crate::core::unwrap_safe::UnwrapSafe;
13use dashmap::DashMap;
14use serde::{Deserialize, Serialize};
15use std::collections::HashMap;
16use std::sync::{Arc, Mutex};
17
18#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
20pub enum EdgeCaseType {
21 NullPointerAccess,
23 AllocationFailure,
25 StackOverflow,
27 HeapCorruption,
29 DoubleFree,
31 UseAfterFree,
33 BufferOverflow,
35 IntegerOverflow,
37 DeadlockDetection,
39 RaceCondition,
41 InvalidMemoryAccess,
43 ResourceLeak,
45 FfiBoundaryViolation,
47 ThreadSafetyViolation,
49 DataCorruption,
51 TimeoutHandling,
53 ConfigurationError,
55 ResourceExhaustion,
57 Unknown,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
63pub enum EdgeCaseSeverity {
64 Low,
65 Medium,
66 High,
67 Critical,
68 Fatal,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct EdgeCaseOccurrence {
74 pub case_type: EdgeCaseType,
76 pub severity: EdgeCaseSeverity,
78 pub description: String,
80 pub context: HashMap<String, String>,
82 pub stack_trace: Option<Vec<String>>,
84 pub timestamp: u64,
86 pub recovery_action: Option<String>,
88 pub handled_successfully: bool,
90 pub metadata: HashMap<String, String>,
92}
93
94#[derive(Debug, Default, Clone, Serialize, Deserialize)]
96pub struct EdgeCaseStats {
97 pub total_cases_detected: u64,
98 pub cases_handled_successfully: u64,
99 pub cases_failed_to_handle: u64,
100 pub critical_cases: u64,
101 pub fatal_cases: u64,
102 pub recovery_actions_taken: u64,
103 pub false_positives: u64,
104 pub detection_accuracy: f64,
105}
106
107#[derive(Debug, Clone)]
109pub struct EdgeCaseConfig {
110 pub enable_detection: bool,
112 pub enable_auto_recovery: bool,
114 pub max_stored_cases: usize,
116 pub enable_detailed_logging: bool,
118 pub recovery_timeout_ms: u64,
120 pub enable_stats: bool,
122}
123
124impl Default for EdgeCaseConfig {
125 fn default() -> Self {
126 Self {
127 enable_detection: true,
128 enable_auto_recovery: true,
129 max_stored_cases: 1000,
130 enable_detailed_logging: true,
131 recovery_timeout_ms: 5000,
132 enable_stats: true,
133 }
134 }
135}
136
137pub struct EdgeCaseHandler {
139 case_storage: DashMap<u64, Arc<EdgeCaseOccurrence>>,
141 case_counters: DashMap<EdgeCaseType, u64>,
143 #[allow(clippy::type_complexity)]
145 recovery_strategies: Arc<
146 DashMap<
147 EdgeCaseType,
148 Box<dyn Fn(&EdgeCaseOccurrence) -> TrackingResult<String> + Send + Sync>,
149 >,
150 >,
151 stats: Arc<Mutex<EdgeCaseStats>>,
153 config: EdgeCaseConfig,
155 next_case_id: std::sync::atomic::AtomicU64,
157}
158
159impl EdgeCaseHandler {
160 pub fn new(config: EdgeCaseConfig) -> Self {
162 tracing::info!("🛡️ Initializing Edge Case Handler");
163 tracing::info!(" • Detection enabled: {}", config.enable_detection);
164 tracing::info!(
165 " • Auto recovery enabled: {}",
166 config.enable_auto_recovery
167 );
168 tracing::info!(" • Max stored cases: {}", config.max_stored_cases);
169
170 let handler = Self {
171 case_storage: DashMap::with_capacity(config.max_stored_cases),
172 case_counters: DashMap::new(),
173 recovery_strategies: Arc::new(DashMap::new()),
174 stats: Arc::new(Mutex::new(EdgeCaseStats::default())),
175 config,
176 next_case_id: std::sync::atomic::AtomicU64::new(1),
177 };
178
179 handler.initialize_recovery_strategies();
181 handler
182 }
183
184 pub fn handle_edge_case(
186 &self,
187 case_type: EdgeCaseType,
188 severity: EdgeCaseSeverity,
189 description: String,
190 context: HashMap<String, String>,
191 ) -> TrackingResult<u64> {
192 if !self.config.enable_detection {
193 return Ok(0);
194 }
195
196 let case_id = self
197 .next_case_id
198 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
199 let timestamp = self.get_current_timestamp();
200
201 let occurrence = EdgeCaseOccurrence {
203 case_type: case_type.clone(),
204 severity: severity.clone(),
205 description: description.clone(),
206 context,
207 stack_trace: self.capture_stack_trace(),
208 timestamp,
209 recovery_action: None,
210 handled_successfully: false,
211 metadata: HashMap::new(),
212 };
213
214 if self.config.enable_detailed_logging {
216 match severity {
217 EdgeCaseSeverity::Fatal | EdgeCaseSeverity::Critical => {
218 tracing::error!("🛡️ Edge case detected: {:?} - {}", case_type, description);
219 }
220 EdgeCaseSeverity::High => {
221 tracing::warn!("🛡️ Edge case detected: {:?} - {}", case_type, description);
222 }
223 _ => {
224 tracing::info!("🛡️ Edge case detected: {:?} - {}", case_type, description);
225 }
226 }
227 }
228
229 self.case_counters
231 .entry(case_type.clone())
232 .and_modify(|count| *count += 1)
233 .or_insert(1);
234
235 let mut final_occurrence = occurrence;
237 if self.config.enable_auto_recovery {
238 final_occurrence = self.attempt_recovery(final_occurrence)?;
239 }
240
241 let occurrence_arc = Arc::new(final_occurrence);
243 let handled_successfully = occurrence_arc.handled_successfully;
244 self.case_storage.insert(case_id, occurrence_arc);
245
246 self.update_stats(&case_type, &severity, handled_successfully);
248
249 if self.case_storage.len() > self.config.max_stored_cases {
251 self.cleanup_old_cases();
252 }
253
254 Ok(case_id)
255 }
256
257 fn attempt_recovery(
259 &self,
260 mut occurrence: EdgeCaseOccurrence,
261 ) -> TrackingResult<EdgeCaseOccurrence> {
262 let start_time = std::time::Instant::now();
263
264 if start_time.elapsed().as_millis() > self.config.recovery_timeout_ms as u128 {
266 occurrence.recovery_action = Some("Recovery timeout".to_string());
267 occurrence.handled_successfully = false;
268 return Ok(occurrence);
269 }
270
271 if let Some(strategy) = self.recovery_strategies.get(&occurrence.case_type) {
273 match strategy(&occurrence) {
274 Ok(recovery_description) => {
275 occurrence.recovery_action = Some(recovery_description);
276 occurrence.handled_successfully = true;
277 tracing::info!(
278 "🛡️ Successfully recovered from edge case: {:?}",
279 occurrence.case_type
280 );
281 }
282 Err(e) => {
283 occurrence.recovery_action = Some(format!("Recovery failed: {e}"));
284 occurrence.handled_successfully = false;
285 tracing::warn!(
286 "🛡️ Failed to recover from edge case: {:?} - {}",
287 occurrence.case_type,
288 e
289 );
290 }
291 }
292 } else {
293 let default_recovery = self.default_recovery_strategy(&occurrence)?;
295 occurrence.recovery_action = Some(default_recovery);
296 occurrence.handled_successfully = true;
297 }
298
299 Ok(occurrence)
300 }
301
302 fn default_recovery_strategy(&self, occurrence: &EdgeCaseOccurrence) -> TrackingResult<String> {
304 match occurrence.severity {
305 EdgeCaseSeverity::Fatal => {
306 tracing::error!("🛡️ Fatal edge case detected, initiating graceful shutdown");
308 Ok("Graceful shutdown initiated".to_string())
309 }
310 EdgeCaseSeverity::Critical => {
311 tracing::error!("🛡️ Critical edge case detected, isolating affected components");
313 Ok("Component isolation applied".to_string())
314 }
315 EdgeCaseSeverity::High => {
316 tracing::warn!(
318 "🛡️ High severity edge case detected, applying conservative measures"
319 );
320 Ok("Conservative measures applied".to_string())
321 }
322 _ => {
323 tracing::info!("🛡️ Edge case logged, continuing normal operation");
325 Ok("Logged and continued".to_string())
326 }
327 }
328 }
329
330 pub fn get_edge_case(&self, case_id: u64) -> TrackingResult<Arc<EdgeCaseOccurrence>> {
332 match self.case_storage.get(&case_id) {
333 Some(occurrence) => Ok(Arc::clone(occurrence.value())),
334 None => Err(crate::core::types::TrackingError::DataError(format!(
335 "Edge case with ID {case_id} not found",
336 ))),
337 }
338 }
339
340 pub fn get_cases_by_type(&self, case_type: &EdgeCaseType) -> Vec<Arc<EdgeCaseOccurrence>> {
342 self.case_storage
343 .iter()
344 .filter_map(|entry| {
345 if &entry.value().case_type == case_type {
346 Some(Arc::clone(entry.value()))
347 } else {
348 None
349 }
350 })
351 .collect()
352 }
353
354 pub fn get_stats(&self) -> TrackingResult<EdgeCaseStats> {
356 match self.stats.safe_lock() {
357 Ok(stats) => Ok(stats.clone()),
358 Err(e) => {
359 tracing::warn!("Failed to get edge case stats: {}", e);
360 Ok(EdgeCaseStats::default())
361 }
362 }
363 }
364
365 pub fn get_case_counts(&self) -> HashMap<EdgeCaseType, u64> {
367 self.case_counters
368 .iter()
369 .map(|entry| (entry.key().clone(), *entry.value()))
370 .collect()
371 }
372
373 pub fn register_recovery_strategy<F>(&self, case_type: EdgeCaseType, strategy: F)
375 where
376 F: Fn(&EdgeCaseOccurrence) -> TrackingResult<String> + Send + Sync + 'static,
377 {
378 self.recovery_strategies
379 .insert(case_type, Box::new(strategy));
380 tracing::info!("🛡️ Registered custom recovery strategy");
381 }
382
383 pub fn clear_cases(&self) {
385 self.case_storage.clear();
386 self.case_counters.clear();
387
388 match self.stats.safe_lock() {
389 Ok(mut stats) => {
390 *stats = EdgeCaseStats::default();
391 }
392 Err(e) => {
393 tracing::warn!("Failed to reset stats during clear: {}", e);
394 }
395 }
396
397 self.next_case_id
398 .store(1, std::sync::atomic::Ordering::Relaxed);
399 tracing::info!("🛡️ Cleared all edge cases");
400 }
401
402 fn initialize_recovery_strategies(&self) {
404 self.register_recovery_strategy(EdgeCaseType::NullPointerAccess, |_| {
406 Ok("Null pointer access prevented, using safe default".to_string())
407 });
408
409 self.register_recovery_strategy(EdgeCaseType::AllocationFailure, |_| {
411 Ok("Allocation failure handled, using alternative allocation strategy".to_string())
412 });
413
414 self.register_recovery_strategy(EdgeCaseType::DoubleFree, |_| {
416 Ok("Double free prevented, memory tracking updated".to_string())
417 });
418
419 self.register_recovery_strategy(EdgeCaseType::UseAfterFree, |_| {
421 Ok("Use after free prevented, access blocked".to_string())
422 });
423
424 self.register_recovery_strategy(EdgeCaseType::BufferOverflow, |_| {
426 Ok("Buffer overflow prevented, bounds checking applied".to_string())
427 });
428
429 self.register_recovery_strategy(EdgeCaseType::IntegerOverflow, |_| {
431 Ok("Integer overflow prevented, safe arithmetic used".to_string())
432 });
433
434 self.register_recovery_strategy(EdgeCaseType::DeadlockDetection, |_| {
436 Ok("Deadlock resolved, lock ordering corrected".to_string())
437 });
438
439 self.register_recovery_strategy(EdgeCaseType::RaceCondition, |_| {
441 Ok("Race condition mitigated, synchronization applied".to_string())
442 });
443
444 self.register_recovery_strategy(EdgeCaseType::ResourceLeak, |_| {
446 Ok("Resource leak prevented, cleanup performed".to_string())
447 });
448
449 self.register_recovery_strategy(EdgeCaseType::FfiBoundaryViolation, |_| {
451 Ok("FFI boundary violation handled, safe wrapper applied".to_string())
452 });
453
454 tracing::info!(
455 "🛡️ Initialized {} default recovery strategies",
456 self.recovery_strategies.len()
457 );
458 }
459
460 fn cleanup_old_cases(&self) {
462 let target_size = self.config.max_stored_cases * 3 / 4; let current_size = self.case_storage.len();
464
465 if current_size <= target_size {
466 return;
467 }
468
469 let mut cases_with_timestamps: Vec<(u64, u64)> = self
471 .case_storage
472 .iter()
473 .map(|entry| (*entry.key(), entry.value().timestamp))
474 .collect();
475
476 cases_with_timestamps.sort_by_key(|(_, timestamp)| *timestamp);
477
478 let to_remove = current_size - target_size;
480 for (case_id, _) in cases_with_timestamps.iter().take(to_remove) {
481 self.case_storage.remove(case_id);
482 }
483
484 tracing::info!("🛡️ Cleaned up {} old edge cases", to_remove);
485 }
486
487 fn capture_stack_trace(&self) -> Option<Vec<String>> {
489 Some(vec![
492 "main".to_string(),
493 "handle_edge_case".to_string(),
494 "edge_case_detected".to_string(),
495 ])
496 }
497
498 fn get_current_timestamp(&self) -> u64 {
500 std::time::SystemTime::now()
501 .duration_since(std::time::UNIX_EPOCH)
502 .unwrap_or_default_safe(std::time::Duration::ZERO, "get current timestamp")
503 .as_secs()
504 }
505
506 fn update_stats(
508 &self,
509 _case_type: &EdgeCaseType,
510 severity: &EdgeCaseSeverity,
511 handled_successfully: bool,
512 ) {
513 if !self.config.enable_stats {
514 return;
515 }
516
517 match self.stats.safe_lock() {
518 Ok(mut stats) => {
519 stats.total_cases_detected += 1;
520
521 if handled_successfully {
522 stats.cases_handled_successfully += 1;
523 stats.recovery_actions_taken += 1;
524 } else {
525 stats.cases_failed_to_handle += 1;
526 }
527
528 match severity {
529 EdgeCaseSeverity::Critical => stats.critical_cases += 1,
530 EdgeCaseSeverity::Fatal => stats.fatal_cases += 1,
531 _ => {}
532 }
533
534 stats.detection_accuracy = if stats.total_cases_detected > 0 {
536 (stats.cases_handled_successfully as f64) / (stats.total_cases_detected as f64)
537 } else {
538 0.0
539 };
540 }
541 Err(e) => {
542 tracing::warn!("Failed to update edge case stats: {}", e);
543 }
544 }
545 }
546}
547
548static GLOBAL_EDGE_CASE_HANDLER: std::sync::OnceLock<Arc<EdgeCaseHandler>> =
550 std::sync::OnceLock::new();
551
552pub fn get_global_edge_case_handler() -> Arc<EdgeCaseHandler> {
554 GLOBAL_EDGE_CASE_HANDLER
555 .get_or_init(|| Arc::new(EdgeCaseHandler::new(EdgeCaseConfig::default())))
556 .clone()
557}
558
559pub fn initialize_global_edge_case_handler(config: EdgeCaseConfig) -> Arc<EdgeCaseHandler> {
561 let handler = Arc::new(EdgeCaseHandler::new(config));
562 match GLOBAL_EDGE_CASE_HANDLER.set(handler.clone()) {
563 Ok(_) => tracing::info!("🛡️ Global edge case handler initialized"),
564 Err(_) => tracing::warn!("🛡️ Global edge case handler already initialized"),
565 }
566 handler
567}
568
569#[macro_export]
571macro_rules! handle_edge_case {
572 ($case_type:expr, $severity:expr, $description:expr) => {{
573 let handler = $crate::core::edge_case_handler::get_global_edge_case_handler();
574 let context = std::collections::HashMap::new();
575 handler.handle_edge_case($case_type, $severity, $description.to_string(), context)
576 }};
577 ($case_type:expr, $severity:expr, $description:expr, $context:expr) => {{
578 let handler = $crate::core::edge_case_handler::get_global_edge_case_handler();
579 handler.handle_edge_case($case_type, $severity, $description.to_string(), $context)
580 }};
581}
582
583#[cfg(test)]
584mod tests {
585 use super::*;
586
587 #[test]
588 fn test_edge_case_handler_basic() {
589 let handler = EdgeCaseHandler::new(EdgeCaseConfig::default());
590
591 let context = HashMap::new();
592 let result = handler.handle_edge_case(
593 EdgeCaseType::NullPointerAccess,
594 EdgeCaseSeverity::High,
595 "Test null pointer access".to_string(),
596 context,
597 );
598
599 assert!(result.is_ok());
600 let case_id = result.unwrap();
601 assert!(case_id > 0);
602
603 let retrieved_case = handler.get_edge_case(case_id).unwrap();
604 assert_eq!(retrieved_case.case_type, EdgeCaseType::NullPointerAccess);
605 assert_eq!(retrieved_case.severity, EdgeCaseSeverity::High);
606 }
607
608 #[test]
609 fn test_recovery_strategies() {
610 let handler = EdgeCaseHandler::new(EdgeCaseConfig::default());
611
612 handler.register_recovery_strategy(EdgeCaseType::Unknown, |_| {
614 Ok("Custom recovery applied".to_string())
615 });
616
617 let context = HashMap::new();
618 let case_id = handler
619 .handle_edge_case(
620 EdgeCaseType::Unknown,
621 EdgeCaseSeverity::Medium,
622 "Test unknown case".to_string(),
623 context,
624 )
625 .unwrap();
626
627 let case = handler.get_edge_case(case_id).unwrap();
628 assert!(case.handled_successfully);
629 assert_eq!(
630 case.recovery_action,
631 Some("Custom recovery applied".to_string())
632 );
633 }
634
635 #[test]
636 fn test_statistics() {
637 let handler = EdgeCaseHandler::new(EdgeCaseConfig::default());
638
639 let context = HashMap::new();
640
641 for i in 0..5 {
643 handler
644 .handle_edge_case(
645 EdgeCaseType::AllocationFailure,
646 EdgeCaseSeverity::Medium,
647 format!("Test case {i}"),
648 context.clone(),
649 )
650 .unwrap();
651 }
652
653 let stats = handler.get_stats().unwrap();
654 assert_eq!(stats.total_cases_detected, 5);
655 assert!(stats.cases_handled_successfully > 0);
656 }
657
658 #[test]
659 fn test_case_cleanup() {
660 let handler = EdgeCaseHandler::new(EdgeCaseConfig {
661 max_stored_cases: 3,
662 ..Default::default()
663 });
664 let context = HashMap::new();
665
666 for i in 0..5 {
668 handler
669 .handle_edge_case(
670 EdgeCaseType::BufferOverflow,
671 EdgeCaseSeverity::Low,
672 format!("Test case {i}"),
673 context.clone(),
674 )
675 .unwrap();
676 }
677
678 assert!(handler.case_storage.len() <= 3);
680 }
681}