forked from bartvdbraak/blender
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
This commit is contained in:
parent
d1c98520f7
commit
f271d85b86
36
source/blender/editors/include/ED_outliner.h
Normal file
36
source/blender/editors/include/ED_outliner.h
Normal file
@ -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__ */
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user