Skip to content

mrregister: fix race condition in displacement update#3277

Open
daljit46 wants to merge 2 commits intomasterfrom
fix_racy_reduction_mrregister
Open

mrregister: fix race condition in displacement update#3277
daljit46 wants to merge 2 commits intomasterfrom
fix_racy_reduction_mrregister

Conversation

@daljit46
Copy link
Copy Markdown
Member

The following race condition was identified with TSAN:

WARNING: ThreadSanitizer: data race (pid=24689)
  Write of size 8 at 0x00016d515ac0 by thread T306:
    #0 MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>::operator()(MR::Iterator const&) <null>:90187328 (libmrtrix-core.dylib:arm64+0x52d0b8)
    #1 void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::execute() <null>:90187328 (libmrtrix-core.dylib:arm64+0x52e168)
    #2 std::__1::__async_assoc_state<void, std::__1::__async_func<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>>::__execute() <null>:90187328 (libmrtrix-core.dylib:arm64+0x52e510)
    #3 void* std::__1::__thread_proxy[abi:ne180100]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (std::__1::__async_assoc_state<void, std::__1::__async_func<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>>::*)(), std::__1::__async_assoc_state<void, std::__1::__async_func<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>>*>>(void*) <null>:90187328 (libmrtrix-core.dylib:arm64+0x52e628)

  Previous read of size 8 at 0x00016d515ac0 by thread T310:
    #0 MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>::operator()(MR::Iterator const&) <null>:90187328 (libmrtrix-core.dylib:arm64+0x52d0a4)
    #1 void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::execute() <null>:90187328 (libmrtrix-core.dylib:arm64+0x52e168)
    #2 std::__1::__async_assoc_state<void, std::__1::__async_func<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>>::__execute() <null>:90187328 (libmrtrix-core.dylib:arm64+0x52e510)
    #3 void* std::__1::__thread_proxy[abi:ne180100]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (std::__1::__async_assoc_state<void, std::__1::__async_func<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>>::*)(), std::__1::__async_assoc_state<void, std::__1::__async_func<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>>*>>(void*) <null>:90187328 (libmrtrix-core.dylib:arm64+0x52e628)

  Location is stack of main thread.

  Thread T306 (tid=13272096, running) created by main thread at:
    #0 pthread_create <null>:93330752 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x309d8)
    #1 std::__1::future<std::__1::__invoke_of<__decay(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&), __decay(void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*)>::type> std::__1::async[abi:ne180100]<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>(std::__1::launch, MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&, void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*&&) <null>:90187520 (libmrtrix-core.dylib:arm64+0x52dd98)
    #2 void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run<MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&)&, MR::Image<double>&>(MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&)&, MR::Image<double>&) <null>:90187520 (libmrtrix-core.dylib:arm64+0x52ac6c)
    #3 void MR::Registration::NonLinear::run<MR::Registration::Transform::Rigid, MR::Image<double>, MR::Image<double>, MR::Image<double>, MR::Image<double>>(MR::Registration::Transform::Rigid, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&) <null>:90187520 (libmrtrix-core.dylib:arm64+0x4fc40c)
    #4 void MR::Registration::NonLinear::run<MR::Registration::Transform::Rigid, MR::Image<double>, MR::Image<double>, MR::Image<double>, MR::Image<double>>(MR::Registration::Transform::Rigid, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&) <null>:90187520 (libmrtrix-core.dylib:arm64+0x4f7e94)
    #5 run() <null>:91235072 (mrregister:arm64+0x100013014)
    #6 run() <null>:91235072 (mrregister:arm64+0x1000083ec)
    #7 <null> <null> (0x000185b48274)

  Thread T310 (tid=13272100, running) created by main thread at:
    #0 pthread_create <null>:93332048 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x309d8)
    #1 std::__1::future<std::__1::__invoke_of<__decay(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&), __decay(void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*)>::type> std::__1::async[abi:ne180100]<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>(std::__1::launch, MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&, void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*&&) <null>:90187328 (libmrtrix-core.dylib:arm64+0x52dd98)
    #2 void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run<MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&)&, MR::Image<double>&>(MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&)&, MR::Image<double>&) <null>:90187328 (libmrtrix-core.dylib:arm64+0x52ac6c)
    #3 void MR::Registration::NonLinear::run<MR::Registration::Transform::Rigid, MR::Image<double>, MR::Image<double>, MR::Image<double>, MR::Image<double>>(MR::Registration::Transform::Rigid, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&) <null>:90187328 (libmrtrix-core.dylib:arm64+0x4fc40c)
    #4 void MR::Registration::NonLinear::run<MR::Registration::Transform::Rigid, MR::Image<double>, MR::Image<double>, MR::Image<double>, MR::Image<double>>(MR::Registration::Transform::Rigid, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&) <null>:90187328 (libmrtrix-core.dylib:arm64+0x4f7e94)
    #5 run() <null>:91230992 (mrregister:arm64+0x100013014)
    #6 run() <null>:91230992 (mrregister:arm64+0x1000083ec)
    #7 <null> <null> (0x000185b48274)

