Skip to content

Commit c4dbaa9

Browse files
authored
gpui: Fix race condition when upgrading a weak reference (#30952)
Release Notes: - N/A
1 parent 97c01c6 commit c4dbaa9

File tree

3 files changed

+28
-13
lines changed

3 files changed

+28
-13
lines changed

crates/gpui/src/app/entity_map.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ use std::{
2020
thread::panicking,
2121
};
2222

23+
use super::Context;
24+
use crate::util::atomic_incr_if_not_zero;
2325
#[cfg(any(test, feature = "leak-detection"))]
2426
use collections::HashMap;
2527

26-
use super::Context;
27-
2828
slotmap::new_key_type! {
2929
/// A unique identifier for a entity across the application.
3030
pub struct EntityId;
@@ -529,11 +529,10 @@ impl AnyWeakEntity {
529529
let ref_counts = ref_counts.read();
530530
let ref_count = ref_counts.counts.get(self.entity_id)?;
531531

532-
// entity_id is in dropped_entity_ids
533-
if ref_count.load(SeqCst) == 0 {
532+
if atomic_incr_if_not_zero(ref_count) == 0 {
533+
// entity_id is in dropped_entity_ids
534534
return None;
535535
}
536-
ref_count.fetch_add(1, SeqCst);
537536
drop(ref_counts);
538537

539538
Some(AnyEntity {

crates/gpui/src/util.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::sync::atomic::AtomicUsize;
2+
use std::sync::atomic::Ordering::SeqCst;
13
#[cfg(any(test, feature = "test-support"))]
24
use std::time::Duration;
35

@@ -108,3 +110,18 @@ impl std::fmt::Debug for CwdBacktrace<'_> {
108110
fmt.finish()
109111
}
110112
}
113+
114+
/// Increment the given atomic counter if it is not zero.
115+
/// Return the new value of the counter.
116+
pub(crate) fn atomic_incr_if_not_zero(counter: &AtomicUsize) -> usize {
117+
let mut loaded = counter.load(SeqCst);
118+
loop {
119+
if loaded == 0 {
120+
return 0;
121+
}
122+
match counter.compare_exchange_weak(loaded, loaded + 1, SeqCst, SeqCst) {
123+
Ok(x) => return x + 1,
124+
Err(actual) => loaded = actual,
125+
}
126+
}
127+
}

crates/gpui/src/window.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ use uuid::Uuid;
5252

5353
mod prompts;
5454

55+
use crate::util::atomic_incr_if_not_zero;
5556
pub use prompts::*;
5657

5758
pub(crate) const DEFAULT_WINDOW_SIZE: Size<Pixels> = size(px(1024.), px(700.));
@@ -263,15 +264,13 @@ impl FocusHandle {
263264
pub(crate) fn for_id(id: FocusId, handles: &Arc<FocusMap>) -> Option<Self> {
264265
let lock = handles.read();
265266
let ref_count = lock.get(id)?;
266-
if ref_count.load(SeqCst) == 0 {
267-
None
268-
} else {
269-
ref_count.fetch_add(1, SeqCst);
270-
Some(Self {
271-
id,
272-
handles: handles.clone(),
273-
})
267+
if atomic_incr_if_not_zero(ref_count) == 0 {
268+
return None;
274269
}
270+
Some(Self {
271+
id,
272+
handles: handles.clone(),
273+
})
275274
}
276275

277276
/// Converts this focus handle into a weak variant, which does not prevent it from being released.

0 commit comments

Comments
 (0)