Fix #10574 - environment pointer sometimes changes before exec, causing

segfault in child process.
This commit is contained in:
Steven Schveighoffer 2024-12-04 21:35:16 -05:00 committed by The Dlang Bot
parent bf6e70b104
commit d767448ea6

View file

@ -148,8 +148,8 @@ private
{ {
version (Darwin) version (Darwin)
{ {
extern(C) char*** _NSGetEnviron() nothrow; extern(C) char*** _NSGetEnviron() @nogc nothrow;
const(char**) getEnvironPtr() @trusted const(char**) getEnvironPtr() @trusted @nogc nothrow
{ {
return *_NSGetEnviron; return *_NSGetEnviron;
} }
@ -158,7 +158,7 @@ private
{ {
// Made available by the C runtime: // Made available by the C runtime:
extern(C) extern __gshared const char** environ; extern(C) extern __gshared const char** environ;
const(char**) getEnvironPtr() @trusted const(char**) getEnvironPtr() @trusted @nogc nothrow
{ {
return environ; return environ;
} }
@ -1119,7 +1119,7 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
} }
// Execute program. // Execute program.
core.sys.posix.unistd.execve(argz[0], argz.ptr, envz); core.sys.posix.unistd.execve(argz[0], argz.ptr, envz is null ? getEnvironPtr : envz);
// If execution fails, exit as quickly as possible. // If execution fails, exit as quickly as possible.
abortOnError(forkPipeOut, InternalError.exec, .errno); abortOnError(forkPipeOut, InternalError.exec, .errno);
@ -1421,7 +1421,7 @@ private Pid spawnProcessWin(scope const(char)[] commandLine,
// on the form "name=value", optionally adding those of the current process' // on the form "name=value", optionally adding those of the current process'
// environment strings that are not present in childEnv. If the parent's // environment strings that are not present in childEnv. If the parent's
// environment should be inherited without modification, this function // environment should be inherited without modification, this function
// returns environ directly. // returns null.
version (Posix) version (Posix)
private const(char*)* createEnv(const string[string] childEnv, private const(char*)* createEnv(const string[string] childEnv,
bool mergeWithParentEnv) bool mergeWithParentEnv)
@ -1431,7 +1431,7 @@ private const(char*)* createEnv(const string[string] childEnv,
auto environ = getEnvironPtr; auto environ = getEnvironPtr;
if (mergeWithParentEnv) if (mergeWithParentEnv)
{ {
if (childEnv.length == 0) return environ; if (childEnv.length == 0) return null;
while (environ[parentEnvLength] != null) ++parentEnvLength; while (environ[parentEnvLength] != null) ++parentEnvLength;
} }
@ -1461,16 +1461,7 @@ version (Posix) @system unittest
assert(e1 != null && *e1 == null); assert(e1 != null && *e1 == null);
auto e2 = createEnv(null, true); auto e2 = createEnv(null, true);
assert(e2 != null); assert(e2 == null);
int i = 0;
auto environ = getEnvironPtr;
for (; environ[i] != null; ++i)
{
assert(e2[i] != null);
import core.stdc.string : strcmp;
assert(strcmp(e2[i], environ[i]) == 0);
}
assert(e2[i] == null);
auto e3 = createEnv(["foo" : "bar", "hello" : "world"], false); auto e3 = createEnv(["foo" : "bar", "hello" : "world"], false);
assert(e3 != null && e3[0] != null && e3[1] != null && e3[2] == null); assert(e3 != null && e3[0] != null && e3[1] != null && e3[2] == null);