Skip to content

Commit e45bb7b

Browse files
committed
f use file name/lineno, not instruction pointer, solving inlining issues
1 parent 873c711 commit e45bb7b

File tree

1 file changed

+35
-37
lines changed

1 file changed

+35
-37
lines changed

lightning/src/debug_sync.rs

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ use core::time::Duration;
55
use std::collections::HashSet;
66
use std::cell::RefCell;
77

8-
#[cfg(not(feature = "backtrace"))]
98
use std::sync::atomic::{AtomicUsize, Ordering};
10-
119
use std::sync::Mutex as StdMutex;
1210
use std::sync::MutexGuard as StdMutexGuard;
1311
use std::sync::RwLock as StdRwLock;
@@ -52,11 +50,10 @@ thread_local! {
5250
/// We track the set of locks currently held by a reference to their `LockMetadata`
5351
static LOCKS_HELD: RefCell<HashSet<Arc<LockMetadata>>> = RefCell::new(HashSet::new());
5452
}
55-
#[cfg(not(feature = "backtrace"))]
5653
static LOCK_IDX: AtomicUsize = AtomicUsize::new(0);
5754

5855
#[cfg(feature = "backtrace")]
59-
static mut LOCKS: Option<StdMutex<HashMap<u64, Arc<LockMetadata>>>> = None;
56+
static mut LOCKS: Option<StdMutex<HashMap<String, Arc<LockMetadata>>>> = None;
6057
#[cfg(feature = "backtrace")]
6158
static LOCKS_INIT: Once = Once::new();
6259

@@ -94,40 +91,36 @@ impl std::hash::Hash for LockDep {
9491
fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) { hasher.write_u64(self.lock.lock_idx); }
9592
}
9693

94+
#[cfg(feature = "backtrace")]
95+
fn get_construction_location(backtrace: &Backtrace) -> String {
96+
// Find the first frame which is after `debug_sync` (or which is in our tests) and use
97+
// that as the mutex construction site. Note that the first few frames may be in
98+
// `backtrace`, so we have to ignore those.
99+
let sync_mutex_constr_regex = regex::Regex::new(r"lightning.*debug_sync.*new").unwrap();
100+
let mut found_debug_sync = false;
101+
for frame in backtrace.frames() {
102+
for symbol in frame.symbols() {
103+
let symbol_name = symbol.name().unwrap().as_str().unwrap();
104+
if !sync_mutex_constr_regex.is_match(symbol_name) {
105+
if found_debug_sync {
106+
if let Some(col) = symbol.colno() {
107+
return format!("{}:{}:{}", symbol.filename().unwrap().display(), symbol.lineno().unwrap(), col);
108+
} else {
109+
// Windows debug symbols don't support column numbers, so fall back to
110+
// line numbers only if no `colno` is available
111+
return format!("{}:{}", symbol.filename().unwrap().display(), symbol.lineno().unwrap());
112+
}
113+
}
114+
} else { found_debug_sync = true; }
115+
}
116+
}
117+
panic!("Couldn't find mutex construction callsite");
118+
}
119+
97120
impl LockMetadata {
98121
fn new() -> Arc<LockMetadata> {
99-
let lock_idx;
100122
let backtrace = Backtrace::new();
101-
102-
#[cfg(not(feature = "backtrace"))]
103-
{ lock_idx = LOCK_IDX.fetch_add(1, Ordering::Relaxed) as u64; }
104-
105-
#[cfg(feature = "backtrace")]
106-
{
107-
let mut ip = None;
108-
// Find the first frame which is after `debug_sync` (or which is in our tests) and use
109-
// that as the mutex construction site. Note that the first few frames may be in
110-
// `backtrace`, so we have to ignore those.
111-
let sync_mutex_constr_regex = regex::Regex::new(r"lightning.*debug_sync.*new").unwrap();
112-
let mut found_debug_sync = false;
113-
for frame in backtrace.frames() {
114-
// If a constructor was inlined we should take the frame in which it was inlined
115-
// (as its specific to the callsite), thus we look at the last available symbol,
116-
// which the `backtrace` docs say will be the caller.
117-
let symbol_name = frame.symbols().last().unwrap().name().unwrap().as_str().unwrap();
118-
if !sync_mutex_constr_regex.is_match(symbol_name) {
119-
if found_debug_sync {
120-
ip = Some(frame.ip() as usize as u64);
121-
break;
122-
}
123-
} else { found_debug_sync = true; }
124-
}
125-
lock_idx = ip.unwrap();
126-
LOCKS_INIT.call_once(|| { unsafe { LOCKS = Some(StdMutex::new(HashMap::new())); } });
127-
if let Some(metadata) = unsafe { LOCKS.as_ref() }.unwrap().lock().unwrap().get(&lock_idx) {
128-
return Arc::clone(&metadata);
129-
}
130-
}
123+
let lock_idx = LOCK_IDX.fetch_add(1, Ordering::Relaxed) as u64;
131124

132125
let res = Arc::new(LockMetadata {
133126
locked_before: StdMutex::new(HashSet::new()),
@@ -137,8 +130,10 @@ impl LockMetadata {
137130

138131
#[cfg(feature = "backtrace")]
139132
{
133+
let lock_constr_location = get_construction_location(&res._lock_construction_bt);
134+
LOCKS_INIT.call_once(|| { unsafe { LOCKS = Some(StdMutex::new(HashMap::new())); } });
140135
let mut locks = unsafe { LOCKS.as_ref() }.unwrap().lock().unwrap();
141-
match locks.entry(lock_idx) {
136+
match locks.entry(lock_constr_location) {
142137
hash_map::Entry::Occupied(e) => return Arc::clone(e.get()),
143138
hash_map::Entry::Vacant(e) => { e.insert(Arc::clone(&res)); },
144139
}
@@ -168,7 +163,10 @@ impl LockMetadata {
168163
for locked_dep in locked.locked_before.lock().unwrap().iter() {
169164
if locked_dep.lock == *this && locked_dep.lock != *locked {
170165
#[cfg(feature = "backtrace")]
171-
panic!("Tried to violate existing lockorder.\nMutex that should be locked after the current lock was created at the following backtrace.\nNote that to get a backtrace for the lockorder violation, you should set RUST_BACKTRACE=1\nLock constructed at:\n{:?}\n\nLock dep created at:\n{:?}\n\n", locked._lock_construction_bt, locked_dep.lockdep_trace);
166+
panic!("Tried to violate existing lockorder.\nMutex that should be locked after the current lock was created at the following backtrace.\nNote that to get a backtrace for the lockorder violation, you should set RUST_BACKTRACE=1\nLock being taken constructed at: {} ({}):\n{:?}\nLock constructed at: {} ({})\n{:?}\n\nLock dep created at:\n{:?}\n\n",
167+
get_construction_location(&this._lock_construction_bt), this.lock_idx, this._lock_construction_bt,
168+
get_construction_location(&locked._lock_construction_bt), locked.lock_idx, locked._lock_construction_bt,
169+
locked_dep.lockdep_trace);
172170
#[cfg(not(feature = "backtrace"))]
173171
panic!("Tried to violate existing lockorder. Build with the backtrace feature for more info.");
174172
}

0 commit comments

Comments
 (0)