dcrypt_api/error/
registry.rs

1//! Error registry for secure error handling
2
3use core::ptr::null_mut;
4use core::sync::atomic::{AtomicPtr, Ordering};
5
6/// Global error registry for recording errors during constant-time operations
7pub static ERROR_REGISTRY: ErrorRegistry = ErrorRegistry::new();
8
9/// Thread-local registry for errors during constant-time operations
10pub struct ErrorRegistry {
11    error: AtomicPtr<()>,
12}
13
14impl ErrorRegistry {
15    /// Create a new, empty error registry
16    pub const fn new() -> Self {
17        Self {
18            error: AtomicPtr::new(null_mut()),
19        }
20    }
21
22    /// Store an error in the registry
23    pub fn store<E>(&self, error: E) {
24        // For simplicity, we use std allocation since that's the default feature
25        #[cfg(feature = "std")]
26        {
27            use std::boxed::Box;
28            // Store the error as a trait object
29            let boxed = Box::into_raw(Box::new(error));
30            let old = self.error.swap(boxed as *mut (), Ordering::SeqCst);
31
32            // Clean up any old error to avoid memory leaks
33            if !old.is_null() {
34                unsafe {
35                    drop(Box::from_raw(old));
36                }
37            }
38        }
39
40        // In no-std environments, we can't store the error
41        #[cfg(not(feature = "std"))]
42        {
43            let _ = error; // Avoid unused variable warning
44                           // Simply set a non-null pointer to indicate an error occurred
45            self.error.store(1 as *mut (), Ordering::SeqCst);
46        }
47    }
48
49    /// Clear any stored error
50    pub fn clear(&self) {
51        #[cfg(feature = "std")]
52        {
53            let ptr = self.error.swap(null_mut(), Ordering::SeqCst);
54            if !ptr.is_null() {
55                unsafe {
56                    drop(Box::from_raw(ptr));
57                }
58            }
59        }
60
61        #[cfg(not(feature = "std"))]
62        {
63            self.error.store(null_mut(), Ordering::SeqCst);
64        }
65    }
66
67    /// Check if an error is present
68    pub fn has_error(&self) -> bool {
69        !self.error.load(Ordering::SeqCst).is_null()
70    }
71
72    /// Get a copy of the last error, if any
73    #[cfg(feature = "std")]
74    pub fn get_error<E: Clone>(&self) -> Option<E> {
75        let ptr = self.error.load(Ordering::SeqCst);
76        if ptr.is_null() {
77            None
78        } else {
79            // Safety: We know the type of the stored error when we retrieve it
80            // The caller must ensure they request the correct type
81            unsafe {
82                let error_ref = &*(ptr as *const E);
83                Some(error_ref.clone())
84            }
85        }
86    }
87}
88
89impl Default for ErrorRegistry {
90    fn default() -> Self {
91        Self::new()
92    }
93}
94
95impl Drop for ErrorRegistry {
96    fn drop(&mut self) {
97        self.clear();
98    }
99}