vtkGradientFilter has thread race, via `TestGradientAndVorticity` test for example
Running the TestGradientAndVorticity
test with TSan shows 2 worker threads writing to the same ivar with the same backtrace:
#0 (anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>::operator()(long long, long long) vtkGradientFilter.cxx:472 (libvtkFiltersGeneral-9.3.9.3.dylib:arm64+0x60d134)
#1 vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>::Execute(long long, long long) vtkSMPTools.h:114 (libvtkFiltersGeneral-9.3.9.3.dylib:arm64+0x60c9d8)
#2 void vtk::detail::smp::vtkSMPToolsImpl<(vtk::detail::smp::BackendType)1>::For<vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>>(long long, long long, long long, vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>&)::'lambda'()::operator()() const vtkSMPToolsImpl.txx:56 (libvtkFiltersGeneral-9.3.9.3.dylib:arm64+0x6127ac)
#3 decltype(std::declval<vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>>()()) std::__1::__invoke[abi:v160006]<void vtk::detail::smp::vtkSMPToolsImpl<(vtk::detail::smp::BackendType)1>::For<vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>>(long long, long long, long long, vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>&)::'lambda'()&>(vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>&&) invoke.h:394 (libvtkFiltersGeneral-9.3.9.3.dylib:arm64+0x612718)
#4 void std::__1::__invoke_void_return_wrapper<void, true>::__call<void vtk::detail::smp::vtkSMPToolsImpl<(vtk::detail::smp::BackendType)1>::For<vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>>(long long, long long, long long, vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>&)::'lambda'()&>(void vtk::detail::smp::vtkSMPToolsImpl<(vtk::detail::smp::BackendType)1>::For<vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>>(long long, long long, long long, vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>&)::'lambda'()&) invoke.h:487 (libvtkFiltersGeneral-9.3.9.3.dylib:arm64+0x61267c)
#5 std::__1::__function::__alloc_func<void vtk::detail::smp::vtkSMPToolsImpl<(vtk::detail::smp::BackendType)1>::For<vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>>(long long, long long, long long, vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>&)::'lambda'(), std::__1::allocator<void vtk::detail::smp::vtkSMPToolsImpl<(vtk::detail::smp::BackendType)1>::For<vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>>(long long, long long, long long, vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>&)::'lambda'()>, void ()>::operator()[abi:v160006]() function.h:185 (libvtkFiltersGeneral-9.3.9.3.dylib:arm64+0x612628)
#6 std::__1::__function::__func<void vtk::detail::smp::vtkSMPToolsImpl<(vtk::detail::smp::BackendType)1>::For<vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>>(long long, long long, long long, vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>&)::'lambda'(), std::__1::allocator<void vtk::detail::smp::vtkSMPToolsImpl<(vtk::detail::smp::BackendType)1>::For<vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>>(long long, long long, long long, vtk::detail::smp::vtkSMPTools_FunctorInternal<(anonymous namespace)::PointGradients<vtkAOSDataArrayTemplate<double>>, true>&)::'lambda'()>, void ()>::operator()() function.h:356 (libvtkFiltersGeneral-9.3.9.3.dylib:arm64+0x6108dc)
#7 std::__1::__function::__value_func<void ()>::operator()[abi:v160006]() const function.h:510 (libvtkCommonCore-9.3.9.3.dylib:arm64+0x48ac12c)
#8 std::__1::function<void ()>::operator()() const function.h:1156 (libvtkCommonCore-9.3.9.3.dylib:arm64+0x48a7004)
#9 vtk::detail::smp::vtkSMPThreadPool::RunJob(vtk::detail::smp::vtkSMPThreadPool::ThreadData&, unsigned long, std::__1::unique_lock<std::__1::mutex>&) vtkSMPThreadPool.cxx:91 (libvtkCommonCore-9.3.9.3.dylib:arm64+0x48a673c)
Basically, in PointGradients::operator()
, both threads are hitting this->HighestDim = 0;
Making it atomic won't help, because a few lines later it's also written to and read from again. Maybe a mutex is needed.
git blame
shows the relevant lines last touched in 5f1e412d.