Skip to content

windows_create_process() does not pass parent environment to child when caller requests to set environment variables #1782

@j6t

Description

@j6t

I use vcpkg in a Visual Studio solution. I observe this error when a new package dependency is added that has not been built, yet:

1>Installing vcpkg dependencies to D:\Projects\VCS\vcpkg_installed\x64-windows-static-md\
1>"D:\Src\vcpkg\vcpkg.exe" install  --x-wait-for-lock --triplet "x64-windows-static-md" --vcpkg-root "D:\Src\vcpkg\\" "--x-manifest-root=D:\Projects\VCS\\" "--x-install-root=D:\Projects\VCS\vcpkg_installed\x64-windows-static-md\\"
1>EXEC : error : "C:\GIT\bin\git.exe" --git-dir "C:\Users\jsixt\AppData\Local\vcpkg\registries\git\.git" -c core.autocrlf=false read-tree 37702e8740157c39e52d0d254487c1811b7e1d7c failed with exit code 3221225781
1>
1>note: while loading [email protected]
1>
1>D:\Src\vcpkg\scripts\buildsystems\msbuild\vcpkg.targets(183,5): error MSB3073: The command ""D:\Src\vcpkg\vcpkg.exe" install  --x-wait-for-lock --triplet "x64-windows-static-md" --vcpkg-root "D:\Src\vcpkg\\" "--x-manifest-root=D:\Projects\VCS\\" "--x-install-root=D:\Projects\VCS\vcpkg_installed\x64-windows-static-md\\" " exited with code 1.

Code 3221225781 is 0xC0000135, but the actual reason is that a DLL is not found.

As can be seen, I have git installed in a non-standard location. To run this git.exe, it is essential to have PATH available that points to the MinGW installation directories. But it is not.

If I copy the missing DLLs next to git.exe, they are found and things work again. But this is by no means a desirable situation.

Here is a Process Monitor screenshot that shows that some invocations of git.exe are successful (when the complete environment was passed on), and that the one fails where the environment has just a single entry.

Image

The reason for the failure is that windows_create_process makes no attempt to transfer the complete environment when it has to insert additional variables:

std::wstring environment_block;
LPVOID call_environment = nullptr;
if (auto env_unpacked = environment.get())
{
environment_block = env_unpacked->get();
environment_block.push_back('\0');
call_environment = environment_block.data();
}
// Leaking process information handle 'process_info.proc_info.hProcess'
// /analyze can't tell that we transferred ownership here
VCPKG_MSVC_WARNING(suppress : 6335)
if (!CreateProcessW(nullptr,
Strings::to_utf16(command_line).data(),
nullptr,
nullptr,
bInheritHandles,
IDLE_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT |
dwCreationFlags,
call_environment,
working_directory_arg,
&startup_info.StartupInfo,
&process_info))

In the case when the caller requests no change in the environment, nullptr is passed to CreateProcessW, so that it inherits the full environment. But if new environment variables are requested, only those are inherited and any existing values, including PATH, are not inherited.

My system is
Edition Windows 10 Pro
Version 22H2
Installed ‎1/‎22/‎2022
OS build 19045.6216
Windows Feature Experience Pack 1000.19062.1000.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions