Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 87e117d

Browse files
committed
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
1 parent f6e4c7d commit 87e117d

File tree

12 files changed

+60
-62
lines changed

12 files changed

+60
-62
lines changed

include/llvm/Support/Program.h

+15-14
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define LLVM_SUPPORT_PROGRAM_H
1616

1717
#include "llvm/ADT/ArrayRef.h"
18+
#include "llvm/ADT/Optional.h"
1819
#include "llvm/Support/ErrorOr.h"
1920
#include <system_error>
2021

@@ -69,7 +70,7 @@ struct ProcessInfo {
6970
/// \returns The fully qualified path to the first \p Name in \p Paths if it
7071
/// exists. \p Name if \p Name has slashes in it. Otherwise an error.
7172
ErrorOr<std::string>
72-
findProgramByName(StringRef Name, ArrayRef<StringRef> Paths = None);
73+
findProgramByName(StringRef Name, ArrayRef<StringRef> Paths = {});
7374

7475
// These functions change the specified standard stream (stdin or stdout) to
7576
// binary mode. They return errc::success if the specified stream
@@ -84,7 +85,7 @@ struct ProcessInfo {
8485
/// This function waits for the program to finish, so should be avoided in
8586
/// library functions that aren't expected to block. Consider using
8687
/// ExecuteNoWait() instead.
87-
/// @returns an integer result code indicating the status of the program.
88+
/// \returns an integer result code indicating the status of the program.
8889
/// A zero or positive value indicates the result code of the program.
8990
/// -1 indicates failure to execute
9091
/// -2 indicates a crash during execution or timeout
@@ -97,14 +98,14 @@ struct ProcessInfo {
9798
const char **Env = nullptr, ///< An optional vector of strings to use for
9899
///< the program's environment. If not provided, the current program's
99100
///< environment will be used.
100-
const StringRef **Redirects = nullptr, ///< An optional array of pointers
101-
///< to paths. If the array is null, no redirection is done. The array
102-
///< should have a size of at least three. The inferior process's
103-
///< stdin(0), stdout(1), and stderr(2) will be redirected to the
104-
///< corresponding paths.
105-
///< When an empty path is passed in, the corresponding file
106-
///< descriptor will be disconnected (ie, /dev/null'd) in a portable
107-
///< way.
101+
ArrayRef<Optional<StringRef>> Redirects = {}, ///<
102+
///< An array of optional paths. Should have a size of zero or three.
103+
///< If the array is empty, no redirections are performed.
104+
///< Otherwise, the inferior process's stdin(0), stdout(1), and stderr(2)
105+
///< will be redirected to the corresponding paths, if the optional path
106+
///< is present (not \c llvm::None).
107+
///< When an empty path is passed in, the corresponding file descriptor
108+
///< will be disconnected (ie, /dev/null'd) in a portable way.
108109
unsigned SecondsToWait = 0, ///< If non-zero, this specifies the amount
109110
///< of time to wait for the child process to exit. If the time
110111
///< expires, the child is killed and this call returns. If zero,
@@ -122,12 +123,12 @@ struct ProcessInfo {
122123

123124
/// Similar to ExecuteAndWait, but returns immediately.
124125
/// @returns The \see ProcessInfo of the newly launced process.
125-
/// \note On Microsoft Windows systems, users will need to either call \see
126-
/// Wait until the process finished execution or win32 CloseHandle() API on
127-
/// ProcessInfo.ProcessHandle to avoid memory leaks.
126+
/// \note On Microsoft Windows systems, users will need to either call
127+
/// \see Wait until the process finished execution or win32 CloseHandle() API
128+
/// on ProcessInfo.ProcessHandle to avoid memory leaks.
128129
ProcessInfo ExecuteNoWait(StringRef Program, const char **Args,
129130
const char **Env = nullptr,
130-
const StringRef **Redirects = nullptr,
131+
ArrayRef<Optional<StringRef>> Redirects = {},
131132
unsigned MemoryLimit = 0,
132133
std::string *ErrMsg = nullptr,
133134
bool *ExecutionFailed = nullptr);

lib/Support/GraphWriter.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,15 @@ static bool ExecGraphViewer(StringRef ExecPath, std::vector<const char *> &args,
9696
std::string &ErrMsg) {
9797
assert(args.back() == nullptr);
9898
if (wait) {
99-
if (sys::ExecuteAndWait(ExecPath, args.data(), nullptr, nullptr, 0, 0,
99+
if (sys::ExecuteAndWait(ExecPath, args.data(), nullptr, {}, 0, 0,
100100
&ErrMsg)) {
101101
errs() << "Error: " << ErrMsg << "\n";
102102
return true;
103103
}
104104
sys::fs::remove(Filename);
105105
errs() << " done. \n";
106106
} else {
107-
sys::ExecuteNoWait(ExecPath, args.data(), nullptr, nullptr, 0, &ErrMsg);
107+
sys::ExecuteNoWait(ExecPath, args.data(), nullptr, {}, 0, &ErrMsg);
108108
errs() << "Remember to erase graph file: " << Filename << "\n";
109109
}
110110
return false;

lib/Support/Program.cpp

+8-5
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@ using namespace sys;
2424
//===----------------------------------------------------------------------===//
2525

2626
static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
27-
const char **Env, const StringRef **Redirects,
27+
const char **Env, ArrayRef<Optional<StringRef>> Redirects,
2828
unsigned MemoryLimit, std::string *ErrMsg);
2929

3030
int sys::ExecuteAndWait(StringRef Program, const char **Args, const char **Envp,
31-
const StringRef **Redirects, unsigned SecondsToWait,
32-
unsigned MemoryLimit, std::string *ErrMsg,
33-
bool *ExecutionFailed) {
31+
ArrayRef<Optional<StringRef>> Redirects,
32+
unsigned SecondsToWait, unsigned MemoryLimit,
33+
std::string *ErrMsg, bool *ExecutionFailed) {
34+
assert(Redirects.empty() || Redirects.size() == 3);
3435
ProcessInfo PI;
3536
if (Execute(PI, Program, Args, Envp, Redirects, MemoryLimit, ErrMsg)) {
3637
if (ExecutionFailed)
@@ -47,9 +48,11 @@ int sys::ExecuteAndWait(StringRef Program, const char **Args, const char **Envp,
4748
}
4849

4950
ProcessInfo sys::ExecuteNoWait(StringRef Program, const char **Args,
50-
const char **Envp, const StringRef **Redirects,
51+
const char **Envp,
52+
ArrayRef<Optional<StringRef>> Redirects,
5153
unsigned MemoryLimit, std::string *ErrMsg,
5254
bool *ExecutionFailed) {
55+
assert(Redirects.empty() || Redirects.size() == 3);
5356
ProcessInfo PI;
5457
if (ExecutionFailed)
5558
*ExecutionFailed = false;

lib/Support/Signals.cpp

+1-5
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,7 @@ static bool printSymbolizedStackTrace(StringRef Argv0,
123123
}
124124
}
125125

126-
StringRef InputFileStr(InputFile);
127-
StringRef OutputFileStr(OutputFile);
128-
StringRef StderrFileStr;
129-
const StringRef *Redirects[] = {&InputFileStr, &OutputFileStr,
130-
&StderrFileStr};
126+
Optional<StringRef> Redirects[] = {InputFile.str(), OutputFile.str(), llvm::None};
131127
const char *Args[] = {"llvm-symbolizer", "--functions=linkage", "--inlining",
132128
#ifdef LLVM_ON_WIN32
133129
// Pass --relative-address on Windows so that we don't

lib/Support/Unix/Program.inc

+6-6
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ ErrorOr<std::string> sys::findProgramByName(StringRef Name,
9393
return errc::no_such_file_or_directory;
9494
}
9595

96-
static bool RedirectIO(const StringRef *Path, int FD, std::string* ErrMsg) {
96+
static bool RedirectIO(Optional<StringRef> Path, int FD, std::string* ErrMsg) {
9797
if (!Path) // Noop
9898
return false;
9999
std::string File;
@@ -165,7 +165,7 @@ static void SetMemoryLimits(unsigned size) {
165165
}
166166

167167
static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
168-
const char **Envp, const StringRef **Redirects,
168+
const char **Envp, ArrayRef<Optional<StringRef>> Redirects,
169169
unsigned MemoryLimit, std::string *ErrMsg) {
170170
if (!llvm::sys::fs::exists(Program)) {
171171
if (ErrMsg)
@@ -186,7 +186,8 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
186186
// so we copy any StringRefs into this variable.
187187
std::string RedirectsStorage[3];
188188

189-
if (Redirects) {
189+
if (!Redirects.empty()) {
190+
assert(Redirects.size() == 3);
190191
std::string *RedirectsStr[3] = {nullptr, nullptr, nullptr};
191192
for (int I = 0; I < 3; ++I) {
192193
if (Redirects[I]) {
@@ -202,8 +203,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
202203
if (RedirectIO_PS(RedirectsStr[0], 0, ErrMsg, FileActions) ||
203204
RedirectIO_PS(RedirectsStr[1], 1, ErrMsg, FileActions))
204205
return false;
205-
if (Redirects[1] == nullptr || Redirects[2] == nullptr ||
206-
*Redirects[1] != *Redirects[2]) {
206+
if (!Redirects[1] || !Redirects[2] || *Redirects[1] != *Redirects[2]) {
207207
// Just redirect stderr
208208
if (RedirectIO_PS(RedirectsStr[2], 2, ErrMsg, FileActions))
209209
return false;
@@ -253,7 +253,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
253253
// Child process: Execute the program.
254254
case 0: {
255255
// Redirect file descriptors...
256-
if (Redirects) {
256+
if (!Redirects.empty()) {
257257
// Redirect stdin
258258
if (RedirectIO(Redirects[0], 0, ErrMsg)) { return false; }
259259
// Redirect stdout

lib/Support/Windows/Program.inc

+5-4
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,10 @@ ErrorOr<std::string> sys::findProgramByName(StringRef Name,
103103
return std::string(U8Result.begin(), U8Result.end());
104104
}
105105

106-
static HANDLE RedirectIO(const StringRef *Path, int fd, std::string* ErrMsg) {
106+
static HANDLE RedirectIO(Optional<StringRef> Path, int fd,
107+
std::string *ErrMsg) {
107108
HANDLE h;
108-
if (Path == 0) {
109+
if (!Path) {
109110
if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
110111
GetCurrentProcess(), &h,
111112
0, TRUE, DUPLICATE_SAME_ACCESS))
@@ -249,7 +250,7 @@ static std::unique_ptr<char[]> flattenArgs(const char **Args) {
249250
}
250251

251252
static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
252-
const char **Envp, const StringRef **Redirects,
253+
const char **Envp, ArrayRef<Optional<StringRef>> Redirects,
253254
unsigned MemoryLimit, std::string *ErrMsg) {
254255
if (!sys::fs::can_execute(Program)) {
255256
if (ErrMsg)
@@ -299,7 +300,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
299300
si.hStdOutput = INVALID_HANDLE_VALUE;
300301
si.hStdError = INVALID_HANDLE_VALUE;
301302

302-
if (Redirects) {
303+
if (!Redirects.empty()) {
303304
si.dwFlags = STARTF_USESTDHANDLES;
304305

305306
si.hStdInput = RedirectIO(Redirects[0], 0, ErrMsg);

tools/bugpoint/OptimizerDriver.cpp

+7-5
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,15 @@ bool BugDriver::runPasses(Module *Program,
230230
<< " " << Args[i];
231231
errs() << "\n";);
232232

233-
// Redirect stdout and stderr to nowhere if SilencePasses is given
234-
StringRef Nowhere;
235-
const StringRef *Redirects[3] = {nullptr, &Nowhere, &Nowhere};
233+
Optional<StringRef> Redirects[3] = {None, None, None};
234+
// Redirect stdout and stderr to nowhere if SilencePasses is given.
235+
if (SilencePasses) {
236+
Redirects[1] = "";
237+
Redirects[2] = "";
238+
}
236239

237240
std::string ErrMsg;
238-
int result = sys::ExecuteAndWait(Prog, Args.data(), nullptr,
239-
(SilencePasses ? Redirects : nullptr),
241+
int result = sys::ExecuteAndWait(Prog, Args.data(), nullptr, Redirects,
240242
Timeout, MemoryLimit, &ErrMsg);
241243

242244
// If we are supposed to delete the bitcode file or if the passes crashed,

tools/bugpoint/ToolRunner.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ static int RunProgramWithTimeout(StringRef ProgramPath, const char **Args,
5858
StringRef StdErrFile, unsigned NumSeconds = 0,
5959
unsigned MemoryLimit = 0,
6060
std::string *ErrMsg = nullptr) {
61-
const StringRef *Redirects[3] = {&StdInFile, &StdOutFile, &StdErrFile};
61+
Optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile};
6262
return sys::ExecuteAndWait(ProgramPath, Args, nullptr, Redirects, NumSeconds,
6363
MemoryLimit, ErrMsg);
6464
}
@@ -75,7 +75,7 @@ static int RunProgramRemotelyWithTimeout(StringRef RemoteClientPath,
7575
StringRef StdErrFile,
7676
unsigned NumSeconds = 0,
7777
unsigned MemoryLimit = 0) {
78-
const StringRef *Redirects[3] = {&StdInFile, &StdOutFile, &StdErrFile};
78+
Optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile};
7979

8080
// Run the program remotely with the remote client
8181
int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, nullptr,

tools/dsymutil/MachOUtils.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ static bool runLipo(StringRef SDKPath, SmallVectorImpl<const char *> &Args) {
4545

4646
std::string ErrMsg;
4747
int result =
48-
sys::ExecuteAndWait(*Path, Args.data(), nullptr, nullptr, 0, 0, &ErrMsg);
48+
sys::ExecuteAndWait(*Path, Args.data(), nullptr, {}, 0, 0, &ErrMsg);
4949
if (result) {
5050
errs() << "error: lipo: " << ErrMsg << "\n";
5151
return false;

tools/llvm-cov/CodeCoverage.cpp

+1-4
Original file line numberDiff line numberDiff line change
@@ -458,10 +458,7 @@ void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) {
458458
for (const std::string &Arg : ViewOpts.DemanglerOpts)
459459
ArgsV.push_back(Arg.c_str());
460460
ArgsV.push_back(nullptr);
461-
StringRef InputPathRef = InputPath.str();
462-
StringRef OutputPathRef = OutputPath.str();
463-
StringRef StderrRef;
464-
const StringRef *Redirects[] = {&InputPathRef, &OutputPathRef, &StderrRef};
461+
Optional<StringRef> Redirects[] = {InputPath.str(), OutputPath.str(), {""}};
465462
std::string ErrMsg;
466463
int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV.data(),
467464
/*env=*/nullptr, Redirects, /*secondsToWait=*/0,

unittests/Support/ProgramTest.cpp

+11-12
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,10 @@ TEST_F(ProgramEnvTest, CreateProcessLongPath) {
145145
LongPath.push_back('\\');
146146
// MAX_PATH = 260
147147
LongPath.append(260 - TestDirectory.size(), 'a');
148-
StringRef LongPathRef(LongPath);
149148

150149
std::string Error;
151150
bool ExecutionFailed;
152-
const StringRef *Redirects[] = { nullptr, &LongPathRef, nullptr };
151+
Optional<StringRef> Redirects[] = {None, LongPath.str(), None};
153152
int RC = ExecuteAndWait(MyExe, ArgV, getEnviron(), Redirects,
154153
/*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &Error,
155154
&ExecutionFailed);
@@ -192,7 +191,7 @@ TEST_F(ProgramEnvTest, CreateProcessTrailingSlash) {
192191
#else
193192
StringRef nul("/dev/null");
194193
#endif
195-
const StringRef *redirects[] = { &nul, &nul, nullptr };
194+
Optional<StringRef> redirects[] = { nul, nul, None };
196195
int rc = ExecuteAndWait(my_exe, argv, getEnviron(), redirects,
197196
/*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &error,
198197
&ExecutionFailed);
@@ -221,8 +220,8 @@ TEST_F(ProgramEnvTest, TestExecuteNoWait) {
221220

222221
std::string Error;
223222
bool ExecutionFailed;
224-
ProcessInfo PI1 = ExecuteNoWait(Executable, argv, getEnviron(), nullptr, 0,
225-
&Error, &ExecutionFailed);
223+
ProcessInfo PI1 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error,
224+
&ExecutionFailed);
226225
ASSERT_FALSE(ExecutionFailed) << Error;
227226
ASSERT_NE(PI1.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
228227

@@ -240,8 +239,8 @@ TEST_F(ProgramEnvTest, TestExecuteNoWait) {
240239

241240
EXPECT_EQ(LoopCount, 1u) << "LoopCount should be 1";
242241

243-
ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), nullptr, 0,
244-
&Error, &ExecutionFailed);
242+
ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error,
243+
&ExecutionFailed);
245244
ASSERT_FALSE(ExecutionFailed) << Error;
246245
ASSERT_NE(PI2.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
247246

@@ -280,7 +279,7 @@ TEST_F(ProgramEnvTest, TestExecuteAndWaitTimeout) {
280279
std::string Error;
281280
bool ExecutionFailed;
282281
int RetCode =
283-
ExecuteAndWait(Executable, argv, getEnviron(), nullptr, /*secondsToWait=*/1, 0,
282+
ExecuteAndWait(Executable, argv, getEnviron(), {}, /*secondsToWait=*/1, 0,
284283
&Error, &ExecutionFailed);
285284
ASSERT_EQ(-2, RetCode);
286285
}
@@ -292,8 +291,8 @@ TEST(ProgramTest, TestExecuteNegative) {
292291
{
293292
std::string Error;
294293
bool ExecutionFailed;
295-
int RetCode = ExecuteAndWait(Executable, argv, nullptr, nullptr, 0, 0,
296-
&Error, &ExecutionFailed);
294+
int RetCode = ExecuteAndWait(Executable, argv, nullptr, {}, 0, 0, &Error,
295+
&ExecutionFailed);
297296
ASSERT_TRUE(RetCode < 0) << "On error ExecuteAndWait should return 0 or "
298297
"positive value indicating the result code";
299298
ASSERT_TRUE(ExecutionFailed);
@@ -303,8 +302,8 @@ TEST(ProgramTest, TestExecuteNegative) {
303302
{
304303
std::string Error;
305304
bool ExecutionFailed;
306-
ProcessInfo PI = ExecuteNoWait(Executable, argv, nullptr, nullptr, 0,
307-
&Error, &ExecutionFailed);
305+
ProcessInfo PI = ExecuteNoWait(Executable, argv, nullptr, {}, 0, &Error,
306+
&ExecutionFailed);
308307
ASSERT_EQ(PI.Pid, ProcessInfo::InvalidPid)
309308
<< "On error ExecuteNoWait should return an invalid ProcessInfo";
310309
ASSERT_TRUE(ExecutionFailed);

utils/not/not.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ int main(int argc, const char **argv) {
3939
}
4040

4141
std::string ErrMsg;
42-
int Result = sys::ExecuteAndWait(*Program, argv, nullptr, nullptr, 0, 0,
43-
&ErrMsg);
42+
int Result = sys::ExecuteAndWait(*Program, argv, nullptr, {}, 0, 0, &ErrMsg);
4443
#ifdef _WIN32
4544
// Handle abort() in msvcrt -- It has exit code as 3. abort(), aka
4645
// unreachable, should be recognized as a crash. However, some binaries use

0 commit comments

Comments
 (0)