fix for bug where notifiers could hold pointers to freed data which listeners would...
authorCampbell Barton <ideasman42@gmail.com>
Mon, 8 Apr 2013 13:03:04 +0000 (13:03 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 8 Apr 2013 13:03:04 +0000 (13:03 +0000)
source/blender/blenkernel/BKE_library.h
source/blender/blenkernel/intern/library.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_init_exit.c

index 99247414cfff955e2a2699891d575e2b4e48251c..3c5406c4a7782f437a57de43146b6473cb9a52c2 100644 (file)
@@ -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")
index 1674fbd55a79db8ab836cfec46b02c977c4c1605..da642f11e8d3ec9ce16277c9c27f01a1be080dc8 100644 (file)
@@ -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);
index a395d535907623cb76510cccc8a94a11487a6360..9e6a483aa763affd83de9c79454c49eb10819d8e 100644 (file)
@@ -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);
 
index 626eeeadfe466f811ded248dcfcf73f048f5eed4..82ad87ed3b0393a117c823d1ac70f6c6afa40c71 100644 (file)
@@ -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;
index 16afad88069399dd13ac4dbb0a1a3aab04abfcd4..ccb463e59cbfb888aace466e6ad1903fc68d6c7e 100644 (file)
@@ -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 */