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