Skip to content

ShapedNeighborhoodIterator silently breaks const-correctness on image argument #6102

@N-Dekker

Description

@N-Dekker

Description

ShapedNeighborhoodIterator has a constructor that accepts a pointer to a const Image:

ShapedNeighborhoodIterator(const SizeType & radius, const ImageType * ptr, const RegionType & region)

At

ShapedNeighborhoodIterator(const SizeType & radius, const ImageType * ptr, const RegionType & region)

This offers a "backdoor" for users to modify an image via a pointer-to-const, thereby breaking logical const-correctness. It is also unusual within ITK. Constructors of other non-const ITK iterators do not have such a const ImageType * parameter.

Steps to Reproduce

The following code shows how to modify an image via a const ImageType, by exploiting this ShapedNeighborhoodIterator bug. It does so by calling shapedNeighborhoodIterator.SetCenterPixel(1), but it might as well do so iteratively, by setting the pixel values from shapedNeighborhoodIterator.Begin() to shapedNeighborhoodIterator.End()

#include "itkShapedNeighborhoodIterator.h"
#include "itkImageBufferRange.h"

void
TestModifyingConstImage()
{
  static constexpr unsigned int dimension{ 2 };
  using ImageType = itk::Image<int, dimension>;

  constexpr auto modifyConstImage = [](const ImageType * const constImage) {
    constexpr auto radius = itk::Size<dimension>::Filled(1);
    const auto     region = constImage->GetBufferedRegion();

    itk::ShapedNeighborhoodIterator<ImageType> shapedNeighborhoodIterator(radius, constImage, region);

    shapedNeighborhoodIterator.SetLocation(itk::Index<dimension>::Filled(1));
    shapedNeighborhoodIterator.SetCenterPixel(1);
  };

  const auto image = ImageType::New();
  image->SetRegions(itk::Size<dimension>::Filled(3));
  image->AllocateInitialized();

  const auto printImage = [image] {
    for (const int pixelValue : itk::ImageBufferRange<ImageType>(*image))
    {
      std::cout << pixelValue;
    }
    std::cout << '\n';
  };

  printImage(); // Prints "000000000".
  modifyConstImage(image);
  printImage(); // Prints "000010000"!
}

Expected behavior

The following line should not compile. ShapedNeighborhoodIterator should not accept a "const" image as argument.

itk::ShapedNeighborhoodIterator<ImageType> shapedNeighborhoodIterator(radius, constImage, region);

Actual behavior

It prints the following lines, indicating the center pixel value of the 3x3 test image has changed.

000000000
000010000

Reproducibility

100%

Versions

Today's main revision: commit 056f5eb

Environment

Any supported ITK platform

Additional Information

I'm considering to submit a pull request to fix this issue.


For the record, it appears that this mistake (having a const ImageType * constructor parameter) was there already when ShapedNeighborhoodIterator was introduced, with commit fc6d1b2, Jan 8, 2003:

ShapedNeighborhoodIterator(const SizeType &radius,
const ImageType * ptr,
const RegionType &region

Metadata

Metadata

Assignees

Labels

type:BugInconsistencies or issues which will cause an incorrect result under some or all circumstances

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions