-
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 SetConsoleWindowInfo being able to crash ConPTY #13212
Conversation
const auto cx = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.width(), 1, coordScreenBufferSize.width)); | ||
const auto cy = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.height(), 1, coordScreenBufferSize.height)); | ||
const auto x = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.left, 0, coordScreenBufferSize.width - cx)); | ||
const auto y = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.top, 0, coordScreenBufferSize.height - cy)); |
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 function needs to correct the newViewport
argument to be within the valid bounds, while retaining the given size as much as possible. If you pass a newViewport
with the top/bottom coordinates -130 and -100, it should still result in a viewport that's 30 high, but with a top/bottom of 0 and 30.
I feel like this change increases the robustness of the code by splitting the viewport into its size (cx/cy) and origin (x/y). That way we can first ensure that the size doesn't exceed our limits (just like the old code seemingly intended) and then adjust the origin to be within the smaller rectangle of valid coordinates.
The gsl::narrow_cast<SHORT>
s will be removed once my 32-bit coord PR has been merged, but it shouldn't pose a problem here either, as GetBufferSize().Dimensions()
is a COORD
which can't exceed a SHORT
.
35deadc
to
02ab51d
Compare
const auto cx = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.width(), 1, coordScreenBufferSize.width)); | ||
const auto cy = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.height(), 1, coordScreenBufferSize.height)); |
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.
const auto cx = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.width(), 1, coordScreenBufferSize.width)); | |
const auto cy = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.height(), 1, coordScreenBufferSize.height)); | |
const auto cx = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.width(), 0, coordScreenBufferSize.width)); | |
const auto cy = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.height(), 0, coordScreenBufferSize.height)); |
curious, why not allow a width/height of 0?
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.
The minimum size the TextBuffer
allows is (1,1)
, so I thought it'd be reasonable if we did the same here.
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.
A text buffer with a zero dimension would not be a particularly useful text buffer :)
Hello @DHowett! 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 (
|
MSFT-33471786 is one of the most common crashes we have right now. Memory dumps suggest that `VtEngine::UpdateViewport` is called with a rectangle like `(0, 46, 119, 29)` (left, top, right, bottom), which is a rectangle of negative height. When the `_invalidMap` is resized the negative size gets turned into a very large unsigned integer, which results in an OOM exception, crashing OpenConsole. `VtEngine::UpdateViewport` is called by `Renderer::_CheckViewportAndScroll` which holds a (cached) old and a new viewport. The old viewport was `(0, 46, 119, 75)` which is exceedingly similar to the invalid, new viewport. It's bottom coordinate is also coincidentally larger by exactly 46 (top). The viewport comes from the `SCREEN_INFORMATION` class whose `SetViewport` function was highly suspicious as it has a branch which updates the bottom to be the buffer height, but leaves the top unmodified. `SCREEN_INFORMATION::SetViewport` is called by `SetConsoleWindowInfo` which processes user-provided data. A repro of the crash can be constructed with: ``` SMALL_RECT rect{0, 46, 119, 75}; SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &rect); ``` Closes #13193 Closes MSFT-33471786 ## Validation Steps Performed Ensured the following code doesn't crash when run under Windows Terminal: ``` SMALL_RECT rect{0, 46, 119, 75}; SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &rect); ``` (cherry picked from commit 7dbe741) Service-Card-Id: 82642053 Service-Version: 1.14
🎉 Handy links: |
🎉 Handy links: |
MSFT-33471786 is one of the most common crashes we have right now.
Memory dumps suggest that
VtEngine::UpdateViewport
is called with a rectanglelike
(0, 46, 119, 29)
(left, top, right, bottom), which is a rectangle ofnegative height. When the
_invalidMap
is resized the negative size getsturned into a very large unsigned integer, which results in an OOM exception,
crashing OpenConsole.
VtEngine::UpdateViewport
is called byRenderer::_CheckViewportAndScroll
which holds a (cached) old and a new viewport. The old viewport was
(0, 46, 119, 75)
which is exceedingly similar to the invalid, new viewport.It's bottom coordinate is also coincidentally larger by exactly 46 (top).
The viewport comes from the
SCREEN_INFORMATION
class whoseSetViewport
function was highly suspicious as it has a branch which updates the bottom
to be the buffer height, but leaves the top unmodified.
SCREEN_INFORMATION::SetViewport
is called bySetConsoleWindowInfo
whichprocesses user-provided data. A repro of the crash can be constructed with:
Closes #13193
Closes MSFT-33471786
Validation Steps Performed
Ensured the following code doesn't crash when run under Windows Terminal: