memscope_rs/core/
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) =
39                    std::panic::catch_unwind(crate::core::tracker::get_global_tracker)
40                {
41                    // Ignore errors to prevent allocation failures from breaking the program
42                    let _ = tracker.track_allocation(ptr as usize, layout.size());
43                }
44
45                // Re-enable tracking
46                TRACKING_DISABLED.with(|disabled| disabled.set(false));
47            }
48        }
49
50        ptr
51    }
52
53    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
54        // Track the deallocation first
55        let should_track = TRACKING_DISABLED.with(|disabled| !disabled.get());
56
57        if should_track {
58            // Temporarily disable tracking to prevent recursion
59            TRACKING_DISABLED.with(|disabled| disabled.set(true));
60
61            // Track the deallocation - use try_lock approach to avoid deadlocks
62            if let Ok(tracker) = std::panic::catch_unwind(crate::core::tracker::get_global_tracker)
63            {
64                // Ignore errors to prevent deallocation failures from breaking the program
65                let _ = tracker.track_deallocation(ptr as usize);
66            }
67
68            // Re-enable tracking
69            TRACKING_DISABLED.with(|disabled| disabled.set(false));
70        }
71
72        // Deallocate the memory
73        System.dealloc(ptr, layout);
74    }
75}
76
77impl Default for TrackingAllocator {
78    fn default() -> Self {
79        Self::new()
80    }
81}