Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LLDB: calling SBProcess::Kill() and SBProcess::ReadMemory() at the same time from two threads hang the debugger #391

Closed
xusheng6 opened this issue Dec 8, 2022 · 1 comment
Milestone

Comments

@xusheng6
Copy link
Member

xusheng6 commented Dec 8, 2022

If two threads call SBProcess::Kill() and SBProcess::ReadMemory() at the same time, then the LLDB debugger hangs. Which will likely hang BN as well.

This can be triggered in several ways, first, as in #384, the string search thread is constantly reading the debugger memory, and trying to kill the target will cause the hang. Second, since a memory read can happen almost anytime during analysis, it is also very likely to happen when the debugger seems idle. Third, this can happen when the UI thread is updating the xref, leading to a BN hang directly.

This is likely an LLDB bug as well, because its API is said to be thread-safe, i.e., it should be fine to make concurrent calls from two threads since it internally uses lock to protect concurrent access.

Related to #384, #389

@xusheng6
Copy link
Member Author

xusheng6 commented Dec 8, 2022

For the third case, here is the stack trace of the related threads:

  1. main thread (updating xref)
    __psynch_mutexwait 0x00000001a9e2da9c
    _pthread_mutex_firstfit_lock_wait 0x00000001a9e67144
    _pthread_mutex_firstfit_lock_slow 0x00000001a9e64a9c
    std::__1::recursive_mutex::lock() 0x00000001a9db9b7c
    0x0000000116989504
    BNGetVariableType 0x00000001169a0f5c
    0x00000001073b8650
    CrossReferenceTreeModel::data(QModelIndex const&, int) const 0x000000010733d410
    QSortFilterProxyModel::data(QModelIndex const&, int) const 0x0000000106c05f10
    CrossReferenceFilterProxyModel::data(QModelIndex const&, int) const 0x000000010734e3bc
    CrossReferenceItemDelegate::paintTreeRow(QPainter*, QStyleOptionViewItem const&, QModelIndex const&) const 0x0000000107348dc4
    QTreeView::drawRow(QPainter*, QStyleOptionViewItem const&, QModelIndex const&) const 0x00000001079bdac4
    QTreeView::drawTree(QPainter*, QRegion const&) const 0x00000001079bbd98
    QTreeView::paintEvent(QPaintEvent*) 0x00000001079bbb68
    QWidget::event(QEvent*) 0x000000010772d620
    QFrame::event(QEvent*) 0x00000001077b07a0
    QAbstractItemView::viewportEvent(QEvent*) 0x000000010794d6f0
    QTreeView::viewportEvent(QEvent*) 0x00000001079bb844
    QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) 0x00000001069e2284
    QApplicationPrivate::notify_helper(QObject*, QEvent*) 0x00000001076e4970
    QApplication::notify(QObject*, QEvent*) 0x00000001076e6450
    QCoreApplication::notifyInternal2(QObject*, QEvent*) 0x00000001069e1fb0
    QWidgetPrivate::drawWidget(QPaintDevice*, QRegion const&, QPoint const&, QFlagsQWidgetPrivate::DrawWidgetFlag, QPainter*, QWidgetRepaintManager*) 0x00000001077210a8
    QWidgetRepaintManager::paintAndFlush() 0x000000010773ddf8
    QWidgetRepaintManager::sync() 0x000000010773e190
    QWidget::event(QEvent*) 0x000000010772dac0
    QMainWindow::event(QEvent*) 0x00000001078408f0
    QApplicationPrivate::notify_helper(QObject*, QEvent*) 0x00000001076e4990
    QApplication::notify(QObject*, QEvent*) 0x00000001076e6450
    QCoreApplication::notifyInternal2(QObject*, QEvent*) 0x00000001069e1fb0
    QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) 0x00000001069e32c4
    QCocoaEventDispatcherPrivate::processPostedEvents() 0x000000010a2aff38
    QCocoaEventDispatcherPrivate::postedEventsSourceCallback(void*) 0x000000010a2b05b4
    CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION 0x00000001a9f49a34
    __CFRunLoopDoSource0 0x00000001a9f499c8
    __CFRunLoopDoSources0 0x00000001a9f49738
    __CFRunLoopRun 0x00000001a9f4833c
    CFRunLoopRunSpecific 0x00000001a9f478a4
    RunCurrentEventLoopInMode 0x00000001b35bb3bc
    ReceiveNextEventCommon 0x00000001b35bb200
    _BlockUntilNextEventMatchingListInModeWithFilter 0x00000001b35baf48
    _DPSNextEvent 0x00000001ad1a0630
    -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] 0x00000001ad19f7c0
    -[NSApplication run] 0x00000001ad193bf0
    QCocoaEventDispatcher::processEvents(QFlagsQEventLoop::ProcessEventsFlag) 0x000000010a2af3c4
    QEventLoop::exec(QFlagsQEventLoop::ProcessEventsFlag) 0x00000001069eb3d0
    QCoreApplication::exec() 0x00000001069e264c
    0x0000000104dcfbb0
    start 0x00000001a9b3fe50

  2. the thread that is calling Quit
    __ulock_wait 0x00000001a9e2cba4
    _pthread_join 0x00000001a9e6c394
    lldb_private::HostThreadPosix::Join(void**) 0x000000015ec005f4
    lldb_private::Process::ControlPrivateStateThread(unsigned int) 0x000000015ecaa530
    lldb_private::Process::DestroyImpl(bool) 0x000000015ec9f840
    lldb::SBProcess::Kill() 0x000000015eac38c8
    BinaryNinjaDebugger::LldbAdapter::Quit() lldbadapter.cpp:362
    BinaryNinjaDebugger::DebuggerController::ExecuteAdapterAndWait(BNDebuggerAdapterOperation) debuggercontroller.cpp:1629
    BinaryNinjaDebugger::DebuggerController::QuitAndWait() debuggercontroller.cpp:806
    BinaryNinjaDebugger::DebuggerController::Restart() debuggercontroller.cpp:684
    BNDebuggerRestart(BNDebuggerController *) ffi.cpp:369
    BinaryNinjaDebuggerAPI::DebuggerController::Restart() debuggercontroller.cpp:263
    $_12::operator()() const controlswidget.cpp:144
    std::__invoke<…>($_12 &&) type_traits:3918
    std::__thread_execute<…>(std::tuple<…> &, std::__tuple_indices<…>) thread:287
    std::__thread_proxy<…>(void *) thread:298
    _pthread_start 0x00000001a9e6a06c

  3. the thread that is calling ReadMemory
    __psynch_mutexwait 0x00000001a9e2da9c
    _pthread_mutex_firstfit_lock_wait 0x00000001a9e67144
    _pthread_mutex_firstfit_lock_slow 0x00000001a9e64a9c
    std::__1::recursive_mutex::lock() 0x00000001a9db9b7c
    lldb::SBProcess::ReadMemory(unsigned long long, void*, unsigned long, lldb::SBError&) 0x000000015eac5368
    BinaryNinjaDebugger::LldbAdapter::ReadMemory(unsigned long, unsigned long) lldbadapter.cpp:676
    BinaryNinjaDebugger::DebuggerMemory::ReadMemory(unsigned long long, unsigned long) debuggerstate.cpp:608
    BinaryNinjaDebugger::DebuggerController::ReadMemory(unsigned long, unsigned long) debuggercontroller.cpp:1180
    BinaryNinjaDebugger::DebugProcessMemoryView::PerformRead(void *, unsigned long long, unsigned long) processview.cpp:164
    BinaryNinja::BinaryView::ReadCallback(void *, void *, unsigned long long, unsigned long) binaryview.cpp:1027
    0x00000001166b1ab4
    0x00000001166b1844
    0x00000001166b1b38
    0x0000000116943f18
    0x000000011695e28c
    0x00000001169ee988
    0x0000000116e96488
    0x0000000116f75e30
    0x0000000116f7567c
    _pthread_start 0x00000001a9e6a06c

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

No branches or pull requests

1 participant