Skip to content

Commit 0a23f48

Browse files
authored
Merge pull request #226 from Tomcc/master
Adding a method to clear the Gimli symbol cache
2 parents e2da24a + 448f2c6 commit 0a23f48

File tree

3 files changed

+44
-8
lines changed

3 files changed

+44
-8
lines changed

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ mod symbolize;
8383
pub use crate::types::BytesOrWideString;
8484
mod types;
8585

86+
#[cfg(feature = "std")]
87+
pub use crate::symbolize::clear_symbol_cache;
88+
8689
cfg_if::cfg_if! {
8790
if #[cfg(feature = "std")] {
8891
pub use crate::backtrace::trace;

src/symbolize/gimli.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use crate::symbolize::ResolveWhat;
1111
use crate::types::BytesOrWideString;
1212
use crate::SymbolName;
1313
use addr2line::gimli;
14-
use core::cell::RefCell;
1514
use core::convert::TryFrom;
1615
use core::mem;
1716
use core::u32;
@@ -329,7 +328,10 @@ impl Mapping {
329328
}
330329
}
331330

332-
thread_local! {
331+
type Cache = Vec<(PathBuf, Mapping)>;
332+
333+
// unsafe because this is required to be externally synchronized
334+
unsafe fn with_cache(f: impl FnOnce(&mut Cache)) {
333335
// A very small, very simple LRU cache for debug info mappings.
334336
//
335337
// The hit rate should be very high, since the typical stack doesn't cross
@@ -340,17 +342,21 @@ thread_local! {
340342
// leverage the structures built when constructing `addr2line::Context`s to
341343
// get nice speedups. If we didn't have this cache, that amortization would
342344
// never happen, and symbolicating backtraces would be ssssllllooooowwww.
343-
static MAPPINGS_CACHE: RefCell<Vec<(PathBuf, Mapping)>>
344-
= RefCell::new(Vec::with_capacity(MAPPINGS_CACHE_SIZE));
345+
static mut MAPPINGS_CACHE: Option<Cache> = None;
346+
347+
f(MAPPINGS_CACHE.get_or_insert_with(|| Vec::with_capacity(MAPPINGS_CACHE_SIZE)))
345348
}
346349

347-
fn with_mapping_for_path<F>(path: PathBuf, f: F)
350+
// unsafe because this is required to be externally synchronized
351+
pub unsafe fn clear_symbol_cache() {
352+
with_cache(|cache| cache.clear());
353+
}
354+
355+
unsafe fn with_mapping_for_path<F>(path: PathBuf, f: F)
348356
where
349357
F: FnMut(&Context<'_>),
350358
{
351-
MAPPINGS_CACHE.with(|cache| {
352-
let mut cache = cache.borrow_mut();
353-
359+
with_cache(|cache| {
354360
let idx = cache.iter().position(|&(ref p, _)| p == &path);
355361

356362
// Invariant: after this conditional completes without early returning

src/symbolize/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,13 +434,35 @@ cfg_if::cfg_if! {
434434
}
435435
}
436436

437+
/// Attempt to reclaim that cached memory used to symbolicate addresses.
438+
///
439+
/// This method will attempt to release any global data structures that have
440+
/// otherwise been cached globally or in the thread which typically represent
441+
/// parsed DWARF information or similar.
442+
///
443+
/// # Caveats
444+
///
445+
/// While this function is always available it doesn't actually do anything on
446+
/// most implementations. Libraries like dbghelp or libbacktrace do not provide
447+
/// facilities to deallocate state and manage the allocated memory. For now the
448+
/// `gimli-symbolize` feature of this crate is the only feature where this
449+
/// function has any effect.
450+
#[cfg(feature = "std")]
451+
pub fn clear_symbol_cache() {
452+
let _guard = crate::lock::lock();
453+
unsafe {
454+
clear_symbol_cache_imp();
455+
}
456+
}
457+
437458
mod dladdr;
438459

439460
cfg_if::cfg_if! {
440461
if #[cfg(all(windows, target_env = "msvc", feature = "dbghelp"))] {
441462
mod dbghelp;
442463
use self::dbghelp::resolve as resolve_imp;
443464
use self::dbghelp::Symbol as SymbolImp;
465+
unsafe fn clear_symbol_cache_imp() {}
444466
} else if #[cfg(all(
445467
feature = "std",
446468
feature = "gimli-symbolize",
@@ -453,6 +475,7 @@ cfg_if::cfg_if! {
453475
mod gimli;
454476
use self::gimli::resolve as resolve_imp;
455477
use self::gimli::Symbol as SymbolImp;
478+
use self::gimli::clear_symbol_cache as clear_symbol_cache_imp;
456479
// Note that we only enable coresymbolication on iOS when debug assertions
457480
// are enabled because it's helpful in debug mode but it looks like apps get
458481
// rejected from the app store if they use this API, see #92 for more info
@@ -462,22 +485,26 @@ cfg_if::cfg_if! {
462485
mod coresymbolication;
463486
use self::coresymbolication::resolve as resolve_imp;
464487
use self::coresymbolication::Symbol as SymbolImp;
488+
unsafe fn clear_symbol_cache_imp() {}
465489
} else if #[cfg(all(feature = "libbacktrace",
466490
any(unix, all(windows, not(target_vendor = "uwp"), target_env = "gnu")),
467491
not(target_os = "fuchsia"),
468492
not(target_os = "emscripten")))] {
469493
mod libbacktrace;
470494
use self::libbacktrace::resolve as resolve_imp;
471495
use self::libbacktrace::Symbol as SymbolImp;
496+
unsafe fn clear_symbol_cache_imp() {}
472497
} else if #[cfg(all(unix,
473498
not(target_os = "emscripten"),
474499
feature = "dladdr"))] {
475500
mod dladdr_resolve;
476501
use self::dladdr_resolve::resolve as resolve_imp;
477502
use self::dladdr_resolve::Symbol as SymbolImp;
503+
unsafe fn clear_symbol_cache_imp() {}
478504
} else {
479505
mod noop;
480506
use self::noop::resolve as resolve_imp;
481507
use self::noop::Symbol as SymbolImp;
508+
unsafe fn clear_symbol_cache_imp() {}
482509
}
483510
}

0 commit comments

Comments
 (0)