diff --git a/libc/calls/getprogramexecutablename.greg.c b/libc/calls/getprogramexecutablename.greg.c index ab72f1727..4c4bbca53 100644 --- a/libc/calls/getprogramexecutablename.greg.c +++ b/libc/calls/getprogramexecutablename.greg.c @@ -23,6 +23,7 @@ #include "libc/cosmo.h" #include "libc/dce.h" #include "libc/errno.h" +#include "libc/intrin/getenv.internal.h" #include "libc/serialize.h" #include "libc/limits.h" #include "libc/macros.internal.h" @@ -36,8 +37,6 @@ #define KERN_PROC 14 #define KERN_PROC_PATHNAME_FREEBSD 12 #define KERN_PROC_PATHNAME_NETBSD 5 -#define VARNAME "COSMOPOLITAN_PROGRAM_EXECUTABLE=" -#define VARSIZE (sizeof(VARNAME) - 1) static struct { atomic_uint once; @@ -79,10 +78,11 @@ static inline void InitProgramExecutableNameImpl(void) { goto CopyString; } - /* new-style loader supplies the full program path as the first - environment variable; if it is defined, trust it as-is. */ - if (*__envp && !strncmp(*__envp, VARNAME, VARSIZE)) { - strlcpy(g_prog.u.buf, *__envp + VARSIZE, sizeof(g_prog.u.buf)); + /* the new-style loader supplies the full program path as the first + environment variable. in the spirit of Postel's Law ("be liberal + in what you accept"), we use __getenv to read it. */ + if ((q = __getenv(__envp, "COSMOPOLITAN_PROGRAM_EXECUTABLE").s)) { + strlcpy(g_prog.u.buf, q, sizeof(g_prog.u.buf)); return; } @@ -162,7 +162,7 @@ static inline void InitProgramExecutableNameImpl(void) { g_prog.u.buf[0] = 0; } -static void InitProgramExecutableName(void) { +void __InitProgramExecutableName(void) { int e = errno; InitProgramExecutableNameImpl(); errno = e; @@ -172,6 +172,6 @@ static void InitProgramExecutableName(void) { * Returns absolute path of program. */ char *GetProgramExecutableName(void) { - cosmo_once(&g_prog.once, InitProgramExecutableName); + cosmo_once(&g_prog.once, __InitProgramExecutableName); return g_prog.u.buf; } diff --git a/test/libc/calls/getprogramexecutablename_test.c b/test/libc/calls/getprogramexecutablename_test.c index 4d43e1454..3a4891c8b 100644 --- a/test/libc/calls/getprogramexecutablename_test.c +++ b/test/libc/calls/getprogramexecutablename_test.c @@ -23,6 +23,7 @@ #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/o.h" +#include "libc/testlib/ezbench.h" #include "libc/testlib/subprocess.h" #include "libc/testlib/testlib.h" @@ -59,12 +60,14 @@ TEST(GetProgramExecutableName, ofThisFile) { TEST(GetProgramExecutableName, nullEnv) { SPAWN(fork); execve(self, (char *[]){self, "Child", self, 0}, (char *[]){ 0 }); + abort(); EXITS(0); } TEST(GetProramExecutableName, weirdArgv0NullEnv) { SPAWN(fork); execve(self, (char *[]){"hello", "Child", self, 0}, (char *[]){ 0 }); + abort(); EXITS(0); } @@ -74,6 +77,7 @@ TEST(GetProgramExecutableName, weirdArgv0CosmoVar) { stpcpy(stpcpy(buf, "COSMOPOLITAN_PROGRAM_EXECUTABLE="), self); SPAWN(fork); execve(self, (char *[]){"hello", "Child", self, 0}, (char *[]){ buf, 0}); + abort(); EXITS(0); } @@ -82,10 +86,11 @@ TEST(GetProgramExecutableName, weirdArgv0WrongCosmoVar) { char *bad = "COSMOPOLITAN_PROGRAM_EXECUTABLE=hi"; SPAWN(fork); execve(self, (char *[]){"hello", "Child", self, 0}, (char *[]){ bad, 0}); + abort(); EXITS(0); } -TEST(GetProgramExecutableName, MovedSelf) { +TEST(GetProgramExecutableName, movedSelf) { char buf[BUFSIZ]; ASSERT_SYS(0, 3, open(GetProgramExecutableName(), O_RDONLY)); ASSERT_SYS(0, 4, creat("test", 0755)); @@ -100,5 +105,12 @@ TEST(GetProgramExecutableName, MovedSelf) { stpcpy(buf + strlen(buf), "/test"); SPAWN(fork); execve(buf, (char *[]){"hello", "Child", buf, 0}, (char *[]){ 0 }); + abort(); EXITS(0); } + +void __InitProgramExecutableName(void); + +BENCH(GetProgramExecutableName, bench) { + EZBENCH2("Init", donothing, __InitProgramExecutableName()); +}