macOS: clear ivar earlier to prevent double free in release (#108)
This commit is contained in:
parent
f6e99e9aa6
commit
004065e9a4
|
@ -178,12 +178,7 @@ extern "C" fn release(this: &mut Object, _sel: Sel) {
|
||||||
let retain_count_after_build = WindowState::from_field(this).retain_count_after_build;
|
let retain_count_after_build = WindowState::from_field(this).retain_count_after_build;
|
||||||
|
|
||||||
if retain_count <= retain_count_after_build {
|
if retain_count <= retain_count_after_build {
|
||||||
WindowState::from_field(this).stop();
|
WindowState::stop_and_free(this);
|
||||||
|
|
||||||
this.set_ivar(BASEVIEW_STATE_IVAR, ::std::ptr::null() as *const c_void);
|
|
||||||
|
|
||||||
// Drop WindowState
|
|
||||||
Box::from_raw(state_ptr as *mut WindowState);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -359,15 +359,26 @@ impl WindowState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call when freeing view
|
/// Call when freeing view
|
||||||
pub(super) unsafe fn stop(&mut self) {
|
pub(super) unsafe fn stop_and_free(ns_view_obj: &mut Object) {
|
||||||
if let Some(frame_timer) = self.frame_timer.take() {
|
let state_ptr: *mut c_void = *ns_view_obj.get_ivar(BASEVIEW_STATE_IVAR);
|
||||||
|
|
||||||
|
// Take back ownership of Box<WindowState> so that it gets dropped
|
||||||
|
// when it goes out of scope
|
||||||
|
let mut window_state = Box::from_raw(state_ptr as *mut WindowState);
|
||||||
|
|
||||||
|
if let Some(frame_timer) = window_state.frame_timer.take() {
|
||||||
CFRunLoop::get_current().remove_timer(&frame_timer, kCFRunLoopDefaultMode);
|
CFRunLoop::get_current().remove_timer(&frame_timer, kCFRunLoopDefaultMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.trigger_event(Event::Window(WindowEvent::WillClose));
|
// Clear ivar before triggering WindowEvent::WillClose. Otherwise, if the
|
||||||
|
// handler of the event causes another call to release, this function could be
|
||||||
|
// called again, leading to a double free.
|
||||||
|
ns_view_obj.set_ivar(BASEVIEW_STATE_IVAR, ::std::ptr::null() as *const c_void);
|
||||||
|
|
||||||
|
window_state.trigger_event(Event::Window(WindowEvent::WillClose));
|
||||||
|
|
||||||
// If in non-parented mode, we want to also quit the app altogether
|
// If in non-parented mode, we want to also quit the app altogether
|
||||||
if let Some(app) = self.window.ns_app.take() {
|
if let Some(app) = window_state.window.ns_app.take() {
|
||||||
app.stop_(app);
|
app.stop_(app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue