There is a note here ITK/Modules/Registration/Metricsv4/include/itkImageToImageMetricv4.hxx at master · InsightSoftwareConsortium/ITK · GitHub that ImageToImageMetricv4
does not allocate the virtual image to save memory. However, this causes undefined behaviour in ImageRegionConstIteratorWithIndex
, because the buffer
pointer is used in some of the iterator calculations and is set to nullptr
. Here is a full stack trace from UBSan:
/Users/tobias/Code/riesling/build/vcpkg_installed/arm64-osx/include/ITK-5.4/itkImageRegionConstIteratorWithIndex.hxx:37:24: runtime error: applying non-zero offset 4 to null pointer
#0 0x1052083d8 in itk::ImageRegionConstIteratorWithIndex<itk::Image<float, 3u>>::operator++() itkImageRegionConstIteratorWithIndex.hxx:37
#1 0x1054a2848 in itk::ImageToImageMetricv4GetValueAndDerivativeThreader<itk::ThreadedImageRegionPartitioner<3u>, itk::ImageToImageMetricv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double, itk::DefaultImageToImageMetricTraitsv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double>>>::ThreadedExecution(itk::ImageRegion<3u> const&, unsigned int) itkImageToImageMetricv4GetValueAndDerivativeThreader.hxx:35
#2 0x1055936f0 in itk::DomainThreader<itk::ThreadedImageRegionPartitioner<3u>, itk::ImageToImageMetricv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double, itk::DefaultImageToImageMetricTraitsv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double>>>::ThreaderCallback(void*) itkDomainThreader.hxx:123
#3 0x105af7ad8 in itk::PoolMultiThreader::SingleMethodExecute()::$_0::operator()() const itkPoolMultiThreader.cxx:144
#4 0x105aeef78 in void itk::(anonymous namespace)::ExceptionHandler::TryAndCatch<itk::PoolMultiThreader::SingleMethodExecute()::$_0>(itk::PoolMultiThreader::SingleMethodExecute()::$_0 const&) itkPoolMultiThreader.cxx:54
#5 0x105aeec8c in itk::PoolMultiThreader::SingleMethodExecute() itkPoolMultiThreader.cxx:144
#6 0x105ab6bb0 in itk::MultiThreaderBase::SetSingleMethodAndExecute(void* (*)(void*), void*) itkMultiThreaderBase.cxx:453
#7 0x105592c0c in itk::DomainThreader<itk::ThreadedImageRegionPartitioner<3u>, itk::ImageToImageMetricv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double, itk::DefaultImageToImageMetricTraitsv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double>>>::StartThreadingSequence() itkDomainThreader.hxx:98
#8 0x105591898 in itk::DomainThreader<itk::ThreadedImageRegionPartitioner<3u>, itk::ImageToImageMetricv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double, itk::DefaultImageToImageMetricTraitsv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double>>>::Execute(itk::ImageToImageMetricv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double, itk::DefaultImageToImageMetricTraitsv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double>>*, itk::ImageRegion<3u> const&) itkDomainThreader.hxx:65
#9 0x1053492f8 in itk::ImageToImageMetricv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double, itk::DefaultImageToImageMetricTraitsv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double>>::GetValueAndDerivativeExecute() const itkImageToImageMetricv4.hxx:273
#10 0x1053142d8 in itk::ImageToImageMetricv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double, itk::DefaultImageToImageMetricTraitsv4<itk::Image<float, 3u>, itk::Image<float, 3u>, itk::Image<float, 3u>, double>>::GetValueAndDerivative(double&, itk::Array<double>&) const itkImageToImageMetricv4.hxx:244
#11 0x1056d0f04 in itk::GradientDescentOptimizerv4Template<double>::ResumeOptimization() itkGradientDescentOptimizerv4.hxx:99
#12 0x1056e9908 in itk::GradientDescentOptimizerv4Template<double>::StartOptimization(bool) itkGradientDescentOptimizerv4.hxx:54
#13 0x1056cf37c in itk::ConjugateGradientLineSearchOptimizerv4Template<double>::StartOptimization(bool) itkConjugateGradientLineSearchOptimizerv4.hxx:45
#14 0x1058aca00 in itk::MultiStartOptimizerv4Template<double>::ResumeOptimization() itkMultiStartOptimizerv4.hxx:177
#15 0x1058aa028 in itk::MultiStartOptimizerv4Template<double>::StartOptimization(bool) itkMultiStartOptimizerv4.hxx:154
#16 0x105216804 in merlin::Register(itk::SmartPointer<itk::Image<float, 3u>>, itk::SmartPointer<itk::Image<float, 3u>>, itk::SmartPointer<itk::Image<float, 3u>>) merlin.cpp:346
#17 0x104f7bdfc in main main_merlin.cpp:43
#18 0x19bffc270 (<unknown module>)
While this is likely benign, it leads to a lot of line noise while trying to use UB San to find other problems. Is there any way to fix this apart from either:
- Allocating the virtual image
- Adding some kind of
RegionIndexIterator
?