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:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user