Skip to content

Commit ef89b5c

Browse files
authored
gpui: Fix macOS memory leaks (#45051)
The below memory leaks were caused by failing to release reference counted resources. I confirmed using instruments that my changes stopped the leaks from occurring. - System prompts - Screen capturing - loading font families There were also two memory leaks I found from some of our dependencies that I made PRs to fix - RustAudio/coreaudio-rs#147 - servo/core-foundation-rs#746 Release Notes: - N/A
1 parent 0ed82ec commit ef89b5c

4 files changed

Lines changed: 42 additions & 4 deletions

File tree

crates/gpui/src/platform/mac/open_type.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ pub fn apply_features_and_fallbacks(
5252
&kCFTypeDictionaryKeyCallBacks,
5353
&kCFTypeDictionaryValueCallBacks,
5454
);
55+
56+
for value in &values {
57+
CFRelease(*value as _);
58+
}
59+
5560
let new_descriptor = CTFontDescriptorCreateWithAttributes(attrs);
5661
CFRelease(attrs as _);
5762
let new_descriptor = CTFontDescriptor::wrap_under_create_rule(new_descriptor);

crates/gpui/src/platform/mac/screen_capture.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,21 @@ impl ScreenCaptureSource for MacScreenCaptureSource {
110110
let _: id = msg_send![configuration, setHeight: meta.resolution.height.0 as i64];
111111
let stream: id = msg_send![stream, initWithFilter:filter configuration:configuration delegate:delegate];
112112

113+
// Stream contains filter, configuration, and delegate internally so we release them here
114+
// to prevent a memory leak when steam is dropped
115+
let _: () = msg_send![filter, release];
116+
let _: () = msg_send![configuration, release];
117+
let _: () = msg_send![delegate, release];
118+
113119
let (mut tx, rx) = oneshot::channel();
114120

115121
let mut error: id = nil;
116122
let _: () = msg_send![stream, addStreamOutput:output type:SCStreamOutputTypeScreen sampleHandlerQueue:0 error:&mut error as *mut id];
117123
if error != nil {
118124
let message: id = msg_send![error, localizedDescription];
119-
tx.send(Err(anyhow!("failed to add stream output {message:?}")))
125+
let _: () = msg_send![stream, release];
126+
let _: () = msg_send![output, release];
127+
tx.send(Err(anyhow!("failed to add stream output {message:?}")))
120128
.ok();
121129
return rx;
122130
}
@@ -132,8 +140,10 @@ impl ScreenCaptureSource for MacScreenCaptureSource {
132140
};
133141
Ok(Box::new(stream) as Box<dyn ScreenCaptureStream>)
134142
} else {
143+
let _: () = msg_send![stream, release];
144+
let _: () = msg_send![output, release];
135145
let message: id = msg_send![error, localizedDescription];
136-
Err(anyhow!("failed to stop screen capture stream {message:?}"))
146+
Err(anyhow!("failed to start screen capture stream {message:?}"))
137147
};
138148
if let Some(tx) = tx.borrow_mut().take() {
139149
tx.send(result).ok();

crates/gpui/src/platform/mac/text_system.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use anyhow::anyhow;
88
use cocoa::appkit::CGFloat;
99
use collections::HashMap;
1010
use core_foundation::{
11+
array::{CFArray, CFArrayRef},
1112
attributed_string::CFMutableAttributedString,
1213
base::{CFRange, TCFType},
1314
number::CFNumber,
@@ -21,8 +22,10 @@ use core_graphics::{
2122
};
2223
use core_text::{
2324
font::CTFont,
25+
font_collection::CTFontCollectionRef,
2426
font_descriptor::{
25-
kCTFontSlantTrait, kCTFontSymbolicTrait, kCTFontWeightTrait, kCTFontWidthTrait,
27+
CTFontDescriptor, kCTFontSlantTrait, kCTFontSymbolicTrait, kCTFontWeightTrait,
28+
kCTFontWidthTrait,
2629
},
2730
line::CTLine,
2831
string_attributes::kCTFontAttributeName,
@@ -97,7 +100,26 @@ impl PlatformTextSystem for MacTextSystem {
97100
fn all_font_names(&self) -> Vec<String> {
98101
let mut names = Vec::new();
99102
let collection = core_text::font_collection::create_for_all_families();
100-
let Some(descriptors) = collection.get_descriptors() else {
103+
// NOTE: We intentionally avoid using `collection.get_descriptors()` here because
104+
// it has a memory leak bug in core-text v21.0.0. The upstream code uses
105+
// `wrap_under_get_rule` but `CTFontCollectionCreateMatchingFontDescriptors`
106+
// follows the Create Rule (caller owns the result), so it should use
107+
// `wrap_under_create_rule`. We call the function directly with correct memory management.
108+
unsafe extern "C" {
109+
fn CTFontCollectionCreateMatchingFontDescriptors(
110+
collection: CTFontCollectionRef,
111+
) -> CFArrayRef;
112+
}
113+
let descriptors: Option<CFArray<CTFontDescriptor>> = unsafe {
114+
let array_ref =
115+
CTFontCollectionCreateMatchingFontDescriptors(collection.as_concrete_TypeRef());
116+
if array_ref.is_null() {
117+
None
118+
} else {
119+
Some(CFArray::wrap_under_create_rule(array_ref))
120+
}
121+
};
122+
let Some(descriptors) = descriptors else {
101123
return names;
102124
};
103125
for descriptor in descriptors.into_iter() {

crates/gpui/src/platform/mac/window.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,7 @@ impl PlatformWindow for MacWindow {
11901190
let (done_tx, done_rx) = oneshot::channel();
11911191
let done_tx = Cell::new(Some(done_tx));
11921192
let block = ConcreteBlock::new(move |answer: NSInteger| {
1193+
let _: () = msg_send![alert, release];
11931194
if let Some(done_tx) = done_tx.take() {
11941195
let _ = done_tx.send(answer.try_into().unwrap());
11951196
}

0 commit comments

Comments
 (0)