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:
Campbell Barton
2023-07-11 12:49:03 +10:00
parent 8a73c36643
commit 6be0c90eab
3 changed files with 36 additions and 5 deletions

View File

@@ -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,

View File

@@ -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;

View File

@@ -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)