Skip to content

Commit 57cc5ef

Browse files
committed
refactor(memtrack): use standard allocation API across allocators
1 parent a6ab935 commit 57cc5ef

File tree

1 file changed

+76
-74
lines changed

1 file changed

+76
-74
lines changed

crates/memtrack/src/ebpf/memtrack.rs

Lines changed: 76 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -262,40 +262,6 @@ impl MemtrackBpf {
262262
// Attach methods grouped by allocator
263263
// =========================================================================
264264

265-
/// Attach standard library allocation probes (libc-style: malloc, free, calloc, etc.)
266-
/// This works for libc and allocators that export standard symbol names.
267-
/// For non-libc allocators, standard names are optional - just try them silently.
268-
pub fn attach_libc_probes(&mut self, lib_path: &Path) -> Result<()> {
269-
self.try_attach_malloc(lib_path, "malloc");
270-
self.try_attach_calloc(lib_path, "calloc");
271-
self.try_attach_realloc(lib_path, "realloc");
272-
self.try_attach_free(lib_path, "free");
273-
self.try_attach_aligned_alloc(lib_path, "aligned_alloc");
274-
self.try_attach_memalign(lib_path, "posix_memalign");
275-
self.try_attach_memalign(lib_path, "memalign");
276-
Ok(())
277-
}
278-
279-
/// Attach C++ operator new/delete probes.
280-
/// These are mangled C++ symbols that wrap the underlying allocator.
281-
/// C++ operators have identical signatures to malloc/free, so we reuse those handlers.
282-
pub fn attach_libcpp_probes(&mut self, lib_path: &Path) -> Result<()> {
283-
self.try_attach_malloc(lib_path, "_Znwm"); // operator new(size_t)
284-
self.try_attach_malloc(lib_path, "_Znam"); // operator new[](size_t)
285-
self.try_attach_malloc(lib_path, "_ZnwmSt11align_val_t"); // operator new(size_t, std::align_val_t)
286-
self.try_attach_malloc(lib_path, "_ZnamSt11align_val_t"); // operator new[](size_t, std::align_val_t)
287-
self.try_attach_free(lib_path, "_ZdlPv"); // operator delete(void*)
288-
self.try_attach_free(lib_path, "_ZdaPv"); // operator delete[](void*)
289-
self.try_attach_free(lib_path, "_ZdlPvm"); // operator delete(void*, size_t) - C++14 sized delete
290-
self.try_attach_free(lib_path, "_ZdaPvm"); // operator delete[](void*, size_t) - C++14 sized delete
291-
self.try_attach_free(lib_path, "_ZdlPvSt11align_val_t"); // operator delete(void*, std::align_val_t)
292-
self.try_attach_free(lib_path, "_ZdaPvSt11align_val_t"); // operator delete[](void*, std::align_val_t)
293-
self.try_attach_free(lib_path, "_ZdlPvmSt11align_val_t"); // operator delete(void*, size_t, std::align_val_t)
294-
self.try_attach_free(lib_path, "_ZdaPvmSt11align_val_t"); // operator delete[](void*, size_t, std::align_val_t)
295-
296-
Ok(())
297-
}
298-
299265
/// Attach probes for a specific allocator kind.
300266
/// This attaches both standard probes (if the allocator exports them) and
301267
/// allocator-specific prefixed probes.
@@ -316,22 +282,77 @@ impl MemtrackBpf {
316282
self.attach_libcpp_probes(lib_path)
317283
}
318284
AllocatorKind::Jemalloc => {
319-
// Try standard names (jemalloc may export these as drop-in replacements)
320-
let _ = self.attach_libc_probes(lib_path);
321285
// Try C++ operators (jemalloc exports these for C++ programs)
322286
let _ = self.attach_libcpp_probes(lib_path);
323287
self.attach_jemalloc_probes(lib_path)
324288
}
325289
AllocatorKind::Mimalloc => {
326-
// Try standard names (mimalloc may export these as drop-in replacements)
327-
let _ = self.attach_libc_probes(lib_path);
328290
// Try C++ operators (mimalloc exports these for C++ programs)
329291
let _ = self.attach_libcpp_probes(lib_path);
330292
self.attach_mimalloc_probes(lib_path)
331293
}
332294
}
333295
}
334296

