diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2015-04-30 15:04:41 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2015-04-30 15:28:22 +0300 |
commit | f271d85b865cb5e82b50a29f91d2cabbbede6a9a (patch) | |
tree | 4811571c2de75cc04bf3dbf15489a26a013a8b80 | |
parent | d1c98520f7b792d5f2f1f2d1eb51d08d172e2e22 (diff) |
Fix T44439: outliner's treestore could keep invalid ID pointers, could crash on undo due to invalid mem access.
We cannot nuke treestore in readfile's `blo_lib_link_screen_restore()`, because this will
destroy all UI-state data (like opened/closed items, etc.).
Since we cannot know for sure whether an ID pointer from tselem->id is valid here, we
have to ensure they are never invalid, i.e. to always set them to NULL when we delete them.
To do so, this commit uses a similar approach as what already exists for ID references
in WM notifiers - it extends `free_notifier_reference_cb()` to also nullify those IDs in
all outliners.
Note that some ID types are not used(shown) by outliner currently, so `TREESTORE_ID_TYPE` macro
was added, that checks whether an ID is possibly used by outliner. Avoids a few searches
in whole tree whene deleting some IDs.
Reviewers: campbellbarton, sergey
Maniphest Tasks: T44439
Differential Revision: https://developer.blender.org/D1272
5 files changed, 100 insertions, 0 deletions
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h new file mode 100644 index 00000000000..af4af8e2f5d --- /dev/null +++ b/source/blender/editors/include/ED_outliner.h @@ -0,0 +1,36 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ED_outliner.h + * \ingroup editors + */ + +#ifndef __ED_OUTLINER_H__ +#define __ED_OUTLINER_H__ + +struct ID; +struct SpaceOops; + +/* Used to check whether a given texture context is valid in current context. */ +void ED_outliner_id_unref(struct SpaceOops *so, const struct ID *id); + +#endif /* __ED_OUTLINER_H__ */ diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 798dae2cef3..058b8c4de5a 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -39,20 +39,24 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_mempool.h" #include "BLF_translation.h" #include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_depsgraph.h" +#include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_outliner_treehash.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_material.h" #include "BKE_group.h" #include "ED_object.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_keyframing.h" @@ -1952,3 +1956,35 @@ void OUTLINER_OT_group_link(wmOperatorType *ot) /* properties */ RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object"); } + +/******** Utils to clear any ref to freed ID... **********/ + +void ED_outliner_id_unref(SpaceOops *so, const ID *id) +{ + /* Some early out checks. */ + if (!TREESTORE_ID_TYPE(id)) { + return; /* ID type is not used by outilner... */ + } + + if (so->search_tse.id == id) { + so->search_tse.id = NULL; + } + + if (so->treestore) { + TreeStoreElem *tselem; + BLI_mempool_iter iter; + bool changed = false; + + BLI_mempool_iternew(so->treestore, &iter); + while ((tselem = BLI_mempool_iterstep(&iter))) { + if (tselem->id == id) { + tselem->id = NULL; + changed = true; + } + } + if (so->treehash && changed) { + /* rebuild hash table, because it depends on ids too */ + BKE_outliner_treehash_rebuild_from_treestore(so->treehash, so->treestore); + } + } +} diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index b4b73a11a14..38672ef14dd 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -57,6 +57,10 @@ typedef struct TreeElement { PointerRNA rnaptr; // RNA Pointer } TreeElement; +#define TREESTORE_ID_TYPE(_id) \ + (ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \ + ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS)) + /* TreeElement->flag */ #define TE_ACTIVE 1 #define TE_ICONROW 2 diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 17a6e952ee1..4b07c400220 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -855,6 +855,11 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i return NULL; } + if (type == 0) { + /* Zero type means real ID, ensure we do not get non-outliner ID types here... */ + BLI_assert(TREESTORE_ID_TYPE(id)); + } + te = MEM_callocN(sizeof(TreeElement), "tree elem"); /* add to the visual tree */ BLI_addtail(lb, te); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index e2b8598b4fe..c883b37f6c5 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -63,6 +63,7 @@ #include "ED_fileselect.h" #include "ED_info.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_view3d.h" #include "ED_util.h" @@ -217,6 +218,8 @@ void WM_main_remove_notifier_reference(const void *reference) { Main *bmain = G.main; wmWindowManager *wm = bmain->wm.first; + bScreen *sc; + if (wm) { wmNotifier *note, *note_next; @@ -230,6 +233,22 @@ void WM_main_remove_notifier_reference(const void *reference) } } } + + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + ScrArea *sa; + + for (sa = sc->areabase.first; sa; sa = sa->next) { + SpaceLink *sl; + + for (sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_OUTLINER) { + SpaceOops *so = (SpaceOops *)sl; + + ED_outliner_id_unref(so, (ID *)reference); + } + } + } + } } static void wm_notifier_clear(wmNotifier *note) |