Fix GetProgramExecutableName() on NetBSD (#1529)

The sysctl parameters for querying KERN_PROC_PATHNAME are different from
FreeBSD. The tests now check the GPEN path using stat instead of strcmp.
This commit is contained in:
Gavin Hayes authored and GitHub committed 2026-10-20 00:04:57 -04:00
1 parent 34fa4edae8
commit b0cebefd8e
4 files changed
+122 -9

No files matched your search

+6 -3
View File
@@ -43,6 +43,7 @@ __static_yoink("_init_program_executable_name");
#define CTL_KERN 1
#define KERN_PROC 14
#define KERN_PROC_ARGS 48
#define KERN_PROC_PATHNAME_FREEBSD 12
#define KERN_PROC_PATHNAME_NETBSD 5
@@ -173,13 +174,15 @@ static inline void InitProgramExecutableNameImpl(void) {
if (IsFreebsd() || IsNetbsd()) {
int cmd[4];
cmd[0] = CTL_KERN;
cmd[1] = KERN_PROC;
if (IsFreebsd()) {
cmd[1] = KERN_PROC;
cmd[2] = KERN_PROC_PATHNAME_FREEBSD;
cmd[3] = -1; // current process
} else {
cmd[2] = KERN_PROC_PATHNAME_NETBSD;
cmd[1] = KERN_PROC_ARGS;
cmd[2] = -1; // current process
cmd[3] = KERN_PROC_PATHNAME_NETBSD;
}
cmd[3] = -1; // current process
if (sysctl(cmd, ARRAYLEN(cmd), b, &n, 0, 0) != -1) {
if (!OldApeLoader(b)) {
goto UseBuf;
+18 -5
View File
@@ -73,6 +73,7 @@ o/$(MODE)/test/libc/calls/getprogramexecutablename_test.dbg: \
$(TEST_LIBC_CALLS_DEPS) \
o/$(MODE)/test/libc/calls/getprogramexecutablename_test.o \
o/$(MODE)/test/libc/calls/ape.elf.zip.o \
o/$(MODE)/test/libc/calls/gpenchild.elf.zip.o \
o/$(MODE)/test/libc/calls/calls.pkg \
$(LIBC_TESTMAIN) \
$(CRT) \
@@ -125,14 +126,25 @@ o/$(MODE)/test/libc/calls/life-nomod.dbg: \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/test/libc/calls/zipread.dbg: \
$(LIBC_RUNTIME) \
o/$(MODE)/test/libc/calls/zipread.o \
o/$(MODE)/test/libc/mem/prog/life.elf.zip.o \
$(CRT) \
o/$(MODE)/test/libc/calls/gpenchild.dbg: \
$(LIBC_RUNTIME) \
o/$(MODE)/test/libc/calls/gpenchild.o \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/test/libc/calls/gpenchild.elf: \
o/$(MODE)/tool/build/assimilate \
o/$(MODE)/test/libc/calls/gpenchild \
o/$(MODE)/tool/build/cp
@$(COMPILE) -wACP -T$@ \
o/$(MODE)/tool/build/cp \
o/$(MODE)/test/libc/calls/gpenchild \
o/$(MODE)/test/libc/calls/gpenchild.elf
@$(COMPILE) -wAASSIMILATE -T$@ \
o/$(MODE)/tool/build/assimilate -bcef \
o/$(MODE)/test/libc/calls/gpenchild.elf
o/$(MODE)/test/libc/calls/ape.elf: \
o/$(MODE)/tool/build/cp \
o/$(MODE)/ape/ape.elf
@@ -142,6 +154,7 @@ o/$(MODE)/test/libc/calls/ape.elf: \
o/$(MODE)/test/libc/calls/ape.elf
o/$(MODE)/test/libc/calls/ape.elf.zip.o \
o/$(MODE)/test/libc/calls/gpenchild.elf.zip.o \
o/$(MODE)/test/libc/calls/tiny64.elf.zip.o \
o/$(MODE)/test/libc/calls/life-nomod.zip.o \
o/$(MODE)/test/libc/calls/life-classic.zip.o: private \
@@ -19,6 +19,7 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/metalfile.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
@@ -70,6 +71,18 @@ void SetUpOnce(void) {
}
}
static bool isAbsPath(const char *path) {
return strlen(path) >= 2 && path[0] == '/' && path[1] != '/';
}
static bool isSameFile(const char *a, const char *b) {
struct stat st_a, st_b;
if (stat(a, &st_a) || stat(b, &st_b)) {
return false;
}
return (st_a.st_dev == st_b.st_dev) && (st_a.st_ino == st_b.st_ino);
}
__attribute__((__constructor__)) static void Child(int argc, char *argv[]) {
loaded = !!__program_executable_name;
if (argc >= 2 && !strcmp(argv[1], "Child")) {
@@ -82,7 +95,8 @@ __attribute__((__constructor__)) static void Child(int argc, char *argv[]) {
if (rc) {
exit(122);
}
if (strcmp(argv[2], GetProgramExecutableName())) {
const char *path = GetProgramExecutableName();
if (!path || !isAbsPath(path) || !isSameFile(argv[2], path)) {
exit(123);
}
if (argc >= 4) {
@@ -192,3 +206,23 @@ TEST(GetProgramExecutableName, nullArgvAPELoader) {
abort();
EXITS(0);
}
TEST(GetProgramExecutableName, elf) {
if (skiptests || IsOpenbsd() || IsXnu() || IsWindows() || IsMetal())
return;
char buf[BUFSIZ];
testlib_extract("/zip/gpenchild.elf", "test.elf", 0555);
ASSERT_NE(NULL, getcwd(buf, BUFSIZ - 5));
stpcpy(buf + strlen(buf), "/test.elf");
SPAWN(fork);
execve(buf, (char *[]){"hello", "Child", buf, skiparg0 ? 0 : "hello", 0},
(char *[]){0});
abort();
EXITS(0);
SPAWN(fork);
execve("./test.elf",
(char *[]){"hello", "Child", buf, skiparg0 ? 0 : "hello", 0},
(char *[]){0});
abort();
EXITS(0);
}
+63
View File
@@ -0,0 +1,63 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2023 Justine Alexandra Roberts Tunney │
│ Copyright 2026 Gavin Arthur Hayes │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
static bool isAbsPath(const char *path) {
return strlen(path) >= 2 && path[0] == '/' && path[1] != '/';
}
static bool isSameFile(const char *a, const char *b) {
struct stat st_a, st_b;
if (stat(a, &st_a) || stat(b, &st_b)) {
return false;
}
return (st_a.st_dev == st_b.st_dev) && (st_a.st_ino == st_b.st_ino);
}
int main(int argc, char *argv[]) {
if (argc >= 2 && !strcmp(argv[1], "Child")) {
int rc;
if (!IsWindows()) {
rc = sys_chdir("/");
} else {
rc = sys_chdir_nt("/");
}
if (rc) {
exit(122);
}
const char *path = GetProgramExecutableName();
if (!path || !isAbsPath(path) || !isSameFile(argv[2], path)) {
exit(123);
}
if (argc >= 4) {
if (strcmp(argv[3], argv[0])) {
exit(124);
}
}
exit(0);
}
exit(128);
}