-
Notifications
You must be signed in to change notification settings - Fork 12k
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
Fix flake in TestZerothFrame.py #96685
Conversation
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write If you have received no comments on your PR for a week, you can request a review If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-lldb Author: Kendal Harland (kendalharland) ChangesThis test is currently flaky on a local Windows amd64 build. If we print lldb's inputs and outputs while running, we can see that the breakpoints are always being set correctly, and always being hit: runCmd: breakpoint set -f "main.c" -l 2
output: Breakpoint 1: where = a.out`func_inner + 1 at main.c:2:9, address = 0x0000000140001001
runCmd: breakpoint set -f "main.c" -l 7
output: Breakpoint 2: where = a.out`main + 17 at main.c:7:5, address = 0x0000000140001021
runCmd: run
output: Process 52328 launched: 'C:\workspace\llvm-project\llvm\build\lldb-test-build.noindex\functionalities\unwind\zeroth_frame\TestZerothFrame.test_dwarf\a.out' (x86_64)
Process 52328 stopped
* thread #<!-- -->1, stop reason = breakpoint 1.1
frame #<!-- -->0: 0x00007ff68f6b1001 a.out`func_inner at main.c:2:9
1 void func_inner() {
-> 2 int a = 1; // Set breakpoint 1 here
^
3 }
4
5 int main() {
6 func_inner();
7 return 0; // Set breakpoint 2 here However, sometimes the backtrace printed in this test shows that the process is stopped inside NtWaitForWorkViaWorkerFactory from Backtrace at the first breakpoint:
frame #<!-- -->0: 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20
frame #<!-- -->1: 0x00007ffecc74585e ntdll.dll`RtlClearThreadWorkOnBehalfTicket + 862
frame #<!-- -->2: 0x00007ffecc3e257d kernel32.dll`BaseThreadInitThunk + 29
frame #<!-- -->3: 0x00007ffecc76af28 ntdll.dll`RtlUserThreadStart + 40 If we print the list of threads each time the test is run, we notice that threads are sometimes in a different order, within Thread 0: thread #<!-- -->4: tid = 0x9c38, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20
Thread 1: thread #<!-- -->2: tid = 0xa950, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20
Thread 2: thread #<!-- -->1: tid = 0xab18, 0x00007ff64bc81001 a.out`func_inner at main.c:2:9, stop reason = breakpoint 1.1
Thread 3: thread #<!-- -->3: tid = 0xc514, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20
Thread 0: thread #<!-- -->3: tid = 0x018c, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20
Thread 1: thread #<!-- -->1: tid = 0x85c8, 0x00007ff7130c1001 a.out`func_inner at main.c:2:9, stop reason = breakpoint 1.1
Thread 2: thread #<!-- -->2: tid = 0xf344, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20
Thread 3: thread #<!-- -->4: tid = 0x6a50, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 We're interested in whichever thread is executing Thread 0: thread #<!-- -->3: tid = 0x2474, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20
-- GetName:
-- GetQueueName: None
-- GetQueueID: 0
-- GetIndexId: 3
Thread 1: thread #<!-- -->2: tid = 0x2864, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20
-- GetName:
-- GetQueueName: None
-- GetQueueID: 0
-- GetIndexId: 2
Thread 2: thread #<!-- -->4: tid = 0x9c90, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20
-- GetName:
-- GetQueueName: None
-- GetQueueID: 0
-- GetIndexId: 4
Thread 3: thread #<!-- -->1: tid = 0xebbc, 0x00007ff643331001 a.out`func_inner at main.c:2:9, stop reason = breakpoint 1.1
-- GetName:
-- GetQueueName: None
-- GetQueueID: 0
-- GetIndexId: 1 By switching from This raises a few more questions that might lead to a different followup solution:
Full diff: https://github.com/llvm/llvm-project/pull/96685.diff 1 Files Affected:
diff --git a/lldb/test/API/functionalities/unwind/zeroth_frame/TestZerothFrame.py b/lldb/test/API/functionalities/unwind/zeroth_frame/TestZerothFrame.py
index f4e883d314644..7e4078bbe887f 100644
--- a/lldb/test/API/functionalities/unwind/zeroth_frame/TestZerothFrame.py
+++ b/lldb/test/API/functionalities/unwind/zeroth_frame/TestZerothFrame.py
@@ -53,14 +53,15 @@ def test(self):
process = target.LaunchSimple(None, None, self.get_process_working_directory())
self.assertTrue(process, VALID_PROCESS)
- thread = process.GetThreadAtIndex(0)
+ thread = process.GetThreadByIndexID(1)
if self.TraceOn():
print("Backtrace at the first breakpoint:")
for f in thread.frames:
print(f)
+
# Check that we have stopped at correct breakpoint.
self.assertEqual(
- process.GetThreadAtIndex(0).frame[0].GetLineEntry().GetLine(),
+ thread.frame[0].GetLineEntry().GetLine(),
bp1_line,
"LLDB reported incorrect line number.",
)
@@ -70,7 +71,7 @@ def test(self):
# 'continue' command.
process.Continue()
- thread = process.GetThreadAtIndex(0)
+ thread = process.GetThreadByIndexID(1)
if self.TraceOn():
print("Backtrace at the second breakpoint:")
for f in thread.frames:
|
5f23d2c
to
97242b7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of assuming the thread's index or index ID, it might be a good idea to have a little helper method that can look through the inferior's threads to find the thread with the property that we care about. In this case, we're looking for the thread that's stopped in a specific module (a.out
in this case).
Concurrent execution and thread order is not guaranteed to be stable between runs, even if in practice they end up being that way on some platforms. The less we can rely on specific indices or IDs that "should" be correct, the better.
Sounds reasonable. I'll work that out with a helper method and resend for review once I upload a new commit. @bulbazord any idea how I can access the module from the |
The module is a property of the target, so you could do:
or you can create an ExecutionContext from the thread, and get the target from that:
|
The thread that you care about is stopped at a breakpoint, right? |
1ca25a2
to
836b5ee
Compare
Thanks, this eventually led to me what I think is the most obvious solution: We can just set the breakpoints in this test while holding onto to the Thanks @JDevlieghere and @bulbazord for the additional suggestions! |
836b5ee
to
abc87f3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be fine, although looking at the test case again, I think that even simply replacing process.GetThreadAtIndex(0)
with self.thread()
should be enough. self.thread()
returns the "selected" thread and lldb should always be selecting the thread which has stopped "for a reason" (e.g. a breakpoint) and not a random (or first) thread in the process.
abc87f3
to
1d2c11e
Compare
This also works. Agreed it's much better. Ty for the suggestion! Updated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Are you able to merge this on your own?
Nope, I'll need someone with write access to do it. |
fa18c81
to
e3d44a2
Compare
✅ With the latest revision this PR passed the Python code formatter. |
Sounds good. Can you just patch the formatter changes in, and then I'll submit it. @bulbazord, if you don't respond, I'm going to assume that new version addresses your comments as well. |
Yes, looks good to me. Thanks for taking the time! :) |
Sure thing, I hadn't hooked up the formatter yet so I'll run it and reupload. Thanks for the reviews! |
e5f11c6
to
b880f6d
Compare
Applied formatter patch and rebased onto main |
401e4a8
to
0ec149a
Compare
This test is relying on the order of `process.threads` which is nondeterministic. By selecting the thread based on whether it is stopped at our breakpoint we can reliably select the correct one.
0ec149a
to
e3715f9
Compare
Apologies, I pushed the wrong commits to this PR and just had the fix them up. Should be good to go. |
I'll need help merging this since I don't have write access to the repo. |
@kendalharland Congratulations on having your first Pull Request (PR) merged into the LLVM Project! Your changes will be combined with recent changes from other authors, then tested Please check whether problems have been caused by your change specifically, as How to do this, and the rest of the post-merge process, is covered in detail here. If your change does cause a problem, it may be reverted, or you can revert it yourself. If you don't get any reports, no action is required from you. Your changes are working as expected, well done! |
This test is currently flaky on a local Windows amd64 build. The reason is that it relies on the order of
process.threads
but this order is nondeterministic:If we print lldb's inputs and outputs while running, we can see that the breakpoints are always being set correctly, and always being hit:
However, sometimes the backtrace printed in this test shows that the process is stopped inside NtWaitForWorkViaWorkerFactory from
ntdll.dll
:When this happens, the test fails with an assertion error that the stopped thread's zeroth frame's current line number does not match the expected line number. This is because the test is looking at the wrong thread:
process.threads[0]
.If we print the list of threads each time the test is run, we notice that threads are sometimes in a different order, within
process.threads
:Use
self.thread()
to consistently select the correct thread, instead.