From 7eb9b7976ff4e6ba820595dc59178f1ac189db3e Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 27 Apr 2021 12:33:40 +0200 Subject: Fix T85889: recursive instances result in crash Generally, it would be good to not allow this from happening in the first place but that is quite tricky because an object does not know which other object instances it. Similar checks might be necessary in other places, but this fixes the bug already. Differential Revision: https://developer.blender.org/D11086 --- source/blender/blenkernel/intern/object_dupli.cc | 25 ++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'source/blender/blenkernel') diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index ddf7826969b..835b62c06bf 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -36,6 +36,7 @@ #include "BLI_math.h" #include "BLI_rand.h" #include "BLI_span.hh" +#include "BLI_vector.hh" #include "DNA_anim_types.h" #include "DNA_collection_types.h" @@ -73,6 +74,7 @@ using blender::Array; using blender::float3; using blender::float4x4; using blender::Span; +using blender::Vector; /* -------------------------------------------------------------------- */ /** \name Internal Duplicate Context @@ -90,6 +92,13 @@ struct DupliContext { Object *object; float space_mat[4][4]; + /** + * A stack that contains all the "parent" objects of a particular instance when recursive + * instancing is used. This is used to prevent objects from instancing themselves accidentally. + * Use a vector instead of a stack because we want to use the #contains method. + */ + Vector *instance_stack; + int persistent_id[MAX_DUPLI_RECUR]; int level; @@ -113,7 +122,8 @@ static void init_context(DupliContext *r_ctx, Depsgraph *depsgraph, Scene *scene, Object *ob, - const float space_mat[4][4]) + const float space_mat[4][4], + Vector &instance_stack) { r_ctx->depsgraph = depsgraph; r_ctx->scene = scene; @@ -122,6 +132,7 @@ static void init_context(DupliContext *r_ctx, r_ctx->object = ob; r_ctx->obedit = OBEDIT_FROM_OBACT(ob); + r_ctx->instance_stack = &instance_stack; if (space_mat) { copy_m4_m4(r_ctx->space_mat, space_mat); } @@ -150,6 +161,7 @@ static void copy_dupli_context( } r_ctx->object = ob; + r_ctx->instance_stack = ctx->instance_stack; if (mat) { mul_m4_m4m4(r_ctx->space_mat, (float(*)[4])ctx->space_mat, mat); } @@ -235,12 +247,19 @@ static void make_recursive_duplis(const DupliContext *ctx, const float space_mat[4][4], int index) { + if (ctx->instance_stack->contains(ob)) { + /* Avoid recursive instances. */ + printf("Warning: '%s' object is trying to instance itself.\n", ob->id.name + 2); + return; + } /* Simple preventing of too deep nested collections with #MAX_DUPLI_RECUR. */ if (ctx->level < MAX_DUPLI_RECUR) { DupliContext rctx; copy_dupli_context(&rctx, ctx, ob, space_mat, index); if (rctx.gen) { + ctx->instance_stack->append(ob); rctx.gen->make_duplis(&rctx); + ctx->instance_stack->remove_last(); } } } @@ -1588,7 +1607,9 @@ ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob) { ListBase *duplilist = (ListBase *)MEM_callocN(sizeof(ListBase), "duplilist"); DupliContext ctx; - init_context(&ctx, depsgraph, sce, ob, nullptr); + Vector instance_stack; + instance_stack.append(ob); + init_context(&ctx, depsgraph, sce, ob, nullptr, instance_stack); if (ctx.gen) { ctx.duplilist = duplilist; ctx.gen->make_duplis(&ctx); -- cgit v1.2.3