-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathallocs.rs
99 lines (85 loc) · 2.85 KB
/
allocs.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#![allow(
clippy::fn_to_numeric_cast,
clippy::incompatible_msrv,
clippy::let_and_return,
clippy::let_unit_value
)]
#![cfg_attr(not(linux), allow(dead_code, unused_imports))]
use std::alloc::GlobalAlloc;
use std::alloc::Layout;
use std::alloc::System;
use std::backtrace::Backtrace;
use std::backtrace::BacktraceStatus;
use std::cell::Cell;
use std::hint::black_box;
use std::thread_local;
use blazesym::normalize::NormalizeOpts;
use blazesym::normalize::Normalizer;
use blazesym::Addr;
use stats_alloc::Region;
use stats_alloc::StatsAlloc;
#[global_allocator]
static GLOBAL: StatsAlloc<TracingAlloc> = StatsAlloc::new(TracingAlloc);
thread_local! {
static ENABLED: Cell<bool> = const { Cell::new(false) };
static TRACING: Cell<bool> = const { Cell::new(false) };
}
/// An allocator that prints a backtrace for each allocation being made.
struct TracingAlloc;
unsafe impl GlobalAlloc for TracingAlloc {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
// Capturing a backtrace will allocate itself. Prevent infinite
// recursion with a flag.
if ENABLED.get() && !TRACING.with(|tracing| tracing.replace(true)) {
let bt = Backtrace::capture();
if let BacktraceStatus::Captured = bt.status() {
println!("{layout:?}:\n{bt}");
}
let () = TRACING.with(|tracing| tracing.set(false));
}
System.alloc(layout)
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
System.dealloc(ptr, layout);
}
}
/// Normalize addresses in the current process and print allocation
/// statistics.
#[cfg(linux)]
#[test]
fn normalize_process() {
let region = Region::new(&GLOBAL);
let () = ENABLED.set(true);
{
let normalizer = Normalizer::builder().build();
let mut addrs = [
libc::atexit as Addr,
libc::chdir as Addr,
libc::fopen as Addr,
normalize_process as Addr,
Normalizer::normalize_user_addrs as Addr,
];
let () = addrs.sort();
let opts = NormalizeOpts {
sorted_addrs: true,
..Default::default()
};
let normalized = normalizer
.normalize_user_addrs_opts(
black_box(0.into()),
black_box(addrs.as_slice()),
black_box(&opts),
)
.unwrap();
assert_eq!(normalized.meta.len(), 2);
assert_eq!(normalized.outputs.len(), 5);
}
let () = ENABLED.set(false);
// We can't make many assumptions about the allocations here,
// because a lot of it is system dependent. E.g., more entries in
// `/proc/<pid>/maps` likely means more allocations. Even the order
// may have an influence, to the point that ASLR could change
// results.
let stats = region.change();
println!("Stats: {stats:#?}");
}