2121using namespace lldb ;
2222using namespace lldb_private ;
2323
24- static void CreateEnvironmentBuffer (const Environment &env,
25- std::vector<char > &buffer) {
26- // The buffer is a list of null-terminated UTF-16 strings, followed by an
27- // extra L'\0' (two bytes of 0). An empty environment must have one
28- // empty string, followed by an extra L'\0'.
24+ // / Create a UTF-16 environment block to use with CreateProcessW.
25+ // /
26+ // / The buffer is a sequence of null-terminated UTF-16 strings, followed by an
27+ // / extra L'\0' (two bytes of 0). An empty environment must have one
28+ // / empty string, followed by an extra L'\0'.
29+ // /
30+ // / The keys are sorted to comply with the CreateProcess API calling convention.
31+ // /
32+ // / Ensure that the resulting buffer is used in conjunction with
33+ // / CreateProcessW and be sure that dwCreationFlags includes
34+ // / CREATE_UNICODE_ENVIRONMENT.
35+ // /
36+ // / \param env The Environment object to convert.
37+ // / \returns The sorted sequence of environment variables and their values,
38+ // / separated by null terminators. The vector is guaranteed to never be empty.
39+ static std::vector<wchar_t > CreateEnvironmentBufferW (const Environment &env) {
40+ std::vector<std::wstring> env_entries;
2941 for (const auto &KV : env) {
30- std::wstring warg;
31- if (llvm::ConvertUTF8toWide (Environment::compose (KV), warg)) {
32- buffer.insert (
33- buffer.end (), reinterpret_cast <const char *>(warg.c_str ()),
34- reinterpret_cast <const char *>(warg.c_str () + warg.size () + 1 ));
35- }
42+ std::wstring wentry;
43+ if (llvm::ConvertUTF8toWide (Environment::compose (KV), wentry))
44+ env_entries.push_back (std::move (wentry));
45+ }
46+ std::sort (env_entries.begin (), env_entries.end (),
47+ [](const std::wstring &a, const std::wstring &b) {
48+ return _wcsicmp (a.c_str (), b.c_str ()) < 0 ;
49+ });
50+
51+ std::vector<wchar_t > buffer;
52+ for (const auto &env_entry : env_entries) {
53+ buffer.insert (buffer.end (), env_entry.begin (), env_entry.end ());
54+ buffer.push_back (L' \0 ' );
3655 }
37- // One null wchar_t (to end the block) is two null bytes
38- buffer.push_back (0 );
39- buffer.push_back (0 );
40- // Insert extra two bytes, just in case the environment was empty.
41- buffer.push_back (0 );
42- buffer.push_back (0 );
56+
57+ if (buffer.empty ())
58+ buffer.push_back (L' \0 ' ); // If there are no environment variables, we have
59+ // to ensure there are 4 zero bytes in the buffer.
60+ buffer.push_back (L' \0 ' );
61+
62+ return buffer;
4363}
4464
45- static bool GetFlattenedWindowsCommandString (Args args, std::wstring &command) {
65+ // / Flattens an Args object into a Windows command-line wide string.
66+ // /
67+ // / Returns an empty string if args is empty.
68+ // /
69+ // / \param args The Args object to flatten.
70+ // / \returns A wide string containing the flattened command line.
71+ static llvm::ErrorOr<std::wstring>
72+ GetFlattenedWindowsCommandStringW (Args args) {
4673 if (args.empty ())
47- return false ;
74+ return L" " ;
4875
4976 std::vector<llvm::StringRef> args_ref;
5077 for (auto &entry : args.entries ())
5178 args_ref.push_back (entry.ref ());
5279
53- llvm::ErrorOr<std::wstring> result =
54- llvm::sys::flattenWindowsCommandLine (args_ref);
55- if (result.getError ())
56- return false ;
57-
58- command = *result;
59- return true ;
80+ return llvm::sys::flattenWindowsCommandLine (args_ref);
6081}
6182
6283HostProcess
@@ -65,9 +86,8 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
6586 error.Clear ();
6687
6788 std::string executable;
68- std::vector<char > environment;
69- STARTUPINFOEX startupinfoex = {};
70- STARTUPINFO &startupinfo = startupinfoex.StartupInfo ;
89+ STARTUPINFOEXW startupinfoex = {};
90+ STARTUPINFOW &startupinfo = startupinfoex.StartupInfo ;
7191 PROCESS_INFORMATION pi = {};
7292
7393 HANDLE stdin_handle = GetStdioHandle (launch_info, STDIN_FILENO);
@@ -149,28 +169,32 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
149169 if (launch_info.GetFlags ().Test (eLaunchFlagDisableSTDIO))
150170 flags &= ~CREATE_NEW_CONSOLE;
151171
152- LPVOID env_block = nullptr ;
153- ::CreateEnvironmentBuffer (launch_info.GetEnvironment(), environment);
154- env_block = environment.data ();
155-
156- executable = launch_info.GetExecutableFile ().GetPath ();
157- std::wstring wcommandLine;
158- GetFlattenedWindowsCommandString (launch_info.GetArguments (), wcommandLine);
172+ std::vector<wchar_t > environment =
173+ CreateEnvironmentBufferW (launch_info.GetEnvironment ());
159174
160- std::wstring wexecutable, wworkingDirectory;
161- llvm::ConvertUTF8toWide (executable, wexecutable);
162- llvm::ConvertUTF8toWide (launch_info.GetWorkingDirectory ().GetPath (),
163- wworkingDirectory);
175+ auto wcommandLineOrErr =
176+ GetFlattenedWindowsCommandStringW (launch_info.GetArguments ());
177+ if (!wcommandLineOrErr) {
178+ error = Status (wcommandLineOrErr.getError ());
179+ return HostProcess ();
180+ }
181+ std::wstring wcommandLine = *wcommandLineOrErr;
164182 // If the command line is empty, it's best to pass a null pointer to tell
165183 // CreateProcessW to use the executable name as the command line. If the
166184 // command line is not empty, its contents may be modified by CreateProcessW.
167185 WCHAR *pwcommandLine = wcommandLine.empty () ? nullptr : &wcommandLine[0 ];
168186
187+ std::wstring wexecutable, wworkingDirectory;
188+ llvm::ConvertUTF8toWide (launch_info.GetExecutableFile ().GetPath (),
189+ wexecutable);
190+ llvm::ConvertUTF8toWide (launch_info.GetWorkingDirectory ().GetPath (),
191+ wworkingDirectory);
192+
169193 BOOL result = ::CreateProcessW (
170194 wexecutable.c_str (), pwcommandLine, NULL , NULL ,
171- /* bInheritHandles=*/ !inherited_handles.empty (), flags, env_block ,
195+ /* bInheritHandles=*/ !inherited_handles.empty (), flags, environment. data () ,
172196 wworkingDirectory.size () == 0 ? NULL : wworkingDirectory.c_str (),
173- reinterpret_cast <STARTUPINFO *>(&startupinfoex), &pi);
197+ reinterpret_cast <STARTUPINFOW *>(&startupinfoex), &pi);
174198
175199 if (!result) {
176200 // Call GetLastError before we make any other system calls.
0 commit comments