Skip to content

Commit 065dc6e

Browse files
committed
Make sure individual mutexes are constructed on different lines
Our lockdep logic (on Windows) identifies a mutex based on which line it was constructed on. Thus, if we have two mutexes constructed on the same line it will generate false positives.
1 parent 22662ef commit 065dc6e

File tree

3 files changed

+23
-15
lines changed

3 files changed

+23
-15
lines changed

lightning/src/chain/channelmonitor.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -4070,7 +4070,10 @@ mod tests {
40704070
fn test_prune_preimages() {
40714071
let secp_ctx = Secp256k1::new();
40724072
let logger = Arc::new(TestLogger::new());
4073-
let broadcaster = Arc::new(TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))});
4073+
let broadcaster = Arc::new(TestBroadcaster {
4074+
txn_broadcasted: Mutex::new(Vec::new()),
4075+
blocks: Arc::new(Mutex::new(Vec::new()))
4076+
});
40744077
let fee_estimator = TestFeeEstimator { sat_per_kw: Mutex::new(253) };
40754078

40764079
let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());

lightning/src/ln/channelmanager.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -7532,7 +7532,10 @@ where
75327532
}
75337533
}
75347534

7535-
let pending_outbounds = OutboundPayments { pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()), retry_lock: Mutex::new(()) };
7535+
let pending_outbounds = OutboundPayments {
7536+
pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()),
7537+
retry_lock: Mutex::new(())
7538+
};
75367539
if !forward_htlcs.is_empty() || pending_outbounds.needs_abandon() {
75377540
// If we have pending HTLCs to forward, assume we either dropped a
75387541
// `PendingHTLCsForwardable` or the user received it but never processed it as they

lightning/src/sync/debug_sync.rs

+15-13
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ struct LockDep {
7575
}
7676

7777
#[cfg(feature = "backtrace")]
78-
fn get_construction_location(backtrace: &Backtrace) -> String {
78+
fn get_construction_location(backtrace: &Backtrace) -> (String, Option<u32>) {
7979
// Find the first frame that is after `debug_sync` (or that is in our tests) and use
8080
// that as the mutex construction site. Note that the first few frames may be in
8181
// the `backtrace` crate, so we have to ignore those.
@@ -86,13 +86,7 @@ fn get_construction_location(backtrace: &Backtrace) -> String {
8686
let symbol_name = symbol.name().unwrap().as_str().unwrap();
8787
if !sync_mutex_constr_regex.is_match(symbol_name) {
8888
if found_debug_sync {
89-
if let Some(col) = symbol.colno() {
90-
return format!("{}:{}:{}", symbol.filename().unwrap().display(), symbol.lineno().unwrap(), col);
91-
} else {
92-
// Windows debug symbols don't support column numbers, so fall back to
93-
// line numbers only if no `colno` is available
94-
return format!("{}:{}", symbol.filename().unwrap().display(), symbol.lineno().unwrap());
95-
}
89+
return (format!("{}:{}", symbol.filename().unwrap().display(), symbol.lineno().unwrap()), symbol.colno());
9690
}
9791
} else { found_debug_sync = true; }
9892
}
@@ -113,11 +107,17 @@ impl LockMetadata {
113107

114108
#[cfg(feature = "backtrace")]
115109
{
116-
let lock_constr_location = get_construction_location(&res._lock_construction_bt);
110+
let (lock_constr_location, lock_constr_colno) =
111+
get_construction_location(&res._lock_construction_bt);
117112
LOCKS_INIT.call_once(|| { unsafe { LOCKS = Some(StdMutex::new(HashMap::new())); } });
118113
let mut locks = unsafe { LOCKS.as_ref() }.unwrap().lock().unwrap();
119114
match locks.entry(lock_constr_location) {
120-
hash_map::Entry::Occupied(e) => return Arc::clone(e.get()),
115+
hash_map::Entry::Occupied(e) => {
116+
assert_eq!(lock_constr_colno,
117+
get_construction_location(&e.get()._lock_construction_bt).1,
118+
"Because Windows doesn't support column number results in backtraces, we cannot construct two mutexes on the same line or we risk lockorder detection false positives.");
119+
return Arc::clone(e.get())
120+
},
121121
hash_map::Entry::Vacant(e) => { e.insert(Arc::clone(&res)); },
122122
}
123123
}
@@ -138,7 +138,7 @@ impl LockMetadata {
138138
#[cfg(feature = "backtrace")]
139139
debug_assert!(_double_lock_self_allowed,
140140
"Tried to acquire a lock while it was held!\nLock constructed at {}",
141-
get_construction_location(&this._lock_construction_bt));
141+
get_construction_location(&this._lock_construction_bt).0);
142142
#[cfg(not(feature = "backtrace"))]
143143
panic!("Tried to acquire a lock while it was held!");
144144
}
@@ -148,8 +148,10 @@ impl LockMetadata {
148148
if *locked_dep_idx == this.lock_idx && *locked_dep_idx != locked.lock_idx {
149149
#[cfg(feature = "backtrace")]
150150
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",
151-
get_construction_location(&this._lock_construction_bt), this.lock_idx, this._lock_construction_bt,
152-
get_construction_location(&locked._lock_construction_bt), locked.lock_idx, locked._lock_construction_bt,
151+
get_construction_location(&this._lock_construction_bt).0,
152+
this.lock_idx, this._lock_construction_bt,
153+
get_construction_location(&locked._lock_construction_bt).0,
154+
locked.lock_idx, locked._lock_construction_bt,
153155
_locked_dep._lockdep_trace);
154156
#[cfg(not(feature = "backtrace"))]
155157
panic!("Tried to violate existing lockorder. Build with the backtrace feature for more info.");

0 commit comments

Comments
 (0)