llvm.org GIT mirror llvm / 87e117d
Convenience/safety fix for llvm::sys::Execute(And|No)Wait Summary: Change the type of the Redirects parameter of llvm::sys::ExecuteAndWait, ExecuteNoWait and other APIs that wrap them from `const StringRef **` to `ArrayRef<Optional<StringRef>>`, which is safer and simplifies the use of these APIs (no more local StringRef variables just to get a pointer to). Corresponding clang changes will be posted as a separate patch. Reviewers: bkramer Reviewed By: bkramer Subscribers: vsk, llvm-commits Differential Revision: https://reviews.llvm.org/D37563 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@313155 91177308-0d34-0410-b5e6-96231b3b80d8 Alexander Kornienko 2 years ago
12 changed file(s) with 60 addition(s) and 62 deletion(s). Raw diff Collapse all Expand all
1414 #define LLVM_SUPPORT_PROGRAM_H
1515
1616 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/Optional.h"
1718 #include "llvm/Support/ErrorOr.h"
1819 #include
1920
6869 /// \returns The fully qualified path to the first \p Name in \p Paths if it
6970 /// exists. \p Name if \p Name has slashes in it. Otherwise an error.
7071 ErrorOr
71 findProgramByName(StringRef Name, ArrayRef Paths = None);
72 findProgramByName(StringRef Name, ArrayRef Paths = {});
7273
7374 // These functions change the specified standard stream (stdin or stdout) to
7475 // binary mode. They return errc::success if the specified stream
8384 /// This function waits for the program to finish, so should be avoided in
8485 /// library functions that aren't expected to block. Consider using
8586 /// ExecuteNoWait() instead.
86 /// @returns an integer result code indicating the status of the program.
87 /// \returns an integer result code indicating the status of the program.
8788 /// A zero or positive value indicates the result code of the program.
8889 /// -1 indicates failure to execute
8990 /// -2 indicates a crash during execution or timeout
9697 const char **Env = nullptr, ///< An optional vector of strings to use for
9798 ///< the program's environment. If not provided, the current program's
9899 ///< environment will be used.
99 const StringRef **Redirects = nullptr, ///< An optional array of pointers
100 ///< to paths. If the array is null, no redirection is done. The array
101 ///< should have a size of at least three. The inferior process's
102 ///< stdin(0), stdout(1), and stderr(2) will be redirected to the
103 ///< corresponding paths.
104 ///< When an empty path is passed in, the corresponding file
105 ///< descriptor will be disconnected (ie, /dev/null'd) in a portable
106 ///< way.
100 ArrayRef> Redirects = {}, ///<
101 ///< An array of optional paths. Should have a size of zero or three.
102 ///< If the array is empty, no redirections are performed.
103 ///< Otherwise, the inferior process's stdin(0), stdout(1), and stderr(2)
104 ///< will be redirected to the corresponding paths, if the optional path
105 ///< is present (not \c llvm::None).
106 ///< When an empty path is passed in, the corresponding file descriptor
107 ///< will be disconnected (ie, /dev/null'd) in a portable way.
107108 unsigned SecondsToWait = 0, ///< If non-zero, this specifies the amount
108109 ///< of time to wait for the child process to exit. If the time
109110 ///< expires, the child is killed and this call returns. If zero,
121122
122123 /// Similar to ExecuteAndWait, but returns immediately.
123124 /// @returns The \see ProcessInfo of the newly launced process.
124 /// \note On Microsoft Windows systems, users will need to either call \see
125 /// Wait until the process finished execution or win32 CloseHandle() API on
126 /// ProcessInfo.ProcessHandle to avoid memory leaks.
125 /// \note On Microsoft Windows systems, users will need to either call
126 /// \see Wait until the process finished execution or win32 CloseHandle() API
127 /// on ProcessInfo.ProcessHandle to avoid memory leaks.
127128 ProcessInfo ExecuteNoWait(StringRef Program, const char **Args,
128129 const char **Env = nullptr,
129 const StringRef **Redirects = nullptr,
130 ArrayRef> Redirects = {},
130131 unsigned MemoryLimit = 0,
131132 std::string *ErrMsg = nullptr,
132133 bool *ExecutionFailed = nullptr);
9595 std::string &ErrMsg) {
9696 assert(args.back() == nullptr);
9797 if (wait) {
98 if (sys::ExecuteAndWait(ExecPath, args.data(), nullptr, nullptr, 0, 0,
98 if (sys::ExecuteAndWait(ExecPath, args.data(), nullptr, {}, 0, 0,
9999 &ErrMsg)) {
100100 errs() << "Error: " << ErrMsg << "\n";
101101 return true;
103103 sys::fs::remove(Filename);
104104 errs() << " done. \n";
105105 } else {
106 sys::ExecuteNoWait(ExecPath, args.data(), nullptr, nullptr, 0, &ErrMsg);
106 sys::ExecuteNoWait(ExecPath, args.data(), nullptr, {}, 0, &ErrMsg);
107107 errs() << "Remember to erase graph file: " << Filename << "\n";
108108 }
109109 return false;
2323 //===----------------------------------------------------------------------===//
2424
2525 static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
26 const char **Env, const StringRef **Redirects,
26 const char **Env, ArrayRef> Redirects,
2727 unsigned MemoryLimit, std::string *ErrMsg);
2828
2929 int sys::ExecuteAndWait(StringRef Program, const char **Args, const char **Envp,
30 const StringRef **Redirects, unsigned SecondsToWait,
31 unsigned MemoryLimit, std::string *ErrMsg,
32 bool *ExecutionFailed) {
30 ArrayRef> Redirects,
31 unsigned SecondsToWait, unsigned MemoryLimit,
32 std::string *ErrMsg, bool *ExecutionFailed) {
33 assert(Redirects.empty() || Redirects.size() == 3);
3334 ProcessInfo PI;
3435 if (Execute(PI, Program, Args, Envp, Redirects, MemoryLimit, ErrMsg)) {
3536 if (ExecutionFailed)
4647 }
4748
4849 ProcessInfo sys::ExecuteNoWait(StringRef Program, const char **Args,
49 const char **Envp, const StringRef **Redirects,
50 const char **Envp,
51 ArrayRef> Redirects,
5052 unsigned MemoryLimit, std::string *ErrMsg,
5153 bool *ExecutionFailed) {
54 assert(Redirects.empty() || Redirects.size() == 3);
5255 ProcessInfo PI;
5356 if (ExecutionFailed)
5457 *ExecutionFailed = false;
122122 }
123123 }
124124
125 StringRef InputFileStr(InputFile);
126 StringRef OutputFileStr(OutputFile);
127 StringRef StderrFileStr;
128 const StringRef *Redirects[] = {&InputFileStr, &OutputFileStr,
129 &StderrFileStr};
125 Optional Redirects[] = {InputFile.str(), OutputFile.str(), llvm::None};
130126 const char *Args[] = {"llvm-symbolizer", "--functions=linkage", "--inlining",
131127 #ifdef LLVM_ON_WIN32
132128 // Pass --relative-address on Windows so that we don't
9292 return errc::no_such_file_or_directory;
9393 }
9494
95 static bool RedirectIO(const StringRef *Path, int FD, std::string* ErrMsg) {
95 static bool RedirectIO(Optional Path, int FD, std::string* ErrMsg) {
9696 if (!Path) // Noop
9797 return false;
9898 std::string File;
164164 }
165165
166166 static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
167 const char **Envp, const StringRef **Redirects,
167 const char **Envp, ArrayRef> Redirects,
168168 unsigned MemoryLimit, std::string *ErrMsg) {
169169 if (!llvm::sys::fs::exists(Program)) {
170170 if (ErrMsg)
185185 // so we copy any StringRefs into this variable.
186186 std::string RedirectsStorage[3];
187187
188 if (Redirects) {
188 if (!Redirects.empty()) {
189 assert(Redirects.size() == 3);
189190 std::string *RedirectsStr[3] = {nullptr, nullptr, nullptr};
190191 for (int I = 0; I < 3; ++I) {
191192 if (Redirects[I]) {
201202 if (RedirectIO_PS(RedirectsStr[0], 0, ErrMsg, FileActions) ||
202203 RedirectIO_PS(RedirectsStr[1], 1, ErrMsg, FileActions))
203204 return false;
204 if (Redirects[1] == nullptr || Redirects[2] == nullptr ||
205 *Redirects[1] != *Redirects[2]) {
205 if (!Redirects[1] || !Redirects[2] || *Redirects[1] != *Redirects[2]) {
206206 // Just redirect stderr
207207 if (RedirectIO_PS(RedirectsStr[2], 2, ErrMsg, FileActions))
208208 return false;
252252 // Child process: Execute the program.
253253 case 0: {
254254 // Redirect file descriptors...
255 if (Redirects) {
255 if (!Redirects.empty()) {
256256 // Redirect stdin
257257 if (RedirectIO(Redirects[0], 0, ErrMsg)) { return false; }
258258 // Redirect stdout
102102 return std::string(U8Result.begin(), U8Result.end());
103103 }
104104
105 static HANDLE RedirectIO(const StringRef *Path, int fd, std::string* ErrMsg) {
105 static HANDLE RedirectIO(Optional Path, int fd,
106 std::string *ErrMsg) {
106107 HANDLE h;
107 if (Path == 0) {
108 if (!Path) {
108109 if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
109110 GetCurrentProcess(), &h,
110111 0, TRUE, DUPLICATE_SAME_ACCESS))
248249 }
249250
250251 static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
251 const char **Envp, const StringRef **Redirects,
252 const char **Envp, ArrayRef> Redirects,
252253 unsigned MemoryLimit, std::string *ErrMsg) {
253254 if (!sys::fs::can_execute(Program)) {
254255 if (ErrMsg)
298299 si.hStdOutput = INVALID_HANDLE_VALUE;
299300 si.hStdError = INVALID_HANDLE_VALUE;
300301
301 if (Redirects) {
302 if (!Redirects.empty()) {
302303 si.dwFlags = STARTF_USESTDHANDLES;
303304
304305 si.hStdInput = RedirectIO(Redirects[0], 0, ErrMsg);
229229 << " " << Args[i];
230230 errs() << "\n";);
231231
232 // Redirect stdout and stderr to nowhere if SilencePasses is given
233 StringRef Nowhere;
234 const StringRef *Redirects[3] = {nullptr, &Nowhere, &Nowhere};
232 Optional Redirects[3] = {None, None, None};
233 // Redirect stdout and stderr to nowhere if SilencePasses is given.
234 if (SilencePasses) {
235 Redirects[1] = "";
236 Redirects[2] = "";
237 }
235238
236239 std::string ErrMsg;
237 int result = sys::ExecuteAndWait(Prog, Args.data(), nullptr,
238 (SilencePasses ? Redirects : nullptr),
240 int result = sys::ExecuteAndWait(Prog, Args.data(), nullptr, Redirects,
239241 Timeout, MemoryLimit, &ErrMsg);
240242
241243 // If we are supposed to delete the bitcode file or if the passes crashed,
5757 StringRef StdErrFile, unsigned NumSeconds = 0,
5858 unsigned MemoryLimit = 0,
5959 std::string *ErrMsg = nullptr) {
60 const StringRef *Redirects[3] = {&StdInFile, &StdOutFile, &StdErrFile};
60 Optional Redirects[3] = {StdInFile, StdOutFile, StdErrFile};
6161 return sys::ExecuteAndWait(ProgramPath, Args, nullptr, Redirects, NumSeconds,
6262 MemoryLimit, ErrMsg);
6363 }
7474 StringRef StdErrFile,
7575 unsigned NumSeconds = 0,
7676 unsigned MemoryLimit = 0) {
77 const StringRef *Redirects[3] = {&StdInFile, &StdOutFile, &StdErrFile};
77 Optional Redirects[3] = {StdInFile, StdOutFile, StdErrFile};
7878
7979 // Run the program remotely with the remote client
8080 int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, nullptr,
4444
4545 std::string ErrMsg;
4646 int result =
47 sys::ExecuteAndWait(*Path, Args.data(), nullptr, nullptr, 0, 0, &ErrMsg);
47 sys::ExecuteAndWait(*Path, Args.data(), nullptr, {}, 0, 0, &ErrMsg);
4848 if (result) {
4949 errs() << "error: lipo: " << ErrMsg << "\n";
5050 return false;
457457 for (const std::string &Arg : ViewOpts.DemanglerOpts)
458458 ArgsV.push_back(Arg.c_str());
459459 ArgsV.push_back(nullptr);
460 StringRef InputPathRef = InputPath.str();
461 StringRef OutputPathRef = OutputPath.str();
462 StringRef StderrRef;
463 const StringRef *Redirects[] = {&InputPathRef, &OutputPathRef, &StderrRef};
460 Optional Redirects[] = {InputPath.str(), OutputPath.str(), {""}};
464461 std::string ErrMsg;
465462 int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV.data(),
466463 /*env=*/nullptr, Redirects, /*secondsToWait=*/0,
144144 LongPath.push_back('\\');
145145 // MAX_PATH = 260
146146 LongPath.append(260 - TestDirectory.size(), 'a');
147 StringRef LongPathRef(LongPath);
148147
149148 std::string Error;
150149 bool ExecutionFailed;
151 const StringRef *Redirects[] = { nullptr, &LongPathRef, nullptr };
150 Optional Redirects[] = {None, LongPath.str(), None};
152151 int RC = ExecuteAndWait(MyExe, ArgV, getEnviron(), Redirects,
153152 /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &Error,
154153 &ExecutionFailed);
191190 #else
192191 StringRef nul("/dev/null");
193192 #endif
194 const StringRef *redirects[] = { &nul, &nul, nullptr };
193 Optional redirects[] = { nul, nul, None };
195194 int rc = ExecuteAndWait(my_exe, argv, getEnviron(), redirects,
196195 /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &error,
197196 &ExecutionFailed);
220219
221220 std::string Error;
222221 bool ExecutionFailed;
223 ProcessInfo PI1 = ExecuteNoWait(Executable, argv, getEnviron(), nullptr, 0,
224 &Error, &ExecutionFailed);
222 ProcessInfo PI1 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error,
223 &ExecutionFailed);
225224 ASSERT_FALSE(ExecutionFailed) << Error;
226225 ASSERT_NE(PI1.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
227226
239238
240239 EXPECT_EQ(LoopCount, 1u) << "LoopCount should be 1";
241240
242 ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), nullptr, 0,
243 &Error, &ExecutionFailed);
241 ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error,
242 &ExecutionFailed);
244243 ASSERT_FALSE(ExecutionFailed) << Error;
245244 ASSERT_NE(PI2.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
246245
279278 std::string Error;
280279 bool ExecutionFailed;
281280 int RetCode =
282 ExecuteAndWait(Executable, argv, getEnviron(), nullptr, /*secondsToWait=*/1, 0,
281 ExecuteAndWait(Executable, argv, getEnviron(), {}, /*secondsToWait=*/1, 0,
283282 &Error, &ExecutionFailed);
284283 ASSERT_EQ(-2, RetCode);
285284 }
291290 {
292291 std::string Error;
293292 bool ExecutionFailed;
294 int RetCode = ExecuteAndWait(Executable, argv, nullptr, nullptr, 0, 0,
295 &Error, &ExecutionFailed);
293 int RetCode = ExecuteAndWait(Executable, argv, nullptr, {}, 0, 0, &Error,
294 &ExecutionFailed);
296295 ASSERT_TRUE(RetCode < 0) << "On error ExecuteAndWait should return 0 or "
297296 "positive value indicating the result code";
298297 ASSERT_TRUE(ExecutionFailed);
302301 {
303302 std::string Error;
304303 bool ExecutionFailed;
305 ProcessInfo PI = ExecuteNoWait(Executable, argv, nullptr, nullptr, 0,
306 &Error, &ExecutionFailed);
304 ProcessInfo PI = ExecuteNoWait(Executable, argv, nullptr, {}, 0, &Error,
305 &ExecutionFailed);
307306 ASSERT_EQ(PI.Pid, ProcessInfo::InvalidPid)
308307 << "On error ExecuteNoWait should return an invalid ProcessInfo";
309308 ASSERT_TRUE(ExecutionFailed);
3838 }
3939
4040 std::string ErrMsg;
41 int Result = sys::ExecuteAndWait(*Program, argv, nullptr, nullptr, 0, 0,
42 &ErrMsg);
41 int Result = sys::ExecuteAndWait(*Program, argv, nullptr, {}, 0, 0, &ErrMsg);
4342 #ifdef _WIN32
4443 // Handle abort() in msvcrt -- It has exit code as 3. abort(), aka
4544 // unreachable, should be recognized as a crash. However, some binaries use