Enable /permissive- and remaining /Zc flags

This commit is contained in:
Leonard Hecker 2021-11-25 00:28:27 +01:00
parent f2386de422
commit 1d6818829e
36 changed files with 283 additions and 374 deletions

View File

@ -69,7 +69,8 @@
<ClCompile>
<AdditionalIncludeDirectories>..;$(OpenConsoleDir)\dep;$(OpenConsoleDir)\dep\jsoncpp\json;$(OpenConsoleDir)src\inc;$(OpenConsoleDir)src\inc\test;$(WinRT_IncludePath)\..\cppwinrt\winrt;"$(OpenConsoleDir)\src\cascadia\TerminalSettingsModel\Generated Files";%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<!-- Required for JsonUtils.h. -->
<AdditionalOptions>%(AdditionalOptions) /Zc:twoPhase-</AdditionalOptions>
<!-- Manually disable unreachable code warning, because jconcpp has a ton of that. -->
<DisableSpecificWarnings>4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>

View File

@ -51,10 +51,10 @@
<ItemDefinitionGroup>
<ClCompile>
<!-- Disable two-phase name lookup for C++/CLI & C++/CX code. -->
<AdditionalOptions>%(AdditionalOptions) /Zc:twoPhase-</AdditionalOptions>
<DisableSpecificWarnings>4453;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)
;$(IntermediateOutputPath)
</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IntermediateOutputPath)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>INLINE_TEST_METHOD_MARKUP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>

View File

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
// pch.h
@ -57,6 +57,7 @@
TRACELOGGING_DECLARE_PROVIDER(g_hTerminalControlProvider);
#include <telemetry/ProjectTelemetry.h>
#include <ShlObj_core.h>
#include <WinUser.h>
#include "til.h"

View File

