Fix #104690: Evaluated positions user-after-free for copied poly curves

The evaluated positions cache can live longer than a specific
`CurvesGeometry`, but for only-poly curves, it pointed to the positions,
which are freed when the curves are. Instead, use the same pattern
as the evaluated offsets and don't store the positions span, just return
it when retrieving evaluated positions.
This commit is contained in:
Hans Goudey
2023-02-15 11:38:17 -05:00
parent b7e39acfcd
commit 72a2229848
2 changed files with 15 additions and 21 deletions

View File

@@ -71,16 +71,11 @@ class CurvesGeometryRuntime {
mutable SharedCache<Vector<curves::nurbs::BasisCache>> nurbs_basis_cache;
/** Cache of evaluated positions. */
struct EvaluatedPositions {
Vector<float3> vector;
/**
* The evaluated positions result, using a separate span in case all curves are poly curves,
* in which case a separate array of evaluated positions is unnecessary.
*/
Span<float3> span;
};
mutable SharedCache<EvaluatedPositions> evaluated_position_cache;
/**
* Cache of evaluated positions for all curves. The positions span will
* be used directly rather than the cache when all curves are poly type.
*/
mutable SharedCache<Vector<float3>> evaluated_position_cache;
/**
* A cache of bounds shared between data-blocks with unchanged positions and radii.

View File

@@ -605,17 +605,15 @@ void CurvesGeometry::ensure_nurbs_basis_cache() const
Span<float3> CurvesGeometry::evaluated_positions() const
{
const bke::CurvesGeometryRuntime &runtime = *this->runtime;
if (this->is_single_type(CURVE_TYPE_POLY)) {
runtime.evaluated_position_cache.ensure(
[&](Vector<float3> &r_data) { r_data.clear_and_shrink(); });
return this->positions();
}
this->ensure_nurbs_basis_cache();
runtime.evaluated_position_cache.ensure([&](CurvesGeometryRuntime::EvaluatedPositions &r_data) {
if (this->is_single_type(CURVE_TYPE_POLY)) {
r_data.span = this->positions();
r_data.vector.clear_and_shrink();
return;
}
r_data.vector.resize(this->evaluated_points_num());
r_data.span = r_data.vector;
MutableSpan<float3> evaluated_positions = r_data.vector;
runtime.evaluated_position_cache.ensure([&](Vector<float3> &r_data) {
r_data.resize(this->evaluated_points_num());
MutableSpan<float3> evaluated_positions = r_data;
const OffsetIndices<int> points_by_curve = this->points_by_curve();
const OffsetIndices<int> evaluated_points_by_curve = this->evaluated_points_by_curve();
@@ -672,7 +670,7 @@ Span<float3> CurvesGeometry::evaluated_positions() const
}
});
});
return runtime.evaluated_position_cache.data().span;
return runtime.evaluated_position_cache.data();
}
Span<float3> CurvesGeometry::evaluated_tangents() const
@@ -781,6 +779,7 @@ static void evaluate_generic_data_for_curve(
Span<float3> CurvesGeometry::evaluated_normals() const
{
const bke::CurvesGeometryRuntime &runtime = *this->runtime;
this->ensure_nurbs_basis_cache();
runtime.evaluated_normal_cache.ensure([&](Vector<float3> &r_data) {
const OffsetIndices<int> points_by_curve = this->points_by_curve();
const OffsetIndices<int> evaluated_points_by_curve = this->evaluated_points_by_curve();