[Suggestion] Some code improvement suggestions #671

Open
opened 2026-01-30 21:58:59 +00:00 by claunia · 0 comments
Owner

Originally created by @fcharlie on GitHub (May 7, 2019).

35229a775d/src/inc/conpty.h (L90)

Open source for Windows Terminal should be the most exciting thing for Build2019, thank you.
I have some suggestions here.

First, using std::wstringstream is not a good choice. You can choose to use a function like absl::StrCat to implement string concatenation. Here is an implementation of wchar_t: https://github.com/M2Team/Privexec/blob/master/include/strcat.hpp

second. In C++17, std::string has a non-constant data() function, so you can use conhostCmdline.data() directly; the improved code is as follows:

__declspec(noinline) inline
HRESULT CreateConPty(const std::wstring& cmdline,
                     const unsigned short w,
                     const unsigned short h,
                     HANDLE* const hInput,
                     HANDLE* const hOutput,
                     HANDLE* const hSignal,
                     PROCESS_INFORMATION* const piPty)
{
    // Create some anon pipes so we can pass handles down and into the console.
    // IMPORTANT NOTE:
    // We're creating the pipe here with un-inheritable handles, then marking
    //      the conhost sides of the pipes as inheritable. We do this because if
    //      the entire pipe is marked as inheritable, when we pass the handles
    //      to CreateProcess, at some point the entire pipe object is copied to
    //      the conhost process, which includes the terminal side of the pipes
    //      (_inPipe and _outPipe). This means that if we die, there's still
    //      outstanding handles to our side of the pipes, and those handles are
    //      in conhost, despite conhost being unable to reference those handles
    //      and close them.
    // CRITICAL: Close our side of the handles. Otherwise you'll get the same
    //      problem if you close conhost, but not us (the terminal).
    HANDLE outPipeConhostSide;
    HANDLE inPipeConhostSide;
    HANDLE signalPipeConhostSide;

    SECURITY_ATTRIBUTES sa;
    sa = {0};
    sa.nLength = sizeof(sa);
    sa.bInheritHandle = FALSE;
    sa.lpSecurityDescriptor = nullptr;

    CreatePipe(&inPipeConhostSide, hInput, &sa, 0);
    CreatePipe(hOutput, &outPipeConhostSide, &sa, 0);

    // Mark inheritable for signal handle when creating. It'll have the same value on the other side.
    sa.bInheritHandle = TRUE;
    CreatePipe(&signalPipeConhostSide, hSignal, &sa, 0);

    SetHandleInformation(inPipeConhostSide, HANDLE_FLAG_INHERIT, 1);
    SetHandleInformation(outPipeConhostSide, HANDLE_FLAG_INHERIT, 1);

    std::wstring conhostCmdline;
    if(w!=0 && h!=0){
    	conhostCmdline=base::StringCat(L"conhost.exe --headless --width ",w,L" --height ",
    		h,L" --signal 0x",base::Hex(HandleToUlong(signalPipeConhostSide)),L" -- ",cmdline);
    }else{
    	conhostCmdline=base::StringCat(L"conhost.exe --headless --signal 0x",base::Hex(HandleToUlong(signalPipeConhostSide)),L" -- ",cmdline);
    }
  
    STARTUPINFO si = {0};
    si.cb = sizeof(STARTUPINFOW);
    si.hStdInput = inPipeConhostSide;
    si.hStdOutput = outPipeConhostSide;
    si.hStdError = outPipeConhostSide;
    si.dwFlags |= STARTF_USESTDHANDLES;

    bool fSuccess = CreateProcessW(
        nullptr,
        conhostCmdline.data(), // https://en.cppreference.com/w/cpp/string/basic_string/data  C++17: CharT* data() noexcept;
        nullptr,    // lpProcessAttributes
        nullptr,    // lpThreadAttributes
        true,       // bInheritHandles
        0,          // dwCreationFlags
        nullptr,    // lpEnvironment
        nullptr,    // lpCurrentDirectory
        &si,        // lpStartupInfo
        piPty       // lpProcessInformation
    )==TRUE;

    CloseHandle(inPipeConhostSide);
    CloseHandle(outPipeConhostSide);
    CloseHandle(signalPipeConhostSide);

    return fSuccess ? S_OK : HRESULT_FROM_WIN32(GetLastError());
}
Originally created by @fcharlie on GitHub (May 7, 2019). https://github.com/microsoft/Terminal/blob/35229a775d9e9908a8dfb102e01f49b494b29194/src/inc/conpty.h#L90 Open source for Windows Terminal should be the most exciting thing for Build2019, thank you. I have some suggestions here. First, using std::wstringstream is not a good choice. You can choose to use a function like [absl::StrCat](https://github.com/abseil/abseil-cpp/blob/master/absl/strings/str_cat.h) to implement string concatenation. Here is an implementation of wchar_t: [https://github.com/M2Team/Privexec/blob/master/include/strcat.hpp](https://github.com/M2Team/Privexec/blob/master/include/strcat.hpp) second. In C++17, std::string has a non-constant `data()` function, so you can use `conhostCmdline.data()` directly; the improved code is as follows: ```c++ __declspec(noinline) inline HRESULT CreateConPty(const std::wstring& cmdline, const unsigned short w, const unsigned short h, HANDLE* const hInput, HANDLE* const hOutput, HANDLE* const hSignal, PROCESS_INFORMATION* const piPty) { // Create some anon pipes so we can pass handles down and into the console. // IMPORTANT NOTE: // We're creating the pipe here with un-inheritable handles, then marking // the conhost sides of the pipes as inheritable. We do this because if // the entire pipe is marked as inheritable, when we pass the handles // to CreateProcess, at some point the entire pipe object is copied to // the conhost process, which includes the terminal side of the pipes // (_inPipe and _outPipe). This means that if we die, there's still // outstanding handles to our side of the pipes, and those handles are // in conhost, despite conhost being unable to reference those handles // and close them. // CRITICAL: Close our side of the handles. Otherwise you'll get the same // problem if you close conhost, but not us (the terminal). HANDLE outPipeConhostSide; HANDLE inPipeConhostSide; HANDLE signalPipeConhostSide; SECURITY_ATTRIBUTES sa; sa = {0}; sa.nLength = sizeof(sa); sa.bInheritHandle = FALSE; sa.lpSecurityDescriptor = nullptr; CreatePipe(&inPipeConhostSide, hInput, &sa, 0); CreatePipe(hOutput, &outPipeConhostSide, &sa, 0); // Mark inheritable for signal handle when creating. It'll have the same value on the other side. sa.bInheritHandle = TRUE; CreatePipe(&signalPipeConhostSide, hSignal, &sa, 0); SetHandleInformation(inPipeConhostSide, HANDLE_FLAG_INHERIT, 1); SetHandleInformation(outPipeConhostSide, HANDLE_FLAG_INHERIT, 1); std::wstring conhostCmdline; if(w!=0 && h!=0){ conhostCmdline=base::StringCat(L"conhost.exe --headless --width ",w,L" --height ", h,L" --signal 0x",base::Hex(HandleToUlong(signalPipeConhostSide)),L" -- ",cmdline); }else{ conhostCmdline=base::StringCat(L"conhost.exe --headless --signal 0x",base::Hex(HandleToUlong(signalPipeConhostSide)),L" -- ",cmdline); } STARTUPINFO si = {0}; si.cb = sizeof(STARTUPINFOW); si.hStdInput = inPipeConhostSide; si.hStdOutput = outPipeConhostSide; si.hStdError = outPipeConhostSide; si.dwFlags |= STARTF_USESTDHANDLES; bool fSuccess = CreateProcessW( nullptr, conhostCmdline.data(), // https://en.cppreference.com/w/cpp/string/basic_string/data C++17: CharT* data() noexcept; nullptr, // lpProcessAttributes nullptr, // lpThreadAttributes true, // bInheritHandles 0, // dwCreationFlags nullptr, // lpEnvironment nullptr, // lpCurrentDirectory &si, // lpStartupInfo piPty // lpProcessInformation )==TRUE; CloseHandle(inPipeConhostSide); CloseHandle(outPipeConhostSide); CloseHandle(signalPipeConhostSide); return fSuccess ? S_OK : HRESULT_FROM_WIN32(GetLastError()); } ```
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#671