Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit 3ba3a4c

Browse files
committed
Support: Add a utility to remap std{in,out,err} to /dev/null if closed
It's possible to start a program with one (or all) of the standard file descriptors closed. Subsequent open system calls will give the program a low-numbered file descriptor. This is problematic because we may believe we are writing to standard out instead of a file. Introduce Process::FixupStandardFileDescriptors, a helper function to remap standard file descriptors to /dev/null if they were closed before the program started. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@219170 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 5b8cd15 commit 3ba3a4c

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

include/llvm/Support/Process.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,12 @@ class Process {
186186
ArrayRef<const char *> ArgsFromMain,
187187
SpecificBumpPtrAllocator<char> &ArgAllocator);
188188

189+
// This functions ensures that the standard file descriptors (input, output,
190+
// and error) are properly mapped to a file descriptor before we use any of
191+
// them. This should only be called by standalone programs, library
192+
// components should not call this.
193+
static std::error_code FixupStandardFileDescriptors();
194+
189195
/// This function determines if the standard input is connected directly
190196
/// to a user's input (keyboard probably), rather than coming from a file
191197
/// or pipe.

lib/Support/Unix/Process.inc

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#include "llvm/Support/Mutex.h"
1919
#include "llvm/Support/MutexGuard.h"
2020
#include "llvm/Support/TimeValue.h"
21+
#if HAVE_FCNTL_H
22+
#include <fcntl.h>
23+
#endif
2124
#ifdef HAVE_SYS_TIME_H
2225
#include <sys/time.h>
2326
#endif
@@ -199,6 +202,62 @@ Process::GetArgumentVector(SmallVectorImpl<const char *> &ArgsOut,
199202
return std::error_code();
200203
}
201204

205+
namespace {
206+
class FDCloser {
207+
public:
208+
FDCloser(int &FD) : FD(FD), KeepOpen(false) {}
209+
void keepOpen() { KeepOpen = true; }
210+
~FDCloser() {
211+
if (!KeepOpen && FD >= 0)
212+
::close(FD);
213+
}
214+
215+
private:
216+
FDCloser(const FDCloser &) LLVM_DELETED_FUNCTION;
217+
void operator=(const FDCloser &) LLVM_DELETED_FUNCTION;
218+
219+
int &FD;
220+
bool KeepOpen;
221+
};
222+
}
223+
224+
std::error_code Process::FixupStandardFileDescriptors() {
225+
int NullFD = -1;
226+
FDCloser FDC(NullFD);
227+
const int StandardFDs[] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO};
228+
for (int StandardFD : StandardFDs) {
229+
struct stat st;
230+
errno = 0;
231+
while (fstat(StandardFD, &st) < 0) {
232+
assert(errno && "expected errno to be set if fstat failed!");
233+
// fstat should return EBADF if the file descriptor is closed.
234+
if (errno == EBADF)
235+
break;
236+
// retry fstat if we got EINTR, otherwise bubble up the failure.
237+
if (errno != EINTR)
238+
return std::error_code(errno, std::generic_category());
239+
}
240+
// if fstat succeeds, move on to the next FD.
241+
if (!errno)
242+
continue;
243+
assert(errno == EBADF && "expected errno to have EBADF at this point!");
244+
245+
if (NullFD < 0) {
246+
while ((NullFD = open("/dev/null", O_RDWR)) < 0) {
247+
if (errno == EINTR)
248+
continue;
249+
return std::error_code(errno, std::generic_category());
250+
}
251+
}
252+
253+
if (NullFD == StandardFD)
254+
FDC.keepOpen();
255+
else if (dup2(NullFD, StandardFD) < 0)
256+
return std::error_code(errno, std::generic_category());
257+
}
258+
return std::error_code();
259+
}
260+
202261
bool Process::StandardInIsUserInput() {
203262
return FileDescriptorIsDisplayed(STDIN_FILENO);
204263
}

lib/Support/Windows/Process.inc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,10 @@ Process::GetArgumentVector(SmallVectorImpl<const char *> &Args,
273273
return ec;
274274
}
275275

276+
std::error_code Process::FixupStandardFileDescriptors() {
277+
return std::error_code();
278+
}
279+
276280
bool Process::StandardInIsUserInput() {
277281
return FileDescriptorIsDisplayed(0);
278282
}

0 commit comments

Comments
 (0)