Fix #136615: Disallow writeback callbacks that are not cleared

Adding "writeback" callbacks to the depsgraph should be temporary, since these
callbacks can bind pointers that become invalid. In this case: the evaluated
nodes modifier bound by a bake node callback. These callbacks are cleared after
being added in the `deg_flush_updates_and_refresh` function, but there are other
cases where depsgraph updates are executed which don't support writeback
callbacks (`object_force_modifier_update_for_bind` run by the smooth modifier
"bind" function).

To prevent dangling invalid pointers in outdated callbacks, disallow adding
callbacks in any case other than the `deg_flush_updates_and_refresh` function.
Since callbacks can be added from any depsgraph update, the safest way to
prevent adding them is in the depsgraph itself. If the `use_writeback_callbacks`
flag is not set, any callback is simply discarded.

Pull Request: https://projects.blender.org/blender/blender/pulls/137083
This commit is contained in:
Lukas Tönne
2025-04-07 13:30:35 +02:00
parent 0ff9a162c1
commit 10e95bebca
4 changed files with 10 additions and 6 deletions

View File

@@ -53,6 +53,7 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati
ctime(BKE_scene_ctime_get(scene)),
scene_cow(nullptr),
is_active(false),
sync_writeback(DEG_EVALUATE_SYNC_WRITEBACK_NO),
use_visibility_optimization(true),
is_evaluating(false),
is_render_pipeline_depsgraph(false),

View File

@@ -178,6 +178,8 @@ struct Depsgraph {
/* The number of times this graph has been evaluated. */
uint64_t update_count;
/* If this mode does not allow writing back to original data any callbacks will be discarded. */
DepsgraphEvaluateSyncWriteback sync_writeback;
/**
* Stores functions that can be called after depsgraph evaluation to writeback some changes to
* original data. Also see `DEG_depsgraph_writeback_sync.hh`.

View File

@@ -37,15 +37,16 @@ static void deg_flush_updates_and_refresh(deg::Depsgraph *deg_graph,
deg::graph_tag_ids_for_visible_update(deg_graph);
deg::deg_graph_flush_updates(deg_graph);
BLI_assert(deg_graph->sync_writeback_callbacks.is_empty());
deg_graph->sync_writeback = sync_writeback;
deg::deg_evaluate_on_refresh(deg_graph);
if (sync_writeback == DEG_EVALUATE_SYNC_WRITEBACK_YES) {
if (deg_graph->is_active) {
for (std::function<void()> &fn : deg_graph->sync_writeback_callbacks) {
fn();
}
if ((deg_graph->sync_writeback == DEG_EVALUATE_SYNC_WRITEBACK_YES) && deg_graph->is_active) {
for (std::function<void()> &fn : deg_graph->sync_writeback_callbacks) {
fn();
}
}
deg_graph->sync_writeback = DEG_EVALUATE_SYNC_WRITEBACK_NO;
deg_graph->sync_writeback_callbacks.clear();
}

View File

@@ -14,7 +14,7 @@ namespace blender::deg::sync_writeback {
void add(::Depsgraph &depsgraph, std::function<void()> fn)
{
deg::Depsgraph &deg_graph = reinterpret_cast<deg::Depsgraph &>(depsgraph);
if (!deg_graph.is_active) {
if (!deg_graph.is_active || deg_graph.sync_writeback == DEG_EVALUATE_SYNC_WRITEBACK_NO) {
return;
}