Skip to content

Fix crash from joining the event thread on itself#1047

Open
xusheng6 wants to merge 2 commits intodevfrom
test_1038-crash-join-event-thread
Open

Fix crash from joining the event thread on itself#1047
xusheng6 wants to merge 2 commits intodevfrom
test_1038-crash-join-event-thread

Conversation

@xusheng6
Copy link
Copy Markdown
Member

@xusheng6 xusheng6 commented Apr 6, 2026

Summary

  • Defer delete m_accessor in EventHandler to a detached std::thread
  • The DebuggerFileAccessor holds a DbgRef<DebuggerController>, and when it's the last reference, deleting it on the event thread triggers ~DebuggerController which calls m_debuggerEventThread.join() — crashing because we ARE the event thread
  • Root cause is a race condition: EventHandler sets ConnectionStatus(NotConnected) before deleting the accessor, and another thread (UI close path or Python) can observe this, call Destroy() to remove the global array ref, making the accessor's DbgRef the last reference
  • By deferring the deletion to a detached thread, the controller's destructor runs off the event thread where join() succeeds normally

Test plan

  • Debug a target, let it exit normally — verify no crash on exit
  • Debug a target, detach — verify no crash on detach
  • Trigger a launch failure (e.g., invalid remote address) — verify no crash
  • Close a file tab while the target is exiting — verify no crash

Fixes #1038

🤖 Generated with Claude Code

ui/ui.cpp Outdated
frame->navigate(m_controller->GetData(), address, true, true);
}

openDebuggerSideBar(frame);
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.

this is the same change as the other PR?

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.

This is a change introduced earlier: #1032. The reason that I wanted it to no longer focus the debugger sidebar is that if the user is using sidekick to automate the debugger, this will cause the sidekick sidebar to lose focus.

I think I made some git mistake so that it gets wiped out unexpectedly. I will add it back

xusheng6 and others added 2 commits April 7, 2026 11:21
When DebuggerController::EventHandler handles TargetExitedEventType,
DetachedEventType, or LaunchFailureEventType, it deletes m_accessor.
The DebuggerFileAccessor holds the last DbgRef<DebuggerController>,
so deleting it triggers ~DebuggerController, which calls
m_debuggerEventThread.join(). Since we're already on that thread,
join() throws std::system_error(resource_deadlock_would_occur),
causing an abort.

Defer the accessor deletion to a worker thread so that if it triggers
controller destruction, the destructor runs off the event thread and
join() succeeds normally.

Fixes #1038

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BinaryNinja's worker threads are meant for analysis tasks. Use a plain
detached thread instead for deferring the m_accessor deletion off the
event thread.

Also expanded the comment to document the race condition root cause:
Destroy() can remove the global array ref between SetConnectionStatus
(NotConnected) and the accessor deletion, making the accessor's DbgRef
the last reference to the controller.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@xusheng6 xusheng6 force-pushed the test_1038-crash-join-event-thread branch from bf18d73 to d490308 Compare April 7, 2026 03:22
Copy link
Copy Markdown
Member

@plafosse plafosse left a comment

Choose a reason for hiding this comment

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

Looks good now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

crashpad::`anonymous namespace'::HandleAbortSignal

2 participants