Skip to content

Data races reported by thread sanitizer related to DebuggerController's member variables #1091

@bdash

Description

@bdash

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions