[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / lib / Support / Windows / Program.inc
blob824834c1cbbe95eeacdb897dbdf62f54f5baa028
1 //===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file provides the Win32 specific implementation of the Program class.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ADT/StringExtras.h"
14 #include "llvm/Support/ConvertUTF.h"
15 #include "llvm/Support/Errc.h"
16 #include "llvm/Support/FileSystem.h"
17 #include "llvm/Support/Path.h"
18 #include "llvm/Support/Windows/WindowsSupport.h"
19 #include "llvm/Support/WindowsError.h"
20 #include "llvm/Support/raw_ostream.h"
21 #include <psapi.h>
22 #include <cstdio>
23 #include <fcntl.h>
24 #include <io.h>
25 #include <malloc.h>
26 #include <numeric>
28 //===----------------------------------------------------------------------===//
29 //=== WARNING: Implementation here must contain only Win32 specific code
30 //===          and must not be UNIX code
31 //===----------------------------------------------------------------------===//
33 namespace llvm {
35 ProcessInfo::ProcessInfo() : Pid(0), Process(0), ReturnCode(0) {}
37 ErrorOr<std::string> sys::findProgramByName(StringRef Name,
38                                             ArrayRef<StringRef> Paths) {
39   assert(!Name.empty() && "Must have a name!");
41   if (Name.find_first_of("/\\") != StringRef::npos)
42     return std::string(Name);
44   const wchar_t *Path = nullptr;
45   std::wstring PathStorage;
46   if (!Paths.empty()) {
47     PathStorage.reserve(Paths.size() * MAX_PATH);
48     for (unsigned i = 0; i < Paths.size(); ++i) {
49       if (i)
50         PathStorage.push_back(L';');
51       StringRef P = Paths[i];
52       SmallVector<wchar_t, MAX_PATH> TmpPath;
53       if (std::error_code EC = windows::UTF8ToUTF16(P, TmpPath))
54         return EC;
55       PathStorage.append(TmpPath.begin(), TmpPath.end());
56     }
57     Path = PathStorage.c_str();
58   }
60   SmallVector<wchar_t, MAX_PATH> U16Name;
61   if (std::error_code EC = windows::UTF8ToUTF16(Name, U16Name))
62     return EC;
64   SmallVector<StringRef, 12> PathExts;
65   PathExts.push_back("");
66   PathExts.push_back(".exe"); // FIXME: This must be in %PATHEXT%.
67   if (const char *PathExtEnv = std::getenv("PATHEXT"))
68     SplitString(PathExtEnv, PathExts, ";");
70   SmallVector<char, MAX_PATH> U8Result;
71   for (StringRef Ext : PathExts) {
72     SmallVector<wchar_t, MAX_PATH> U16Result;
73     DWORD Len = MAX_PATH;
74     do {
75       U16Result.reserve(Len);
76       // Lets attach the extension manually. That is needed for files
77       // with a point in name like aaa.bbb. SearchPathW will not add extension
78       // from its argument to such files because it thinks they already had one.
79       SmallVector<wchar_t, MAX_PATH> U16NameExt;
80       if (std::error_code EC =
81               windows::UTF8ToUTF16(Twine(Name + Ext).str(), U16NameExt))
82         return EC;
84       Len = ::SearchPathW(Path, c_str(U16NameExt), nullptr,
85                           U16Result.capacity(), U16Result.data(), nullptr);
86     } while (Len > U16Result.capacity());
88     if (Len == 0)
89       continue;
91     U16Result.set_size(Len);
93     if (std::error_code EC =
94         windows::UTF16ToUTF8(U16Result.data(), U16Result.size(), U8Result))
95       return EC;
97     if (sys::fs::can_execute(U8Result))
98       break; // Found it.
100     U8Result.clear();
101   }
103   if (U8Result.empty())
104     return mapWindowsError(::GetLastError());
106   return std::string(U8Result.begin(), U8Result.end());
109 bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix) {
110   if (!ErrMsg)
111     return true;
112   char *buffer = NULL;
113   DWORD LastError = GetLastError();
114   DWORD R = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
115                                FORMAT_MESSAGE_FROM_SYSTEM |
116                                FORMAT_MESSAGE_MAX_WIDTH_MASK,
117                            NULL, LastError, 0, (LPSTR)&buffer, 1, NULL);
118   if (R)
119     *ErrMsg = prefix + ": " + buffer;
120   else
121     *ErrMsg = prefix + ": Unknown error";
122   *ErrMsg += " (0x" + llvm::utohexstr(LastError) + ")";
124   LocalFree(buffer);
125   return R != 0;
128 static HANDLE RedirectIO(Optional<StringRef> Path, int fd,
129                          std::string *ErrMsg) {
130   HANDLE h;
131   if (!Path) {
132     if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
133                          GetCurrentProcess(), &h,
134                          0, TRUE, DUPLICATE_SAME_ACCESS))
135       return INVALID_HANDLE_VALUE;
136     return h;
137   }
139   std::string fname;
140   if (Path->empty())
141     fname = "NUL";
142   else
143     fname = std::string(*Path);
145   SECURITY_ATTRIBUTES sa;
146   sa.nLength = sizeof(sa);
147   sa.lpSecurityDescriptor = 0;
148   sa.bInheritHandle = TRUE;
150   SmallVector<wchar_t, 128> fnameUnicode;
151   if (Path->empty()) {
152     // Don't play long-path tricks on "NUL".
153     if (windows::UTF8ToUTF16(fname, fnameUnicode))
154       return INVALID_HANDLE_VALUE;
155   } else {
156     if (sys::windows::widenPath(fname, fnameUnicode))
157       return INVALID_HANDLE_VALUE;
158   }
159   h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ,
160                   FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS,
161                   FILE_ATTRIBUTE_NORMAL, NULL);
162   if (h == INVALID_HANDLE_VALUE) {
163     MakeErrMsg(ErrMsg, fname + ": Can't open file for " +
164         (fd ? "input" : "output"));
165   }
167   return h;
172 static bool Execute(ProcessInfo &PI, StringRef Program,
173                     ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env,
174                     ArrayRef<Optional<StringRef>> Redirects,
175                     unsigned MemoryLimit, std::string *ErrMsg,
176                     BitVector *AffinityMask) {
177   if (!sys::fs::can_execute(Program)) {
178     if (ErrMsg)
179       *ErrMsg = "program not executable";
180     return false;
181   }
183   // can_execute may succeed by looking at Program + ".exe". CreateProcessW
184   // will implicitly add the .exe if we provide a command line without an
185   // executable path, but since we use an explicit executable, we have to add
186   // ".exe" ourselves.
187   SmallString<64> ProgramStorage;
188   if (!sys::fs::exists(Program))
189     Program = Twine(Program + ".exe").toStringRef(ProgramStorage);
191   // Windows wants a command line, not an array of args, to pass to the new
192   // process.  We have to concatenate them all, while quoting the args that
193   // have embedded spaces (or are empty).
194   auto Result = flattenWindowsCommandLine(Args);
195   if (std::error_code ec = Result.getError()) {
196     SetLastError(ec.value());
197     MakeErrMsg(ErrMsg, std::string("Unable to convert command-line to UTF-16"));
198     return false;
199   }
200   std::wstring Command = *Result;
202   // The pointer to the environment block for the new process.
203   std::vector<wchar_t> EnvBlock;
205   if (Env) {
206     // An environment block consists of a null-terminated block of
207     // null-terminated strings. Convert the array of environment variables to
208     // an environment block by concatenating them.
209     for (StringRef E : *Env) {
210       SmallVector<wchar_t, MAX_PATH> EnvString;
211       if (std::error_code ec = windows::UTF8ToUTF16(E, EnvString)) {
212         SetLastError(ec.value());
213         MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16");
214         return false;
215       }
217       llvm::append_range(EnvBlock, EnvString);
218       EnvBlock.push_back(0);
219     }
220     EnvBlock.push_back(0);
221   }
223   // Create a child process.
224   STARTUPINFOW si;
225   memset(&si, 0, sizeof(si));
226   si.cb = sizeof(si);
227   si.hStdInput = INVALID_HANDLE_VALUE;
228   si.hStdOutput = INVALID_HANDLE_VALUE;
229   si.hStdError = INVALID_HANDLE_VALUE;
231   if (!Redirects.empty()) {
232     si.dwFlags = STARTF_USESTDHANDLES;
234     si.hStdInput = RedirectIO(Redirects[0], 0, ErrMsg);
235     if (si.hStdInput == INVALID_HANDLE_VALUE) {
236       MakeErrMsg(ErrMsg, "can't redirect stdin");
237       return false;
238     }
239     si.hStdOutput = RedirectIO(Redirects[1], 1, ErrMsg);
240     if (si.hStdOutput == INVALID_HANDLE_VALUE) {
241       CloseHandle(si.hStdInput);
242       MakeErrMsg(ErrMsg, "can't redirect stdout");
243       return false;
244     }
245     if (Redirects[1] && Redirects[2] && *Redirects[1] == *Redirects[2]) {
246       // If stdout and stderr should go to the same place, redirect stderr
247       // to the handle already open for stdout.
248       if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput,
249                            GetCurrentProcess(), &si.hStdError,
250                            0, TRUE, DUPLICATE_SAME_ACCESS)) {
251         CloseHandle(si.hStdInput);
252         CloseHandle(si.hStdOutput);
253         MakeErrMsg(ErrMsg, "can't dup stderr to stdout");
254         return false;
255       }
256     } else {
257       // Just redirect stderr
258       si.hStdError = RedirectIO(Redirects[2], 2, ErrMsg);
259       if (si.hStdError == INVALID_HANDLE_VALUE) {
260         CloseHandle(si.hStdInput);
261         CloseHandle(si.hStdOutput);
262         MakeErrMsg(ErrMsg, "can't redirect stderr");
263         return false;
264       }
265     }
266   }
268   PROCESS_INFORMATION pi;
269   memset(&pi, 0, sizeof(pi));
271   fflush(stdout);
272   fflush(stderr);
274   SmallVector<wchar_t, MAX_PATH> ProgramUtf16;
275   if (std::error_code ec = sys::windows::widenPath(Program, ProgramUtf16)) {
276     SetLastError(ec.value());
277     MakeErrMsg(ErrMsg,
278                std::string("Unable to convert application name to UTF-16"));
279     return false;
280   }
282   unsigned CreateFlags = CREATE_UNICODE_ENVIRONMENT;
283   if (AffinityMask)
284     CreateFlags |= CREATE_SUSPENDED;
286   std::vector<wchar_t> CommandUtf16(Command.size() + 1, 0);
287   std::copy(Command.begin(), Command.end(), CommandUtf16.begin());
288   BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0, TRUE,
289                            CreateFlags, EnvBlock.empty() ? 0 : EnvBlock.data(),
290                            0, &si, &pi);
291   DWORD err = GetLastError();
293   // Regardless of whether the process got created or not, we are done with
294   // the handles we created for it to inherit.
295   CloseHandle(si.hStdInput);
296   CloseHandle(si.hStdOutput);
297   CloseHandle(si.hStdError);
299   // Now return an error if the process didn't get created.
300   if (!rc) {
301     SetLastError(err);
302     MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") +
303                Program.str() + "'");
304     return false;
305   }
307   PI.Pid = pi.dwProcessId;
308   PI.Process = pi.hProcess;
310   // Make sure these get closed no matter what.
311   ScopedCommonHandle hThread(pi.hThread);
313   // Assign the process to a job if a memory limit is defined.
314   ScopedJobHandle hJob;
315   if (MemoryLimit != 0) {
316     hJob = CreateJobObjectW(0, 0);
317     bool success = false;
318     if (hJob) {
319       JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
320       memset(&jeli, 0, sizeof(jeli));
321       jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY;
322       jeli.ProcessMemoryLimit = uintptr_t(MemoryLimit) * 1048576;
323       if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation,
324                                   &jeli, sizeof(jeli))) {
325         if (AssignProcessToJobObject(hJob, pi.hProcess))
326           success = true;
327       }
328     }
329     if (!success) {
330       SetLastError(GetLastError());
331       MakeErrMsg(ErrMsg, std::string("Unable to set memory limit"));
332       TerminateProcess(pi.hProcess, 1);
333       WaitForSingleObject(pi.hProcess, INFINITE);
334       return false;
335     }
336   }
338   // Set the affinity mask
339   if (AffinityMask) {
340     ::SetProcessAffinityMask(pi.hProcess,
341                              (DWORD_PTR)AffinityMask->getData().front());
342     ::ResumeThread(pi.hThread);
343   }
345   return true;
348 static bool argNeedsQuotes(StringRef Arg) {
349   if (Arg.empty())
350     return true;
351   return StringRef::npos != Arg.find_first_of("\t \"&\'()*<>\\`^|\n");
354 static std::string quoteSingleArg(StringRef Arg) {
355   std::string Result;
356   Result.push_back('"');
358   while (!Arg.empty()) {
359     size_t FirstNonBackslash = Arg.find_first_not_of('\\');
360     size_t BackslashCount = FirstNonBackslash;
361     if (FirstNonBackslash == StringRef::npos) {
362       // The entire remainder of the argument is backslashes.  Escape all of
363       // them and just early out.
364       BackslashCount = Arg.size();
365       Result.append(BackslashCount * 2, '\\');
366       break;
367     }
369     if (Arg[FirstNonBackslash] == '\"') {
370       // This is an embedded quote.  Escape all preceding backslashes, then
371       // add one additional backslash to escape the quote.
372       Result.append(BackslashCount * 2 + 1, '\\');
373       Result.push_back('\"');
374     } else {
375       // This is just a normal character.  Don't escape any of the preceding
376       // backslashes, just append them as they are and then append the
377       // character.
378       Result.append(BackslashCount, '\\');
379       Result.push_back(Arg[FirstNonBackslash]);
380     }
382     // Drop all the backslashes, plus the following character.
383     Arg = Arg.drop_front(FirstNonBackslash + 1);
384   }
386   Result.push_back('"');
387   return Result;
390 namespace llvm {
391 ErrorOr<std::wstring> sys::flattenWindowsCommandLine(ArrayRef<StringRef> Args) {
392   std::string Command;
393   for (StringRef Arg : Args) {
394     if (argNeedsQuotes(Arg))
395       Command += quoteSingleArg(Arg);
396     else
397       Command += Arg;
399     Command.push_back(' ');
400   }
402   SmallVector<wchar_t, MAX_PATH> CommandUtf16;
403   if (std::error_code ec = windows::UTF8ToUTF16(Command, CommandUtf16))
404     return ec;
406   return std::wstring(CommandUtf16.begin(), CommandUtf16.end());
409 ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
410                       bool WaitUntilChildTerminates, std::string *ErrMsg,
411                       Optional<ProcessStatistics> *ProcStat) {
412   assert(PI.Pid && "invalid pid to wait on, process not started?");
413   assert((PI.Process && PI.Process != INVALID_HANDLE_VALUE) &&
414          "invalid process handle to wait on, process not started?");
415   DWORD milliSecondsToWait = 0;
416   if (WaitUntilChildTerminates)
417     milliSecondsToWait = INFINITE;
418   else if (SecondsToWait > 0)
419     milliSecondsToWait = SecondsToWait * 1000;
421   ProcessInfo WaitResult = PI;
422   if (ProcStat)
423     ProcStat->reset();
424   DWORD WaitStatus = WaitForSingleObject(PI.Process, milliSecondsToWait);
425   if (WaitStatus == WAIT_TIMEOUT) {
426     if (SecondsToWait) {
427       if (!TerminateProcess(PI.Process, 1)) {
428         if (ErrMsg)
429           MakeErrMsg(ErrMsg, "Failed to terminate timed-out program");
431         // -2 indicates a crash or timeout as opposed to failure to execute.
432         WaitResult.ReturnCode = -2;
433         CloseHandle(PI.Process);
434         return WaitResult;
435       }
436       WaitForSingleObject(PI.Process, INFINITE);
437       CloseHandle(PI.Process);
438     } else {
439       // Non-blocking wait.
440       return ProcessInfo();
441     }
442   }
444   // Get process execution statistics.
445   if (ProcStat) {
446     FILETIME CreationTime, ExitTime, KernelTime, UserTime;
447     PROCESS_MEMORY_COUNTERS MemInfo;
448     if (GetProcessTimes(PI.Process, &CreationTime, &ExitTime, &KernelTime,
449                         &UserTime) &&
450         GetProcessMemoryInfo(PI.Process, &MemInfo, sizeof(MemInfo))) {
451       auto UserT = std::chrono::duration_cast<std::chrono::microseconds>(
452           toDuration(UserTime));
453       auto KernelT = std::chrono::duration_cast<std::chrono::microseconds>(
454           toDuration(KernelTime));
455       uint64_t PeakMemory = MemInfo.PeakPagefileUsage / 1024;
456       *ProcStat = ProcessStatistics{UserT + KernelT, UserT, PeakMemory};
457     }
458   }
460   // Get its exit status.
461   DWORD status;
462   BOOL rc = GetExitCodeProcess(PI.Process, &status);
463   DWORD err = GetLastError();
464   if (err != ERROR_INVALID_HANDLE)
465     CloseHandle(PI.Process);
467   if (!rc) {
468     SetLastError(err);
469     if (ErrMsg)
470       MakeErrMsg(ErrMsg, "Failed getting status for program");
472     // -2 indicates a crash or timeout as opposed to failure to execute.
473     WaitResult.ReturnCode = -2;
474     return WaitResult;
475   }
477   if (!status)
478     return WaitResult;
480   // Pass 10(Warning) and 11(Error) to the callee as negative value.
481   if ((status & 0xBFFF0000U) == 0x80000000U)
482     WaitResult.ReturnCode = static_cast<int>(status);
483   else if (status & 0xFF)
484     WaitResult.ReturnCode = status & 0x7FFFFFFF;
485   else
486     WaitResult.ReturnCode = 1;
488   return WaitResult;
491 std::error_code llvm::sys::ChangeStdinMode(sys::fs::OpenFlags Flags){
492   if (!(Flags & fs::OF_CRLF))
493     return ChangeStdinToBinary();
494   return std::error_code();
497 std::error_code llvm::sys::ChangeStdoutMode(sys::fs::OpenFlags Flags){
498   if (!(Flags & fs::OF_CRLF))
499     return ChangeStdoutToBinary();
500   return std::error_code();
503 std::error_code sys::ChangeStdinToBinary() {
504   int result = _setmode(_fileno(stdin), _O_BINARY);
505   if (result == -1)
506     return std::error_code(errno, std::generic_category());
507   return std::error_code();
510 std::error_code sys::ChangeStdoutToBinary() {
511   int result = _setmode(_fileno(stdout), _O_BINARY);
512   if (result == -1)
513     return std::error_code(errno, std::generic_category());
514   return std::error_code();
517 std::error_code
518 llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,
519                                  WindowsEncodingMethod Encoding) {
520   std::error_code EC;
521   llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OF_TextWithCRLF);
522   if (EC)
523     return EC;
525   if (Encoding == WEM_UTF8) {
526     OS << Contents;
527   } else if (Encoding == WEM_CurrentCodePage) {
528     SmallVector<wchar_t, 1> ArgsUTF16;
529     SmallVector<char, 1> ArgsCurCP;
531     if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16)))
532       return EC;
534     if ((EC = windows::UTF16ToCurCP(
535              ArgsUTF16.data(), ArgsUTF16.size(), ArgsCurCP)))
536       return EC;
538     OS.write(ArgsCurCP.data(), ArgsCurCP.size());
539   } else if (Encoding == WEM_UTF16) {
540     SmallVector<wchar_t, 1> ArgsUTF16;
542     if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16)))
543       return EC;
545     // Endianness guessing
546     char BOM[2];
547     uint16_t src = UNI_UTF16_BYTE_ORDER_MARK_NATIVE;
548     memcpy(BOM, &src, 2);
549     OS.write(BOM, 2);
550     OS.write((char *)ArgsUTF16.data(), ArgsUTF16.size() << 1);
551   } else {
552     llvm_unreachable("Unknown encoding");
553   }
555   if (OS.has_error())
556     return make_error_code(errc::io_error);
558   return EC;
561 bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program,
562                                                   ArrayRef<StringRef> Args) {
563   // The documentation on CreateProcessW states that the size of the argument
564   // lpCommandLine must not be greater than 32767 characters, including the
565   // Unicode terminating null character. We use smaller value to reduce risk
566   // of getting invalid command line due to unaccounted factors.
567   static const size_t MaxCommandStringLength = 32000;
568   SmallVector<StringRef, 8> FullArgs;
569   FullArgs.push_back(Program);
570   FullArgs.append(Args.begin(), Args.end());
571   auto Result = flattenWindowsCommandLine(FullArgs);
572   assert(!Result.getError());
573   return (Result->size() + 1) <= MaxCommandStringLength;