InsightSoftwareConsortium / ITK

Insight Toolkit (ITK) -- Official Repository. ITK builds on a proven, spatially-oriented architecture for processing, segmentation, and registration of scientific images in two, three, or more dimensions.
https://itk.org
Apache License 2.0
1.37k stars 660 forks source link

itkTestTransformGetInverse test fails under TSan #3037

Open seanm opened 2 years ago

seanm commented 2 years ago

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

  Previous write of size 8 at 0x7b08000588c0 by thread T1:
    #0 itk::MatrixOffsetTransformBase<double, 3u, 3u>::GetFixedParameters() const itkMatrixOffsetTransformBase.hxx:482 (ITKTransformTestDriver:x86_64+0x10003d32e)
    #1 itk::MatrixOffsetTransformBase<double, 3u, 3u>::GetInverse(itk::MatrixOffsetTransformBase<double, 3u, 3u>*) const itkMatrixOffsetTransformBase.hxx:427 (ITKTransformTestDriver:x86_64+0x1000427f4)
    #2 itk::AffineTransform<double, 3u>::GetInverse(itk::AffineTransform<double, 3u>*) const itkAffineTransform.hxx:277 (ITKTransformTestDriver:x86_64+0x100037500)
    #3 void* TestGetInverseThreadFunction<itk::AffineTransform<double, 3u> >(void*) itkTestTransformGetInverse.cxx:72 (ITKTransformTestDriver:x86_64+0x100270fcd)
    #4 decltype(std::__1::forward<void* (*&)(void*)>(fp)(std::__1::forward<itk::PoolMultiThreader::ThreadPoolInfoStruct*&>(fp0))) std::__1::__invoke<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&>(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&&) type_traits:4361 (ITKTransformTestDriver:x86_64+0x1003634f7)
    #5 std::__1::__bind_return<void* (*)(void*), std::__1::tuple<itk::PoolMultiThreader::ThreadPoolInfoStruct*>, std::__1::tuple<>, __is_valid_bind_return<void* (*)(void*), std::__1::tuple<itk::PoolMultiThreader::ThreadPoolInfoStruct*>, std::__1::tuple<> >::value>::type std::__1::__apply_functor<void* (*)(void*), std::__1::tuple<itk::PoolMultiThreader::ThreadPoolInfoStruct*>, 0ul, std::__1::tuple<> >(void* (*&)(void*), std::__1::tuple<itk::PoolMultiThreader::ThreadPoolInfoStruct*>&, std::__1::__tuple_indices<0ul>, std::__1::tuple<>&&) functional:2644 (ITKTransformTestDriver:x86_64+0x100363480)
    #6 std::__1::__bind_return<void* (*)(void*), std::__1::tuple<itk::PoolMultiThreader::ThreadPoolInfoStruct*>, std::__1::tuple<>, __is_valid_bind_return<void* (*)(void*), std::__1::tuple<itk::PoolMultiThreader::ThreadPoolInfoStruct*>, std::__1::tuple<> >::value>::type std::__1::__bind<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*>::operator()<>() functional:2677 (ITKTransformTestDriver:x86_64+0x10036341d)
    #7 decltype(std::__1::forward<std::__1::__bind<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*>&>(fp)()) std::__1::__invoke<std::__1::__bind<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*>&>(std::__1::__bind<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*>&&&) type_traits:4361 (ITKTransformTestDriver:x86_64+0x1003633a1)
    #8 std::__1::__packaged_task_func<std::__1::__bind<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*>, std::__1::allocator<std::__1::__bind<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*> >, void* ()>::operator()() future:1821 (ITKTransformTestDriver:x86_64+0x100363085)
    #9 std::__1::__packaged_task_function<void* ()>::operator()() const future:1998 (ITKTransformTestDriver:x86_64+0x100368f5f)
    #10 std::__1::packaged_task<void* ()>::operator()() future:2089 (ITKTransformTestDriver:x86_64+0x100368e0e)
    #11 std::__1::future<std::__1::result_of<void* (*& (itk::PoolMultiThreader::ThreadPoolInfoStruct*))(void*)>::type> itk::ThreadPool::AddWork<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*>(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()::operator()() const itkThreadPool.h:97 (ITKTransformTestDriver:x86_64+0x100368d81)
    #12 decltype(std::__1::forward<void* (*&)(void*)>(fp)(std::__1::forward<itk::PoolMultiThreader::ThreadPoolInfoStruct*>(fp0))) std::__1::__invoke<std::__1::future<std::__1::result_of<void* (*& (itk::PoolMultiThreader::ThreadPoolInfoStruct*))(void*)>::type> itk::ThreadPool::AddWork<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*>(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<void>::__call<std::__1::future<std::__1::result_of<void* (*& (itk::PoolMultiThreader::ThreadPoolInfoStruct*))(void*)>::type> itk::ThreadPool::AddWork<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*>(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()&>(std::__1::future<std::__1::result_of<void* (*& (itk::PoolMultiThreader::ThreadPoolInfoStruct*))(void*)>::type> itk::ThreadPool::AddWork<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*>(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()&&&) __functional_base:349 (ITKTransformTestDriver:x86_64+0x100368ca1)
    #14 std::__1::__function::__alloc_func<std::__1::future<std::__1::result_of<void* (*& (itk::PoolMultiThreader::ThreadPoolInfoStruct*))(void*)>::type> itk::ThreadPool::AddWork<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*>(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'(), std::__1::allocator<std::__1::future<std::__1::result_of<void* (*& (itk::PoolMultiThreader::ThreadPoolInfoStruct*))(void*)>::type> itk::ThreadPool::AddWork<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*>(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()>, void ()>::operator()() functional:1527 (ITKTransformTestDriver:x86_64+0x100368c61)
    #15 std::__1::__function::__func<std::__1::future<std::__1::result_of<void* (*& (itk::PoolMultiThreader::ThreadPoolInfoStruct*))(void*)>::type> itk::ThreadPool::AddWork<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*>(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'(), std::__1::allocator<std::__1::future<std::__1::result_of<void* (*& (itk::PoolMultiThreader::ThreadPoolInfoStruct*))(void*)>::type> itk::ThreadPool::AddWork<void* (*&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*>(void* (*&&&)(void*), itk::PoolMultiThreader::ThreadPoolInfoStruct*&&)::'lambda'()>, void ()>::operator()() functional:1651 (ITKTransformTestDriver:x86_64+0x1003676ad)
    #16 std::__1::__function::__value_func<void ()>::operator()() const functional:1799 (ITKTransformTestDriver:x86_64+0x10033b024)
    #17 std::__1::function<void ()>::operator()() const functional:2347 (ITKTransformTestDriver:x86_64+0x100336b89)
    #18 itk::ThreadPool::ThreadExecute() itkThreadPool.cxx:211 (ITKTransformTestDriver:x86_64+0x1003730fa)
    #19 decltype(std::__1::forward<void (*)()>(fp)()) std::__1::__invoke<void (*)()>(void (*&&)()) type_traits:4361 (ITKTransformTestDriver:x86_64+0x10037a216)
    #20 void std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)()>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)()>&, std::__1::__tuple_indices<>) thread:342 (ITKTransformTestDriver:x86_64+0x10037a0f9)
    #21 void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, 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) <null>: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<double>::allocate_T(unsigned long) vnl_c_vector.hxx:404 (ITKTransformTestDriver:x86_64+0x100b9b0ff)
    #4 vnl_vector<double>::set_size(unsigned long) vnl_vector.hxx:226 (ITKTransformTestDriver:x86_64+0x100d6c32e)
    #5 itk::Array<double>::SetSize(unsigned long) itkArray.hxx:141 (ITKTransformTestDriver:x86_64+0x100012a03)
    #6 itk::MatrixOffsetTransformBase<double, 3u, 3u>::MatrixOffsetTransformBase(unsigned int) itkMatrixOffsetTransformBase.hxx:36 (ITKTransformTestDriver:x86_64+0x10003c544)
    #7 itk::AffineTransform<double, 3u>::AffineTransform() itkAffineTransform.hxx:29 (ITKTransformTestDriver:x86_64+0x10003c40f)
    #8 itk::AffineTransform<double, 3u>::AffineTransform() itkAffineTransform.hxx:30 (ITKTransformTestDriver:x86_64+0x10003c369)
    #9 itk::AffineTransform<double, 3u>::New() itkAffineTransform.h:117 (ITKTransformTestDriver:x86_64+0x100036dc5)
    #10 unsigned int TransformTest<itk::AffineTransform<double, 3u> >() 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 <null>: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 (*)(), void>(void (*&&)()) thread:368 (ITKTransformTestDriver:x86_64+0x10037966c)
    #3 std::__1::thread::thread<void (*)(), void>(void (*&&)()) thread:360 (ITKTransformTestDriver:x86_64+0x1003795a0)
    #4 void std::__1::allocator<std::__1::thread>::construct<std::__1::thread, void (*)()>(std::__1::thread*, void (*&&)()) memory:1826 (ITKTransformTestDriver:x86_64+0x100379558)
    #5 void std::__1::allocator_traits<std::__1::allocator<std::__1::thread> >::__construct<std::__1::thread, void (*)()>(std::__1::integral_constant<bool, true>, std::__1::allocator<std::__1::thread>&, std::__1::thread*, void (*&&)()) memory:1718 (ITKTransformTestDriver:x86_64+0x100379508)
    #6 void std::__1::allocator_traits<std::__1::allocator<std::__1::thread> >::construct<std::__1::thread, void (*)()>(std::__1::allocator<std::__1::thread>&, std::__1::thread*, void (*&&)()) memory:1561 (ITKTransformTestDriver:x86_64+0x1003793b8)
    #7 void std::__1::vector<std::__1::thread, std::__1::allocator<std::__1::thread> >::emplace_back<void (*)()>(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<itk::ThreadPool::GetInstance()::$_2>(fp)()) std::__1::__invoke<itk::ThreadPool::GetInstance()::$_2>(itk::ThreadPool::GetInstance()::$_2&&) type_traits:4361 (ITKTransformTestDriver:x86_64+0x1003783a3)
    #12 void std::__1::__call_once_param<std::__1::tuple<itk::ThreadPool::GetInstance()::$_2&&> >::__execute<>(std::__1::__tuple_indices<>) mutex:622 (ITKTransformTestDriver:x86_64+0x100378371)
    #13 std::__1::__call_once_param<std::__1::tuple<itk::ThreadPool::GetInstance()::$_2&&> >::operator()() mutex:614 (ITKTransformTestDriver:x86_64+0x100378319)
    #14 void std::__1::__call_once_proxy<std::__1::tuple<itk::ThreadPool::GetInstance()::$_2&&> >(void*) mutex:650 (ITKTransformTestDriver:x86_64+0x1003781b9)
    #15 __tsan::(anonymous namespace)::call_once_callback_wrapper(void*) <null>: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<itk::AffineTransform<double, 3u> >() 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 <null>: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 (*)(), void>(void (*&&)()) thread:368 (ITKTransformTestDriver:x86_64+0x10037966c)
    #3 std::__1::thread::thread<void (*)(), void>(void (*&&)()) thread:360 (ITKTransformTestDriver:x86_64+0x1003795a0)
    #4 void std::__1::allocator<std::__1::thread>::construct<std::__1::thread, void (*)()>(std::__1::thread*, void (*&&)()) memory:1826 (ITKTransformTestDriver:x86_64+0x100379558)
    #5 void std::__1::allocator_traits<std::__1::allocator<std::__1::thread> >::__construct<std::__1::thread, void (*)()>(std::__1::integral_constant<bool, true>, std::__1::allocator<std::__1::thread>&, std::__1::thread*, void (*&&)()) memory:1718 (ITKTransformTestDriver:x86_64+0x100379508)
    #6 void std::__1::allocator_traits<std::__1::allocator<std::__1::thread> >::construct<std::__1::thread, void (*)()>(std::__1::allocator<std::__1::thread>&, std::__1::thread*, void (*&&)()) memory:1561 (ITKTransformTestDriver:x86_64+0x1003793b8)
    #7 void std::__1::vector<std::__1::thread, std::__1::allocator<std::__1::thread> >::emplace_back<void (*)()>(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<itk::ThreadPool::GetInstance()::$_2>(fp)()) std::__1::__invoke<itk::ThreadPool::GetInstance()::$_2>(itk::ThreadPool::GetInstance()::$_2&&) type_traits:4361 (ITKTransformTestDriver:x86_64+0x1003783a3)
    #12 void std::__1::__call_once_param<std::__1::tuple<itk::ThreadPool::GetInstance()::$_2&&> >::__execute<>(std::__1::__tuple_indices<>) mutex:622 (ITKTransformTestDriver:x86_64+0x100378371)
    #13 std::__1::__call_once_param<std::__1::tuple<itk::ThreadPool::GetInstance()::$_2&&> >::operator()() mutex:614 (ITKTransformTestDriver:x86_64+0x100378319)
    #14 void std::__1::__call_once_proxy<std::__1::tuple<itk::ThreadPool::GetInstance()::$_2&&> >(void*) mutex:650 (ITKTransformTestDriver:x86_64+0x1003781b9)
    #15 __tsan::(anonymous namespace)::call_once_callback_wrapper(void*) <null>: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<itk::AffineTransform<double, 3u> >() 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<double, 3u, 3u>::GetFixedParameters() const
