Version and Platform (required):
- Binary Ninja Version: Local build from dev
- OS: macOS 25.0
- CPU Architecture: arm64
- Local or Remote Debugging: local
Bug Description:
With a local build of Binary Ninja with TSan enabled (-DTSAN=ON -DBUILD_BINEXPORT=OFF), I see a number of data races reported when starting / stopping a debug session of a hello world executable.
WARNING: ThreadSanitizer: data race (pid=8354)
Read of size 8 at 0x0001129b1f50 by main thread:
#0 BNDebuggerGetIP ffi.cpp:898 (libdebuggercore.dylib:arm64+0x8d1b8)
#1 BinaryNinjaDebuggerAPI::DebuggerController::IP() debuggercontroller.cpp:923 (libdebuggerui.dylib:arm64+0x126480)
#2 DebuggerRenderLayer::ApplyToHighLevelILBody(BinaryNinja::Ref<BinaryNinja::Function>, std::__1::vector<BinaryNinja::LinearDisassemblyLine, std::__1::allocator<BinaryNinja::LinearDisassemblyLine>>&) renderlayer.cpp:225 (libdebuggerui.dylib:arm64+0x7ca10)
…
Previous write of size 8 at 0x0001129b1f50 by thread T334:
#0 BinaryNinjaDebugger::DebuggerController::EventHandler(BinaryNinjaDebugger::DebuggerEvent const&) debuggercontroller.cpp:1892 (libdebuggercore.dylib:arm64+0x46634)
#1 std::__1::__function::__func<BinaryNinjaDebugger::DebuggerController::DebuggerController(BinaryNinja::Ref<BinaryNinja::BinaryView>)::$_0, void (BinaryNinjaDebugger::DebuggerEvent const&)>::operator()(BinaryNinjaDebugger::DebuggerEvent const&) function.h:174 (libdebuggercore.dylib:arm64+0x67e70)
#2 BinaryNinjaDebugger::DebuggerController::DebuggerMainThread() debuggercontroller.cpp:2110 (libdebuggercore.dylib:arm64+0x4a3a4)
Location is heap block of size 1352 at 0x0001129b1c00 allocated by main thread:
#0 operator new(unsigned long) <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x91254)
#1 BinaryNinjaDebugger::DebuggerController::GetController(BinaryNinja::Ref<BinaryNinja::BinaryView>) debuggercontroller.cpp:1762 (libdebuggercore.dylib:arm64+0x45414)
WARNING: ThreadSanitizer: data race (pid=8354)
Read of size 4 at 0x000337770ff0 by main thread:
#0 BinaryNinjaDebugger::DebuggerController::ReadMemory(unsigned long, unsigned long) debuggercontroller.cpp:2186 (libdebuggercore.dylib:arm64+0x4b138)
#1 BinaryNinjaDebugger::DebuggerFileAccessor::Read(void*, unsigned long long, unsigned long) debuggerfileaccessor.cpp:58 (libdebuggercore.dylib:arm64+0x6db3c)
#2 BinaryNinja::FileAccessor::ReadCallback(void*, void*, unsigned long long, unsigned long) fileaccessor.cpp:37 (libdebuggercore.dylib:arm64+0x21a650)
#3 BinaryNinjaCore::MemoryAccessor::Read(void*, unsigned long long, unsigned long) binaryview.h:1557 (libbinaryninjacore.1.dylib:arm64+0x418ca0)
…
Previous write of size 8 at 0x000337770ff0 by thread T334:
#0 BinaryNinjaDebugger::DebuggerController::EventHandler(BinaryNinjaDebugger::DebuggerEvent const&) debuggercontroller.cpp:1855 (libdebuggercore.dylib:arm64+0x46424)
#1 std::__1::__function::__func<BinaryNinjaDebugger::DebuggerController::DebuggerController(BinaryNinja::Ref<BinaryNinja::BinaryView>)::$_0, void (BinaryNinjaDebugger::DebuggerEvent const&)>::operator()(BinaryNinjaDebugger::DebuggerEvent const&) function.h:174 (libdebuggercore.dylib:arm64+0x67e70)
#2 BinaryNinjaDebugger::DebuggerController::DebuggerMainThread() debuggercontroller.cpp:2110 (libdebuggercore.dylib:arm64+0x4a3a4)
#3 void* std::__1::__thread_proxy[abi:nqe210106]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, BinaryNinjaDebugger::DebuggerController::DebuggerController(BinaryNinja::Ref<BinaryNinja::BinaryView>)::$_1>>(void*) thread.h:168 (libdebuggercore.dylib:arm64+0x67f78)
Location is heap block of size 136 at 0x000337770fe0 allocated by main thread:
#0 operator new(unsigned long) <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x91254)
#1 BinaryNinjaDebugger::DebuggerController::DebuggerController(BinaryNinja::Ref<BinaryNinja::BinaryView>) debuggercontroller.cpp:36 (libdebuggercore.dylib:arm64+0x36168)
The common theme is that there are member variables of DebuggerController that are accessed from both debugger event thread and the main thread without any synchronization.
Version and Platform (required):
Bug Description:
With a local build of Binary Ninja with TSan enabled (
-DTSAN=ON -DBUILD_BINEXPORT=OFF), I see a number of data races reported when starting / stopping a debug session of a hello world executable.The common theme is that there are member variables of
DebuggerControllerthat are accessed from both debugger event thread and the main thread without any synchronization.