-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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 a crash when closing panes #17333
Conversation
// copy `weakThis` onto the stack, because that's the only thing that gets captured in coroutines. | ||
// See: https://devblogs.microsoft.com/oldnewthing/20211103-00/?p=105870 | ||
const auto weakThisCopy = weakThis; | ||
co_await wil::resume_foreground(dispatcher); |
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.
is it no longer necessary to switch to the UI thread?
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.
Never was! TerminalPaneContent
raises CloseRequested
in its Close
method where it also performs UI cleanup, so it can't possibly be on a background thread.
BTW since a tab owns the pane which owns the content, it's a little weird that Close() on the content goes into the tab and then back down into Close() in the pane, which then doesn't call Close() on the content. Seems like it should be the other way around. 🤔
I think I introduced a bug in this PR. Closing 1 tab now closes 2. |
#17333 introduced a regression: While it fixes a recursion *into* `Pane::Close()` that doesn't fix the recursion outside of it. In this case, `Close()` raises the `Closed` event which results in another tab being closed because it's bound to `_RemoveTab`. The recursion is now obvious, because I made the entire process synchronous. Previously, it would (hopefully) just be scheduled after the pane and its content are already gone. The issue can be fixed by moving the recursion check from `Pane::Close()` to `TerminalTab::Shutdown()` but I felt like it would better to fix the issue a bit more thoroughly. `IPaneContent` can raise a `CloseRequested` event to indicate it wants to be closed. However, that also contained recursion, because the content would call its own `Close()` to raise the event, which the tab catches, calls `Close()` on the `Pane` which calls `Close()` on the content which raises the event again and so on. That's what was fixed in #17333 among others. We can do this better by not raising the event from `IPaneContent::Close()`. Instead, that method will now be exclusively called by `Pane`. The `CloseRequested` event will now truly be just a request and nothing more. Furthermore, the ownership of the event handling was moved from the `TerminalTab` to the `Pane`. To make all of this a bit simpler and more robust, two new methods were added to `Pane`: `_takePaneContent` and `_setPaneContent`. These methods ensure that `Close()` is called on the content, that the event handlers are always added and revoked and that the ownership transfers cleanly between panes. ## Validation Steps Performed * Open 3 tabs, close the middle one ✅ * Open 3 vertical panes, close the middle one ✅ * Drag tabs with multiple panes between windows ✅
Calling Close() from within WalkPanes is not safe. Simply using _FindPane is enough to fix this. This PR also fixes another potential source of infinite recursion, and fixes panes being passed by-value into the callbacks. Closes #17305 ## Validation Steps Performed * Split panes vertically 3 times * `exit` the middle, the bottom and final one, in that order * Doesn't crash ✅ (cherry picked from commit baba406) Service-Card-Id: 92643006 Service-Version: 1.21
#17333 introduced a regression: While it fixes a recursion *into* `Pane::Close()` that doesn't fix the recursion outside of it. In this case, `Close()` raises the `Closed` event which results in another tab being closed because it's bound to `_RemoveTab`. The recursion is now obvious, because I made the entire process synchronous. Previously, it would (hopefully) just be scheduled after the pane and its content are already gone. The issue can be fixed by moving the recursion check from `Pane::Close()` to `TerminalTab::Shutdown()` but I felt like it would better to fix the issue a bit more thoroughly. `IPaneContent` can raise a `CloseRequested` event to indicate it wants to be closed. However, that also contained recursion, because the content would call its own `Close()` to raise the event, which the tab catches, calls `Close()` on the `Pane` which calls `Close()` on the content which raises the event again and so on. That's what was fixed in #17333 among others. We can do this better by not raising the event from `IPaneContent::Close()`. Instead, that method will now be exclusively called by `Pane`. The `CloseRequested` event will now truly be just a request and nothing more. Furthermore, the ownership of the event handling was moved from the `TerminalTab` to the `Pane`. To make all of this a bit simpler and more robust, two new methods were added to `Pane`: `_takePaneContent` and `_setPaneContent`. These methods ensure that `Close()` is called on the content, that the event handlers are always added and revoked and that the ownership transfers cleanly between panes. ## Validation Steps Performed * Open 3 tabs, close the middle one ✅ * Open 3 vertical panes, close the middle one ✅ * Drag tabs with multiple panes between windows ✅ (cherry picked from commit ce0f8d6) Service-Card-Id: 92678790 Service-Version: 1.21
Calling Close() from within WalkPanes is not safe. Simply using _FindPane is enough to fix this.
This PR also fixes another potential source of infinite recursion, and fixes panes being passed by-value into the callbacks.
Closes #17305
Validation Steps Performed
exit
the middle, the bottom and final one, in that order