diff --git a/src/unix/apple/disk.rs b/src/unix/apple/disk.rs index 048c85268..cb702403f 100644 --- a/src/unix/apple/disk.rs +++ b/src/unix/apple/disk.rs @@ -92,7 +92,11 @@ impl crate::DisksInner { pub(crate) fn refresh_list(&mut self) { unsafe { - get_list(&mut self.disks); + // SAFETY: We don't keep any Objective-C objects around because we + // don't make any direct Objective-C calls in this code. + AutoreleasePool::new_with(|| { + get_list(&mut self.disks); + }) } } @@ -431,3 +435,32 @@ unsafe fn new_disk( }, }) } + +struct AutoreleasePool { + ctx: *mut c_void, +} + +impl AutoreleasePool { + /// Calls the provided closure in the context of a new autorelease pool that is drained + /// before returning. + /// + /// ## SAFETY: + /// You must not return an Objective-C object that is autoreleased from this function since it + /// will be freed before usable. + unsafe fn new_with T>(call: F) -> T { + // SAFETY: Creating a new pool is safe in any context. They can be arbitrarily nested + // as long as pool objects are not used in deeper layers, but we only have one and don't + // allow it to leave this scope. + let _pool_ctx = Self { ctx: unsafe { ffi::objc_autoreleasePoolPush() } }; + call() + // Pool is drained here before returning + } +} + +impl Drop for AutoreleasePool { + fn drop(&mut self) { + // SAFETY: We have not manipulated `pool_ctx` since it was received from a corresponding + // pool push call. + unsafe { ffi::objc_autoreleasePoolPop(self.ctx) } + } +} \ No newline at end of file diff --git a/src/unix/apple/ffi.rs b/src/unix/apple/ffi.rs index fb6dc0460..75ae0e1ec 100644 --- a/src/unix/apple/ffi.rs +++ b/src/unix/apple/ffi.rs @@ -13,6 +13,7 @@ cfg_if! { array::CFArrayRef, dictionary::CFDictionaryRef, error::CFErrorRef, string::CFStringRef, url::CFURLRef, }; + use std::ffi::c_void; #[link(name = "CoreFoundation", kind = "framework")] extern "C" { @@ -32,6 +33,12 @@ cfg_if! { pub static kCFURLVolumeIsInternalKey: CFStringRef; pub static kCFURLVolumeIsBrowsableKey: CFStringRef; } + + #[link(name = "objc", kind = "dylib")] + extern "C" { + pub fn objc_autoreleasePoolPop(pool: *mut c_void); + pub fn objc_autoreleasePoolPush() -> *mut c_void; + } } }