Skip to content

Commit 5aafc01

Browse files
lheckerDHowett
authored andcommitted
Fix a crash during commandline handoff (#19096)
The crash occurs because WinRT `abort()`s when it encounters a `std::wstring_view` without null-terminator. Closes #19093 ## Validation Steps Performed * Set `wtd` as the default terminal * Launch `cmd` * Launch `wtd` * 2 windows ✅ (cherry picked from commit ac07afe) Service-Card-Id: PVTI_lADOAF3p4s4AxadtzgcO9T4 Service-Version: 1.23
1 parent 6157302 commit 5aafc01

File tree

2 files changed

+20
-18
lines changed

2 files changed

+20
-18
lines changed

src/cascadia/WindowsTerminal/WindowEmperor.cpp

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ static std::vector<winrt::hstring> commandlineToArgArray(const wchar_t* commandL
4949
}
5050

5151
// Returns the length of a double-null encoded string *excluding* the trailing double-null character.
52-
static std::wstring_view stringFromDoubleNullTerminated(const wchar_t* beg)
52+
static wil::zwstring_view stringFromDoubleNullTerminated(const wchar_t* beg)
5353
{
5454
auto end = beg;
5555

5656
for (; *end; end += wcsnlen(end, SIZE_T_MAX) + 1)
5757
{
5858
}
5959

60-
return { beg, end };
60+
return { beg, gsl::narrow_cast<size_t>(end - beg) };
6161
}
6262

6363
// Appends an uint32_t to a byte vector.
@@ -78,36 +78,39 @@ static const uint8_t* deserializeUint32(const uint8_t* it, const uint8_t* end, u
7878
return it + sizeof(uint32_t);
7979
}
8080

81-
// Writes an uint32_t length prefix, followed by the string data, to the output vector.
82-
static void serializeString(std::vector<uint8_t>& out, std::wstring_view str)
81+
// Writes a null-terminated string to `out`: A uint32_t length prefix,
82+
// *including null byte*, followed by the string data, followed by the null-terminator.
83+
static void serializeString(std::vector<uint8_t>& out, wil::zwstring_view str)
8384
{
8485
const auto ptr = reinterpret_cast<const uint8_t*>(str.data());
85-
const auto len = gsl::narrow<uint32_t>(str.size());
86-
serializeUint32(out, len);
86+
const auto len = str.size() + 1;
87+
serializeUint32(out, gsl::narrow<uint32_t>(len));
8788
out.insert(out.end(), ptr, ptr + len * sizeof(wchar_t));
8889
}
8990

90-
// Parses the next string from the input iterator. Performs bounds-checks.
91+
// Counter-part to `serializeString`. Performs bounds-checks.
9192
// Returns an iterator that points past it.
92-
static const uint8_t* deserializeString(const uint8_t* it, const uint8_t* end, std::wstring_view& str)
93+
static const uint8_t* deserializeString(const uint8_t* it, const uint8_t* end, wil::zwstring_view& str)
9394
{
9495
uint32_t len;
9596
it = deserializeUint32(it, end, len);
9697

97-
if (static_cast<size_t>(end - it) < len * sizeof(wchar_t))
98+
const auto bytes = static_cast<size_t>(len) * sizeof(wchar_t);
99+
100+
if (bytes == 0 || static_cast<size_t>(end - it) < bytes)
98101
{
99102
throw std::out_of_range("Not enough data for string content");
100103
}
101104

102-
str = { reinterpret_cast<const wchar_t*>(it), len };
103-
return it + len * sizeof(wchar_t);
105+
str = { reinterpret_cast<const wchar_t*>(it), len - 1 };
106+
return it + bytes;
104107
}
105108

106109
struct Handoff
107110
{
108-
std::wstring_view args;
109-
std::wstring_view env;
110-
std::wstring_view cwd;
111+
wil::zwstring_view args;
112+
wil::zwstring_view env;
113+
wil::zwstring_view cwd;
111114
uint32_t show;
112115
};
113116

@@ -610,7 +613,7 @@ void WindowEmperor::_dispatchCommandline(winrt::TerminalApp::CommandlineArgs arg
610613
}
611614
}
612615

613-
void WindowEmperor::_dispatchCommandlineCommon(winrt::array_view<const winrt::hstring> args, std::wstring_view currentDirectory, std::wstring_view envString, uint32_t showWindowCommand)
616+
void WindowEmperor::_dispatchCommandlineCommon(winrt::array_view<const winrt::hstring> args, wil::zwstring_view currentDirectory, wil::zwstring_view envString, uint32_t showWindowCommand)
614617
{
615618
winrt::TerminalApp::CommandlineArgs c;
616619
c.Commandline(args);
@@ -927,8 +930,7 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c
927930
if (const auto cds = reinterpret_cast<COPYDATASTRUCT*>(lParam); cds->dwData == TERMINAL_HANDOFF_MAGIC)
928931
{
929932
const auto handoff = deserializeHandoffPayload(static_cast<const uint8_t*>(cds->lpData), static_cast<const uint8_t*>(cds->lpData) + cds->cbData);
930-
const winrt::hstring args{ handoff.args };
931-
const auto argv = commandlineToArgArray(args.c_str());
933+
const auto argv = commandlineToArgArray(handoff.args.c_str());
932934
_dispatchCommandlineCommon(argv, handoff.cwd, handoff.env, handoff.show);
933935
}
934936
return 0;

src/cascadia/WindowsTerminal/WindowEmperor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class WindowEmperor
5252
void _summonAllWindows() const;
5353
void _dispatchSpecialKey(const MSG& msg) const;
5454
void _dispatchCommandline(winrt::TerminalApp::CommandlineArgs args);
55-
void _dispatchCommandlineCommon(winrt::array_view<const winrt::hstring> args, std::wstring_view currentDirectory, std::wstring_view envString, uint32_t showWindowCommand);
55+
void _dispatchCommandlineCommon(winrt::array_view<const winrt::hstring> args, wil::zwstring_view currentDirectory, wil::zwstring_view envString, uint32_t showWindowCommand);
5656
safe_void_coroutine _dispatchCommandlineCurrentDesktop(winrt::TerminalApp::CommandlineArgs args);
5757
LRESULT _messageHandler(HWND window, UINT message, WPARAM wParam, LPARAM lParam) noexcept;
5858
void _createMessageWindow(const wchar_t* className);

0 commit comments

Comments
 (0)