cutter
cutter copied to clipboard
Breakpoints don't work with multiple threads
Environment information
- Operating System: Linux
- Cutter version: 59af77fb7272765b3d50e0af6067e036e4d4e93b
- File format: ELF
Describe the bug
Triggering breakpoint with secondary thread causes UI to freeze.
To Reproduce
Steps to reproduce the behavior:
- compile test program
g++ -o a a.cpp -pthread
- open test executable
- start debugging
- insert breakpoint in thread_func
- continue
- observe main thread gets stopped
- try switching to one of secondary threads - observe that gui freezes
Expected behavior
GUI doesn't freeze.
When breakpoint gets triggered by a thread cutter switches to thread that triggered it.
Additional context
Test program
#include <thread>
#include <iostream>
void thread_func() {
int64_t counter = 0;
while(true) {
++counter;
if (counter%10000000000LL == 0) {
std::cout << counter << "\n";
}
}
}
int main() {
std::thread t1(thread_func);
std::thread t2(thread_func);
t1.join();
t2.join();
}
Looked at the stacktraces. One thread is stuck in linux_select -> linux_stop_thread waiting for thread to stop. Not sure what happens to Qt event loop. My initial guess was one of the GUI updates is waiting for r2 lock which is blocked by task doing waitpid but I didn't saw any threads with Qt event loop in stacktrace.
Repeating it second time I saw what I expected GUI trying to refresh information waiting on r2 lock, task thread waiting for debugged thread to stop. Can a thread be stopped if it is already stopped due to other reasons?
Small note: tested and this doesn't happen in windows.
Thanks for debugging and trying to reproduce the issue!
Can a thread be stopped if it is already stopped due to other reasons?
You are supposed to be able to queue multiple signals. You'll have SIGSTOP and SIGTRAP waiting for the debugging process to handle. Not sure why it doesn't receive any one of those..
linux_select
So it does try to switch to the breakpoint. I remember this working while we were working on the ThreadsWidget so it must be some regression due to attach changes.
Yeah, this is probably specific to Linux native debug backend.
I just noticed dbg.threads: Stop all threads when debugger breaks (see dbg.forks)
option which is false by default.
I wonder how can it work reliably without stopping all threads when breakpoint is hit and user/debugger is poking process memory and changing breakpoints while some of the threads are running.
Didn't notice any difference after enabling it but there might be more than one problem.
I wonder how can it work reliably without stopping all threads when breakpoint is hit
Yep, and dbg.threads is only in use in windows debug. Another issue is that unless dbg.trace_clone is enabled the debugger won't even attach after clone and configure a new thread. I started working on a refactor before the release and didn't have time since, should finish it by this weekend.
Retest after radareorg/radare2#17251
Retested this with the latest Cutter on Linux. GUI doesn't freeze anymore but the debugging process never stopped and reached a breakpoint.