seanm commented 2 years ago

168f84f1ac3e209cc46d1c9b07a896fc895cdd8a looks to be related. So @thewtex maybe you have some idea for this one?

thewtex commented 2 years ago

@seanm taking a look, it seems we should be calling:

  this->m_FixedParameters.SetSize(NInputDimensions);
  this->m_FixedParameters.Fill(0.0);

in:

template <typename TScalar, unsigned int NInputDimensions,
          unsigned int NOutputDimensions>
MatrixOffsetTransformBase<TScalar, NInputDimensions, NOutputDimensions>
::MatrixOffsetTransformBase(const MatrixType & matrix, const OutputVectorType & offset)
{
  m_Matrix = matrix;
  m_MatrixMTime.Modified();
  m_Offset = offset;
  m_Center.Fill(0);
  m_Translation.Fill(0);
  for( unsigned int i = 0; i < NOutputDimensions; i++ )
    {
    m_Translation[i] = offset[i];
    }
  this->ComputeMatrixParameters();
}

but that may not be the source of this warning.

Thanks for looking into these static analysis issues.

seanm commented 2 years ago

Sorry, where is that code? I don't seem able to find it in master...

PS: TSan is not static analysis, it's a runtime checker.

dzenanz commented 2 years ago

Here it is: https://github.com/InsightSoftwareConsortium/ITK/blob/6a1575d68cea6d94a946533c79f42a8ab6aa3f5b/Modules/Core/Transform/include/itkMatrixOffsetTransformBase.hxx#L41-L51