SUMMARY: ThreadSanitizer: data race (libmrtrix-core.dylib:arm64+0x52d0b8) in MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>::operator()(MR::Iterator const&)+0x34c
==================
==================
WARNING: ThreadSanitizer: data race (pid=24689)
  Write of size 8 at 0x00016d515ac0 by thread T312:
    #0 MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>::operator()(MR::Iterator const&) <null>:90187520 (libmrtrix-core.dylib:arm64+0x52d0b8)
    #1 void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::execute() <null>:90187520 (libmrtrix-core.dylib:arm64+0x52e168)
    #2 std::__1::__async_assoc_state<void, std::__1::__async_func<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>>::__execute() <null>:90187520 (libmrtrix-core.dylib:arm64+0x52e510)
    #3 void* std::__1::__thread_proxy[abi:ne180100]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (std::__1::__async_assoc_state<void, std::__1::__async_func<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>>::*)(), std::__1::__async_assoc_state<void, std::__1::__async_func<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>>*>>(void*) <null>:90187520 (libmrtrix-core.dylib:arm64+0x52e628)

  Previous write of size 8 at 0x00016d515ac0 by thread T310:
    #0 MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>::operator()(MR::Iterator const&) <null>:90187520 (libmrtrix-core.dylib:arm64+0x52d0b8)
    #1 void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::execute() <null>:90187520 (libmrtrix-core.dylib:arm64+0x52e168)
    #2 std::__1::__async_assoc_state<void, std::__1::__async_func<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>>::__execute() <null>:90187520 (libmrtrix-core.dylib:arm64+0x52e510)
    #3 void* std::__1::__thread_proxy[abi:ne180100]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (std::__1::__async_assoc_state<void, std::__1::__async_func<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>>::*)(), std::__1::__async_assoc_state<void, std::__1::__async_func<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>>*>>(void*) <null>:90187520 (libmrtrix-core.dylib:arm64+0x52e628)

  Location is stack of main thread.

  Thread T312 (tid=13272102, running) created by main thread at:
    #0 pthread_create <null>:93332048 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x309d8)
    #1 std::__1::future<std::__1::__invoke_of<__decay(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&), __decay(void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*)>::type> std::__1::async[abi:ne180100]<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>(std::__1::launch, MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&, void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*&&) <null>:90177536 (libmrtrix-core.dylib:arm64+0x52dd98)
    #2 void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run<MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&)&, MR::Image<double>&>(MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&)&, MR::Image<double>&) <null>:90177536 (libmrtrix-core.dylib:arm64+0x52af14)
    #3 void MR::Registration::NonLinear::run<MR::Registration::Transform::Rigid, MR::Image<double>, MR::Image<double>, MR::Image<double>, MR::Image<double>>(MR::Registration::Transform::Rigid, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&) <null>:90177536 (libmrtrix-core.dylib:arm64+0x4fc40c)
    #4 void MR::Registration::NonLinear::run<MR::Registration::Transform::Rigid, MR::Image<double>, MR::Image<double>, MR::Image<double>, MR::Image<double>>(MR::Registration::Transform::Rigid, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&) <null>:90177536 (libmrtrix-core.dylib:arm64+0x4f7e94)
    #5 run() <null>:91230992 (mrregister:arm64+0x100013014)
    #6 run() <null>:91230992 (mrregister:arm64+0x1000083ec)
    #7 <null> <null> (0x000185b48274)

  Thread T310 (tid=13272100, running) created by main thread at:
    #0 pthread_create <null>:93330752 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x309d8)
    #1 std::__1::future<std::__1::__invoke_of<__decay(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&), __decay(void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*)>::type> std::__1::async[abi:ne180100]<void (void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread::*)(), void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*>(std::__1::launch, MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&, void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run_outer<MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&>(MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>&)::PerThread*&&) <null>:90187520 (libmrtrix-core.dylib:arm64+0x52dd98)
    #2 void MR::(anonymous namespace)::ThreadedLoopRunOuter<MR::LoopAlongDynamicAxes>::run<MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&)&, MR::Image<double>&>(MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&)&, MR::Image<double>&) <null>:90187520 (libmrtrix-core.dylib:arm64+0x52ac6c)
    #3 void MR::Registration::NonLinear::run<MR::Registration::Transform::Rigid, MR::Image<double>, MR::Image<double>, MR::Image<double>, MR::Image<double>>(MR::Registration::Transform::Rigid, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&) <null>:90187520 (libmrtrix-core.dylib:arm64+0x4fc40c)
    #4 void MR::Registration::NonLinear::run<MR::Registration::Transform::Rigid, MR::Image<double>, MR::Image<double>, MR::Image<double>, MR::Image<double>>(MR::Registration::Transform::Rigid, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, MR::Image<double>&) <null>:90187520 (libmrtrix-core.dylib:arm64+0x4f7e94)
    #5 run() <null>:91235072 (mrregister:arm64+0x100013014)
    #6 run() <null>:91235072 (mrregister:arm64+0x1000083ec)
    #7 <null> <null> (0x000185b48274)

