java-topology/defects/vtk/ticket.md

100 lines
3.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# vtk-0001: CWE-407 — O(C×npts²) linear dedup scan in vtkStaticCleanPolyData
# vtk-0002: CWE-407 — O(numPts×numLabels) linear label-set scan in vtkGeneralizedSurfaceNets3D
---
## vtk-0001
### Severity
HIGH
### File
`Filters/Core/vtkStaticCleanPolyData.cxx:257,293,343,403`
### Description
`vtkStaticCleanPolyData::RequestData()` deduplicates point IDs within each
cell using a `std::vector<vtkIdType> cellIds` maintained per cell. For each
point in the cell the code calls `std::find(cellIds.begin(), cellIds.end(),
ptId)` before appending to the vector. The pattern appears four times for
the four cell types: verts, lines, polys, and triangle strips.
The outer loop iterates over all C cells in the mesh. For each cell the
inner loop iterates npts times and each iteration does an O(k) linear scan
(where k grows from 0 to npts1). Total cost per cell: O(npts²). Total
cost: O(C × npts²).
For a triangulated surface with C = 10 000 000 triangles this is
O(C × 9) ≈ 90 M ops — manageable. But for strip-based or high-valence mesh
data (npts up to 64256) the cost becomes O(C × npts²) = O(C × 65536) ops,
a 7 000× regression over the expected O(C × npts) cost.
The source comment even notes: "Just use a vector to keep track of unique
ids — it's a small set so find() will execute relatively fast." This is
only true when npts is always small, but VTK processes arbitrary meshes.
### Root Cause
`cellIds` is a `std::vector<vtkIdType>`. Deduplication via linear scan is
O(k) per point. Replacing with `std::unordered_set<vtkIdType>` reduces the
membership test to O(1) amortized, cutting deduplication from O(npts²) to
O(npts) per cell.
### Fix
Replace `std::vector<vtkIdType> cellIds` with `std::unordered_set<vtkIdType>
seenIds` for the dedup check; accumulate the insertion-ordered result in a
separate `std::vector` only when building the output cell.
### Speedup
At npts = 64 (strip with 64 points): 64²/64 = 64× per cell.
At npts = 256: 256× per cell.
Asymptotic: O(C × npts²) → O(C × npts).
### Affected Operations
- `vtkStaticCleanPolyData::RequestData()` — used as a preprocessing step
before virtually every VTK geometry pipeline (surface nets, voronoi,
ghost-cell generation, smoothing, etc.)
---
## vtk-0002
### Severity
HIGH
### File
`Filters/Meshing/vtkGeneralizedSurfaceNets3D.cxx:1150`
### Description
When no explicit labels are provided, `RequestData()` collects the unique
set of region IDs by iterating all numPts point scalars and calling
`std::find(autoLabels.begin(), autoLabels.end(), regionId)` before
appending to `autoLabels`:
```cpp
for (vtkIdType i = 0; i < numPts; ++i) {
double regionId = static_cast<double>(regions->GetValue(i));
if (regionId >= 0 &&
std::find(autoLabels.begin(), autoLabels.end(), regionId) == autoLabels.end())
{
autoLabels.push_back(regionId);
}
}
```
Cost: O(numPts × numLabels). For a 50 M-point segmentation volume with
200 tissue classes: 50M × 200 = 10^10 comparisons where O(numPts) suffices.
### Root Cause
`autoLabels` is a `std::vector<double>`. The uniqueness check is a linear
scan. An `std::unordered_set<double>` provides O(1) membership.
### Fix
Use `std::unordered_set<double>` for the existence check during collection,
then move the sorted result into a vector if ordering is needed.
### Speedup
At numPts = 50 000 000, numLabels = 200: 200× speedup.
Asymptotic: O(numPts × numLabels) → O(numPts).
### Affected Operations
- `vtkGeneralizedSurfaceNets3D::RequestData()` — called when processing
multi-label segmentation volumes (medical imaging, simulation data)