Repository: microsoft/terminal
File: src/server/ConsoleShimPolicy.cpp (C++)

Code before:
// Routine Description:
// - Constructs a new instance of the shim policy class.
// Arguments:
// - All arguments specify a true/false status to a policy that could be applied to a console client app.
ConsoleShimPolicy::ConsoleShimPolicy(const HANDLE hProcess)
{
    // If we cannot determine the exe name, then we're probably not cmd or powershell.
    try
    {
        const std::filesystem::path processName = wil::GetModuleFileNameExW<std::wstring>(hProcess, nullptr);
        auto clientName = processName.filename().wstring();
        // For whatever reason, wil::GetModuleFileNameExW leaves trailing nulls, so get rid of them.
        clientName.erase(std::find(clientName.begin(), clientName.end(), '\0'), clientName.end());

        // Convert to lower case, just in case
        std::transform(clientName.begin(), clientName.end(), clientName.begin(), std::towlower);

        _isCmd = clientName.compare(L"cmd.exe") == 0;

        // For powershell, we need both Windows PowersShell (powershell.exe) and
        // PowerShell Core (pwsh.exe). If PowerShell Core is ever updated to use
        // ^[[3J for Clear-Host, then it won't ever hit the shim code path, but
        // we're keeping this for the long tail of pwsh versions that still
        // _don't_ use that sequence.
        const auto isInboxPowershell = clientName.compare(L"powershell.exe") == 0;
        const auto isPwsh = clientName.compare(L"pwsh.exe") == 0;
        _isPowershell = isInboxPowershell || isPwsh;

        // Inside Windows, we are guaranteed that we're building alongside a new (good) inbox PowerShell.
        // Therefore, we can default _requiresVtColorQuirk to false.
#ifndef __INSIDE_WINDOWS
        // Outside of Windows, we need to check the OS version: PowerShell was fixed in early Iron builds.
        static auto doesInboxPowershellVersionRequireQuirk = [] {
            OSVERSIONINFOEXW osver{};
            osver.dwOSVersionInfoSize = sizeof(osver);
            osver.dwBuildNumber = 20348; // Windows Server 2022 RTM

            DWORDLONG dwlConditionMask = 0;
            VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_LESS);

            return VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE;
        }();
        _requiresVtColorQuirk = isInboxPowershell && doesInboxPowershellVersionRequireQuirk;
        // All modern versions of pwsh.exe have been fixed, and we can direct users to update.
#endif
    }
    CATCH_LOG();
}

// Method Description:
// - Returns true if the connected client application is literally "cmd.exe". If

Review comment (security):
BTW even though it says on the tin `towlower`, as in "I support UCS-2", what's actually inside the can is "I'm locale dependent and so by default I actually only convert code points <256". See here: https://godbolt.org/z/Wjcefx3vs

If we need to write such code in the future, lets use [`CompareStringOrdinal`](https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-comparestringordinal) which among others specifically exists for exactly such path comparisons (see [here](https://docs.microsoft.com/en-us/windows/win32/intl/handling-sorting-in-your-applications#sort-strings-ordinally)). 🙂 In this particular case however we're dealing with a plain ASCII comparison, so `til::equals_insensitive_ascii` can be used without the above `std::transform`.

Code after:
// Routine Description:
// - Constructs a new instance of the shim policy class.
// Arguments:
// - All arguments specify a true/false status to a policy that could be applied to a console client app.
ConsoleShimPolicy::ConsoleShimPolicy(const HANDLE hProcess)
{
    // If we cannot determine the exe name, then we're probably not cmd or powershell.
    try
    {
        const std::filesystem::path processName = wil::GetModuleFileNameExW<std::wstring>(hProcess, nullptr);
        const auto clientName = processName.filename().native();

        _isCmd = til::equals_insensitive_ascii(clientName, L"cmd.exe");

        // For powershell, we need both Windows Powershell (powershell.exe) and
        // Powershell Core (pwsh.exe). If Powershell Core is ever updated to use
        // ^[[3J for Clear-Host, then it won't ever hit the shim code path, but
        // we're keeping this for the long tail of pwsh versions that still
        // _don't_ use that sequence.
        const auto isInboxPowershell = til::equals_insensitive_ascii(clientName, L"powershell.exe");
        const auto isPwsh = til::equals_insensitive_ascii(clientName, L"pwsh.exe");
        _isPowershell = isInboxPowershell || isPwsh;

        // Inside Windows, we are guaranteed that we're building alongside a new (good) inbox Powershell.
        // Therefore, we can default _requiresVtColorQuirk to false.
#ifndef __INSIDE_WINDOWS
        // Outside of Windows, we need to check the OS version: Powershell was fixed in early Iron builds.
        static auto doesInboxPowershellVersionRequireQuirk = [] {
            OSVERSIONINFOEXW osver{};
            osver.dwOSVersionInfoSize = sizeof(osver);
            osver.dwBuildNumber = 20348; // Windows Server 2022 RTM

            DWORDLONG dwlConditionMask = 0;
            VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_LESS);

            return VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE;
        }();
        _requiresVtColorQuirk = isInboxPowershell && doesInboxPowershellVersionRequireQuirk;
        // All modern versions of pwsh.exe have been fixed, and we can direct users to update.
#endif
    }
    CATCH_LOG();
}

// Method Description:
// - Returns true if the connected client application is literally "cmd.exe". If
//   it is, we'll need to enable certain compatibility shims.
// Arguments:
// - <none>
// Return Value:
// - rue iff the process is "cmd.exe"