Skip to content

[cherry-pick][lldb][swift] Fix StackID comparisons to enable stepping out of async functions #9211

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

Conversation

felipepiovezan
Copy link

No description provided.

The optimization in swiftlang#7877
accidentally changed the default answer for this function.

It's important to default to "On Stack" when we don't know, because that's where
most CFAs live, and because we don't want to trigger the expensive heap
comparisons unless we're absolutely sure the CFA is on the heap.

(cherry picked from commit 57757e9)
Currently, if we're comparing a StackID on the stack with one StackID on the
heap, we perform a special kind of IsYounger comparison. However, if
`IsYounger(A, b)` returns true, it must be the case that `IsYounger(B, A)`
returns false. But this is not necessarily the case today because, before this
patch, we would fallback to the traditional "stack" comparison, which is wrong
if one of the StackIDs is on the heap.

(cherry picked from commit 349d906)
For two StackIDs whose CFAs are on the heap, i.e., they are both async frames,
we can decide which one is younger by finding one async context in the
continuation chain of the other.

A lot of stepping algorithms rely on frame comparisons. In particular, this
patch fixes stepping out of async functions, and makes strides towards fixing
other stepping algorithms.

The explanation below is not needed to understand this patch, but it sheds some
light into why the most common kind of step out fails.

Consider the case where a breakpoint was set inside some async function, the
program hit that breakpoint, and then a "step out" operation is performed. This
is a very common use case.

The thread plan looks like this:

0. Single step past breakpoint.
1. Step out

LLDB performs a single step, and thread plan 0 says "continue running, I'm
done". Before continuing program execution, LLDB asks all thread plans, in this
case there's only the step out plan, if it should stop.

To answer the "should stop" question, the step out plan compares the current
frame (which is the same as when step out was pushed, since LLDB has only
performed a single step so far) with its target frame (which is just one frame
above). In this scenario, the current frame is async, and so the parent frame
must also be async. The StepOut plan is going to compare two async StackIDs.

Using the incorrect comparison, StepOut concludes the current frame is _older_
than the target frame. In other words, the program reached an older frame
without ever stopping on the target frame. Something weird must have happened,
and the plan concludes it is done.

(cherry picked from commit 8d7935d)
@felipepiovezan
Copy link
Author

Cherry-pick from #9162

@felipepiovezan felipepiovezan merged commit 989517f into swiftlang:next Sep 4, 2024
@felipepiovezan felipepiovezan deleted the felipe/stack_id_comp_cherry_pick_next branch September 4, 2024 14:19
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.

1 participant