297+
fn attach_standard_probes(
298+
&mut self,
299+
lib_path: &Path,
300+
prefixes: &[&str],
301+
suffixes: &[&str],
302+
) -> Result<()> {
303+
// Always include "" to capture the basic case
304+
let prefixes_with_base: Vec<&str> = std::iter::once("")
305+
.chain(prefixes.iter().copied())
306+
.unique()
307+
.collect();
308+
309+
let suffixes_with_base: Vec<&str> = std::iter::once("")
310+
.chain(suffixes.iter().copied())
311+
.unique()
312+
.collect();
313+
314+
for prefix in &prefixes_with_base {
315+
for suffix in &suffixes_with_base {
316+
self.try_attach_malloc(lib_path, &format!("{prefix}malloc{suffix}"));
317+
self.try_attach_calloc(lib_path, &format!("{prefix}calloc{suffix}"));
318+
self.try_attach_realloc(lib_path, &format!("{prefix}realloc{suffix}"));
319+
self.try_attach_aligned_alloc(lib_path, &format!("{prefix}aligned_alloc{suffix}"));
320+
self.try_attach_memalign(lib_path, &format!("{prefix}memalign{suffix}"));
321+
self.try_attach_memalign(lib_path, &format!("{prefix}posix_memalign{suffix}"));
322+
self.try_attach_free(lib_path, &format!("{prefix}free{suffix}"));
323+
}
324+
}
325+
326+
Ok(())
327+
}
328+
329+
/// Attach standard library allocation probes (libc-style: malloc, free, calloc, etc.)
330+
/// This works for libc and allocators that export standard symbol names.
331+
/// For non-libc allocators, standard names are optional - just try them silently.
332+
fn attach_libc_probes(&mut self, lib_path: &Path) -> Result<()> {
333+
self.attach_standard_probes(lib_path, &[], &[])
334+
}
335+
336+
/// Attach C++ operator new/delete probes.
337+
/// These are mangled C++ symbols that wrap the underlying allocator.
338+
/// C++ operators have identical signatures to malloc/free, so we reuse those handlers.
339+
fn attach_libcpp_probes(&mut self, lib_path: &Path) -> Result<()> {
340+
self.try_attach_malloc(lib_path, "_Znwm"); // operator new(size_t)
341+
self.try_attach_malloc(lib_path, "_Znam"); // operator new[](size_t)
342+
self.try_attach_malloc(lib_path, "_ZnwmSt11align_val_t"); // operator new(size_t, std::align_val_t)
343+
self.try_attach_malloc(lib_path, "_ZnamSt11align_val_t"); // operator new[](size_t, std::align_val_t)
344+
self.try_attach_free(lib_path, "_ZdlPv"); // operator delete(void*)
345+
self.try_attach_free(lib_path, "_ZdaPv"); // operator delete[](void*)
346+
self.try_attach_free(lib_path, "_ZdlPvm"); // operator delete(void*, size_t) - C++14 sized delete
347+
self.try_attach_free(lib_path, "_ZdaPvm"); // operator delete[](void*, size_t) - C++14 sized delete
348+
self.try_attach_free(lib_path, "_ZdlPvSt11align_val_t"); // operator delete(void*, std::align_val_t)
349+
self.try_attach_free(lib_path, "_ZdaPvSt11align_val_t"); // operator delete[](void*, std::align_val_t)
350+
self.try_attach_free(lib_path, "_ZdlPvmSt11align_val_t"); // operator delete(void*, size_t, std::align_val_t)
351+
self.try_attach_free(lib_path, "_ZdaPvmSt11align_val_t"); // operator delete[](void*, size_t, std::align_val_t)
352+
353+
Ok(())
354+
}
355+
335356
/// Attach jemalloc-specific probes (prefixed and extended API).
336357
fn attach_jemalloc_probes(&mut self, lib_path: &Path) -> Result<()> {
337358
// The following functions are used in Rust when setting a global allocator:
@@ -340,36 +361,23 @@ impl MemtrackBpf {
340361
// - rust_dealloc: _rjem_sdallocx
341362
// - rust_realloc: _rjem_realloc / _rjem_rallocx
342363

343-
// je_*_default API (C++ with static linking)
344-
self.try_attach_malloc(lib_path, "je_malloc_default");
345-
self.try_attach_malloc(lib_path, "je_mallocx_default");
346-
self.try_attach_free(lib_path, "je_free_default");
347-
self.try_attach_free(lib_path, "je_sdallocx_default");
348-
self.try_attach_realloc(lib_path, "je_realloc_default");
349-
self.try_attach_realloc(lib_path, "je_rallocx_default");
350-
self.try_attach_calloc(lib_path, "je_calloc_default");
351-
352364
// je_* API (internal jemalloc functions, static linking)
353-
self.try_attach_malloc(lib_path, "je_malloc");
354-
self.try_attach_malloc(lib_path, "je_mallocx");
355-
self.try_attach_calloc(lib_path, "je_calloc");
356-
self.try_attach_realloc(lib_path, "je_realloc");
357-
self.try_attach_realloc(lib_path, "je_rallocx");
358-
self.try_attach_aligned_alloc(lib_path, "je_aligned_alloc");
359-
self.try_attach_memalign(lib_path, "je_memalign");
360-
self.try_attach_free(lib_path, "je_free");
361-
self.try_attach_free(lib_path, "je_sdallocx");
362-
363365
// _rjem_* API (Rust jemalloc crate, dynamic linking)
364-
self.try_attach_malloc(lib_path, "_rjem_malloc");
365-
self.try_attach_malloc(lib_path, "_rjem_mallocx"); // Also used for `calloc`
366-
self.try_attach_calloc(lib_path, "_rjem_calloc");
367-
self.try_attach_realloc(lib_path, "_rjem_realloc");
368-
self.try_attach_realloc(lib_path, "_rjem_rallocx");
369-
self.try_attach_aligned_alloc(lib_path, "_rjem_aligned_alloc");
370-
self.try_attach_memalign(lib_path, "_rjem_memalign");
371-
self.try_attach_free(lib_path, "_rjem_free");
372-
self.try_attach_free(lib_path, "_rjem_sdallocx");
366+
let prefixes = ["je_", "_rjem_"];
367+
let suffixes = ["", "_default"];
368+
369+
self.attach_standard_probes(lib_path, &prefixes, &suffixes)?;
370+
371+
// Non-standard API that has an additional flag parameter
372+
// See: https://jemalloc.net/jemalloc.3.html
373+
for prefix in prefixes {
374+
for suffix in suffixes {
375+
self.try_attach_malloc(lib_path, &format!("{prefix}mallocx{suffix}"));
376+
self.try_attach_realloc(lib_path, &format!("{prefix}rallocx{suffix}"));
377+
self.try_attach_free(lib_path, &format!("{prefix}dallocx{suffix}"));
378+
self.try_attach_free(lib_path, &format!("{prefix}sdallocx{suffix}"));
379+
}
380+
}
373381

374382
Ok(())
375383
}
@@ -382,16 +390,10 @@ impl MemtrackBpf {
382390
// - mi_realloc_aligned
383391
// - mi_zalloc_aligned
384392

385-
// Core API
386-
self.try_attach_malloc(lib_path, "mi_malloc");
387-
self.try_attach_malloc(lib_path, "mi_malloc_aligned");
388-
self.try_attach_calloc(lib_path, "mi_calloc");
389-
self.try_attach_realloc(lib_path, "mi_realloc");
390-
self.try_attach_aligned_alloc(lib_path, "mi_aligned_alloc");
391-
self.try_attach_memalign(lib_path, "mi_memalign");
392-
self.try_attach_free(lib_path, "mi_free");
393+
self.attach_standard_probes(lib_path, &["mi_"], &[])?;
393394

394395
// Zero-initialized and aligned variants
396+
self.try_attach_calloc(lib_path, "mi_malloc_aligned");
395397
self.try_attach_calloc(lib_path, "mi_zalloc");
396398
self.try_attach_calloc(lib_path, "mi_zalloc_aligned");
397399
self.try_attach_realloc(lib_path, "mi_realloc_aligned");

0 commit comments

Comments
 (0)