From f004eace39e4201362390005130db2cbbaffbbbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Je=CC=81re=CC=81mie=20Dumas?= Date: Wed, 8 Apr 2026 17:07:12 -0700 Subject: [PATCH] Fix heap-buffer-overflow in getCharts() for cross-chart vertices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `getCharts()` function in `AtlasCharts.inl` uses a flat `chartVertexID` vector to map atlas mesh vertex indices to chart-local vertex indices. When an atlas mesh vertex is shared between two UV charts (a "pinch point" — same UV position and same surface vertex at a seam), the first chart sets `chartVertexID[v]` to its local index. The second chart then skips adding the vertex and reuses the first chart's local index, which is invalid for the second chart's vertex array. This causes an out-of-bounds read in `AtlasChart::vertex()` when the second chart later accesses its (smaller) vertex vector with an index that belongs to the first chart. The fix adds a parallel `chartVertexChart` vector to track which chart each vertex was last assigned to. When a vertex is encountered in a different chart, it is re-added to the new chart with a fresh local index. Co-Authored-By: Claude Opus 4.6 (1M context) --- include/Src/AtlasCharts.inl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/include/Src/AtlasCharts.inl b/include/Src/AtlasCharts.inl index 8f493ad..1327eee 100644 --- a/include/Src/AtlasCharts.inl +++ b/include/Src/AtlasCharts.inl @@ -46,21 +46,26 @@ const atlasCharts[ ChartIndex(i) ].maxCorner = Point2D< GeometryReal >(0,0); } - // The map taking a vertex index in the atlas and giving the index of the corresponding vertex within the chart + // The map taking a vertex index in the atlas and giving the index of the corresponding vertex within the chart. + // Also track which chart the vertex was assigned to, so that vertices shared between charts (pinch points) + // are correctly added to each chart independently. std::vector< unsigned int > chartVertexID( SimpleTriangleMesh< GeometryReal , 2 >::vertices.size() , static_cast< unsigned int >(-1) ); + std::vector< unsigned int > chartVertexChart( SimpleTriangleMesh< GeometryReal , 2 >::vertices.size() , static_cast< unsigned int >(-1) ); for( unsigned int t=0 ; t::triangles.size() ; t++ ) { - AtlasChart< GeometryReal > &atlasChart = atlasCharts[ triangleToChart( AtlasMeshTriangleIndex( t ) ) ]; + unsigned int chartIdx = static_cast< unsigned int >( triangleToChart( AtlasMeshTriangleIndex( t ) ) ); + AtlasChart< GeometryReal > &atlasChart = atlasCharts[ ChartIndex( chartIdx ) ]; SimplexIndex< 2 > tri; for( unsigned int k=0 ; k<3 ; k++ ) { atlasChart._chartHalfEdgeToAtlasEdge.push_back( halfEdgeToEdge( AtlasMeshHalfEdgeIndex( 3*t+k ) ) ); unsigned int v = SimpleTriangleMesh< GeometryReal , 2 >::triangles[t][k]; - if( chartVertexID[v]==-1 ) + if( chartVertexID[v]==static_cast< unsigned int >(-1) || chartVertexChart[v]!=chartIdx ) { chartVertexID[v] = (unsigned int)atlasChart.vertices.size(); + chartVertexChart[v] = chartIdx; Point2D< GeometryReal > vertexPos = SimpleTriangleMesh< GeometryReal , 2 >::vertices[v]; for( unsigned int c=0 ; c<2 ; c++ ) {