SUMMARY: ThreadSanitizer: data race (libmrtrix-core.dylib:arm64+0x52d0b8) in MR::(anonymous namespace)::ThreadedLoopRunInner<1, MR::Registration::Warp::update_displacement_scaling_and_squaring(MR::Image<double>&, MR::Image<double>&, MR::Image<double>&, double)::'lambda'(MR::Image<double>&), MR::Image<double>>::operator()(MR::Iterator const&)+0x34c

The cause was this piece of code:

  auto max_norm_func = [&max_norm](Image<default_type> &update) {
    default_type norm = Eigen::Vector3d(update.row(3)).norm();
    if (norm > max_norm)
      max_norm = norm;
  };
  ThreadedLoop(update).run(max_norm_func, update);

Here, max_norm is a local stack variable. The lambda captures it by reference thus the variable is subject to reads/writes from different threads without any synchronisation. This PR fixes the problem by replacing the shared max norm lambda with a thread local functor reduction and mutex-protected merge. Also rather than computing as square root inside the functor, we compute the squared norm and only at the end evaluate the square root.

@daljit46 daljit46 self-assigned this Mar 17, 2026
@daljit46 daljit46 added the bug label Mar 17, 2026
@daljit46 daljit46 requested a review from a team March 17, 2026 16:01
Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

Comment thread cpp/core/registration/warp/compose.h Outdated
Comment thread cpp/core/registration/warp/compose.h Outdated
}

private:
default_type &overall_max_norm_squared;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: member 'overall_max_norm_squared' of type 'default_type &' (aka 'double &') is a reference [cppcoreguidelines-avoid-const-or-ref-data-members]

  default_type &overall_max_norm_squared;
                ^

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we've used this approach throughout the code base, but I think it may have been criticised at some point. Is there something better, even if only for my own knowledge when I need to do similar in the future? My naive instinct would be std::shared_ptr<default_type>, but there's lots in the language I don't know about.

Copy link
Copy Markdown
Member Author

@daljit46 daljit46 Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the code above, I did stick with using references to conform to our existing conventions, but perhaps we should change this. My opinion is that we should use raw pointers for this sort of thing. In particular, we should use const pointers:

// Cannot modify the pointer once set, but can modify value
default_type* const overall_max_norm_squared;

The "modern C++" recommendation is to avoid raw pointers only if they're owning, but I think it's perfectly legitimate to use them non-owning versions.
Shared pointers would be a mistake here I think. std::shared_ptr is about ownership, in this case the functor isn't an owner of the resource but just a reader.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::shared_ptr is about ownership

Would this not be a circumstance in which to use std::weak_ptr<>? Wouldn't obviate mutexing but would better implicitly communicate that it's not accessed unless .lock() is called.

(again, happy to refactor all instances of such at a later date if a design pattern is accepted)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::weak_ptr would make sense if we have a std::shared_ptr already. In this case, we're dealing a local stack variable, so smart pointers aren't in the picture. If max_norm_squared was encapsulated in a shared pointer, then a weak_ptr may makes sense.

Comment thread cpp/core/registration/warp/compose.h Outdated
@Lestropie
Copy link
Copy Markdown
Member

Even if the fault was discovered on dev, it would nevertheless be preferable given that it is a bug fix to be ported to master. Could still use this PR as it is, just replicate on master and then when master has to be merged back in to dev resolve the conflict by keeping these contents.

@daljit46
Copy link
Copy Markdown
Member Author

daljit46 commented Mar 25, 2026

OK will rebase this onto master.

Replace the shared max norm lambda in scaling-and-squaring with
a thread local functor reduction and mutex-protected merge.
@daljit46 daljit46 force-pushed the fix_racy_reduction_mrregister branch from 7b81eb1 to 88ffd23 Compare March 25, 2026 16:17
@daljit46 daljit46 changed the base branch from dev to master March 25, 2026 16:18
@daljit46 daljit46 requested a review from Lestropie March 25, 2026 16:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants