Skip to content

Commit 41bf1b9

Browse files
committed
BUG: Harden CopyIterationBenchmark to not crash on ITK 1d87efa52+ regression
The previous CreateAndInitializeImage used it.Set(static_cast<PixelType>(count)); to seed pixel values. For scalar and FixedArray pixels this performs a value cast, but for VectorImage (where PixelType is itk::VariableLengthVector<T>) it invokes the LENGTH constructor — producing a vector of size 'count', not a N-component pixel with value 'count'. In particular the first iteration produces a length-0 VLV, which ITK commit 1d87efa52 changed to store a null data pointer. Under ITK >= 1d87efa52, the iterator's implicit copy of NumberOfComponentsPerPixel elements from that null source causes a SIGSEGV. Under earlier ITK, the out-of-spec read 'happens to work' by reading uninitialized memory. Either way, the benchmark was never constructing semantically correct pixel values for the VectorImage case. Introduce a PixelFiller trait that specializes for VariableLengthVector so the VectorImage branch constructs a properly sized VLV and Fills it with 'count'. Scalar and FixedArray branches keep the existing static_cast path. With this change the benchmark produces well-defined output across the ITK v5.3 -> main range regardless of the internal representation of VariableLengthVector(0).
1 parent cf89d96 commit 41bf1b9

1 file changed

Lines changed: 42 additions & 1 deletion

File tree

examples/Core/itkCopyIterationBenchmark.cxx

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,47 @@
3333
#include <fstream>
3434

3535

36+
// Pixel-construction traits.
37+
//
38+
// For scalar and FixedArray-backed images, `static_cast<PixelType>(count)`
39+
// produces a pixel whose value encodes `count`. For VectorImage, whose
40+
// PixelType is `itk::VariableLengthVector<T>`, the single-argument
41+
// constructor is a LENGTH constructor — `VLV<float>(count)` yields a
42+
// vector of size `count`, not a multi-component pixel with value `count`.
43+
// Passing that length-mismatched value through the VectorImage pixel
44+
// accessor used to read out-of-spec memory ("happens to work" prior to
45+
// ITK commit 1d87efa5) and now segfaults, because the accessor copies
46+
// exactly `NumberOfComponentsPerPixel` elements from the source's
47+
// internal data pointer — which is null when the source VLV has size 0.
48+
//
49+
// The specialization below constructs a correctly-sized
50+
// VariableLengthVector pixel, filled with `count` (cast to the value
51+
// type). This makes the benchmark portable across all ITK versions in
52+
// the v5.3 → main range regardless of how `VLV(0)` is represented
53+
// internally.
54+
template <typename TPixel>
55+
struct PixelFiller
56+
{
57+
static TPixel
58+
Make(unsigned int count, unsigned int /*componentsPerPixel*/)
59+
{
60+
return static_cast<TPixel>(count);
61+
}
62+
};
63+
64+
template <typename TValue>
65+
struct PixelFiller<itk::VariableLengthVector<TValue>>
66+
{
67+
static itk::VariableLengthVector<TValue>
68+
Make(unsigned int count, unsigned int componentsPerPixel)
69+
{
70+
itk::VariableLengthVector<TValue> pixel(componentsPerPixel);
71+
pixel.Fill(static_cast<TValue>(count));
72+
return pixel;
73+
}
74+
};
75+
76+
3677
// Helper function to initialize an image with random values
3778
template <typename TImage>
3879
typename TImage::Pointer
@@ -54,7 +95,7 @@ CreateAndInitializeImage(const typename TImage::SizeType & size, unsigned int nu
5495
itk::ImageRegionIterator<TImage> it(image, region);
5596
for (; !it.IsAtEnd(); ++it)
5697
{
57-
it.Set(static_cast<PixelType>(count));
98+
it.Set(PixelFiller<PixelType>::Make(count, numberOfComponentsPerPixel));
5899
++count;
59100
}
60101

0 commit comments

Comments
 (0)