diff options
author | Campbell Barton <ideasman42@gmail.com> | 2013-04-08 17:03:04 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2013-04-08 17:03:04 +0400 |
commit | 85e53317be8f2d390752878dfc0a1aafc33df7ca (patch) | |
tree | 7ef81e83d7319fe4ac567759a932457179040acb | |
parent | 3fbaece0d63f9bf9826fee988624f195a8431fa4 (diff) |
fix for bug where notifiers could hold pointers to freed data which listeners would operate on.
-rw-r--r-- | source/blender/blenkernel/BKE_library.h | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/library.c | 12 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 1 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_system.c | 21 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_init_exit.c | 1 |
5 files changed, 36 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 99247414cff..3c5406c4a77 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -119,6 +119,7 @@ void flag_all_listbases_ids(short flag, short value); void recalc_all_library_objects(struct Main *main); void set_free_windowmanager_cb(void (*func)(struct bContext *, struct wmWindowManager *) ); +void set_free_notifier_reference_cb(void (*func)(const void *) ); /* use when "" is given to new_id() */ #define ID_FALLBACK_NAME N_("Untitled") diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 1674fbd55a7..da642f11e8d 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -823,6 +823,14 @@ void set_free_windowmanager_cb(void (*func)(bContext *C, wmWindowManager *) ) free_windowmanager_cb = func; } +static void (*free_notifier_reference_cb)(const void *) = NULL; + +void set_free_notifier_reference_cb(void (*func)(const void *) ) +{ + free_notifier_reference_cb = func; +} + + static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata) { ChannelDriver *driver; @@ -969,6 +977,10 @@ void BKE_libblock_free(ListBase *lb, void *idv) break; } + /* avoid notifying on removed data */ + if (free_notifier_reference_cb) + free_notifier_reference_cb(id); + BLI_remlink(lb, id); BKE_libblock_free_data(id); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index a395d535907..9e6a483aa76 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -170,6 +170,7 @@ int WM_modal_tweak_exit(const struct wmEvent *event, int tweak_event); /* notifiers */ void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference); void WM_main_add_notifier(unsigned int type, void *reference); +void WM_main_remove_notifier_reference(const void *reference); void wm_event_add(struct wmWindow *win, const struct wmEvent *event_to_add); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 626eeeadfe4..82ad87ed3b0 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -187,6 +187,27 @@ void WM_main_add_notifier(unsigned int type, void *reference) } } +/** + * Clear notifiers by reference, Used so listeners don't act on freed data. + */ +void WM_main_remove_notifier_reference(const void *reference) +{ + Main *bmain = G.main; + wmWindowManager *wm = bmain->wm.first; + if (wm) { + wmNotifier *note, *note_next; + + for (note = wm->queue.first; note; note = note_next) { + note_next = note->next; + + if (note->reference == reference) { + BLI_remlink(&wm->queue, note); + MEM_freeN(note); + } + } + } +} + static wmNotifier *wm_notifier_next(wmWindowManager *wm) { wmNotifier *note = wm->queue.first; diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 16afad88069..ccb463e59cb 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -145,6 +145,7 @@ void WM_init(bContext *C, int argc, const char **argv) WM_uilisttype_init(); set_free_windowmanager_cb(wm_close_and_free); /* library.c */ + set_free_notifier_reference_cb(WM_main_remove_notifier_reference); /* library.c */ set_blender_test_break_cb(wm_window_testbreak); /* blender.c */ DAG_editors_update_cb(ED_render_id_flush_update, ED_render_scene_update); /* depsgraph.c */ |