mirror of
https://github.com/dlang/phobos.git
synced 2025-05-01 07:30:33 +03:00
Merge pull request #9048 from the-horo/closefrom-spawn-process
std/process: Default to libc closefrom in spawnProcessPosix
This commit is contained in:
commit
eab6595ade
1 changed files with 100 additions and 45 deletions
|
@ -880,6 +880,7 @@ version (Posix) private enum InternalError : ubyte
|
||||||
doubleFork,
|
doubleFork,
|
||||||
malloc,
|
malloc,
|
||||||
preExec,
|
preExec,
|
||||||
|
closefds_dup2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1008,7 +1009,7 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
|
||||||
if (config.flags & Config.Flags.detached)
|
if (config.flags & Config.Flags.detached)
|
||||||
close(pidPipe[0]);
|
close(pidPipe[0]);
|
||||||
close(forkPipe[0]);
|
close(forkPipe[0]);
|
||||||
immutable forkPipeOut = forkPipe[1];
|
auto forkPipeOut = forkPipe[1];
|
||||||
immutable pidPipeOut = pidPipe[1];
|
immutable pidPipeOut = pidPipe[1];
|
||||||
|
|
||||||
// Set the working directory.
|
// Set the working directory.
|
||||||
|
@ -1042,6 +1043,17 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
|
||||||
|
|
||||||
if (!(config.flags & Config.Flags.inheritFDs))
|
if (!(config.flags & Config.Flags.inheritFDs))
|
||||||
{
|
{
|
||||||
|
version (FreeBSD)
|
||||||
|
import core.sys.freebsd.unistd : closefrom;
|
||||||
|
else version (OpenBSD)
|
||||||
|
import core.sys.openbsd.unistd : closefrom;
|
||||||
|
|
||||||
|
static if (!__traits(compiles, closefrom))
|
||||||
|
{
|
||||||
|
// FIXME: This implementation crashes the system when RLIMIT_NOFILE
|
||||||
|
// has a big value. For a possible solution see:
|
||||||
|
// https://github.com/dlang/phobos/pull/8990
|
||||||
|
void fallback (int lowfd) {
|
||||||
// NOTE: malloc() and getrlimit() are not on the POSIX async
|
// NOTE: malloc() and getrlimit() are not on the POSIX async
|
||||||
// signal safe functions list, but practically this should
|
// signal safe functions list, but practically this should
|
||||||
// not be a problem. Java VM and CPython also use malloc()
|
// not be a problem. Java VM and CPython also use malloc()
|
||||||
|
@ -1058,8 +1070,7 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
|
||||||
}
|
}
|
||||||
immutable maxDescriptors = cast(int) r.rlim_cur;
|
immutable maxDescriptors = cast(int) r.rlim_cur;
|
||||||
|
|
||||||
// The above, less stdin, stdout, and stderr
|
immutable maxToClose = maxDescriptors - lowfd;
|
||||||
immutable maxToClose = maxDescriptors - 3;
|
|
||||||
|
|
||||||
// Call poll() to see which ones are actually open:
|
// Call poll() to see which ones are actually open:
|
||||||
auto pfds = cast(pollfd*) malloc(pollfd.sizeof * maxToClose);
|
auto pfds = cast(pollfd*) malloc(pollfd.sizeof * maxToClose);
|
||||||
|
@ -1069,7 +1080,7 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
|
||||||
}
|
}
|
||||||
foreach (i; 0 .. maxToClose)
|
foreach (i; 0 .. maxToClose)
|
||||||
{
|
{
|
||||||
pfds[i].fd = i + 3;
|
pfds[i].fd = i + lowfd;
|
||||||
pfds[i].events = 0;
|
pfds[i].events = 0;
|
||||||
pfds[i].revents = 0;
|
pfds[i].revents = 0;
|
||||||
}
|
}
|
||||||
|
@ -1077,8 +1088,6 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
|
||||||
{
|
{
|
||||||
foreach (i; 0 .. maxToClose)
|
foreach (i; 0 .. maxToClose)
|
||||||
{
|
{
|
||||||
// don't close pipe write end
|
|
||||||
if (pfds[i].fd == forkPipeOut) continue;
|
|
||||||
// POLLNVAL will be set if the file descriptor is invalid.
|
// POLLNVAL will be set if the file descriptor is invalid.
|
||||||
if (!(pfds[i].revents & POLLNVAL)) close(pfds[i].fd);
|
if (!(pfds[i].revents & POLLNVAL)) close(pfds[i].fd);
|
||||||
}
|
}
|
||||||
|
@ -1086,13 +1095,55 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Fall back to closing everything.
|
// Fall back to closing everything.
|
||||||
foreach (i; 3 .. maxDescriptors)
|
foreach (i; lowfd .. maxDescriptors)
|
||||||
{
|
{
|
||||||
if (i == forkPipeOut) continue;
|
|
||||||
close(i);
|
close(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// closefrom may not be available on the version of glibc we build against.
|
||||||
|
// Until we find a way to perform this check we will try to use dlsym to
|
||||||
|
// check for the function. See: https://github.com/dlang/phobos/pull/9048
|
||||||
|
version (CRuntime_Glibc)
|
||||||
|
void closefrom (int lowfd) {
|
||||||
|
static bool tryGlibcClosefrom (int lowfd) {
|
||||||
|
import core.sys.posix.dlfcn : dlopen, dlclose, dlsym, dlerror, RTLD_LAZY;
|
||||||
|
|
||||||
|
void *handle = dlopen("libc.so.6", RTLD_LAZY);
|
||||||
|
if (!handle)
|
||||||
|
return false;
|
||||||
|
scope(exit) dlclose(handle);
|
||||||
|
|
||||||
|
// Clear errors
|
||||||
|
dlerror();
|
||||||
|
alias closefromT = extern(C) void function(int) @nogc @system nothrow;
|
||||||
|
auto closefrom = cast(closefromT) dlsym(handle, "closefrom");
|
||||||
|
if (dlerror())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
closefrom(lowfd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tryGlibcClosefrom(lowfd))
|
||||||
|
fallback(lowfd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
alias closefrom = fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to close all open file descriptors excluding std{in,out,err}
|
||||||
|
// and forkPipeOut because we still need it.
|
||||||
|
// Since the various libc's provide us with `closefrom` move forkPipeOut
|
||||||
|
// to position 3, right after STDERR_FILENO, and close all FDs following that.
|
||||||
|
if (dup2(forkPipeOut, 3) == -1)
|
||||||
|
abortOnError(forkPipeOut, InternalError.closefds_dup2, .errno);
|
||||||
|
forkPipeOut = 3;
|
||||||
|
// forkPipeOut needs to be closed after we call `exec`.
|
||||||
|
setCLOEXEC(forkPipeOut, true);
|
||||||
|
closefrom(forkPipeOut + 1);
|
||||||
|
}
|
||||||
else // This is already done if we don't inherit descriptors.
|
else // This is already done if we don't inherit descriptors.
|
||||||
{
|
{
|
||||||
// Close the old file descriptors, unless they are
|
// Close the old file descriptors, unless they are
|
||||||
|
@ -1205,6 +1256,10 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
|
||||||
case InternalError.preExec:
|
case InternalError.preExec:
|
||||||
errorMsg = "Failed to execute preExecFunction or preExecDelegate";
|
errorMsg = "Failed to execute preExecFunction or preExecDelegate";
|
||||||
break;
|
break;
|
||||||
|
case InternalError.closefds_dup2:
|
||||||
|
assert(!(config.flags & Config.Flags.inheritFDs));
|
||||||
|
errorMsg = "Failed to close inherited file descriptors";
|
||||||
|
break;
|
||||||
case InternalError.noerror:
|
case InternalError.noerror:
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue