Fix T89196: Depsgraph use-after-free after scene switching undo

Delay depsgraph visibility update tagging until it is known that
graph relations are up to date, and until it is known that the graph
is actually needed to be evaluated.

Differential Revision: https://developer.blender.org/D11660
This commit is contained in:
Sergey Sharybin 2021-06-21 14:27:26 +02:00
parent d3a792431e
commit 956c539e59
Notes: blender-bot 2023-02-14 01:21:16 +01:00
Referenced by commit 978f2cb900, Fix T89487: Crash adding Rigid Body to object with shared mesh data
Referenced by issue #89487, Crash adding Rigid Body to object with shared mesh data
Referenced by issue #89196, Depsgraph use-after-free after scene switching undo
8 changed files with 39 additions and 12 deletions

View File

@ -110,7 +110,7 @@ void DEG_free_node_types(void);
/* Update Tagging -------------------------------- */
/* Tag dependency graph for updates when visible scenes/layers changes. */
void DEG_graph_tag_on_visible_update(struct Main *bmain, Depsgraph *depsgraph, const bool do_time);
void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, const bool do_time);
/* Tag all dependency graphs for update when visible scenes/layers changes. */
void DEG_tag_on_visible_update(struct Main *bmain, const bool do_time);

View File

@ -98,7 +98,7 @@ void AbstractBuilderPipeline::build_step_finalize()
deg_graph_->scene_cow = (Scene *)deg_graph_->get_cow_id(&deg_graph_->scene->id);
/* Flush visibility layer and re-schedule nodes for update. */
deg_graph_build_finalize(bmain_, deg_graph_);
DEG_graph_tag_on_visible_update(bmain_, reinterpret_cast<::Depsgraph *>(deg_graph_), false);
DEG_graph_tag_on_visible_update(reinterpret_cast<::Depsgraph *>(deg_graph_), false);
#if 0
if (!DEG_debug_consistency_check(deg_graph_)) {
printf("Consistency validation failed, ABORTING!\n");

View File

@ -62,6 +62,8 @@ namespace blender::deg {
Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
: time_source(nullptr),
need_update(true),
need_visibility_update(true),
need_visibility_time_update(false),
bmain(bmain),
scene(scene),
view_layer(view_layer),

View File

@ -108,6 +108,11 @@ struct Depsgraph {
/* Indicates whether relations needs to be updated. */
bool need_update;
/* Indicated whether IDs in this graph are to be tagged as if they first appear visible, with
* an optional tag for their animation (time) update. */
bool need_visibility_update;
bool need_visibility_time_update;
/* Indicates which ID types were updated. */
char id_type_updated[INDEX_ID_MAX];

View File

@ -500,8 +500,23 @@ void deg_graph_node_tag_zero(Main *bmain,
deg_graph_id_tag_legacy_compat(bmain, graph, id, (IDRecalcFlag)0, update_source);
}
void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_time)
void graph_tag_on_visible_update(Depsgraph *graph, const bool do_time)
{
graph->need_visibility_update = true;
graph->need_visibility_time_update |= do_time;
}
} /* namespace */
void graph_tag_ids_for_visible_update(Depsgraph *graph)
{
if (!graph->need_visibility_update) {
return;
}
const bool do_time = graph->need_visibility_time_update;
Main *bmain = graph->bmain;
/* NOTE: It is possible to have this function called with `do_time=false` first and later (prior
* to evaluation though) with `do_time=true`. This means early output checks should be aware of
* this. */
@ -559,9 +574,10 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti
* dependency graph. */
id_node->previously_visible_components_mask = id_node->visible_components_mask;
}
}
} /* namespace */
graph->need_visibility_update = false;
graph->need_visibility_time_update = false;
}
NodeType geometry_tag_to_component(const ID *id)
{
@ -804,16 +820,16 @@ void DEG_id_type_tag(Main *bmain, short id_type)
}
/* Update dependency graph when visible scenes/layers changes. */
void DEG_graph_tag_on_visible_update(Main *bmain, Depsgraph *depsgraph, const bool do_time)
void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, const bool do_time)
{
deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph;
deg::deg_graph_on_visible_update(bmain, graph, do_time);
deg::graph_tag_on_visible_update(graph, do_time);
}
void DEG_tag_on_visible_update(Main *bmain, const bool do_time)
{
for (deg::Depsgraph *depsgraph : deg::get_all_registered_graphs(bmain)) {
deg::deg_graph_on_visible_update(bmain, depsgraph, do_time);
deg::graph_tag_on_visible_update(depsgraph, do_time);
}
}

View File

@ -41,5 +41,9 @@ void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source);
void graph_id_tag_update(
Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source);
/* Tag IDs of the graph for the visibility update tags.
* Will do nothing if the graph is not tagged for visibility update. */
void graph_tag_ids_for_visible_update(Depsgraph *graph);
} // namespace deg
} // namespace blender

View File

@ -45,6 +45,7 @@
#include "intern/depsgraph.h"
#include "intern/depsgraph_relation.h"
#include "intern/depsgraph_tag.h"
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/eval/deg_eval_flush.h"
#include "intern/eval/deg_eval_stats.h"
@ -365,6 +366,8 @@ static TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state)
*/
void deg_evaluate_on_refresh(Depsgraph *graph)
{
graph_tag_ids_for_visible_update(graph);
/* Nothing to update, early out. */
if (graph->entry_tags.is_empty()) {
return;

View File

@ -380,10 +380,7 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
*/
Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
if (is_after_open_file) {
/* TODO(sergey): Remove after the handling of visibility tags is delayed until graph
* evaluation. */
DEG_graph_relations_update(depsgraph);
DEG_graph_tag_on_visible_update(bmain, depsgraph, true);
DEG_graph_tag_on_visible_update(depsgraph, true);
}
DEG_make_active(depsgraph);
BKE_scene_graph_update_tagged(depsgraph, bmain);