@ -250,6 +250,8 @@
<ClCompile>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..;$(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
<!-- Required for JsonUtils.h. -->
<AdditionalOptions>%(AdditionalOptions) /Zc:twoPhase-</AdditionalOptions>
<!-- Manually disable unreachable code warning, because jconcpp has a ton of that. -->
<DisableSpecificWarnings>4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>

View File

@ -171,7 +171,7 @@ public:
auto mismatched = (actualChars != expectedChars || actualAttrs != expectedAttrs);
if (mismatched)
{
Log::Comment(NoThrowString().Format(
WEX::Logging::Log::Comment(WEX::Common::NoThrowString().Format(
L"Character or attribute at index %d was mismatched", charsProcessed));
}

View File

@ -60,7 +60,8 @@
<ClCompile>
<AdditionalIncludeDirectories>..;$(OpenConsoleDir)\dep\jsoncpp\json;$(OpenConsoleDir)src\inc;$(OpenConsoleDir)src\inc\test;$(WinRT_IncludePath)\..\cppwinrt\winrt;"$(OpenConsoleDir)\src\cascadia\TerminalApp\Generated Files";"$(OpenConsoleDir)\src\cascadia\TerminalSettingsModel\Generated Files";%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
<!-- Required for JsonUtils.h. -->
<AdditionalOptions>%(AdditionalOptions) /Zc:twoPhase-</AdditionalOptions>
<!-- Manually disable unreachable code warning, because jconcpp has a ton of that. -->
<DisableSpecificWarnings>4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>

View File

@ -116,9 +116,11 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<ConformanceMode>true</ConformanceMode>
<UseStandardPreprocessor>true</UseStandardPreprocessor>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>%(AdditionalOptions) /utf-8 /Zc:externConstexpr /Zc:lambda /Zc:throwingNew</AdditionalOptions>
<ControlFlowGuard>Guard</ControlFlowGuard>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>

View File

@ -71,10 +71,8 @@
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<!-- All new code should be in non-permissive mode. Big objects for C++/WinRT. -->
<ConformanceMode>true</ConformanceMode>
<UseStandardPreprocessor>true</UseStandardPreprocessor>
<AdditionalOptions>%(AdditionalOptions) /bigobj /Zc:twoPhase-</AdditionalOptions>
<!-- Big objects for C++/WinRT. -->
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
<DisableSpecificWarnings>5104;28204;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>

View File

@ -1001,7 +1001,7 @@ using Microsoft::Console::VirtualTerminal::StateMachine;
// - STATUS_SUCCESS if OK.
// - CONSOLE_STATUS_WAIT if we couldn't finish now and need to be called back later (see ppWaiter).
// - Or a suitable NTSTATUS format error code for memory/string/math failures.
[[nodiscard]] NTSTATUS DoWriteConsole(_In_reads_bytes_(*pcbBuffer) PWCHAR pwchBuffer,
[[nodiscard]] NTSTATUS DoWriteConsole(_In_reads_bytes_(*pcbBuffer) PCWCHAR pwchBuffer,
_Inout_ size_t* const pcbBuffer,
SCREEN_INFORMATION& screenInfo,
bool requiresVtQuirk,

View File

@ -90,7 +90,7 @@ Note:
// NOTE: console lock must be held when calling this routine
// String has been translated to unicode at this point.
[[nodiscard]] NTSTATUS DoWriteConsole(_In_reads_bytes_(*pcbBuffer) PWCHAR pwchBuffer,
[[nodiscard]] NTSTATUS DoWriteConsole(_In_reads_bytes_(*pcbBuffer) PCWCHAR pwchBuffer,
_Inout_ size_t* const pcbBuffer,
SCREEN_INFORMATION& screenInfo,
bool requiresVtQuirk,

View File

@ -1216,7 +1216,7 @@ std::wstring Alias::s_MatchAndCopyAlias(const std::wstring& sourceText,
// - LineCount - aliases can contain multiple commands. $T is the command separator
// Return Value:
// - None. It will just maintain the source as the target if we can't match an alias.
void Alias::s_MatchAndCopyAliasLegacy(_In_reads_bytes_(cbSource) PWCHAR pwchSource,
void Alias::s_MatchAndCopyAliasLegacy(_In_reads_bytes_(cbSource) PCWCH pwchSource,
_In_ size_t cbSource,
_Out_writes_bytes_(cbTargetWritten) PWCHAR pwchTarget,
_In_ const size_t cbTargetSize,

View File

@ -16,7 +16,7 @@ class Alias
public:
static void s_ClearCmdExeAliases();
static void s_MatchAndCopyAliasLegacy(_In_reads_bytes_(cbSource) PWCHAR pwchSource,
static void s_MatchAndCopyAliasLegacy(_In_reads_bytes_(cbSource) PCWCH pwchSource,
_In_ size_t cbSource,
_Out_writes_bytes_(cbTargetWritten) PWCHAR pwchTarget,
_In_ const size_t cbTargetSize,

View File

@ -104,7 +104,7 @@ void FileTests::TestUtf8WriteFileInvalid()
DWORD dwWritten;
DWORD dwExpectedWritten;
char* str;
const char* str;
DWORD cbStr;
// \x80 is an invalid UTF-8 continuation

View File

@ -12,8 +12,6 @@
// - Ensures the SxS initialization for the process.
void InitSideBySide(_Out_writes_(ScratchBufferSize) PWSTR ScratchBuffer, __range(MAX_PATH, MAX_PATH) DWORD ScratchBufferSize)
{
ACTCTXW actctx = { 0 };
// Account for the fact that sidebyside stuff happens in CreateProcess
// but conhost is run with RtlCreateUserProcess.
@ -30,38 +28,35 @@ void InitSideBySide(_Out_writes_(ScratchBufferSize) PWSTR ScratchBuffer, __range
// make references to DLLs in the system that are in the SxS cache (ex. a 3rd party IME is loaded and asks for
// comctl32.dll. The load will fail if SxS wasn't initialized.) This was bug# WIN7:681280.
// We look at the first few chars without being careful about a terminal nul, so init them.
ScratchBuffer[0] = 0;
ScratchBuffer[1] = 0;
ScratchBuffer[2] = 0;
ScratchBuffer[3] = 0;
ScratchBuffer[4] = 0;
ScratchBuffer[5] = 0;
ScratchBuffer[6] = 0;
// GetModuleFileNameW truncates its result to fit in the buffer, so to detect if we fit, we have to do this.
ScratchBuffer[ScratchBufferSize - 2] = 0;
DWORD const dwModuleFileNameLength = GetModuleFileNameW(nullptr, ScratchBuffer, ScratchBufferSize);
if (dwModuleFileNameLength == 0)
{
RIPMSG1(RIP_ERROR, "GetModuleFileNameW failed %d.\n", GetLastError());
goto Exit;
return;
}
if (ScratchBuffer[ScratchBufferSize - 2] != 0)
// GetModuleFileNameW truncates its result to fit in the buffer
// and returns the given buffer size in such cases.
if (dwModuleFileNameLength == ScratchBufferSize)
{
RIPMSG1(RIP_ERROR, "GetModuleFileNameW requires more than ScratchBufferSize(%d) - 1.\n", ScratchBufferSize);
goto Exit;
return;
}
// We get an NT path from the Win32 api. Fix it to be Win32.
// We can test for NT paths by checking whether the string starts with "\??\C:\", or any
// alternative letter other than C. We specifically don't test for the drive letter below.
UINT NtToWin32PathOffset = 0;
if (ScratchBuffer[0] == '\\' && ScratchBuffer[1] == '?' && ScratchBuffer[2] == '?' && ScratchBuffer[3] == '\\'
//&& ScratchBuffer[4] == a drive letter
&& ScratchBuffer[5] == ':' && ScratchBuffer[6] == '\\')
static constexpr wchar_t ntPathSpec1[]{ L'\\', L'?', L'?', L'\\' };
static constexpr wchar_t ntPathSpec2[]{ L':', L'\\' };
if (
dwModuleFileNameLength >= 7 &&
memcmp(&ScratchBuffer[0], &ntPathSpec1[0], sizeof(ntPathSpec1)) == 0 &&
memcmp(&ScratchBuffer[5], &ntPathSpec2[0], sizeof(ntPathSpec2)) == 0)
{
NtToWin32PathOffset = 4;
}
ACTCTXW actctx{};
actctx.cbSize = sizeof(actctx);
actctx.dwFlags = (ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_SET_PROCESS_DEFAULT);
actctx.lpResourceName = MAKEINTRESOURCE(IDR_SYSTEM_MANIFEST);
@ -83,11 +78,7 @@ void InitSideBySide(_Out_writes_(ScratchBufferSize) PWSTR ScratchBuffer, __range
{
RIPMSG1(RIP_WARNING, "InitSideBySide failed create an activation context. Error: %d\r\n", error);
}
goto Exit;
}
Exit:
ScratchBuffer[0] = 0;
}
// Routine Description:

View File

@ -58,7 +58,7 @@ Tracing::~Tracing()
// Return Value:
// - An object for the caller to hold until the API call is complete.
// Then destroy it to signal that the call is over so the stop trace can be written.
Tracing Tracing::s_TraceApiCall(const NTSTATUS& result, PCSTR traceName)
Tracing Tracing::s_TraceApiCall(const NTSTATUS result, PCSTR traceName)
{
// clang-format off
TraceLoggingWrite(

View File

@ -40,7 +40,7 @@ class Tracing
public:
~Tracing();
static Tracing s_TraceApiCall(const NTSTATUS& result, PCSTR traceName);
static Tracing s_TraceApiCall(const NTSTATUS result, PCSTR traceName);
static void s_TraceApi(const NTSTATUS status, const CONSOLE_GETLARGESTWINDOWSIZE_MSG* const a);
static void s_TraceApi(const NTSTATUS status, const CONSOLE_SCREENBUFFERINFO_MSG* const a, const bool fSet);

View File

@ -153,7 +153,7 @@ class AliasTests
TEST_METHOD(TestMatchAndCopyTrailingCRLF)
{
PWSTR pwszSource = L"SourceWithoutCRLF\r\n";
const auto pwszSource = L"SourceWithoutCRLF\r\n";
const size_t cbSource = wcslen(pwszSource) * sizeof(wchar_t);
const size_t cchTarget = 60;
@ -193,7 +193,7 @@ class AliasTests
TEST_METHOD(TestMatchAndCopyInvalidExeName)
{
PWSTR pwszSource = L"Source";
const auto pwszSource = L"Source";
const size_t cbSource = wcslen(pwszSource) * sizeof(wchar_t);
const size_t cchTarget = 12;
@ -225,7 +225,7 @@ class AliasTests
TEST_METHOD(TestMatchAndCopyExeNotFound)
{
PWSTR pwszSource = L"Source";
const auto pwszSource = L"Source";
const size_t cbSource = wcslen(pwszSource) * sizeof(wchar_t);
const size_t cchTarget = 12;
@ -257,7 +257,7 @@ class AliasTests
TEST_METHOD(TestMatchAndCopyAliasNotFound)
{
PWSTR pwszSource = L"Source";
const auto pwszSource = L"Source";
const size_t cbSource = wcslen(pwszSource) * sizeof(wchar_t);
const size_t cchTarget = 12;
@ -294,7 +294,7 @@ class AliasTests
TEST_METHOD(TestMatchAndCopyTargetTooSmall)
{
PWSTR pwszSource = L"Source";
const auto pwszSource = L"Source";
const size_t cbSource = wcslen(pwszSource) * sizeof(wchar_t);
const size_t cchTarget = 12;
@ -330,7 +330,7 @@ class AliasTests
TEST_METHOD(TestMatchAndCopyLeadingSpaces)
{
PWSTR pwszSource = L" Source";
const auto pwszSource = L" Source";
const size_t cbSource = wcslen(pwszSource) * sizeof(wchar_t);
const size_t cchTarget = 12;

View File

@ -118,7 +118,7 @@ class InputRecordConversionTests
dbcsChars,
INPUT_RECORD_COUNT * 2,
nullptr,
false);
FALSE);
VERIFY_ARE_EQUAL(writtenBytes, static_cast<int>(INPUT_RECORD_COUNT * 2));
for (size_t i = 0; i < INPUT_RECORD_COUNT * 2; ++i)
{

View File

@ -2572,7 +2572,7 @@ void ScreenBufferTests::BackspaceDefaultAttrsWriteCharsLegacy()
if (writeSingly)
{
wchar_t* str = L"X";
auto str = L"X";
size_t seqCb = 2;
VERIFY_SUCCESS_NTSTATUS(WriteCharsLegacy(si, str, str, str, &seqCb, nullptr, cursor.GetPosition().X, writeCharsLegacyMode, nullptr));
VERIFY_SUCCESS_NTSTATUS(WriteCharsLegacy(si, str, str, str, &seqCb, nullptr, cursor.GetPosition().X, writeCharsLegacyMode, nullptr));
@ -2581,7 +2581,7 @@ void ScreenBufferTests::BackspaceDefaultAttrsWriteCharsLegacy()
}
else
{
wchar_t* str = L"XX\x08";
const auto str = L"XX\x08";
size_t seqCb = 6;
VERIFY_SUCCESS_NTSTATUS(WriteCharsLegacy(si, str, str, str, &seqCb, nullptr, cursor.GetPosition().X, writeCharsLegacyMode, nullptr));
}

View File

@ -22,6 +22,61 @@ using namespace WEX::Logging;
using namespace WEX::TestExecution;
using Microsoft::Console::Interactivity::ServiceLocator;
template<typename T>
T GetIterator()
{
}
template<typename T>
T GetIteratorAt(COORD at)
{
}
template<typename T>
T GetIteratorWithAdvance()
{
}
template<>
TextBufferCellIterator GetIteratorAt<TextBufferCellIterator>(COORD at)
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
const auto& outputBuffer = gci.GetActiveOutputBuffer();
return outputBuffer.GetCellDataAt(at);
}
template<>
TextBufferCellIterator GetIterator<TextBufferCellIterator>()
{
return GetIteratorAt<TextBufferCellIterator>({ 0 });
}
template<>
TextBufferCellIterator GetIteratorWithAdvance<TextBufferCellIterator>()
{
return GetIteratorAt<TextBufferCellIterator>({ 5, 5 });
}
template<>
TextBufferTextIterator GetIteratorAt<TextBufferTextIterator>(COORD at)
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
const auto& outputBuffer = gci.GetActiveOutputBuffer();
return outputBuffer.GetTextDataAt(at);
}
template<>
TextBufferTextIterator GetIterator<TextBufferTextIterator>()
{
return GetIteratorAt<TextBufferTextIterator>({ 0 });
}
template<>
TextBufferTextIterator GetIteratorWithAdvance<TextBufferTextIterator>()
{
return GetIteratorAt<TextBufferTextIterator>({ 5, 5 });
}
class TextBufferIteratorTests
{
CommonState* m_state;
@ -268,61 +323,6 @@ class TextBufferIteratorTests
TEST_METHOD(ConstructedLimits);
};
template<typename T>
T GetIterator()
{
}
template<typename T>
T GetIteratorAt(COORD at)
{
}
template<typename T>
T GetIteratorWithAdvance()
{
}
template<>
TextBufferCellIterator GetIteratorAt<TextBufferCellIterator>(COORD at)
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
const auto& outputBuffer = gci.GetActiveOutputBuffer();
return outputBuffer.GetCellDataAt(at);
}
template<>
TextBufferCellIterator GetIterator<TextBufferCellIterator>()
{
return GetIteratorAt<TextBufferCellIterator>({ 0 });
}
template<>
TextBufferCellIterator GetIteratorWithAdvance<TextBufferCellIterator>()
{
return GetIteratorAt<TextBufferCellIterator>({ 5, 5 });
}
template<>
TextBufferTextIterator GetIteratorAt<TextBufferTextIterator>(COORD at)
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
const auto& outputBuffer = gci.GetActiveOutputBuffer();
return outputBuffer.GetTextDataAt(at);
}
template<>
TextBufferTextIterator GetIterator<TextBufferTextIterator>()
{
return GetIteratorAt<TextBufferTextIterator>({ 0 });
}
template<>
TextBufferTextIterator GetIteratorWithAdvance<TextBufferTextIterator>()
{
return GetIteratorAt<TextBufferTextIterator>({ 5, 5 });
}
void TextBufferIteratorTests::BoolOperatorText()
{
BoolOperatorTestHelper<TextBufferTextIterator>();

View File

@ -81,7 +81,7 @@ class TextBufferTests
TEST_METHOD(TestDoubleBytePadFlag);
void DoBoundaryTest(PWCHAR const pwszInputString,
void DoBoundaryTest(PCWCHAR const pwszInputString,
short const cLength,
short const cMax,
short const cLeft,
@ -300,7 +300,7 @@ void TextBufferTests::TestDoubleBytePadFlag()
VERIFY_IS_FALSE(Row.WasDoubleBytePadded());
}
void TextBufferTests::DoBoundaryTest(PWCHAR const pwszInputString,
void TextBufferTests::DoBoundaryTest(PCWCHAR const pwszInputString,
short const cLength,
short const cMax,
short const cLeft,
@ -336,7 +336,7 @@ void TextBufferTests::TestBoundaryMeasuresRegularString()
SHORT csBufferWidth = GetBufferWidth();
// length 44, left 0, right 44
const PWCHAR pwszLazyDog = L"The quick brown fox jumps over the lazy dog.";
const auto pwszLazyDog = L"The quick brown fox jumps over the lazy dog.";
DoBoundaryTest(pwszLazyDog, 44, csBufferWidth, 0, 44);
}
@ -345,7 +345,7 @@ void TextBufferTests::TestBoundaryMeasuresFloatingString()
SHORT csBufferWidth = GetBufferWidth();
// length 5 spaces + 4 chars + 5 spaces = 14, left 5, right 9
const PWCHAR pwszOffsets = L" C:\\> ";
const auto pwszOffsets = L" C:\\> ";
DoBoundaryTest(pwszOffsets, 14, csBufferWidth, 5, 9);
}
@ -648,7 +648,7 @@ void TextBufferTests::TestMixedRgbAndLegacyForeground()
// FG = rgb(64;128;255), BG = rgb(default)
Log::Comment(L"Case 1 \"\\E[m\\E[38;2;64;128;255mX\\E[49mX\\E[m\"");
wchar_t* sequence = L"\x1b[m\x1b[38;2;64;128;255mX\x1b[49mX\x1b[m";
const auto sequence = L"\x1b[m\x1b[38;2;64;128;255mX\x1b[49mX\x1b[m";
stateMachine.ProcessString(sequence);
const short x = cursor.GetPosition().X;
@ -675,7 +675,7 @@ void TextBufferTests::TestMixedRgbAndLegacyForeground()
VERIFY_ARE_EQUAL(gci.LookupAttributeColors(attrA), std::make_pair(fgColor, bgColor));
VERIFY_ARE_EQUAL(gci.LookupAttributeColors(attrB), std::make_pair(fgColor, bgColor));
wchar_t* reset = L"\x1b[0m";
const auto reset = L"\x1b[0m";
stateMachine.ProcessString(reset);
}
@ -693,7 +693,7 @@ void TextBufferTests::TestMixedRgbAndLegacyBackground()
// FG = rgb(default), BG = rgb(64;128;255)
Log::Comment(L"Case 2 \"\\E[m\\E[48;2;64;128;255mX\\E[39mX\\E[m\"");
wchar_t* sequence = L"\x1b[m\x1b[48;2;64;128;255mX\x1b[39mX\x1b[m";
const auto sequence = L"\x1b[m\x1b[48;2;64;128;255mX\x1b[39mX\x1b[m";
stateMachine.ProcessString(sequence);
const auto x = cursor.GetPosition().X;
const auto y = cursor.GetPosition().Y;
@ -719,7 +719,7 @@ void TextBufferTests::TestMixedRgbAndLegacyBackground()
VERIFY_ARE_EQUAL(gci.LookupAttributeColors(attrA), std::make_pair(fgColor, bgColor));
VERIFY_ARE_EQUAL(gci.LookupAttributeColors(attrB), std::make_pair(fgColor, bgColor));
wchar_t* reset = L"\x1b[0m";
const auto reset = L"\x1b[0m";
stateMachine.ProcessString(reset);
}
@ -735,7 +735,7 @@ void TextBufferTests::TestMixedRgbAndLegacyUnderline()
// '\E[m\E[48;2;64;128;255mX\E[4mX\E[m'
// Make sure that the second X has RGB attributes AND underline
Log::Comment(L"Case 3 \"\\E[m\\E[48;2;64;128;255mX\\E[4mX\\E[m\"");
wchar_t* sequence = L"\x1b[m\x1b[48;2;64;128;255mX\x1b[4mX\x1b[m";
const auto sequence = L"\x1b[m\x1b[48;2;64;128;255mX\x1b[4mX\x1b[m";
stateMachine.ProcessString(sequence);
const auto x = cursor.GetPosition().X;
const auto y = cursor.GetPosition().Y;
@ -764,7 +764,7 @@ void TextBufferTests::TestMixedRgbAndLegacyUnderline()
VERIFY_ARE_EQUAL(attrA.IsUnderlined(), false);
VERIFY_ARE_EQUAL(attrB.IsUnderlined(), true);
wchar_t* reset = L"\x1b[0m";
const auto reset = L"\x1b[0m";
stateMachine.ProcessString(reset);
}
@ -783,7 +783,7 @@ void TextBufferTests::TestMixedRgbAndLegacyBrightness()
const auto bright_green = gci.GetColorTableEntry(TextColor::BRIGHT_GREEN);
VERIFY_ARE_NOT_EQUAL(dark_green, bright_green);
wchar_t* sequence = L"\x1b[m\x1b[32mX\x1b[1mX";
const auto sequence = L"\x1b[m\x1b[32mX\x1b[1mX";
stateMachine.ProcessString(sequence);
const auto x = cursor.GetPosition().X;
const auto y = cursor.GetPosition().Y;
@ -806,7 +806,7 @@ void TextBufferTests::TestMixedRgbAndLegacyBrightness()
VERIFY_ARE_EQUAL(gci.LookupAttributeColors(attrA).first, dark_green);
VERIFY_ARE_EQUAL(gci.LookupAttributeColors(attrB).first, bright_green);
wchar_t* reset = L"\x1b[0m";
const auto reset = L"\x1b[0m";
stateMachine.ProcessString(reset);
}
@ -1384,7 +1384,7 @@ void TextBufferTests::TestRgbThenBold()
VERIFY_ARE_EQUAL(gci.LookupAttributeColors(attrA), std::make_pair(foreground, background));
VERIFY_ARE_EQUAL(gci.LookupAttributeColors(attrB), std::make_pair(foreground, background));
wchar_t* reset = L"\x1b[0m";
const auto reset = L"\x1b[0m";
stateMachine.ProcessString(reset);
}
@ -1408,7 +1408,7 @@ void TextBufferTests::TestResetClearsBoldness()
const auto dark_green = gci.GetColorTableEntry(TextColor::DARK_GREEN);
const auto bright_green = gci.GetColorTableEntry(TextColor::BRIGHT_GREEN);
wchar_t* sequence = L"\x1b[32mA\x1b[1mB\x1b[0mC\x1b[32mD";
const auto sequence = L"\x1b[32mA\x1b[1mB\x1b[0mC\x1b[32mD";
Log::Comment(NoThrowString().Format(sequence));
stateMachine.ProcessString(sequence);
@ -1443,7 +1443,7 @@ void TextBufferTests::TestResetClearsBoldness()
VERIFY_IS_FALSE(attrC.IsBold());
VERIFY_IS_FALSE(attrD.IsBold());
wchar_t* reset = L"\x1b[0m";
const auto reset = L"\x1b[0m";
stateMachine.ProcessString(reset);
}
@ -1552,7 +1552,7 @@ void TextBufferTests::TestBackspaceStringsAPI()
Log::Comment(NoThrowString().Format(
L"Using WriteCharsLegacy, write \\b \\b as a single string."));
{
wchar_t* str = L"\b \b";
const auto str = L"\b \b";
VERIFY_SUCCESS_NTSTATUS(WriteCharsLegacy(si, str, str, str, &seqCb, nullptr, cursor.GetPosition().X, 0, nullptr));
VERIFY_ARE_EQUAL(cursor.GetPosition().X, x0);
@ -1583,19 +1583,19 @@ void TextBufferTests::TestBackspaceStringsAPI()
Log::Comment(NoThrowString().Format(
L"Using WriteCharsLegacy, write \\b \\b as separate strings."));
{
wchar_t* str = L"a";
const auto str = L"a";
VERIFY_SUCCESS_NTSTATUS(WriteCharsLegacy(si, str, str, str, &seqCb, nullptr, cursor.GetPosition().X, 0, nullptr));
}
{
wchar_t* str = L"\b";
const auto str = L"\b";
VERIFY_SUCCESS_NTSTATUS(WriteCharsLegacy(si, str, str, str, &seqCb, nullptr, cursor.GetPosition().X, 0, nullptr));
}
{
wchar_t* str = L" ";
const auto str = L" ";
VERIFY_SUCCESS_NTSTATUS(WriteCharsLegacy(si, str, str, str, &seqCb, nullptr, cursor.GetPosition().X, 0, nullptr));
}
{
wchar_t* str = L"\b";
const auto str = L"\b";
VERIFY_SUCCESS_NTSTATUS(WriteCharsLegacy(si, str, str, str, &seqCb, nullptr, cursor.GetPosition().X, 0, nullptr));
}

View File

@ -22,7 +22,7 @@
// Return Value:
// - THROW: Throws if space cannot be allocated to copy the given string
WriteData::WriteData(SCREEN_INFORMATION& siContext,
_In_reads_bytes_(cbContext) wchar_t* const pwchContext,
_In_reads_bytes_(cbContext) PCWCHAR pwchContext,
const size_t cbContext,
const UINT uiOutputCodepage,
const bool requiresVtQuirk) :

View File

@ -25,7 +25,7 @@ class WriteData : public IWaitRoutine
{
public:
WriteData(SCREEN_INFORMATION& siContext,
_In_reads_bytes_(cbContext) wchar_t* const pwchContext,
_In_reads_bytes_(cbContext) PCWCHAR pwchContext,
const size_t cbContext,
const UINT uiOutputCodepage,
const bool requiresVtQuirk);

View File

@ -97,7 +97,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
public:
template<typename... Args>
constexpr explicit presorted_static_map(const Args&... args) noexcept :
static_map{ args... } {};
static_map<K, V, Compare, N, details::presorted_input_t>{ args... } {};
};
// this is a deduction guide that ensures two things:

View File

@ -169,7 +169,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
// and 5x or more for long strings (128 characters or more).
// See: https://github.com/microsoft/STL/issues/2289
template<typename T, typename Traits>
bool equals(const std::basic_string_view<T, Traits>& str1, const std::basic_string_view<T, Traits>& str2) noexcept
bool equals(const std::basic_string_view<T, Traits>& lhs, const std::basic_string_view<T, Traits>& rhs) noexcept
{
return lhs.size() == rhs.size() && __builtin_memcmp(lhs.data(), rhs.data(), lhs.size() * sizeof(T)) == 0;
}

View File

@ -315,7 +315,7 @@ class UiaTextRangeTests
short yPos;
};
static constexpr wchar_t* toString(TextUnit unit) noexcept
static constexpr const wchar_t* toString(TextUnit unit) noexcept
{
// if a format is not supported, it goes to the next largest text unit
switch (unit)
@ -1368,17 +1368,17 @@ class UiaTextRangeTests
Log::Comment(NoThrowString().Format(L"Forward by %s", toString(textUnit)));
// Create an UTR at EndExclusive
const auto utrEnd{ atDocumentEnd ? documentEndExclusive : endExclusive };
const auto utrEnd{ atDocumentEnd ? documentEndExclusive : static_cast<COORD>(endExclusive) };
if (degenerate)
{
// UTR: (exclusive, exclusive) range
const auto utrStart{ atDocumentEnd ? documentEndExclusive : endExclusive };
const auto utrStart{ atDocumentEnd ? documentEndExclusive : static_cast<COORD>(endExclusive) };
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd));
}
else
{
// UTR: (inclusive, exclusive) range
const auto utrStart{ atDocumentEnd ? documentEndInclusive : endInclusive };
const auto utrStart{ atDocumentEnd ? documentEndInclusive : static_cast<COORD>(endInclusive) };
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd));
}
THROW_IF_FAILED(utr->Move(textUnit, 1, &moveAmt));
@ -1414,13 +1414,13 @@ class UiaTextRangeTests
if (degenerate)
{
// UTR: (exclusive, exclusive) range
const auto utrStart{ atDocumentEnd ? documentEndExclusive : endExclusive };
const auto utrStart{ atDocumentEnd ? documentEndExclusive : static_cast<COORD>(endExclusive) };
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd));
}
else
{
// UTR: (inclusive, exclusive) range
const auto utrStart{ atDocumentEnd ? documentEndInclusive : endInclusive };
const auto utrStart{ atDocumentEnd ? documentEndInclusive : static_cast<COORD>(endInclusive) };
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd));
}
@ -1447,14 +1447,14 @@ class UiaTextRangeTests
else if (textUnit <= TextUnit::TextUnit_Line)
{
VERIFY_ARE_EQUAL(-1, moveAmt);
VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? lastLineStart : secondToLastLinePos, til::point{ utr->_start });
VERIFY_ARE_EQUAL(lastLineStart, til::point{ utr->_end });
VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? lastLineStart : static_cast<COORD>(secondToLastLinePos), utr->_start);
VERIFY_ARE_EQUAL(lastLineStart, utr->_end);
}
else // textUnit <= TextUnit::TextUnit_Document:
{
VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? -1 : 0, moveAmt);
VERIFY_ARE_EQUAL(origin, til::point{ utr->_start });
VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? origin : documentEndExclusive, til::point{ utr->_end });
VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? static_cast<COORD>(origin) : documentEndExclusive, utr->_end);
}
}

