1
1

Fix #105583: crash when weld modifier checks for duplicate polygons

In very specific cases, during intersection testing, `intersect` can
add polygons already checked as duplicates in the buffer that
corresponds to the rest of polygons that can form groups of duplicates.

As the buffer cannot have repeated indices, re-adding, even
temporarily, these duplicates can cause a buffer overflow.

While this may have some impact on performance, it's difficult to
predict these cases and thus add a buffer pad.

So the solution is to check if they are already duplicated.
This commit is contained in:
2023-03-10 16:07:32 -03:00
parent 55281c0eed
commit d7c023eb25

View File

@@ -1102,8 +1102,11 @@ static int poly_find_doubles(const OffsetIndices<int> poly_corners_offsets,
{
/* Fills the `r_buffer` buffer with the intersection of the arrays in `buffer_a` and `buffer_b`.
* `buffer_a` and `buffer_b` have a sequence of sorted, non-repeating indices representing
* polygons. */
const auto intersect = [](const Span<int> buffer_a, const Span<int> buffer_b, int *r_buffer) {
* polygons. */
const auto intersect = [](const Span<int> buffer_a,
const Span<int> buffer_b,
const BitVector<> is_double,
int *r_buffer) {
int result_num = 0;
int index_a = 0, index_b = 0;
while (index_a < buffer_a.size() && index_b < buffer_b.size()) {
@@ -1117,7 +1120,12 @@ static int poly_find_doubles(const OffsetIndices<int> poly_corners_offsets,
}
else {
/* Equality. */
r_buffer[result_num++] = value_a;
/* Do not add duplicates.
* As they are already in the original array, this can cause buffer overflow. */
if (!is_double[value_a]) {
r_buffer[result_num++] = value_a;
}
index_a++;
index_b++;
}
@@ -1204,6 +1212,7 @@ static int poly_find_doubles(const OffsetIndices<int> poly_corners_offsets,
int *isect_result = doubles_buffer.data() + doubles_buffer_num + 1;
/* `polys_a` are the polygons connected to the first corner. So skip the first corner. */
for (int corner_index : IndexRange(corner_first + 1, corner_num - 1)) {
elem_index = corners[corner_index];
link_offs = linked_polys_offset[elem_index];
@@ -1217,8 +1226,10 @@ static int poly_find_doubles(const OffsetIndices<int> poly_corners_offsets,
polys_b_num--;
} while (poly_to_test != poly_index);
doubles_num = intersect(
Span<int>{polys_a, polys_a_num}, Span<int>{polys_b, polys_b_num}, isect_result);
doubles_num = intersect(Span<int>{polys_a, polys_a_num},
Span<int>{polys_b, polys_b_num},
is_double,
isect_result);
if (doubles_num == 0) {
break;
@@ -1236,6 +1247,12 @@ static int poly_find_doubles(const OffsetIndices<int> poly_corners_offsets,
}
doubles_buffer_num += doubles_num;
doubles_offsets.append(++doubles_buffer_num);
if ((doubles_buffer_num + 1) == poly_num) {
/* The last slot is the remaining unduplicated polygon.
* Avoid checking intersection as there are no more slots left. */
break;
}
}
}