-
Notifications
You must be signed in to change notification settings - Fork 8.4k
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 racy access to _tsfTryRedrawCanvas in TermControl #10549
Conversation
@@ -183,6 +183,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation | |||
|
|||
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker; | |||
|
|||
inline bool _IsClosing() const noexcept { | |||
// _closing isn't atomic and may only be accessed from the main thread. | |||
assert(Dispatcher().HasThreadAccess()); |
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.
I previously wanted to introduce a cool macro for this in WinRTUtils, but I realized, that global state would only work properly if it's shared using a .dll. A .lib like that wouldn't do that for us. 😟
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 assert is compiled out in debug builds, correct?
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.
Sorry, compiled out in release builds./
A branch with a minimalistic set of changes for 1.8 is ready for backporting. This PR in particular needs to be evaluated very carefully and theoretically as the interaction with |
note: i edited your PR body to make sure the |
@@ -183,6 +183,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation | |||
|
|||
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker; | |||
|
|||
inline bool _IsClosing() const noexcept { | |||
// _closing isn't atomic and may only be accessed from the main thread. | |||
assert(Dispatcher().HasThreadAccess()); |
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.
Sorry, compiled out in release builds./
Hello @lhecker! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
Previously `TermControl::Close` destroyed all `ThrottledFunc`s to ensure they're not scheduling any callbacks on the UI thread, as the call to `Close` signals the point at which the `TermControl` isn't part of the UI thread anymore. `_CursorPositionChanged` tried to prevent access to the potentially deallocated `_tsfTryRedrawCanvas` by checking the `std::shared_ptr` for nullability, but since the deallocation happens on the UI thread and the nullability check on a background thread, this check introduced a race condition. This commit solves the issue by not deallocating any `ThrottledFunc`s anymore and instead checking the `_closing` flag inside the `ThrottledFunc` callback on the UI thread. Additionally this commit cleans up some antipatterns around the use of `std::optional`. ## PR Checklist * [x] Closes #10479 * [x] Closes #10302 ## Validation Steps Performed * Opening and closing tabs doesn't crash ✔️ * Printing long text doesn't crash ✔️ * Manual scrolling doesn't crash ✔️ * ^G / the audible bell doesn't crash ✔️ (cherry picked from commit 83c6bce)
🎉 Handy links: |
🎉 Handy links: |
Previously
TermControl::Close
destroyed allThrottledFunc
s to ensure they're not scheduling any callbacks on the UI thread, as the call toClose
signals the point at which theTermControl
isn't part of the UI thread anymore._CursorPositionChanged
tried to prevent access to the potentially deallocated_tsfTryRedrawCanvas
by checking thestd::shared_ptr
for nullability, but since the deallocation happens on the UI thread and the nullability check on a background thread, this check introduced a race condition.This commit solves the issue by not deallocating any
ThrottledFunc
s anymore and instead checking the_closing
flag inside theThrottledFunc
callback on the UI thread.Additionally this commit cleans up some antipatterns around the use of
std::optional
.PR Checklist
Validation Steps Performed