From b8d26e24188dfa0616bc8e177749fd268fdc58bb Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Fri, 29 Jan 2021 23:19:29 -0800 Subject: [PATCH] Fix fork() on Windows after chdir() --- libc/calls/hefty/fork-nt.c | 8 ++- libc/nt/dll.h | 1 + libc/nt/files.h | 9 ++++ libc/nt/kernel32/GetFinalPathNameByHandleA.s | 10 ++++ libc/nt/kernel32/GetFinalPathNameByHandleW.s | 10 ++++ libc/nt/master.sh | 4 +- test/libc/calls/lseek_test.c | 55 ++++++++++++++++++++ 7 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 test/libc/calls/lseek_test.c diff --git a/libc/calls/hefty/fork-nt.c b/libc/calls/hefty/fork-nt.c index 5c85a314..ed465a2f 100644 --- a/libc/calls/hefty/fork-nt.c +++ b/libc/calls/hefty/fork-nt.c @@ -22,7 +22,9 @@ #include "libc/calls/internal.h" #include "libc/calls/ntspawn.h" #include "libc/fmt/itoa.h" +#include "libc/macros.h" #include "libc/nexgen32e/nt2sysv.h" +#include "libc/nt/dll.h" #include "libc/nt/enum/filemapflags.h" #include "libc/nt/enum/pageflags.h" #include "libc/nt/enum/startf.h" @@ -119,6 +121,7 @@ textwindows void WinMainForked(void) { textwindows int fork$nt(void) { jmp_buf jb; int i, rc, pid; + char exe[PATH_MAX]; int64_t reader, writer; char *p, buf[21 + 1 + 21 + 1]; struct NtStartupInfo startinfo; @@ -137,8 +140,9 @@ textwindows int fork$nt(void) { startinfo.hStdInput = g_fds.p[0].handle; startinfo.hStdOutput = g_fds.p[1].handle; startinfo.hStdError = g_fds.p[2].handle; - if (ntspawn(g_argv[0], g_argv, environ, &kNtIsInheritable, NULL, true, 0, - NULL, &startinfo, &procinfo) != -1) { + GetModuleFileNameA(0, exe, ARRAYLEN(exe)); + if (ntspawn(exe, g_argv, environ, &kNtIsInheritable, NULL, true, 0, NULL, + &startinfo, &procinfo) != -1) { CloseHandle(reader); CloseHandle(procinfo.hThread); if (weaken(__sighandrvas) && diff --git a/libc/nt/dll.h b/libc/nt/dll.h index 22b45ed9..507e0e61 100644 --- a/libc/nt/dll.h +++ b/libc/nt/dll.h @@ -32,6 +32,7 @@ int64_t LoadLibraryEx(const char16_t *lpLibFileName, int64_t hFile, uint32_t dwFlags); uint32_t GetModuleFileName(int64_t hModule, char16_t *lpFilename, uint32_t nSize); +uint32_t GetModuleFileNameA(int64_t hModule, char *lpFilename, uint32_t nSize); intptr_t GetModuleHandle(const char *opt_lpModuleName); intptr_t GetModuleHandleW(const char16_t *opt_lpModuleName); void *GetProcAddress(int64_t hModule, const char *lpProcName); diff --git a/libc/nt/files.h b/libc/nt/files.h index 865f0924..f95ce68d 100644 --- a/libc/nt/files.h +++ b/libc/nt/files.h @@ -199,6 +199,15 @@ bool32 WriteFileGather(int64_t hFileOpenedWithOverlappedAndNoBuffering, uint32_t nNumberOfBytesToWrite, uint32_t *lpReserved, struct NtOverlapped inout_lpOverlapped) paramsnonnull(); +#define kNtFileNameNormalized 0x0 +#define kNtVolumeNameDos 0x0 +#define kNtVolumeNameGuid 0x1 +#define kNtVolumeNameNt 0x2 +#define kNtVolumeNameNone 0x4 +#define kNtFileNameOpened 0x8 +uint32_t GetFinalPathNameByHandle(int64_t hFile, char16_t *out_path, + uint32_t size, uint32_t flags); + #if ShouldUseMsabiAttribute() #include "libc/nt/thunk/files.inc" #endif /* ShouldUseMsabiAttribute() */ diff --git a/libc/nt/kernel32/GetFinalPathNameByHandleA.s b/libc/nt/kernel32/GetFinalPathNameByHandleA.s index 83086100..b7517f7c 100644 --- a/libc/nt/kernel32/GetFinalPathNameByHandleA.s +++ b/libc/nt/kernel32/GetFinalPathNameByHandleA.s @@ -1,2 +1,12 @@ .include "o/libc/nt/codegen.inc" .imp kernel32,__imp_GetFinalPathNameByHandleA,GetFinalPathNameByHandleA,0 + + .text.windows +GetFinalPathNameByHandleA: + push %rbp + mov %rsp,%rbp + .profilable + mov __imp_GetFinalPathNameByHandleA(%rip),%rax + jmp __sysv2nt + .endfn GetFinalPathNameByHandleA,globl + .previous diff --git a/libc/nt/kernel32/GetFinalPathNameByHandleW.s b/libc/nt/kernel32/GetFinalPathNameByHandleW.s index 8f25bef4..91b1c0e3 100644 --- a/libc/nt/kernel32/GetFinalPathNameByHandleW.s +++ b/libc/nt/kernel32/GetFinalPathNameByHandleW.s @@ -1,2 +1,12 @@ .include "o/libc/nt/codegen.inc" .imp kernel32,__imp_GetFinalPathNameByHandleW,GetFinalPathNameByHandleW,0 + + .text.windows +GetFinalPathNameByHandle: + push %rbp + mov %rsp,%rbp + .profilable + mov __imp_GetFinalPathNameByHandleW(%rip),%rax + jmp __sysv2nt + .endfn GetFinalPathNameByHandle,globl + .previous diff --git a/libc/nt/master.sh b/libc/nt/master.sh index ae0099df..eab15780 100755 --- a/libc/nt/master.sh +++ b/libc/nt/master.sh @@ -2176,8 +2176,8 @@ imp 'GetFileVersionInfoSizeExA' GetFileVersionInfoSizeExA KernelBase 561 imp 'GetFileVersionInfoSizeEx' GetFileVersionInfoSizeExW KernelBase 562 imp 'GetFileVersionInfoSize' GetFileVersionInfoSizeW KernelBase 563 imp 'GetFileVersionInfo' GetFileVersionInfoW KernelBase 564 -imp 'GetFinalPathNameByHandleA' GetFinalPathNameByHandleA kernel32 0 # KernelBase -imp 'GetFinalPathNameByHandle' GetFinalPathNameByHandleW kernel32 0 # KernelBase +imp 'GetFinalPathNameByHandleA' GetFinalPathNameByHandleA kernel32 0 4 # KernelBase +imp 'GetFinalPathNameByHandle' GetFinalPathNameByHandleW kernel32 0 4 # KernelBase imp 'GetFirmwareEnvironmentVariableA' GetFirmwareEnvironmentVariableA kernel32 597 imp 'GetFirmwareEnvironmentVariableExA' GetFirmwareEnvironmentVariableExA kernel32 598 imp 'GetFirmwareEnvironmentVariableEx' GetFirmwareEnvironmentVariableExW kernel32 599 diff --git a/test/libc/calls/lseek_test.c b/test/libc/calls/lseek_test.c new file mode 100644 index 00000000..905b75dd --- /dev/null +++ b/test/libc/calls/lseek_test.c @@ -0,0 +1,55 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ 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/internal.h" +#include "libc/fmt/fmt.h" +#include "libc/log/check.h" +#include "libc/runtime/runtime.h" +#include "libc/sysv/consts/o.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +char testdir[PATH_MAX]; + +void SetUp(void) { + sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid()); + makedirs(testdir, 0755); + CHECK_NE(-1, chdir(testdir)); +} + +void TearDown(void) { + CHECK_NE(-1, chdir("../../..")); + CHECK_NE(-1, rmrf(testdir)); +} + +TEST(lseek, wat) { + int fd, pid; + char buf[8] = {0}; + ASSERT_NE(-1, (fd = open("wut", O_RDWR | O_CREAT, 0644))); + ASSERT_EQ(3, write(fd, "wut", 3)); + ASSERT_NE(-1, lseek(fd, 0, SEEK_SET)); + if (!(pid = fork())) { + lseek(fd, 1, SEEK_SET); + _exit(0); + } + EXPECT_NE(-1, waitpid(pid, 0, 0)); + EXPECT_EQ(1, read(fd, buf, 1)); + EXPECT_EQ('u', buf[0]); /* wat?! */ + EXPECT_NE(-1, close(fd)); +}