Repository navigation
BUG: C14: Parameter values not validated in preflight in 65 filters #1873
Description
Summary
Many filters accept parameter values that the algorithm cannot use. Preflight does not check the value, or checks only one bad value (for example == 0 but not < 0 or NaN). Execute then casts, divides by or loops on the value. The result is a crash, a hang, undefined behavior, or a wrong output with no error.
As of develop 419f9db (2026-10-21) this class has 68 open findings in 65 filters: 15 CRASH, 44 WRONG_DATA, 9 MINOR. All findings are candidates. They were found and re-checked by reading the code, not by running it.
Mechanism
Most simplnx numeric parameters (Float32Parameter, Float64Parameter, Int32Parameter, VectorUInt32Parameter, DynamicTableParameter and others) have no range. The filter must check the value in preflightImpl(). Many filters do not. The findings have five sub-patterns. Each checklist line has its letter.
| Sub-pattern | Findings | What goes wrong | |
|---|---|---|---|
| A | Kernel Radius (VectorUInt32) cast to int32 with no bound |
14 | >= 2^31 becomes negative, so the structuring element is empty and the output is a copy of the input. 2147483647 overflows the int32 loop in MakeStructuringElement and does not end. |
| B | Spacing, step, scale or distance not checked to be finite and > 0 | 15 | Division by 0, inf or NaN geometry, an empty output, or a loop with step 0 that does not end. CreateImageGeometryAction and UpdateImageGeomAction do not check spacing either. |
| C | Count, dimension or index not checked before use | 20 | 0, a negative value or a fraction is cast to usize, used as a divisor or used as an index: crash, huge allocation, or silent truncation (2.7 becomes 2). |
| D | Float64 value cast to the array element type with no range check | 9 | Out-of-range or NaN float-to-integer conversion is undefined behavior; a fraction is truncated. Local guards that compare with double(max) let 2^63 and 2^64 pass. |
| E | Parameter domain or relation not checked (Min < Max, Alpha != 0, 0 < Maximum Error < 1, legal combinations) | 10 | The filter gives a constant, NaN or meaningless output. |
Example on develop (sub-pattern C). CreateDataArrayFilter rejects only a tuple dimension of exactly 0, then casts the double to usize:
src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CreateDataArrayFilter.cpp#L135-L142
for(size_t idx = 0; idx < rowData.size(); idx++)
{
if(rowData[idx] == 0)
{
return MakePreflightErrorResult(-78603, fmt::format("Tuple dimension at index {} cannot be 0", idx));
}
tupleDims.push_back(static_cast<usize>(rowData[idx]));
}PR #1763 (8bed04c) fixed the same code in CreateDataArrayAdvancedFilter. It rejects every value that is not a positive whole number, before the cast:
src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CreateDataArrayAdvancedFilter.cpp#L204-L211
for(size_t idx = 0; idx < rowData.size(); idx++)
{
const double dim = rowData[idx];
if(!(dim >= 1.0) || std::floor(dim) != dim)
{
return MakePreflightErrorResult(-78603, fmt::format("Tuple dimension at index {} must be a positive whole number, but was {}", idx, dim));
}
tupleDims.push_back(static_cast<usize>(dim));The !(dim >= 1.0) form also rejects NaN. A check written as dim < 1.0 does not.
Rule
Decided:
- Every parameter value that the algorithm cannot use is rejected in preflight with a clear error. A parameter value does not need array values, so the check belongs in preflight, not in execute.
- If a new preflight check makes an execute-time check unreachable, remove the execute-time check. Do not keep duplicate checks.
Decision needed:
- Kernel Radius upper limit (A). Options: (a) reject a radius larger than the image extent on that axis; (b) reject a radius above a fixed cap such as
INT32_MAX / 2; (c) clamp the radius to the image extent with a warning. In all options,MakeStructuringElementshould also loop inint64. - Out-of-range values cast to the element type (D). Options: (a) reject in preflight (error for out of range or non-finite, warning for a fraction), as
ImageProcessing::ValidateScalarValueForTypedoes now; (b) saturate withImageProcessing::detail::SaturateCastFromDouble. The code comment in DoubleThresholdImageFilter says a saturating cast would differ from ITK; option (a) avoids that question. - Shared helpers (B, C). Options: (a) add shared validators to
src/simplnx/Utilities/DataArrayUtilities.hpp(a finite-and-positive check for spacing-like values, and a positive-whole-number check for dimensions and counts); (b) write the check in each filter. Option (a) is proposed.
How to fix
- Read each value in
preflightImpl()and validate it before any cast tousize,int32or the element typeT. - Use the existing helpers where they fit. All exist at 419f9db in namespace
nx::core::ImageProcessing, filesrc/simplnx/Utilities/ImageProcessing/ImageProcessingFilterUtilities.hpp:ValidateScalarValueForType(DataType, float64 value, label, nonFiniteCode, outOfRangeCode, truncatedWarnCode)for one float64 value against any element type (D). It uses an exclusiveldexpupper bound, so 2^63 and 2^64 are rejected.ValidateOneValueInRange<T>(...)for an integer type that is known at compile time (D). It replaces local guards such as the one in BinaryProjectionImageFilter.ValidatePositiveSpacing(spacing, dims, errorCode, minSpacing)for Image Geometry spacing. Note: it testsabs(spacing) > minSpacing, so it does not reject negative spacing. Add a sign check, or extend the helper, where negative spacing is wrong (for example IsoContourDistanceImageFilter).- BinaryDilateImageFilter already calls
ValidateBinaryFgBgInRangein preflight for its Foreground/Background values. Use it as the model.
- Write the checks so that NaN fails:
if(!(value > 0.0)), notif(value <= 0.0). Usestd::isfinitewhere inf is also invalid. - For dimensions and counts (C), require a whole number >= 1 with
std::floor(v) == vbefore the cast, as CreateDataArrayAdvancedFilter does. For a signed integer parameter, test the sign before the cast tousize. - For an index, test
index >= 0 && index < size, withsizefrom the selected DataArray or geometry. - For filters that share code, fix the shared code once:
CreateImageGeometryAction,ImageGeometryResample.cpp(ResampleImageGeomFilter and ReadImageStackFilter),MakeStructuringElement, and the Pearson distance inClusteringUtilities.hpp(used by ComputeKMeansFilter, ComputeKMedoidsFilter and other clustering filters). - Each new error code uses the filter's existing error-code range (codes more negative than -10000, one range of 100 per filter). Check that the code is unique with
git grep -nE -- "-NNNN([^0-9]|$)"on develop and on the open PR branches. Do not copy a code from another filter: for example, -78603 is used by three filters on develop. - Remove execute-time checks that the new preflight check makes unreachable (for example the Min > Max check at
ComputeArrayHistogram.cpp:657, error -23760).
How to test
- Write the test first. It must fail on develop.
- For each finding, add a preflight test: set the bad value from the finding, run
preflight(), andREQUIREthat the result is invalid with the new error code. A preflight-only test cannot hang or crash on develop, so it is safe for the hang and crash findings. - Add a boundary test: the smallest valid value (for example spacing 1e-6, one bin, index
size - 1) must pass preflight. - For sub-pattern D, test the exact limits: 2^63 for int64, 2^64 for uint64, -1 and 256 for uint8, NaN, and a fraction for an integer type.
- For findings where a valid value gives a wrong output (CreateDataArrayAdvancedFilter#3, CropVertexGeometryFilter#1, HierarchicalSmoothFilter#5), add an execute test and compare with an independent expected result (oracle).
- For filters with Direct and Scanline algorithms, run the execute tests for both with
GENERATE(from_range(UnitTest::SelectAlgorithmTestScenariosForInMemoryStores()))andUnitTest::AlgorithmTestScope.
Conventions
- One PR for the whole class, one commit per filter. Commit prefix
BUG:with aSigned-off-byline. No AI attribution. - This class is large. If one PR is too large to review, split it by sub-pattern (A to E) and link each PR to this issue.
- Every fix starts with a unit test that fails on develop. If you cannot reproduce a finding, write that and the reason in the PR and on this issue. Do not force a fix.
- Value checks need an independent expected result (oracle), not the code's own output.
- Run ctest serially. Never use
-j; the tests depend on each other. - Format with clang-format 19.1.1 and the repository
.clang-format. - Do not add sentences about input requirements to the filter documentation. The generated parameter table documents them.
- If a fix touches a filter that has a V&V report (
src/Plugins/<Plugin>/vv/<Filter>.md), update every file of its V&V package (report, deviations, provenance, test tables). V&V documents reference DREAM3D 6.5.171 only. - Rebase on develop. Never merge develop into the branch.
Checklist
- CRASH · AdaptiveHistogramEqualizationImageFilter · AdaptiveHistogramEqualizationEngine.hpp:109 — [A] Radius has no upper limit. {1000000, 1000000, 1000000} makes the neighborhood loop run about 10^12 times per cell, so the filter does not finish (cancel is checked once per plane).
AdaptiveHistogramEqualizationImageFilter#1 - CRASH · AlignSectionsFeatureCentroidFilter · AlignSectionsFeatureCentroidFilter.cpp:148 — [C] Preflight checks only Reference Slice < 0. A value >= the Z dimension makes execute read past the end of the per-slice centroid vectors.
AlignSectionsFeatureCentroidFilter#1 - CRASH · ComputeArrayHistogramFilter · ComputeArrayHistogramFilter.cpp:128 — [C] Number of Bins is not checked. 0 bins makes execute dereference
max_elementof an empty range; a negative value is cast tousize.ComputeArrayHistogramFilter#5 - CRASH · ComputeGBCDPoleFigureFilter · ComputeGBCDPoleFigureScanline.cpp:323 — [C] Output Image Dimension is cast to
usizewith no check. 0 divides by zero in the Scanline path (SIGFPE); a negative value wraps to a huge size.ComputeGBCDPoleFigureFilter#2 - CRASH · ComputeGBPDMetricBasedFilter · ComputeGBPDMetricBased.cpp:745 — [B] Limiting Distance <= 0 is not rejected. The loop
phi += stepwith step 0 or negative does not end and keeps callingpush_back(hang, out of memory).ComputeGBPDMetricBasedFilter#1 - CRASH · ConvertColorToGrayScaleFilter · ColorToGrayScale.cpp:24 — [C] The check
ColorChannel > 3lets 3 and negative values pass. SingleChannel then reads component 3 or -1 (out-of-bounds read, or an exception in a parallel worker).ConvertColorToGrayScaleFilter#2 - CRASH · ConvertHexGridToSquareGridFilter · ConvertHexGridToSquareGrid.cpp:119 — [B] Spacing 0 or negative is not rejected. Execute divides by it: 0 gives inf cast to
int32(undefined, a huge grid or an endless loop), negative gives an empty output.ConvertHexGridToSquareGridFilter#2 - CRASH · CreateAMScanPathsFilter · CreateAMScanPaths.cpp:190 — [B] Hatch Spacing is not checked. A negative value makes the
lineY += lineSpacingloop never end (no cancel check); 0 gives NaN and an empty output.CreateAMScanPathsFilter#4 - CRASH · ExtractComponentAsArrayFilter · ExtractComponentAsArrayFilter.cpp:108 — [C] The check
selectedArrayComp < pCompNumberValuelets index == component count pass. Execute reads past each tuple, and the remove path copies a wrapped length (heap overflow).ExtractComponentAsArrayFilter#1 - CRASH · PartitionGeometryFilter · PartitionGeometryFilter.cpp:550 — [C] Number Of Cells Per Axis is cast to
usizebefore the<= 0test, so -1 passes. Cell Length = 0 passes the< 0test, and Direct divides by 0.PartitionGeometryFilter#5 - CRASH · PointSampleEdgeGeometryFilter · PointSampleEdgeGeometry.cpp:73 — [B] Sampling Spacing <= 0 is not rejected.
dist / 0= inf is cast tousize(undefined): on ARM this gives 0 vertices and a read of an empty store, on x86 a huge resize.PointSampleEdgeGeometryFilter#3 - CRASH · ReadEnsembleInfoFilter · ReadEnsembleInfoFilter.cpp:120 — [C] Preflight rejects only Number_Phases == 0. -1 gives 0 tuples and execute writes
visited[0]of an empty vector; -2 or less wraps to about 2^64 tuples.ReadEnsembleInfoFilter#1 - CRASH · ReadHDF5DatasetFilter · ReadHDF5DatasetFilter.cpp:35 — [C] Dimensions from
std::stoigo intousizewith no sign check. Negative values wrap, their product can match the dataset size, and an array with about 2^64 tuples is created.ReadHDF5DatasetFilter#3 - CRASH · ReadStringDataArrayFilter · ReadStringDataArrayFilter.cpp:126 — [C] Only a tuple dimension of 0 is rejected. 0.5 becomes 0 and -1 a huge
usize;CreateStringArrayActioncan then throwstd::length_erroroutside the execute try/catch.ReadStringDataArrayFilter#3 - CRASH · WhiteTopHatImageFilter · WhiteTopHatImageFilter.cpp:102 — [A] Kernel Radius = 2147483647 makes the
int32loop inMakeStructuringElementoverflow and not end (hang); >= 2^31 gives an empty structuring element.WhiteTopHatImageFilter#1 - WRONG_DATA · ApplyTransformationToGeometryFilter · GeometryTransformation.cpp:222 — [B] Transformation Type = Scale with a Scale component <= 0 is not rejected. The Image Geometry spacing becomes 0 or negative.
ApplyTransformationToGeometryFilter#9 - WRONG_DATA · ApproximateSignedDistanceMapImageFilter · ImageProcessingFilterUtilities.hpp:3749 — [E] Inside Value or Outside Value = NaN or Inf is not rejected. The level set (inside + outside) / 2 is not finite and the output map is constant, with no error.
ApproximateSignedDistanceMapImageFilter#1 - WRONG_DATA · BinaryDilateImageFilter · BinaryDilateImageFilter.cpp:148 — [A] Kernel Radius >= 2^31 becomes negative after
static_cast<int32>, so the structuring element is empty and the output is a copy of the input with no error.BinaryDilateImageFilter#2 - WRONG_DATA · BinaryErodeImageFilter · BinaryErodeImageFilter.cpp:147 — [A] Kernel Radius >= 2^31 becomes negative after
static_cast<int32>, so the structuring element is empty and the output is a copy of the input with no error.BinaryErodeImageFilter#1 - WRONG_DATA · BinaryMorphologicalClosingImageFilter · BinaryMorphologicalClosingImageFilter.cpp:143 — [A] Kernel Radius >= 2^31 becomes negative after
static_cast<int32>, so the structuring element is empty and the output is a copy of the input with no error.BinaryMorphologicalClosingImageFilter#1 - WRONG_DATA · BinaryMorphologicalOpeningImageFilter · BinaryMorphologicalOpeningImageFilter.cpp:145 — [A] Kernel Radius >= 2^31 becomes negative after
static_cast<int32>, so the structuring element is empty and the output is a copy of the input with no error. 2147483647 overflows the loop.BinaryMorphologicalOpeningImageFilter#1 - WRONG_DATA · BinaryProjectionImageFilter · BinaryProjectionImageFilter.cpp:62 — [D] The local guard compares with
double(max), which rounds up to 2^63 or 2^64. Foreground Value = 2^63 passes for int64 and the later cast is undefined.BinaryProjectionImageFilter#1 - WRONG_DATA · ComputeArrayHistogramByFeatureFilter · ComputeArrayHistogramByFeatureFilter.cpp:134 — [E] With Use Custom Min & Max Range, Min >= Max is not rejected. Min == Max puts every value in bin 0; Min > Max gives inverted counts (Direct) or overflow (Scanline).
ComputeArrayHistogramByFeatureFilter#5 - WRONG_DATA · ComputeArrayHistogramByFeatureFilter · ComputeArrayHistogramByFeature.cpp:229 — [D] The custom Min/Max (float64) are cast to each input type with
static_cast<Type>and no range check. Max = 300 on a UInt8 array is undefined; fractional bounds are truncated.ComputeArrayHistogramByFeatureFilter#6 - WRONG_DATA · ComputeArrayHistogramFilter · ComputeArrayHistogram.cpp:656 — [D] Custom Min/Max are cast to T with no range check, Min == Max gives a zero bin width, and Min > Max is rejected only at execute (-23760).
ComputeArrayHistogramFilter#7 - WRONG_DATA · ComputeBoundingBoxStatsFilter · ComputeBoundingBoxStatsDirect.cpp:67 — [B] Preflight rejects only spacing 0. A negative Image Geometry spacing makes every bounding box empty or the full axis.
ComputeBoundingBoxStatsFilter#7 - WRONG_DATA · ComputeKMeansFilter · ClusteringUtilities.hpp:140 — [E] Distance Metric = Pearson or Squared Pearson on a 1-component array gives distance 1 for every pair, so every tuple goes to cluster 1. ComputeKMedoidsFilter shares the code.
ComputeKMeansFilter#8 - WRONG_DATA · CreateAttributeMatrixFilter · CreateAttributeMatrixFilter.cpp:75 — [C] Attribute Matrix Dimensions values are cast to
usizewith no check. 2.7 becomes 2, and a negative or NaN value is an undefined cast.CreateAttributeMatrixFilter#1 - WRONG_DATA · CreateDataArrayAdvancedFilter · InitializeData.cpp:275 — [D] Random With Range on a uint64 array uses
uniform_int_distribution<int64>. An End Range above INT64_MAX becomes negative, which is undefined and gives wrong values.CreateDataArrayAdvancedFilter#3 - WRONG_DATA · CreateDataArrayFilter · CreateDataArrayFilter.cpp:141 — [C] Only a tuple dimension of 0 is rejected. 0.4 becomes 0 tuples and -3 is an undefined cast. CreateDataArrayAdvancedFilter already has the correct check.
CreateDataArrayFilter#1 - WRONG_DATA · DilateObjectMorphologyImageFilter · DilateObjectMorphologyImageFilter.cpp:139 — [A] Kernel Radius = 2147483647 makes the
int32loop inMakeStructuringElementoverflow and not end (hang); >= 2^31 gives an empty structuring element.DilateObjectMorphologyImageFilter#1 - WRONG_DATA · DiscreteGaussianImageFilter · DiscreteGaussianEngine.hpp:227 — [E] A large effective variance (Variance 1000, or 1 with spacing 0.01 and Use Image Spacing on) makes exp(-v) * I0(v) = 0 * inf = NaN, so the kernel is NaN. Preflight has no limit.
DiscreteGaussianImageFilter#1 - WRONG_DATA · DiscreteGaussianImageFilter · DiscreteGaussianImageFilter.cpp:95 — [E] Maximum Error >= 1 and negative Variance are not rejected. The kernel becomes 3 taps or gets negative taps, and the filter runs with no error.
DiscreteGaussianImageFilter#2 - WRONG_DATA · DoubleThresholdImageFilter · ImageProcessingFilterUtilities.hpp:3967 — [D] Thresholds 1-4 are cast to the input type with
static_cast<T>and no range check. The defaults 254/255 on int8 input are undefined and give a platform-dependent band.DoubleThresholdImageFilter#1 - WRONG_DATA · ErodeObjectMorphologyImageFilter · ErodeObjectMorphologyImageFilter.cpp:157 — [A] Kernel Radius = 2147483647 makes the
int32loop inMakeStructuringElementoverflow and not end (hang); >= 2^31 gives an empty structuring element.ErodeObjectMorphologyImageFilter#1 - WRONG_DATA · FlyingEdges3DFilter · FlyingEdges3D.cpp:31 — [D] Contour Value is cast to the array type with no range check. 300 or -1 on UInt8 is undefined, so the surface is at a wrong value or missing.
FlyingEdges3DFilter#5 - WRONG_DATA · GrayscaleDilateImageFilter · GrayscaleDilateImageFilter.cpp:99 — [A] Kernel Radius >= 2^31 becomes negative after
static_cast<int32>, so the structuring element is empty and the output is a copy of the input with no error.GrayscaleDilateImageFilter#1 - WRONG_DATA · GrayscaleErodeImageFilter · GrayscaleErodeImageFilter.cpp:99 — [A] Kernel Radius >= 2^31 becomes negative after
static_cast<int32>, so the structuring element is empty and the output is a copy of the input with no error.GrayscaleErodeImageFilter#1 - WRONG_DATA · GrayscaleMorphologicalClosingImageFilter · GrayscaleMorphologicalClosingImageFilter.cpp:102 — [A] Kernel Radius >= 2^31 becomes negative after
static_cast<int32>, so the structuring element is empty and the output is a copy of the input with no error.GrayscaleMorphologicalClosingImageFilter#1 - WRONG_DATA · GrayscaleMorphologicalOpeningImageFilter · GrayscaleMorphologicalOpeningImageFilter.cpp:102 — [A] Kernel Radius >= 2^31 becomes negative after
static_cast<int32>, so the structuring element is empty and the output is a copy of the input with no error.GrayscaleMorphologicalOpeningImageFilter#1 - WRONG_DATA · HierarchicalSmoothFilter · HierarchicalSmooth.cpp:612 — [E] The error scale uses only the two edges of face 0. A zero-length edge there gives 0 and every node is reverted. Error Threshold <= 0 is also not rejected.
HierarchicalSmoothFilter#5 - WRONG_DATA · InitializeImageGeomCellDataFilter · InitializeImageGeomCellDataFilter.cpp:72 — [D] The range check is in float64. [0.2, 0.7] passes for integer arrays but both bounds become 0 (constant fill); 1.8446744073709552e19 passes for UInt64 and the cast is undefined.
InitializeImageGeomCellDataFilter#4 - WRONG_DATA · IsoContourDistanceImageFilter · IsoContourDistanceImageFilter.cpp:76 — [B] Image Geometry spacing is not checked. The engine divides by 2 * spacing, so spacing 0 or negative gives inf/NaN or wrong-sign distances.
IsoContourDistanceImageFilter#1 - WRONG_DATA · MorphologicalGradientImageFilter · MorphologicalGradientImageFilter.cpp:99 — [A] Kernel Radius >= 2^31 becomes negative after
static_cast<int32>, so the structuring element is empty and the gradient output is all zero with no error.MorphologicalGradientImageFilter#1 - WRONG_DATA · MorphologicalWatershedImageFilter · ImageProcessingFilterUtilities.hpp:5734 — [D] Level is cast to the input type with no finite or range check. Level = 300, -1 or NaN on uint8 is undefined, and the basin count depends on the platform.
MorphologicalWatershedImageFilter#1 - WRONG_DATA · NearestPointFuseRegularGridsFilter · NearestPointFuseRegularGridsDirect.cpp:111 — [D] Fill Value is cast to each sampled array type with no range check (Direct and Scanline). -1 into UInt8 or NaN into an integer type is undefined.
NearestPointFuseRegularGridsFilter#3 - WRONG_DATA · OpeningByReconstructionImageFilter · OpeningByReconstructionImageFilter.cpp:101 — [A] Kernel Radius >= 2^31 becomes negative after
static_cast<int32>, so the structuring element is empty and the output is a copy of the input with no error.OpeningByReconstructionImageFilter#1 - WRONG_DATA · PadImageGeometryFilter · PadImageGeometryFilter.cpp:152 — [C] Negative X/Y/Z Min & Max Padding values are not rejected. They wrap when cast to
size_toffsets, and the output rows are scrambled with no error.PadImageGeometryFilter#2 - WRONG_DATA · ReadImageFilter · ReadImageFilter.cpp:62 — [B] Set Spacing with a 0, negative or non-finite Spacing is not rejected. With a physical crop the crop code divides by 0; without a crop an invalid geometry is created.
ReadImageFilter#5 - WRONG_DATA · ReadImageStackFilter · ReadImageStackFilter.cpp:302 — [C] Exact 2D Dimensions with a 0 is not rejected (only Scaling is checked). The resample divides by 0 and the spacing becomes inf.
ReadImageStackFilter#5 - WRONG_DATA · ReadOnScaleTableFileFilter · ReadOnScaleTableFile.cpp:398 — [B] Fallback Spacing 0 or negative is not rejected, so the RectGrid gets a cell of zero or negative width. The bounds from the file are not checked to increase.
ReadOnScaleTableFileFilter#1 - WRONG_DATA · ReadStlFileFilter · ReadStlFile.cpp:166 — [B] Scale Factor <= 0 is not rejected. -1 mirrors the vertices but keeps the Face Normals from the file (now inverted); 0 moves all vertices to one point.
ReadStlFileFilter#3 - WRONG_DATA · ResampleImageGeomFilter · ImageGeometryResample.cpp:260 — [B] Preflight rejects only New Spacing < 0, so 0 or NaN passes (inf cast to
size_t). Exact Dimensions = 0 gives an inf-spacing geometry with no error.ResampleImageGeomFilter#2 - WRONG_DATA · ResampleRectGridToImageGeomFilter · ResampleRectGridToImageGeomFilter.cpp:113 — [C] The checks use
< 0, so a Dimensions value of 0 passes. Execute sets spacing (max - origin) / 0 = inf.ResampleRectGridToImageGeomFilter#3 - WRONG_DATA · RescaleIntensityImageFilter · RescaleIntensityImageFilter.cpp:66 — [E] Output Minimum > Output Maximum or NaN bounds are not rejected (
validate()is empty). Every value becomes Output Minimum, or the scale is NaN.RescaleIntensityImageFilter#1 - WRONG_DATA · ReshapeDataArrayFilter · ReshapeDataArrayFilter.cpp:103 — [C] Only 0 is rejected. -1 is an undefined cast, 0.5 becomes 0 (an empty array), and 2.7 becomes 2.
ReshapeDataArrayFilter#1 - WRONG_DATA · SetImageGeomOriginScalingFilter · SetImageGeomOriginScalingFilter.cpp:110 — [B] With Set Spacing on, spacing 0, negative or NaN is written to the Image Geometry with no error. Later filters divide by it.
SetImageGeomOriginScalingFilter#4 - WRONG_DATA · SigmoidImageFilter · SigmoidImageFilter.cpp:33 — [E] Alpha = 0 is not rejected. When the value equals Beta the result is NaN: 0 (outside the output range) for integer output, NaN for float output.
SigmoidImageFilter#1 - WRONG_DATA · SplitDataArrayByTupleFilter · SplitDataArrayByTupleFilter.cpp:174 — [C] The checks reject only <= 0. 0.5 becomes 0 (a 0-tuple output that passes the sum check), and 2.9 becomes 2.
SplitDataArrayByTupleFilter#4 - MINOR · ApproximatePointCloudHullFilter · ApproximatePointCloudHull.cpp:178 — [C] Minimum Number of Empty Neighbors >= 26 is accepted, but a voxel has at most 26 neighbors. The hull is always empty, with no message.
ApproximatePointCloudHullFilter#3 - MINOR · CreateGeometryFilter · CreateImageGeometryAction.cpp:58 — [B] Image Dimensions with a 0 or Spacing <= 0 or NaN are not rejected (also in CreateImageGeometryFilter). The preflight info prints
dims[0] - 1, which wraps for 0.CreateGeometryFilter#4 - MINOR · CropVertexGeometryFilter · CropVertexGeometryFilter.cpp:104 — [E] Equal Min and Max on one axis is rejected (-58550 to -58552), but the execute test is inclusive. A valid planar crop (all z = 0) is refused.
CropVertexGeometryFilter#1 - MINOR · EBSDSegmentFeaturesFilter · EBSDSegmentFeaturesFilter.cpp:121 — [E] Preflight rejects only Misorientation Tolerance == 0. A negative tolerance passes and every Cell becomes its own Feature.
EBSDSegmentFeaturesFilter#3 - MINOR · EbsdToH5EbsdFilter · EbsdToH5EbsdFilter.cpp:56 — [B] Z Spacing (Microns) 0 or negative is not checked and is written into the .h5ebsd file.
EbsdToH5EbsdFilter#3 - MINOR · FeatureFaceCurvatureFilter · FeatureFaceCurvatureFilter.cpp:58 — [C] Neighborhood Ring Count <= 0 is not rejected. Execute throws and fails with error -2, not with a clear preflight error.
FeatureFaceCurvatureFilter#7 - MINOR · PointSampleTriangleGeometryFilter · PointSampleTriangleGeometry.cpp:64 — [C] Number of Sample Points <= 0 is not rejected. A negative value becomes a huge
usizeand execute fails with an allocation error; 0 gives an empty output.PointSampleTriangleGeometryFilter#5 - MINOR · ReadH5OimDataFilter · ReadH5OimDataFilter.cpp:118 — [B] The check
Z Spacing <= 0lets NaN pass, and the X/Y step and cell counts from the file are not checked. NaN or non-positive spacing goes into the Image Geometry.ReadH5OimDataFilter#5 - MINOR · ReadRawBinaryFilter · ReadRawBinaryFilter.cpp:158 — [C] Only exact 0 dimensions are rejected. 2.7 becomes 2, 0.5 becomes 0 (a later failure), and -1 is an undefined cast.
ReadRawBinaryFilter#2
Related issues
- PR BUG: Check that grid-geometry cell inputs have one tuple per cell #1840 "BUG: Check that grid-geometry cell inputs have one tuple per cell" changes AlignSectionsFeatureCentroidFilter but keeps only the
Reference Slice < 0check. AlignSectionsFeatureCentroidFilter#1 is still open there.
Out of scope
- 8 findings in 7 filters that have a V&V report are not in this issue: CAxisSegmentFeaturesFilter, DBSCANFilter, ErodeDilateBadDataFilter, MultiThresholdObjectsFilter, RegularizeZSpacingFilter, RotateSampleRefFrameFilter, WritePoleFigureFilter. They are handled on a separate V&V branch.
- Checks that need array values (for example a Feature Id larger than the Feature Attribute Matrix) belong to execute and to their own issues.
- Tuple-count and Attribute Matrix requirements for input DataArrays belong to their own issues.
Activity
[-]BUG: Parameter values not validated in preflight in 65 filters[/-][+]BUG: C14: Parameter values not validated in preflight in 65 filters[/+]