memscope_rs/
allocator.rs

1//! Custom global allocator for tracking memory allocations.
2
3use std::alloc::{GlobalAlloc, Layout, System};
4
5/// A custom allocator that tracks memory allocations and deallocations.
6///
7/// This allocator wraps the system allocator and records all allocation
8/// and deallocation events through the global memory tracker.
9pub struct TrackingAllocator;
10
11impl TrackingAllocator {
12    /// Create a new tracking allocator instance.
13    pub const fn new() -> Self {
14        Self
15    }
16}
17
18// Thread-local flag to prevent recursive tracking
19thread_local! {
20    static TRACKING_DISABLED: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
21}
22
23unsafe impl GlobalAlloc for TrackingAllocator {
24    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
25        // Allocate memory first
26        let ptr = System.alloc(layout);
27
28        // Track the allocation if it succeeded and tracking is not disabled
29        if !ptr.is_null() {
30            // Check if tracking is disabled for this thread to prevent recursion
31            let should_track = TRACKING_DISABLED.with(|disabled| !disabled.get());
32
33            if should_track {
34                // Temporarily disable tracking to prevent recursion during tracking operations
35                TRACKING_DISABLED.with(|disabled| disabled.set(true));
36
37                // Track the allocation - use try_lock approach to avoid deadlocks
38                if let Ok(tracker) = std::panic::catch_unwind(crate::tracker::get_global_tracker) {
39                    // Ignore errors to prevent allocation failures from breaking the program
40                    let _ = tracker.track_allocation(ptr as usize, layout.size());
41                }
42
43                // Re-enable tracking
44                TRACKING_DISABLED.with(|disabled| disabled.set(false));
45            }
46        }
47
48        ptr
49    }
50
51    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
52        // Track the deallocation first
53        let should_track = TRACKING_DISABLED.with(|disabled| !disabled.get());
54
55        if should_track {
56            // Temporarily disable tracking to prevent recursion
57            TRACKING_DISABLED.with(|disabled| disabled.set(true));
58
59            // Track the deallocation - use try_lock approach to avoid deadlocks
60            if let Ok(tracker) = std::panic::catch_unwind(crate::tracker::get_global_tracker) {
61                // Ignore errors to prevent deallocation failures from breaking the program
62                let _ = tracker.track_deallocation(ptr as usize);
63            }
64
65            // Re-enable tracking
66            TRACKING_DISABLED.with(|disabled| disabled.set(false));
67        }
68
69        // Deallocate the memory
70        System.dealloc(ptr, layout);
71    }
72}
73
74impl Default for TrackingAllocator {
75    fn default() -> Self {
76        Self::new()
77    }
78}