View File

@ -18,14 +18,7 @@ static CONSOLE_STATE_INFO g_csi;
using namespace Microsoft::WRL;
// This class exposes console property sheets for use when launching the filesystem shortcut properties dialog.
// clang-format off
[uuid(D2942F8E-478E-41D3-870A-35A16238F4EE)]
class ConsolePropertySheetHandler WrlFinal : public RuntimeClass<RuntimeClassFlags<ClassicCom>,
IShellExtInit,
IShellPropSheetExt,
IPersist,
FtmBase>
// clang-format on
class __declspec(uuid("D2942F8E-478E-41D3-870A-35A16238F4EE")) ConsolePropertySheetHandler final : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IShellExtInit, IShellPropSheetExt, IPersist, FtmBase>
{
public:
HRESULT RuntimeClassInitialize()
@ -34,7 +27,7 @@ public:
}
// IPersist
STDMETHODIMP GetClassID(_Out_ CLSID * clsid) override
STDMETHODIMP GetClassID(_Out_ CLSID* clsid) override
{
*clsid = __uuidof(this);
return S_OK;
@ -43,7 +36,7 @@ public:
// IShellExtInit
// Shell QI's for IShellExtInit and calls Initialize first. If we return a succeeding HRESULT, the shell will QI for
// IShellPropSheetExt and call AddPages. A failing HRESULT causes the shell to skip us.
STDMETHODIMP Initialize(_In_ PCIDLIST_ABSOLUTE /*pidlFolder*/, _In_ IDataObject * pdtobj, _In_ HKEY /*hkeyProgID*/)
STDMETHODIMP Initialize(_In_ PCIDLIST_ABSOLUTE /*pidlFolder*/, _In_ IDataObject* pdtobj, _In_ HKEY /*hkeyProgID*/)
{
WCHAR szLinkFileName[MAX_PATH];
HRESULT hr = _ShouldAddPropertySheet(pdtobj, szLinkFileName, ARRAYSIZE(szLinkFileName));
@ -139,7 +132,7 @@ private:
///////////////////////////////////////////////////////////////////////////
// CODE FROM THE SHELL DEPOT'S `idllib.h`
// get a link target item without resolving it.
HRESULT GetTargetIdList(_In_ IShellItem * psiLink, _COM_Outptr_ PIDLIST_ABSOLUTE * ppidl)
HRESULT GetTargetIdList(_In_ IShellItem* psiLink, _COM_Outptr_ PIDLIST_ABSOLUTE* ppidl)
{
*ppidl = nullptr;
@ -156,7 +149,7 @@ private:
}
return hr;
}
HRESULT GetTargetItem(_In_ IShellItem * psiLink, _In_ REFIID riid, _COM_Outptr_ void** ppv)
HRESULT GetTargetItem(_In_ IShellItem* psiLink, _In_ REFIID riid, _COM_Outptr_ void** ppv)
{
*ppv = nullptr;
@ -171,7 +164,7 @@ private:
}
///////////////////////////////////////////////////////////////////////////
HRESULT _GetShellItemLinkTargetExpanded(_In_ IShellItem * pShellItem,
HRESULT _GetShellItemLinkTargetExpanded(_In_ IShellItem* pShellItem,
_Out_writes_(cchFilePathExtended) PWSTR pszFilePathExtended,
const size_t cchFilePathExtended)
{
@ -190,7 +183,7 @@ private:
return hr;
}
HRESULT _ShouldAddPropertySheet(_In_ IDataObject * pdtobj,
HRESULT _ShouldAddPropertySheet(_In_ IDataObject* pdtobj,
_Out_writes_(cchLinkFileName) PWSTR pszLinkFileName,
const size_t cchLinkFileName)
{

View File

@ -359,7 +359,9 @@ namespace Microsoft::Console::Render
bool is_inline() const noexcept
{
return (__builtin_bit_cast(uintptr_t, allocated) & 1) != 0;
// VSO-1430353: __builtin_bitcast crashes the compiler under /permissive-.
#pragma warning(suppress : 26490) // Don't use reinterpret_cast (type.1).
return (reinterpret_cast<uintptr_t>(allocated) & 1) != 0;
}
const T* data() const noexcept

View File

@ -144,11 +144,10 @@ PCONSOLE_API_MSG ApiSorter::ConsoleDispatchRequest(_Inout_ PCONSOLE_API_MSG Mess
ULONG const LayerNumber = (Message->msgHeader.ApiNumber >> 24) - 1;
ULONG const ApiNumber = Message->msgHeader.ApiNumber & 0xffffff;
NTSTATUS Status;
if ((LayerNumber >= RTL_NUMBER_OF(ConsoleApiLayerTable)) || (ApiNumber >= ConsoleApiLayerTable[LayerNumber].Count))
if ((LayerNumber >= std::size(ConsoleApiLayerTable)) || (ApiNumber >= ConsoleApiLayerTable[LayerNumber].Count))
{
Status = STATUS_ILLEGAL_FUNCTION;
goto Complete;
Message->SetReplyStatus(STATUS_ILLEGAL_FUNCTION);
return Message;
}
CONSOLE_API_DESCRIPTOR const* Descriptor = &ConsoleApiLayerTable[LayerNumber].Descriptor[ApiNumber];
@ -159,8 +158,8 @@ PCONSOLE_API_MSG ApiSorter::ConsoleDispatchRequest(_Inout_ PCONSOLE_API_MSG Mess
(Message->msgHeader.ApiDescriptorSize > Message->Descriptor.InputSize - sizeof(CONSOLE_MSG_HEADER)) ||
(Message->msgHeader.ApiDescriptorSize < Descriptor->RequiredSize))
{
Status = STATUS_ILLEGAL_FUNCTION;
goto Complete;
Message->SetReplyStatus(STATUS_ILLEGAL_FUNCTION);
return Message;
}
BOOL ReplyPending = FALSE;
@ -173,6 +172,7 @@ PCONSOLE_API_MSG ApiSorter::ConsoleDispatchRequest(_Inout_ PCONSOLE_API_MSG Mess
// hard dependencies on NTSTATUS codes that aren't readily expressible as an HRESULT. There's currently only one
// such known code -- STATUS_BUFFER_TOO_SMALL. There's a conlibk dependency on this being returned from the console
// alias API.
NTSTATUS Status = S_OK;
{
const auto trace = Tracing::s_TraceApiCall(Status, Descriptor->TraceName);
Status = (*Descriptor->Routine)(Message, &ReplyPending);
@ -184,14 +184,9 @@ PCONSOLE_API_MSG ApiSorter::ConsoleDispatchRequest(_Inout_ PCONSOLE_API_MSG Mess
if (!ReplyPending)
{
goto Complete;
Message->SetReplyStatus(Status);
return Message;
}
return nullptr;
Complete:
Message->SetReplyStatus(Status);
return Message;
}

View File

@ -92,7 +92,9 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleCreateObject(_In_ PCONSOLE_API_MSG pMessa
if (!NT_SUCCESS(Status))
{
goto Error;
UnlockConsole();
pMessage->SetReplyStatus(Status);
return pMessage;
}
auto deviceComm{ ServiceLocator::LocateGlobals().pDeviceComm };
@ -110,16 +112,6 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleCreateObject(_In_ PCONSOLE_API_MSG pMessa
UnlockConsole();
return nullptr;
Error:
FAIL_FAST_IF(NT_SUCCESS(Status));
UnlockConsole();
pMessage->SetReplyStatus(Status);
return pMessage;
}
// Routine Description:
@ -256,17 +248,32 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API
Telemetry::Instance().LogApiCall(Telemetry::ApiCall::AttachConsole);
ConsoleProcessHandle* ProcessData = nullptr;
NTSTATUS Status;
LockConsole();
const auto cleanup = wil::scope_exit([&]() noexcept {
UnlockConsole();
if (!NT_SUCCESS(Status))
{
pReceiveMsg->SetReplyStatus(Status);
if (ProcessData != nullptr)
{
CommandHistory::s_Free(ProcessData);
gci.ProcessHandleList.FreeProcessData(ProcessData);
}
}
});
DWORD const dwProcessId = (DWORD)pReceiveMsg->Descriptor.Process;
DWORD const dwThreadId = (DWORD)pReceiveMsg->Descriptor.Object;
CONSOLE_API_CONNECTINFO Cac;
NTSTATUS Status = ConsoleInitializeConnectInfo(pReceiveMsg, &Cac);
Status = ConsoleInitializeConnectInfo(pReceiveMsg, &Cac);
if (!NT_SUCCESS(Status))
{
goto Error;
return pReceiveMsg;
}
// If we pass the tests...
@ -354,7 +361,7 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API
if (!NT_SUCCESS(Status))
{
goto Error;
return pReceiveMsg;
}
ProcessData->fRootProcess = WI_IsFlagClear(gci.Flags, CONSOLE_INITIALIZED);
@ -376,7 +383,7 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API
Status = ConsoleAllocateConsole(&Cac);
if (!NT_SUCCESS(Status))
{
goto Error;
return pReceiveMsg;
}
WI_SetFlag(gci.Flags, CONSOLE_INITIALIZED);
@ -389,7 +396,7 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API
catch (...)
{
LOG_CAUGHT_EXCEPTION();
goto Error;
return pReceiveMsg;
}
gci.ProcessHandleList.ModifyConsoleProcessFocus(WI_IsFlagSet(gci.Flags, CONSOLE_HAS_FOCUS));
@ -403,7 +410,7 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API
if (!NT_SUCCESS(Status))
{
goto Error;
return pReceiveMsg;
}
auto& screenInfo = gci.GetActiveOutputBuffer().GetMainBuffer();
@ -414,7 +421,7 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API
if (!NT_SUCCESS(Status))
{
goto Error;
return pReceiveMsg;
}
// Complete the request.
@ -434,24 +441,7 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API
Tracing::s_TraceConsoleAttachDetach(ProcessData, true);
UnlockConsole();
return nullptr;
Error:
FAIL_FAST_IF(NT_SUCCESS(Status));
if (ProcessData != nullptr)
{
CommandHistory::s_Free((HANDLE)ProcessData);
gci.ProcessHandleList.FreeProcessData(ProcessData);
}
UnlockConsole();
pReceiveMsg->SetReplyStatus(Status);
return pReceiveMsg;
}
// Routine Description:

View File

@ -25,7 +25,7 @@ using namespace Microsoft::Console::VirtualTerminal;
// For magic reasons, this has to live outside the class. Something wonderful about TAEF macros makes it
// invisible to the linker when inside the class.
static wchar_t* s_pwszInputExpected;
static const wchar_t* s_pwszInputExpected;
static wchar_t s_pwszExpectedBuffer[BYTE_MAX]; // big enough for anything
@ -46,7 +46,7 @@ static COORD s_rgTestCoords[] = {
// Note: We're going to be changing the value of the third char (the space) of
// these strings as we test things with this array, to alter the expected button value.
// The default value is the button=WM_LBUTTONDOWN case, which is element[3]=' '
static wchar_t* s_rgDefaultTestOutput[] = {
static const wchar_t* s_rgDefaultTestOutput[] = {
L"\x1b[M !!",
L"\x1b[M !\"",
L"\x1b[M \"\"",
@ -64,7 +64,7 @@ static wchar_t* s_rgDefaultTestOutput[] = {
// these strings as we test things with this array, to alter the expected button value.
// The default value is the button=WM_LBUTTONDOWN case, which is element[3]='0'
// We're also going to change the last element, for button-down (M) vs button-up (m)
static wchar_t* s_rgSgrTestOutput[] = {
static const wchar_t* s_rgSgrTestOutput[] = {
L"\x1b[<%d;1;1M",
L"\x1b[<%d;1;2M",
L"\x1b[<%d;2;2M",
@ -113,7 +113,7 @@ public:
// Routine Description:
// Constructs a string from s_rgDefaultTestOutput with the third char
// correctly filled in to match uiButton.
wchar_t* BuildDefaultTestOutput(wchar_t* pwchTestOutput, unsigned int uiButton, short sModifierKeystate, short sScrollDelta)
wchar_t* BuildDefaultTestOutput(const wchar_t* pwchTestOutput, unsigned int uiButton, short sModifierKeystate, short sScrollDelta)
{
Log::Comment(NoThrowString().Format(L"Input Test Output:\'%s\'", pwchTestOutput));
// Copy the expected output into the buffer
@ -136,7 +136,7 @@ public:
// Routine Description:
// Constructs a string from s_rgSgrTestOutput with the third and last chars
// correctly filled in to match uiButton.
wchar_t* BuildSGRTestOutput(wchar_t* pwchTestOutput, unsigned int uiButton, short sModifierKeystate, short sScrollDelta)
wchar_t* BuildSGRTestOutput(const wchar_t* pwchTestOutput, unsigned int uiButton, short sModifierKeystate, short sScrollDelta)
{
ClearTestBuffer();

View File

@ -112,7 +112,7 @@ std::string GenerateWhiteSpaceToken()
std::string GenerateTextToken()
{
const LPSTR tokens[] = {
const LPCSTR tokens[] = {
"The cow jumped over the moon.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?",
@ -134,14 +134,14 @@ std::string GenerateTextToken()
std::string GenerateInvalidToken()
{
const LPSTR tokens[]{ ":", "'", "\"", "\\" };
const LPCSTR tokens[]{ ":", "'", "\"", "\\" };
return std::string(CFuzzChance::SelectOne(tokens, ARRAYSIZE(tokens)));
}
std::string GenerateFuzzedToken(
__in_ecount(cmap) const _fuzz_type_entry<std::string>* map,
__in DWORD cmap,
__in_ecount(ctokens) const LPSTR* tokens,
__in_ecount(ctokens) const LPCSTR* tokens,
__in DWORD ctokens)
{
std::string csis[] = { CSI, C1CSI };
@ -165,7 +165,7 @@ std::string GenerateFuzzedToken(
std::string GenerateFuzzedOscToken(
__in_ecount(cmap) const _fuzz_type_entry<std::string>* map,
__in DWORD cmap,
__in_ecount(ctokens) const LPSTR* tokens,
__in_ecount(ctokens) const LPCSTR* tokens,
__in DWORD ctokens)
{
std::string s(OSC);
@ -227,7 +227,7 @@ std::string GenerateSGRToken()
49,
};
const LPSTR tokens[] = { "m" };
const LPCSTR tokens[] = { "m" };
const _fuzz_type_entry<std::string> map[] = {
{ 40, [&](std::string) { std::string s; AppendFormat(s, "%02d", CFuzzChance::SelectOne(psValid, ARRAYSIZE(psValid))); return s; } },
{ 10, [](std::string) { std::string s; AppendFormat(s, "%d", CFuzzChance::GetRandom<BYTE>()); return s; } },
@ -242,7 +242,7 @@ std::string GenerateSGRToken()
// For example, moving the cursor to the next line, previous line, up, down, etc.
std::string GenerateCUXToken()
{
const LPSTR tokens[] = { "A", "B", "C", "D", "E", "F", "G" };
const LPCSTR tokens[] = { "A", "B", "C", "D", "E", "F", "G" };
const _fuzz_type_entry<std::string> map[] = {
{ 25, [](std::string) { std::string s; AppendFormat(s, "%d", CFuzzChance::GetRandom<USHORT>()); return s; } },
{ 25, [](std::string) { std::string s; AppendFormat(s, "%d", CFuzzChance::GetRandom<BYTE>()); return s; } }
@ -255,7 +255,7 @@ std::string GenerateCUXToken()
// Differs from other cursor functions since these are ESC sequences and not CSI sequences.
std::string GenerateCUXToken2()
{
const LPSTR tokens[] = { "7", "8" };
const LPCSTR tokens[] = { "7", "8" };
std::string cux(ESC);
cux += GenerateTokenLowProbability();
cux += CFuzzChance::SelectOne(tokens, ARRAYSIZE(tokens));
@ -266,7 +266,7 @@ std::string GenerateCUXToken2()
// Cursor positioning with two arguments
std::string GenerateCUXToken3()
{
const LPSTR tokens[]{ "H" };
const LPCSTR tokens[]{ "H" };
const _fuzz_type_entry<std::string> map[] = {
{ 60, [](std::string) { std::string s; AppendFormat(s, "%d;%d", CFuzzChance::GetRandom<BYTE>(), CFuzzChance::GetRandom<BYTE>()); return s; } }, // 60% give us two numbers in the valid range
{ 10, [](std::string) { return std::string(";"); } }, // 10% give us just a ;
@ -281,7 +281,7 @@ std::string GenerateCUXToken3()
// Hard Reset (has no args)
std::string GenerateHardResetToken()
{
const LPSTR tokens[] = { "c" };
const LPCSTR tokens[] = { "c" };
std::string cux(ESC);
cux += GenerateTokenLowProbability();
cux += CFuzzChance::SelectOne(tokens, ARRAYSIZE(tokens));
@ -292,7 +292,7 @@ std::string GenerateHardResetToken()
// Soft Reset (has no args)
std::string GenerateSoftResetToken()
{
const LPSTR tokens[] = { "p" };
const LPCSTR tokens[] = { "p" };
std::string cux(CSI);
cux += GenerateTokenLowProbability();
cux += CFuzzChance::SelectOne(tokens, ARRAYSIZE(tokens));
@ -304,7 +304,7 @@ std::string GenerateSoftResetToken()
// enabling mouse mode, changing to the alt buffer, blinking the cursor, etc.
std::string GeneratePrivateModeParamToken()
{
const LPSTR tokens[] = { "h", "l" };
const LPCSTR tokens[] = { "h", "l" };
const _fuzz_type_entry<std::string> map[] = {
{ 12, [](std::string) { std::string s; AppendFormat(s, "?%02d", CFuzzChance::GetRandom<BYTE>()); return s; } },
{ 8, [](std::string) { return std::string("?1"); } },
@ -327,7 +327,7 @@ std::string GeneratePrivateModeParamToken()
// Erase sequences, valid numerical values are 0-2. If no numeric value is specified, 0 is assumed.
std::string GenerateEraseToken()
{
const LPSTR tokens[] = { "J", "K" };
const LPCSTR tokens[] = { "J", "K" };
const _fuzz_type_entry<std::string> map[] = {
{ 9, [](std::string) { return std::string(""); } },
{ 25, [](std::string) { return std::string("0"); } },
@ -343,7 +343,7 @@ std::string GenerateEraseToken()
// Device Attributes
std::string GenerateDeviceAttributesToken()
{
const LPSTR tokens[] = { "c" };
const LPCSTR tokens[] = { "c" };
const _fuzz_type_entry<std::string> map[] = {
{ 70, [](std::string) { return std::string(""); } }, // 70% leave it blank (valid)
{ 29, [](std::string) { return std::string("0"); } }, // 29% put in a 0 (valid)
@ -356,7 +356,7 @@ std::string GenerateDeviceAttributesToken()
// Device Attributes
std::string GenerateDeviceStatusReportToken()
{
const LPSTR tokens[] = { "n" };
const LPCSTR tokens[] = { "n" };
const _fuzz_type_entry<std::string> map[] = {
{ 50, [](std::string) { return std::string("6"); } }, // 50% of the time, give us the one we were looking for (6, cursor report)
{ 49, [](std::string) { std::string s; AppendFormat(s, "%02d", CFuzzChance::GetRandom<BYTE>()); return s; } } // 49% of the time, put in a random value
@ -369,7 +369,7 @@ std::string GenerateDeviceStatusReportToken()
// Scroll sequences, valid numeric values include 0-16384.
std::string GenerateScrollToken()
{
const LPSTR tokens[] = { "S", "T" };
const LPCSTR tokens[] = { "S", "T" };
const _fuzz_type_entry<std::string> map[] = {
{ 5, [](std::string) { std::string s; AppendFormat(s, "%08d", CFuzzChance::GetRandom<ULONG>()); return s; } },
{ 5, [](std::string) { std::string s; AppendFormat(s, "%08d", CFuzzChance::GetRandom<USHORT>()); return s; } },
@ -383,7 +383,7 @@ std::string GenerateScrollToken()
// Resize sequences, valid numeric values include 0-16384.
std::string GenerateResizeToken()
{
const LPSTR tokens[] = { "t" };
const LPCSTR tokens[] = { "t" };
// 5% - generate a random window manipulation with 1 params
// 5% - generate a random window manipulation with 2 params
// 5% - generate a random window manipulation with no params
@ -406,7 +406,7 @@ std::string GenerateResizeToken()
// and BEL terminated.
std::string GenerateOscTitleToken()
{
const LPSTR tokens[] = { "\x7" };
const LPCSTR tokens[] = { "\x7" };
const _fuzz_type_entry<std::string> map[] = {
{ 100,
[](std::string) {
@ -435,7 +435,7 @@ std::string GenerateOscTitleToken()
// and BEL terminated.
std::string GenerateOscColorTableToken()
{
const LPSTR tokens[] = { "\x7", "\x1b\\" };
const LPCSTR tokens[] = { "\x7", "\x1b\\" };
const _fuzz_type_entry<std::string> map[] = {
{ 100,
[](std::string) {
@ -515,7 +515,7 @@ std::string GenerateOscColorTableToken()
// VT52 sequences without parameters.
std::string GenerateVt52Token()
{
const LPSTR tokens[] = { "A", "B", "C", "D", "F", "G", "H", "I", "J", "K", "Z", "<" };
const LPCSTR tokens[] = { "A", "B", "C", "D", "F", "G", "H", "I", "J", "K", "Z", "<" };
std::string cux(ESC);
cux += GenerateTokenLowProbability();
cux += CFuzzChance::SelectOne(tokens, ARRAYSIZE(tokens));
@ -525,7 +525,7 @@ std::string GenerateVt52Token()
// VT52 direct cursor address sequence with parameters.
std::string GenerateVt52CursorAddressToken()
{
const LPSTR tokens[] = { "Y" };
const LPCSTR tokens[] = { "Y" };
std::string cux(ESC);
cux += GenerateTokenLowProbability();
cux += CFuzzChance::SelectOne(tokens, ARRAYSIZE(tokens));
@ -540,7 +540,7 @@ std::string GenerateVt52CursorAddressToken()
// followed by a ";", followed by a string, and BEL terminated.
std::string GenerateOscHyperlinkToken()
{
const LPSTR tokens[] = { "\x7" };
const LPCSTR tokens[] = { "\x7" };
const _fuzz_type_entry<std::string> map[] = {
{ 100,
[](std::string) {

View File

@ -898,7 +898,7 @@ namespace fuzz
_Type operator->() const throw()
{
return (this->m_fFuzzed) ? this->m_t : m_tInit;
return (this->m_fFuzzed) ? this->m_t : CFuzzType<_Type, _Args...>::m_tInit;
}
// This operator makes it possible to invoke the fuzzing map
@ -909,7 +909,7 @@ namespace fuzz
// the logic of the fuzz map).
__inline void operator()() throw()
{
GetValueFromMap();
CFuzzType<_Type, _Args...>::GetValueFromMap();
}
};
@ -960,7 +960,7 @@ namespace fuzz
__inline virtual _Type** operator&() throw()
{
m_ftEffectiveTraits |= TRAIT_TRANSFER_ALLOCATION;
return (this->m_fFuzzed) ? &(this->m_t) : &m_tInit;
return (this->m_fFuzzed) ? &(this->m_t) : &CFuzzType<_Type, _Args...>::m_tInit;
}
private:
@ -1087,7 +1087,7 @@ namespace fuzz
int iLow = iHigh - (r.range.iHigh - r.range.iLow);
if (iLow <= wRandom && wRandom < iHigh)
{
this->m_t |= CallFuzzMapFunction(r.fte.pfnFuzz, this->m_tInit, m_tArgs);
this->m_t |= CallFuzzMapFunction(r.fte.pfnFuzz, this->m_tInit, CFuzzType<_Type, _Args...>::m_tArgs);
}
}
}

View File

@ -38,12 +38,12 @@ namespace fuzz
{
if (rcch > 1)
{
const LPWSTR rgFormatStringChars[] = { L"%n", L"%s", L"%d" };
const PCWSTR rgFormatStringChars[] = { L"%n", L"%s", L"%d" };
size_t cbDestSize = 2 * sizeof(WCHAR);
memcpy_s(
&(pwsz[CFuzzChance::GetRandom<size_t>(rcch - 1)]), // -1 because we are writing 2 chars
cbDestSize,
CFuzzChance::SelectOne<const LPWSTR>(rgFormatStringChars, ARRAYSIZE(rgFormatStringChars)),
CFuzzChance::SelectOne<const PCWSTR>(rgFormatStringChars, ARRAYSIZE(rgFormatStringChars)),
cbDestSize);
}
@ -56,12 +56,12 @@ namespace fuzz
{
if (rcch > 1)
{
const LPSTR rgFormatStringChars[] = { "%n", "%s", "%d" };
const LPCSTR rgFormatStringChars[] = { "%n", "%s", "%d" };
size_t cbDestSize = 2 * sizeof(CHAR);
memcpy_s(
&(psz[CFuzzChance::GetRandom<size_t>(rcch - 1)]),
cbDestSize,
CFuzzChance::SelectOne<const LPSTR>(rgFormatStringChars, ARRAYSIZE(rgFormatStringChars)),
CFuzzChance::SelectOne<const LPCSTR>(rgFormatStringChars, ARRAYSIZE(rgFormatStringChars)),
cbDestSize);
}
@ -238,12 +238,40 @@ namespace fuzz
return _strrev(psz);
}
template<class _Alloc = CFuzzCRTAllocator>
class CFuzzLogic;
// Flips a random byte value within the buffer.
template<typename _Type>
static _Type* _fz_flipByte(__inout_ecount(rcelms) _Type* p, __inout size_t& rcelms)
{
if (rcelms > 0)
{
return reinterpret_cast<_Type*>(CFuzzLogic<>::FuzzArrayElement(
reinterpret_cast<BYTE*>(p), (rcelms) * sizeof(_Type)));
}
return p;
}
// Flips a random entry value within the buffer
template<typename _Type>
static _Type* _fz_flipEntry(__inout_ecount(rcelms) _Type* p, __inout size_t& rcelms)
{
if (rcelms > 0)
{
return CFuzzLogic<>::FuzzArrayElement(p, rcelms);
}
return p;
}
// Contains fuzzing logic based upon a variety of default scenarios. The
// idea is to capture and make available a comprehensive fuzzing library
// that does not require external modules or complex setup. This should
// make fuzzing easier to implement and test, as well as more explicit
// with regard to what fuzzing manipulations are possible.
template<class _Alloc = CFuzzCRTAllocator>
template<class _Alloc>
class CFuzzLogic
{
public:
@ -429,31 +457,6 @@ namespace fuzz
}
};
// Flips a random byte value within the buffer.
template<typename _Type>
static _Type* _fz_flipByte(__inout_ecount(rcelms) _Type* p, __inout size_t& rcelms)
{
if (rcelms > 0)
{
return reinterpret_cast<_Type*>(CFuzzLogic<>::FuzzArrayElement(
reinterpret_cast<BYTE*>(p), (rcelms) * sizeof(_Type)));
}
return p;
}
// Flips a random entry value within the buffer
template<typename _Type>
static _Type* _fz_flipEntry(__inout_ecount(rcelms) _Type* p, __inout size_t& rcelms)
{
if (rcelms > 0)
{
return CFuzzLogic<>::FuzzArrayElement(p, rcelms);
}
return p;
}
static char* _fz_sz_tokenizeSpaces(__in char* psz)
{
const _fuzz_type_entry<DWORD> repeatMap[] = {

View File

@ -121,6 +121,16 @@ namespace Microsoft::Console::Types
[[nodiscard]] static SomeViewports Subtract(const Viewport& original, const Viewport& removeMe) noexcept;
constexpr bool operator==(const Viewport& other) const noexcept
{
return _sr == other._sr;
}
constexpr bool operator!=(const Viewport& other) const noexcept
{
return _sr != other._sr;
}
private:
Viewport(const SMALL_RECT sr) noexcept;
@ -142,15 +152,3 @@ inline COORD operator-(const COORD& c) noexcept
{
return { -c.X, -c.Y };
}
inline bool operator==(const Microsoft::Console::Types::Viewport& a,
const Microsoft::Console::Types::Viewport& b) noexcept
{
return a.ToInclusive() == b.ToInclusive();
}
inline bool operator!=(const Microsoft::Console::Types::Viewport& a,
const Microsoft::Console::Types::Viewport& b) noexcept
{
return !(a == b);
}

View File

@ -22,44 +22,48 @@ class ConPtyTests
TEST_METHOD(DiesOnClose);
};
HRESULT _CreatePseudoConsole(const COORD size,
const HANDLE hInput,
const HANDLE hOutput,
const DWORD dwFlags,
_Inout_ PseudoConsole* pPty)
static HRESULT _CreatePseudoConsole(const COORD size,
const HANDLE hInput,
const HANDLE hOutput,
const DWORD dwFlags,
_Inout_ PseudoConsole* pPty)
{
return _CreatePseudoConsole(INVALID_HANDLE_VALUE, size, hInput, hOutput, dwFlags, pPty);
}
HRESULT AttachPseudoConsole(HPCON hPC, LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList)
static HRESULT AttachPseudoConsole(HPCON hPC, std::wstring& command, PROCESS_INFORMATION* ppi)
{
BOOL fSuccess = UpdateProcThreadAttribute(lpAttributeList,
0,
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
hPC,
sizeof(HANDLE),
nullptr,
nullptr);
return fSuccess ? S_OK : HRESULT_FROM_WIN32(GetLastError());
}
SIZE_T size = 0;
InitializeProcThreadAttributeList(nullptr, 1, 0, &size);
RETURN_LAST_ERROR_IF(size == 0);
void _CreateChildProcess(std::wstring& command, STARTUPINFOEXW* psiEx, PROCESS_INFORMATION* ppi)
{
std::unique_ptr<wchar_t[]> mutableCommandline = std::make_unique<wchar_t[]>(command.length() + 1);
VERIFY_IS_NOT_NULL(mutableCommandline);
VERIFY_SUCCEEDED(StringCchCopyW(mutableCommandline.get(), command.length() + 1, command.c_str()));
VERIFY_IS_TRUE(CreateProcessW(
const auto buffer = std::make_unique<std::byte[]>(gsl::narrow_cast<size_t>(size));
STARTUPINFOEXW siEx{};
siEx.StartupInfo.cb = sizeof(STARTUPINFOEXW);
siEx.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(buffer.get());
RETURN_IF_WIN32_BOOL_FALSE(InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &size));
auto deleteAttrList = wil::scope_exit([&] {
DeleteProcThreadAttributeList(siEx.lpAttributeList);
});
RETURN_IF_WIN32_BOOL_FALSE(UpdateProcThreadAttribute(siEx.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, hPC, sizeof(HANDLE), nullptr, nullptr));
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
nullptr,
mutableCommandline.get(),
command.data(),
nullptr, // lpProcessAttributes
nullptr, // lpThreadAttributes
true, // bInheritHandles
EXTENDED_STARTUPINFO_PRESENT, // dwCreationFlags
nullptr, // lpEnvironment
nullptr, // lpCurrentDirectory
&psiEx->StartupInfo, // lpStartupInfo
&siEx.StartupInfo, // lpStartupInfo
ppi // lpProcessInformation
));
return S_OK;
}
void ConPtyTests::CreateConPtyNoPipes()
@ -200,27 +204,9 @@ void ConPtyTests::SurvivesOnBreakInput()
VERIFY_IS_TRUE(GetExitCodeProcess(pty.hConPtyProcess, &dwExit));
VERIFY_ARE_EQUAL(dwExit, (DWORD)STILL_ACTIVE);
STARTUPINFOEXW siEx;
siEx = { 0 };
siEx.StartupInfo.cb = sizeof(STARTUPINFOEXW);
size_t size;
VERIFY_IS_FALSE(InitializeProcThreadAttributeList(NULL, 1, 0, (PSIZE_T)&size));
BYTE* attrList = new BYTE[size];
auto freeAttrList = wil::scope_exit([&] {
delete[] attrList;
});
siEx.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(attrList);
VERIFY_IS_TRUE(InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, (PSIZE_T)&size));
auto deleteAttrList = wil::scope_exit([&] {
DeleteProcThreadAttributeList(siEx.lpAttributeList);
});
VERIFY_SUCCEEDED(
AttachPseudoConsole(reinterpret_cast<HPCON>(&pty), siEx.lpAttributeList));
wil::unique_process_information piClient;
std::wstring realCommand = L"cmd.exe";
_CreateChildProcess(realCommand, &siEx, piClient.addressof());
VERIFY_SUCCEEDED(AttachPseudoConsole(&pty, realCommand, piClient.addressof()));
VERIFY_IS_TRUE(GetExitCodeProcess(piClient.hProcess, &dwExit));
VERIFY_ARE_EQUAL(dwExit, (DWORD)STILL_ACTIVE);
@ -263,27 +249,9 @@ void ConPtyTests::SurvivesOnBreakOutput()
VERIFY_IS_TRUE(GetExitCodeProcess(pty.hConPtyProcess, &dwExit));
VERIFY_ARE_EQUAL(dwExit, (DWORD)STILL_ACTIVE);
STARTUPINFOEXW siEx;
siEx = { 0 };
siEx.StartupInfo.cb = sizeof(STARTUPINFOEXW);
size_t size;
VERIFY_IS_FALSE(InitializeProcThreadAttributeList(NULL, 1, 0, (PSIZE_T)&size));
BYTE* attrList = new BYTE[size];
auto freeAttrList = wil::scope_exit([&] {
delete[] attrList;
});
siEx.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(attrList);
VERIFY_IS_TRUE(InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, (PSIZE_T)&size));
auto deleteAttrList = wil::scope_exit([&] {
DeleteProcThreadAttributeList(siEx.lpAttributeList);
});
VERIFY_SUCCEEDED(
AttachPseudoConsole(reinterpret_cast<HPCON>(&pty), siEx.lpAttributeList));
wil::unique_process_information piClient;
std::wstring realCommand = L"cmd.exe";
_CreateChildProcess(realCommand, &siEx, piClient.addressof());
VERIFY_SUCCEEDED(AttachPseudoConsole(&pty, realCommand, piClient.addressof()));
VERIFY_IS_TRUE(GetExitCodeProcess(piClient.hProcess, &dwExit));
VERIFY_ARE_EQUAL(dwExit, (DWORD)STILL_ACTIVE);
@ -326,27 +294,9 @@ void ConPtyTests::DiesOnBreakBoth()
VERIFY_IS_TRUE(GetExitCodeProcess(pty.hConPtyProcess, &dwExit));
VERIFY_ARE_EQUAL(dwExit, (DWORD)STILL_ACTIVE);
STARTUPINFOEXW siEx;
siEx = { 0 };
siEx.StartupInfo.cb = sizeof(STARTUPINFOEXW);
size_t size;
VERIFY_IS_FALSE(InitializeProcThreadAttributeList(NULL, 1, 0, (PSIZE_T)&size));
BYTE* attrList = new BYTE[size];
auto freeAttrList = wil::scope_exit([&] {
delete[] attrList;
});
siEx.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(attrList);
VERIFY_IS_TRUE(InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, (PSIZE_T)&size));
auto deleteAttrList = wil::scope_exit([&] {
DeleteProcThreadAttributeList(siEx.lpAttributeList);
});
VERIFY_SUCCEEDED(
AttachPseudoConsole(reinterpret_cast<HPCON>(&pty), siEx.lpAttributeList));
wil::unique_process_information piClient;
std::wstring realCommand = L"cmd.exe";
_CreateChildProcess(realCommand, &siEx, piClient.addressof());
VERIFY_SUCCEEDED(AttachPseudoConsole(&pty, realCommand, piClient.addressof()));
VERIFY_IS_TRUE(GetExitCodeProcess(piClient.hProcess, &dwExit));
VERIFY_ARE_EQUAL(dwExit, (DWORD)STILL_ACTIVE);
@ -415,27 +365,9 @@ void ConPtyTests::DiesOnClose()
VERIFY_IS_TRUE(GetExitCodeProcess(pty.hConPtyProcess, &dwExit));
VERIFY_ARE_EQUAL(dwExit, (DWORD)STILL_ACTIVE);
STARTUPINFOEXW siEx;
siEx = { 0 };
siEx.StartupInfo.cb = sizeof(STARTUPINFOEXW);
size_t size;
VERIFY_IS_FALSE(InitializeProcThreadAttributeList(NULL, 1, 0, (PSIZE_T)&size));
BYTE* attrList = new BYTE[size];
auto freeAttrList = wil::scope_exit([&] {
delete[] attrList;
});
siEx.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(attrList);
VERIFY_IS_TRUE(InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, (PSIZE_T)&size));
auto deleteAttrList = wil::scope_exit([&] {
DeleteProcThreadAttributeList(siEx.lpAttributeList);
});
VERIFY_SUCCEEDED(
AttachPseudoConsole(reinterpret_cast<HPCON>(&pty), siEx.lpAttributeList));
wil::unique_process_information piClient;
std::wstring realCommand = testCommandline;
_CreateChildProcess(realCommand, &siEx, piClient.addressof());
std::wstring realCommand(reinterpret_cast<const wchar_t*>(testCommandline.GetBuffer()), testCommandline.GetLength());
VERIFY_SUCCEEDED(AttachPseudoConsole(&pty, realCommand, piClient.addressof()));
VERIFY_IS_TRUE(GetExitCodeProcess(piClient.hProcess, &dwExit));
VERIFY_ARE_EQUAL(dwExit, (DWORD)STILL_ACTIVE);