InsightSoftwareConsortium / InsightSoftwareConsortium/ITK

itkTestTransformGetInverse test fails under TSan

Open
#3,037 11 comments 0 reactions 0 assignees View on GitHub
type:Bug
Dominant language
C++
Stars
1.7k
Forks
748
Avg merge
1d 1h
Merged PRs (30d)
64

Description

According to bc1bcae24435fd76c430180e709a50e920eba6f4, `itkTestTransformGetInverse` was added to demonstrate a threading bug.

Seems it was never fixed though?

The test looks to me to be deliberately using `GetInverse` on a transform shared between threads.

The root of the weridness, to me, comes from [here](https://github.com/InsightSoftwareConsortium/ITK/blob/9da82ba3016b360f593f69699a92b3c19a94595b/Modules/Core/Transform/include/itkMatrixOffsetTransformBase.hxx#L482) where a getter method mutates the object.

Full TSan report:

```
==================
WARNING: ThreadSanitizer: data race (pid=18275)
Write of size 8 at 0x7b08000588c0 by thread T2:
#0 itk::MatrixOffsetTransformBase::GetFixedParameters() const itkMatrixOffsetTransformBase.hxx:482 (ITKTransformTestDriver:x86_64+0x10003d32e)
#1 itk::MatrixOffsetTransformBase::GetInverse(itk::MatrixOffsetTransformBase*) const itkMatrixOffsetTransformBase.hxx:427 (ITKTransformTestDriver:x86_64+0x1000427f4)
#2 itk::AffineTransform::GetInverse(itk::AffineTransform*) const itkAffineTransform.hxx:277 (ITKTransformTestDriver:x86_64+0x100037500)
#3 void* TestGetInverseThreadFunction >(void*) itkTestTransformGetInverse.cxx:72 (ITKTransformTestDriver:x86_64+0x100270fcd)
#4 decltype(std::__1::forward(fp)(std::__1::forward(fp0))) std::__1::__invoke(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&&) type_traits:4361 (ITKTransformTestDriver:x86_64+0x1003634f7)
#5 std::__1::__bind_return, std::__1::tuple<>, __is_valid_bind_return, std::__1::tuple<> >::value>::type std::__1::__apply_functor, 0ul, std::__1::tuple<> >(void* (*&)(void*), std::__1::tuple&, std::__1::__tuple_indices<0ul>, std::__1::tuple<>&&) functional:2644 (ITKTransformTestDriver:x86_64+0x100363480)
#6 std::__1::__bind_return, std::__1::tuple<>, __is_valid_bind_return, std::__1::tuple<> >::value>::type std::__1::__bind::operator()<>() functional:2677 (ITKTransformTestDriver:x86_64+0x10036341d)
#7 decltype(std::__1::forward&>(fp)()) std::__1::__invoke&>(std::__1::__bind&&&) type_traits:4361 (ITKTransformTestDriver:x86_64+0x1003633a1)
#8 std::__1::__packaged_task_func, std::__1::allocator >, void* ()>::operator()() future:1821 (ITKTransformTestDriver:x86_64+0x100363085)
#9 std::__1::__packaged_task_function::operator()() const future:1998 (ITKTransformTestDriver:x86_64+0x100368f5f)
#10 std::__1::packaged_task::operator()() future:2089 (ITKTransformTestDriver:x86_64+0x100368e0e)
#11 std::__1::future::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()::operator()() const itkThreadPool.h:97 (ITKTransformTestDriver:x86_64+0x100368d81)
#12 decltype(std::__1::forward(fp)(std::__1::forward(fp0))) std::__1::__invoke::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()&>(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&) type_traits:4361 (ITKTransformTestDriver:x86_64+0x100368d11)
#13 void std::__1::__invoke_void_return_wrapper::__call::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()&>(std::__1::future::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()&&&) __functional_base:349 (ITKTransformTestDriver:x86_64+0x100368ca1)
#14 std::__1::__function::__alloc_func::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'(), std::__1::allocator::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()>, void ()>::operator()() functional:1527 (ITKTransformTestDriver:x86_64+0x100368c61)
#15 std::__1::__function::__func::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'(), std::__1::allocator::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()>, void ()>::operator()() functional:1651 (ITKTransformTestDriver:x86_64+0x1003676ad)
#16 std::__1::__function::__value_func::operator()() const functional:1799 (ITKTransformTestDriver:x86_64+0x10033b024)
#17 std::__1::function::operator()() const functional:2347 (ITKTransformTestDriver:x86_64+0x100336b89)
#18 itk::ThreadPool::ThreadExecute() itkThreadPool.cxx:211 (ITKTransformTestDriver:x86_64+0x1003730fa)
#19 decltype(std::__1::forward(fp)()) std::__1::__invoke(void (*&&)()) type_traits:4361 (ITKTransformTestDriver:x86_64+0x10037a216)
#20 void std::__1::__thread_execute >, void (*)()>(std::__1::tuple >, void (*)()>&, std::__1::__tuple_indices<>) thread:342 (ITKTransformTestDriver:x86_64+0x10037a0f9)
#21 void* std::__1::__thread_proxy >, void (*)()> >(void*) thread:352 (ITKTransformTestDriver:x86_64+0x1003798aa)

Previous write of size 8 at 0x7b08000588c0 by thread T1:
#0 itk::MatrixOffsetTransformBase::GetFixedParameters() const itkMatrixOffsetTransformBase.hxx:482 (ITKTransformTestDriver:x86_64+0x10003d32e)
#1 itk::MatrixOffsetTransformBase::GetInverse(itk::MatrixOffsetTransformBase*) const itkMatrixOffsetTransformBase.hxx:427 (ITKTransformTestDriver:x86_64+0x1000427f4)
#2 itk::AffineTransform::GetInverse(itk::AffineTransform*) const itkAffineTransform.hxx:277 (ITKTransformTestDriver:x86_64+0x100037500)
#3 void* TestGetInverseThreadFunction >(void*) itkTestTransformGetInverse.cxx:72 (ITKTransformTestDriver:x86_64+0x100270fcd)
#4 decltype(std::__1::forward(fp)(std::__1::forward(fp0))) std::__1::__invoke(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&&) type_traits:4361 (ITKTransformTestDriver:x86_64+0x1003634f7)
#5 std::__1::__bind_return, std::__1::tuple<>, __is_valid_bind_return, std::__1::tuple<> >::value>::type std::__1::__apply_functor, 0ul, std::__1::tuple<> >(void* (*&)(void*), std::__1::tuple&, std::__1::__tuple_indices<0ul>, std::__1::tuple<>&&) functional:2644 (ITKTransformTestDriver:x86_64+0x100363480)
#6 std::__1::__bind_return, std::__1::tuple<>, __is_valid_bind_return, std::__1::tuple<> >::value>::type std::__1::__bind::operator()<>() functional:2677 (ITKTransformTestDriver:x86_64+0x10036341d)
#7 decltype(std::__1::forward&>(fp)()) std::__1::__invoke&>(std::__1::__bind&&&) type_traits:4361 (ITKTransformTestDriver:x86_64+0x1003633a1)
#8 std::__1::__packaged_task_func, std::__1::allocator >, void* ()>::operator()() future:1821 (ITKTransformTestDriver:x86_64+0x100363085)
#9 std::__1::__packaged_task_function::operator()() const future:1998 (ITKTransformTestDriver:x86_64+0x100368f5f)
#10 std::__1::packaged_task::operator()() future:2089 (ITKTransformTestDriver:x86_64+0x100368e0e)
#11 std::__1::future::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()::operator()() const itkThreadPool.h:97 (ITKTransformTestDriver:x86_64+0x100368d81)
#12 decltype(std::__1::forward(fp)(std::__1::forward(fp0))) std::__1::__invoke::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()&>(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&) type_traits:4361 (ITKTransformTestDriver:x86_64+0x100368d11)
#13 void std::__1::__invoke_void_return_wrapper::__call::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()&>(std::__1::future::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()&&&) __functional_base:349 (ITKTransformTestDriver:x86_64+0x100368ca1)
#14 std::__1::__function::__alloc_func::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'(), std::__1::allocator::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()>, void ()>::operator()() functional:1527 (ITKTransformTestDriver:x86_64+0x100368c61)
#15 std::__1::__function::__func::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'(), std::__1::allocator::type> itk::ThreadPool::AddWork(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()>, void ()>::operator()() functional:1651 (ITKTransformTestDriver:x86_64+0x1003676ad)
#16 std::__1::__function::__value_func::operator()() const functional:1799 (ITKTransformTestDriver:x86_64+0x10033b024)
#17 std::__1::function::operator()() const functional:2347 (ITKTransformTestDriver:x86_64+0x100336b89)
#18 itk::ThreadPool::ThreadExecute() itkThreadPool.cxx:211 (ITKTransformTestDriver:x86_64+0x1003730fa)
#19 decltype(std::__1::forward(fp)()) std::__1::__invoke(void (*&&)()) type_traits:4361 (ITKTransformTestDriver:x86_64+0x10037a216)
#20 void std::__1::__thread_execute >, void (*)()>(std::__1::tuple >, void (*)()>&, std::__1::__tuple_indices<>) thread:342 (ITKTransformTestDriver:x86_64+0x10037a0f9)
#21 void* std::__1::__thread_proxy >, void (*)()> >(void*) thread:352 (ITKTransformTestDriver:x86_64+0x1003798aa)

Location is heap block of size 24 at 0x7b08000588c0 allocated by main thread:
#0 operator new[](unsigned long) :1599776 (libclang_rt.tsan_osx_dynamic.dylib:x86_64+0x6ed8b)
#1 vnl_sse_alloc(unsigned long, unsigned int) vnl_sse.h:106 (ITKTransformTestDriver:x86_64+0x100b9b324)
#2 vnl_c_vector_alloc(unsigned long, unsigned int) vnl_c_vector.hxx:350 (ITKTransformTestDriver:x86_64+0x100b9b0b0)
#3 vnl_c_vector::allocate_T(unsigned long) vnl_c_vector.hxx:404 (ITKTransformTestDriver:x86_64+0x100b9b0ff)
#4 vnl_vector::set_size(unsigned long) vnl_vector.hxx:226 (ITKTransformTestDriver:x86_64+0x100d6c32e)
#5 itk::Array::SetSize(unsigned long) itkArray.hxx:141 (ITKTransformTestDriver:x86_64+0x100012a03)
#6 itk::MatrixOffsetTransformBase::MatrixOffsetTransformBase(unsigned int) itkMatrixOffsetTransformBase.hxx:36 (ITKTransformTestDriver:x86_64+0x10003c544)
#7 itk::AffineTransform::AffineTransform() itkAffineTransform.hxx:29 (ITKTransformTestDriver:x86_64+0x10003c40f)
#8 itk::AffineTransform::AffineTransform() itkAffineTransform.hxx:30 (ITKTransformTestDriver:x86_64+0x10003c369)
#9 itk::AffineTransform::New() itkAffineTransform.h:117 (ITKTransformTestDriver:x86_64+0x100036dc5)
#10 unsigned int TransformTest >() itkTestTransformGetInverse.cxx:85 (ITKTransformTestDriver:x86_64+0x10026da80)
#11 itkTestTransformGetInverse(int, char**) itkTestTransformGetInverse.cxx:110 (ITKTransformTestDriver:x86_64+0x10026d8ee)
#12 main ITKTransformTestDriver.cxx:373 (ITKTransformTestDriver:x86_64+0x100003083)

Thread T2 (tid=106811422, running) created by main thread at:
#0 pthread_create :1599824 (libclang_rt.tsan_osx_dynamic.dylib:x86_64+0x2933d)
#1 std::__1::__libcpp_thread_create(_opaque_pthread_t**, void* (*)(void*), void*) __threading_support:328 (ITKTransformTestDriver:x86_64+0x100379829)
#2 std::__1::thread::thread(void (*&&)()) thread:368 (ITKTransformTestDriver:x86_64+0x10037966c)
#3 std::__1::thread::thread(void (*&&)()) thread:360 (ITKTransformTestDriver:x86_64+0x1003795a0)
#4 void std::__1::allocator::construct(std::__1::thread*, void (*&&)()) memory:1826 (ITKTransformTestDriver:x86_64+0x100379558)
#5 void std::__1::allocator_traits >::__construct(std::__1::integral_constant, std::__1::allocator&, std::__1::thread*, void (*&&)()) memory:1718 (ITKTransformTestDriver:x86_64+0x100379508)
#6 void std::__1::allocator_traits >::construct(std::__1::allocator&, std::__1::thread*, void (*&&)()) memory:1561 (ITKTransformTestDriver:x86_64+0x1003793b8)
#7 void std::__1::vector >::emplace_back(void (*&&)()) vector:1688 (ITKTransformTestDriver:x86_64+0x100372fb2)
#8 itk::ThreadPool::ThreadPool() itkThreadPool.cxx:118 (ITKTransformTestDriver:x86_64+0x100372d66)
#9 itk::ThreadPool::ThreadPool() itkThreadPool.cxx:108 (ITKTransformTestDriver:x86_64+0x1003731e9)
#10 itk::ThreadPool::GetInstance()::$_2::operator()() const itkThreadPool.cxx:83 (ITKTransformTestDriver:x86_64+0x1003784ab)
#11 decltype(std::__1::forward(fp)()) std::__1::__invoke(itk::ThreadPool::GetInstance()::$_2&&) type_traits:4361 (ITKTransformTestDriver:x86_64+0x1003783a3)
#12 void std::__1::__call_once_param >::__execute<>(std::__1::__tuple_indices<>) mutex:622 (ITKTransformTestDriver:x86_64+0x100378371)
#13 std::__1::__call_once_param >::operator()() mutex:614 (ITKTransformTestDriver:x86_64+0x100378319)
#14 void std::__1::__call_once_proxy >(void*) mutex:650 (ITKTransformTestDriver:x86_64+0x1003781b9)
#15 __tsan::(anonymous namespace)::call_once_callback_wrapper(void*) :1599824 (libclang_rt.tsan_osx_dynamic.dylib:x86_64+0x69a0e)
#16 itk::ThreadPool::GetInstance() itkThreadPool.cxx:79 (ITKTransformTestDriver:x86_64+0x100372921)
#17 itk::PoolMultiThreader::PoolMultiThreader() itkPoolMultiThreader.cxx:81 (ITKTransformTestDriver:x86_64+0x10035c736)
#18 itk::PoolMultiThreader::PoolMultiThreader() itkPoolMultiThreader.cxx:82 (ITKTransformTestDriver:x86_64+0x10035ca59)
#19 itk::PoolMultiThreader::New() itkPoolMultiThreader.h:57 (ITKTransformTestDriver:x86_64+0x1002e70a5)
#20 itk::MultiThreaderBase::New() itkMultiThreaderBase.cxx:419 (ITKTransformTestDriver:x86_64+0x1002e6bd0)
#21 unsigned int TransformTest >() itkTestTransformGetInverse.cxx:82 (ITKTransformTestDriver:x86_64+0x10026da6e)
#22 itkTestTransformGetInverse(int, char**) itkTestTransformGetInverse.cxx:110 (ITKTransformTestDriver:x86_64+0x10026d8ee)
#23 main ITKTransformTestDriver.cxx:373 (ITKTransformTestDriver:x86_64+0x100003083)

Thread T1 (tid=106811421, running) created by main thread at:
#0 pthread_create :1599824 (libclang_rt.tsan_osx_dynamic.dylib:x86_64+0x2933d)
#1 std::__1::__libcpp_thread_create(_opaque_pthread_t**, void* (*)(void*), void*) __threading_support:328 (ITKTransformTestDriver:x86_64+0x100379829)
#2 std::__1::thread::thread(void (*&&)()) thread:368 (ITKTransformTestDriver:x86_64+0x10037966c)
#3 std::__1::thread::thread(void (*&&)()) thread:360 (ITKTransformTestDriver:x86_64+0x1003795a0)
#4 void std::__1::allocator::construct(std::__1::thread*, void (*&&)()) memory:1826 (ITKTransformTestDriver:x86_64+0x100379558)
#5 void std::__1::allocator_traits >::__construct(std::__1::integral_constant, std::__1::allocator&, std::__1::thread*, void (*&&)()) memory:1718 (ITKTransformTestDriver:x86_64+0x100379508)
#6 void std::__1::allocator_traits >::construct(std::__1::allocator&, std::__1::thread*, void (*&&)()) memory:1561 (ITKTransformTestDriver:x86_64+0x1003793b8)
#7 void std::__1::vector >::emplace_back(void (*&&)()) vector:1688 (ITKTransformTestDriver:x86_64+0x100372fb2)
#8 itk::ThreadPool::ThreadPool() itkThreadPool.cxx:118 (ITKTransformTestDriver:x86_64+0x100372d66)
#9 itk::ThreadPool::ThreadPool() itkThreadPool.cxx:108 (ITKTransformTestDriver:x86_64+0x1003731e9)
#10 itk::ThreadPool::GetInstance()::$_2::operator()() const itkThreadPool.cxx:83 (ITKTransformTestDriver:x86_64+0x1003784ab)
#11 decltype(std::__1::forward(fp)()) std::__1::__invoke(itk::ThreadPool::GetInstance()::$_2&&) type_traits:4361 (ITKTransformTestDriver:x86_64+0x1003783a3)
#12 void std::__1::__call_once_param >::__execute<>(std::__1::__tuple_indices<>) mutex:622 (ITKTransformTestDriver:x86_64+0x100378371)
#13 std::__1::__call_once_param >::operator()() mutex:614 (ITKTransformTestDriver:x86_64+0x100378319)
#14 void std::__1::__call_once_proxy >(void*) mutex:650 (ITKTransformTestDriver:x86_64+0x1003781b9)
#15 __tsan::(anonymous namespace)::call_once_callback_wrapper(void*) :1599824 (libclang_rt.tsan_osx_dynamic.dylib:x86_64+0x69a0e)
#16 itk::ThreadPool::GetInstance() itkThreadPool.cxx:79 (ITKTransformTestDriver:x86_64+0x100372921)
#17 itk::PoolMultiThreader::PoolMultiThreader() itkPoolMultiThreader.cxx:81 (ITKTransformTestDriver:x86_64+0x10035c736)
#18 itk::PoolMultiThreader::PoolMultiThreader() itkPoolMultiThreader.cxx:82 (ITKTransformTestDriver:x86_64+0x10035ca59)
#19 itk::PoolMultiThreader::New() itkPoolMultiThreader.h:57 (ITKTransformTestDriver:x86_64+0x1002e70a5)
#20 itk::MultiThreaderBase::New() itkMultiThreaderBase.cxx:419 (ITKTransformTestDriver:x86_64+0x1002e6bd0)
#21 unsigned int TransformTest >() itkTestTransformGetInverse.cxx:82 (ITKTransformTestDriver:x86_64+0x10026da6e)
#22 itkTestTransformGetInverse(int, char**) itkTestTransformGetInverse.cxx:110 (ITKTransformTestDriver:x86_64+0x10026d8ee)
#23 main ITKTransformTestDriver.cxx:373 (ITKTransformTestDriver:x86_64+0x100003083)

SUMMARY: ThreadSanitizer: data race itkMatrixOffsetTransformBase.hxx:482 in itk::MatrixOffsetTransformBase::GetFixedParameters() const
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.