diff --git a/libc/sysv/consts/auxv.h b/libc/sysv/consts/auxv.h index 208b5851e..5d897de82 100644 --- a/libc/sysv/consts/auxv.h +++ b/libc/sysv/consts/auxv.h @@ -4,13 +4,15 @@ /* * integral getauxval() keys */ -#define AT_PHDR 3 -#define AT_PHENT 4 -#define AT_PHNUM 5 -#define AT_PAGESZ 6 -#define AT_BASE 7 -#define AT_FLAGS 8 -#define AT_ENTRY 9 +#define AT_PHDR 3 +#define AT_PHENT 4 +#define AT_PHNUM 5 +#define AT_PAGESZ 6 +#define AT_BASE 7 +#define AT_FLAGS 8 +#define AT_FLAGS_PRESERVE_ARGV0_BIT 0 +#define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT) +#define AT_ENTRY 9 COSMOPOLITAN_C_START_ diff --git a/test/libc/calls/getprogramexecutablename_test.c b/test/libc/calls/getprogramexecutablename_test.c index 2665d34eb..0c4b8e830 100644 --- a/test/libc/calls/getprogramexecutablename_test.c +++ b/test/libc/calls/getprogramexecutablename_test.c @@ -27,6 +27,7 @@ #include "libc/serialize.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" +#include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/ok.h" #include "libc/testlib/ezbench.h" @@ -34,32 +35,44 @@ #include "libc/testlib/testlib.h" static char *self; -static bool skiptests; +static bool skiptests, skiparg0; void SetUpOnce(void) { - self = GetProgramExecutableName(); testlib_enable_tmp_setup_teardown(); - if (IsMetal()) { - skiptests = true; - } else if (IsOpenbsd() || (IsXnu() && !IsXnuSilicon())) { - ASSERT_STRNE(self, ""); - ASSERT_SYS(0, 3, open(self, O_RDONLY)); - char buf[8]; - ASSERT_SYS(0, 8, pread(3, buf, 8, 0)); - ASSERT_SYS(0, 0, close(3)); - if (READ64LE(buf) != READ64LE("MZqFpD='") && - READ64LE(buf) != READ64LE("jartsr='") && - READ64LE(buf) != READ64LE("APEDBG='")) { - fprintf(stderr, - "we appear to be running as an assimilated binary on OpenBSD or " - "x86_64 XNU;\nGetProgramExecutableName is unreliable here\n"); - skiptests = true; - } - } } __attribute__((__constructor__)) static void Child(int argc, char *argv[]) { - if (argc >= 2 && !strcmp(argv[1], "Child")) { + if (argc < 2 || strcmp(argv[1], "Child")) { + bool loaded = !!__program_executable_name; + self = GetProgramExecutableName(); + if (IsMetal()) { + skiptests = true; + } else if (IsWindows()) { + /* do all tests */ + } else if (!loaded) { + ASSERT_STRNE(self, ""); + ASSERT_SYS(0, 3, open(self, O_RDONLY)); + char buf[8]; + ASSERT_SYS(0, 8, pread(3, buf, 8, 0)); + ASSERT_SYS(0, 0, close(3)); + if (READ64LE(buf) != READ64LE("MZqFpD='") && + READ64LE(buf) != READ64LE("jartsr='") && + READ64LE(buf) != READ64LE("APEDBG='")) { + // GetProgramExecutableName does not work reliably for assimilated + // OpenBSD or XNU binaries. + skiptests = IsOpenbsd() || (IsXnu() && !IsXnuSilicon()); + } + } else { + skiparg0 = + !(IsXnuSilicon() || (getauxval(AT_FLAGS) & AT_FLAGS_PRESERVE_ARGV0)); + } + fprintf(stderr, loaded ? "loaded\n" : "not loaded\n"); + if (skiptests) { + fprintf(stderr, "skipping most GetProgramExecutableName tests\n"); + } else if (skiparg0) { + fprintf(stderr, "skipping argv[0] tests\n"); + } + } else { int rc; if (!IsWindows()) { rc = sys_chdir("/"); @@ -72,14 +85,10 @@ __attribute__((__constructor__)) static void Child(int argc, char *argv[]) { if (strcmp(argv[2], GetProgramExecutableName())) { exit(123); } - if (!IsXnuSilicon()) exit(0); - /* TODO(mrdomino): argv[0] tests only pass on XnuSilicon right now because - __sys_execve fails there, so the ape loader is used. - the correct check is "we have been invoked either as an - assimilated binary or via the ape loader, and not via a - raw __sys_execve." */ - if (strcmp(argv[3], argv[0])) { - exit(124); + if (argc >= 4) { + if (strcmp(argv[3], argv[0])) { + exit(124); + } } exit(0); } @@ -98,7 +107,8 @@ TEST(GetProgramExecutableName, ofThisFile) { TEST(GetProgramExecutableName, nullEnv) { if (skiptests) return; SPAWN(fork); - execve(self, (char *[]){self, "Child", self, self, 0}, (char *[]){0}); + execve(self, (char *[]){self, "Child", self, skiparg0 ? 0 : self, 0}, + (char *[]){0}); abort(); EXITS(0); } @@ -106,7 +116,8 @@ TEST(GetProgramExecutableName, nullEnv) { TEST(GetProramExecutableName, weirdArgv0NullEnv) { if (skiptests) return; SPAWN(fork); - execve(self, (char *[]){"hello", "Child", self, "hello", 0}, (char *[]){0}); + execve(self, (char *[]){"hello", "Child", self, skiparg0 ? 0 : "hello", 0}, + (char *[]){0}); abort(); EXITS(0); } @@ -133,11 +144,12 @@ TEST(GetProgramExecutableName, movedSelf) { ASSERT_NE(NULL, getcwd(buf, BUFSIZ - 5)); stpcpy(buf + strlen(buf), "/test"); SPAWN(fork); - execve(buf, (char *[]){"hello", "Child", buf, "hello", 0}, (char *[]){0}); + execve(buf, (char *[]){"hello", "Child", buf, skiparg0 ? 0 : "hello", 0}, + (char *[]){0}); abort(); EXITS(0); SPAWN(fork); - execve("./test", (char *[]){"hello", "Child", buf, "hello", 0}, + execve("./test", (char *[]){"hello", "Child", buf, skiparg0 ? 0 : "hello", 0}, (char *[]){0}); abort(); EXITS(0);