Fix #109953: Timers without an associated window leak memory on exit
Thanks to @mod_moder & @Harley for their investigation, see !109603.
This commit is contained in:
@@ -623,6 +623,16 @@ struct wmTimer *WM_event_add_timer_notifier(struct wmWindowManager *wm,
|
||||
struct wmWindow *win,
|
||||
unsigned int type,
|
||||
double timestep);
|
||||
|
||||
void WM_event_timer_free_data(struct wmTimer *timer);
|
||||
/**
|
||||
* Free all timers immediately.
|
||||
*
|
||||
* \note This should only be used on-exit,
|
||||
* in all other cases timers should be tagged for removal by #WM_event_remove_timer.
|
||||
*/
|
||||
void WM_event_timers_free_all(wmWindowManager *wm);
|
||||
|
||||
/** Mark the given `timer` to be removed, actual removal and deletion is deferred and handled
|
||||
* internally by the window manager code. */
|
||||
void WM_event_remove_timer(struct wmWindowManager *wm,
|
||||
|
||||
@@ -607,6 +607,11 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
|
||||
|
||||
wm_reports_free(wm);
|
||||
|
||||
/* NOTE(@ideasman42): typically timers are associated with windows and timers will have been
|
||||
* freed when the windows are removed. However timers can be created which don't have windows
|
||||
* and in this case it's necessary to free them on exit, see: #109953. */
|
||||
WM_event_timers_free_all(wm);
|
||||
|
||||
if (wm->undo_stack) {
|
||||
BKE_undosys_stack_destroy(wm->undo_stack);
|
||||
wm->undo_stack = NULL;
|
||||
|
||||
@@ -1947,6 +1947,25 @@ void wm_window_delete_removed_timers(wmWindowManager *wm)
|
||||
}
|
||||
}
|
||||
|
||||
void WM_event_timer_free_data(wmTimer *timer)
|
||||
{
|
||||
if (timer->customdata != NULL && (timer->flags & WM_TIMER_NO_FREE_CUSTOM_DATA) == 0) {
|
||||
MEM_freeN(timer->customdata);
|
||||
timer->customdata = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void WM_event_timers_free_all(wmWindowManager *wm)
|
||||
{
|
||||
BLI_assert_msg(BLI_listbase_is_empty(&wm->windows),
|
||||
"This should only be called when freeing the window-manager");
|
||||
wmTimer *timer;
|
||||
while ((timer = BLI_pophead(&wm->timers))) {
|
||||
WM_event_timer_free_data(timer);
|
||||
MEM_freeN(timer);
|
||||
}
|
||||
}
|
||||
|
||||
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
|
||||
{
|
||||
/* Extra security check. */
|
||||
@@ -1970,12 +1989,9 @@ void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *
|
||||
}
|
||||
}
|
||||
|
||||
/* Immediately free customdata if requested, so that invalid usages of that data after
|
||||
/* Immediately free `customdata` if requested, so that invalid usages of that data after
|
||||
* calling `WM_event_remove_timer` can be easily spotted (through ASAN errors e.g.). */
|
||||
if (timer->customdata != NULL && (timer->flags & WM_TIMER_NO_FREE_CUSTOM_DATA) == 0) {
|
||||
MEM_freeN(timer->customdata);
|
||||
timer->customdata = NULL;
|
||||
}
|
||||
WM_event_timer_free_data(timer);
|
||||
}
|
||||
|
||||
void WM_event_remove_timer_notifier(wmWindowManager *wm, wmWindow *win, wmTimer *timer)
|
||||
|
||||
Reference in New Issue
Block a user