seanm commented 2 years ago

Ah, quite different! I'll try adding those 2 lines...

seanm commented 2 years ago

@thewtex so I added those 2 lines at the end of that function, but alas it does not fix the TSan error.

thewtex commented 2 years ago

@seanm could that fix please be submitted? It may not be the TSan error, but I think it is still a bug.

seanm commented 1 month ago

@thewtex ok will do. though I'll need help writing a commit message, since I don't know what I'm doing here.


Just looking at this again years later...

template <typename TParametersValueType, unsigned int VInputDimension, unsigned int VOutputDimension>
const typename MatrixOffsetTransformBase<TParametersValueType, VInputDimension, VOutputDimension>::FixedParametersType &
MatrixOffsetTransformBase<TParametersValueType, VInputDimension, VOutputDimension>::GetFixedParameters() const
{
  for (unsigned int i = 0; i < VInputDimension; ++i)
  {
    this->m_FixedParameters[i] = this->m_Center[i];
  }
  return this->m_FixedParameters;
}

I'm confused: How can this method be const when it's mutating the thing it's returning?

seanm commented 1 month ago

@seanm could that fix please be submitted? It may not be the TSan error, but I think it is still a bug.

https://github.com/InsightSoftwareConsortium/ITK/pull/4698

seanm commented 1 week ago

4698 is now merged, and, as suspected, wasn't related to the TSan failure, which still occurs in current master.