From a0652430d0f824adb26de9d2ae22f80fec721f4e Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 23 Apr 2020 14:47:06 +0200 Subject: Array modifier: limit maximum amount of generated geometry. Fixes T75278: Crash when modifier "Array-Fit Curve-Relative Offset" nears zero. --- source/blender/modifiers/intern/MOD_array.c | 36 ++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) (limited to 'source/blender/modifiers') diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index ff5bf3d0ee4..bad1d7d3cf9 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -353,7 +353,6 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, const ModifierEvalContext *ctx, Mesh *mesh) { - const float eps = 1e-6f; const MVert *src_mvert; MVert *mv, *mv_prev, *result_dm_verts; @@ -473,21 +472,52 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, } } + /* About 67 million vertices max seems a decent limit for now. */ + const size_t max_num_vertices = 1 << 26; + /* calculate the maximum number of copies which will fit within the * prescribed length */ if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) { + const float float_epsilon = 1e-6f; + bool offset_is_too_small = false; float dist = len_v3(offset[3]); - if (dist > eps) { + if (dist > float_epsilon) { /* this gives length = first copy start to last copy end * add a tiny offset for floating point rounding errors */ - count = (length + eps) / dist + 1; + count = (length + float_epsilon) / dist + 1; + + /* Ensure we keep things to a reasonable level, in terms of rough total amount of generated + * vertices. + */ + if (((size_t)count * (size_t)chunk_nverts + (size_t)start_cap_nverts + + (size_t)end_cap_nverts) > max_num_vertices) { + count = 1; + offset_is_too_small = true; + } } else { /* if the offset has no translation, just make one copy */ count = 1; + offset_is_too_small = true; + } + + if (offset_is_too_small) { + modifier_setError( + &amd->modifier, + "The offset is too small, we cannot generate the amount of geometry it would require"); } } + /* Ensure we keep things to a reasonable level, in terms of rough total amount of generated + * vertices. + */ + else if (((size_t)count * (size_t)chunk_nverts + (size_t)start_cap_nverts + + (size_t)end_cap_nverts) > max_num_vertices) { + count = 1; + modifier_setError(&amd->modifier, + "The amount of copies is too high, we cannot generate the amount of " + "geometry it would require"); + } if (count < 1) { count = 1; -- cgit v1.2.3