From 0cb6b6ff4b34a3503cd899ccbb12538a58d73b49 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Sun, 20 Mar 2022 08:01:14 -0700 Subject: [PATCH] Get Redbean fork() working on the New Technology Now that we have understandable system call tracing on Windows, this change rewrites many of the polyfill internals for that platform, to help things get closer to tip top shape. Support for complex forking scenarios had been in a regressed state for quite some time. Now, it works! Subsequent changes should be able to address the performance. --- ape/ape.S | 21 ++ ape/ape.lds | 14 +- examples/forkrand.c | 5 + libc/calls/calls.mk | 1 + libc/calls/directmap-nt.c | 58 ++-- libc/calls/execve-nt.c | 3 +- libc/calls/mprotect.greg.c | 3 +- libc/calls/ntspawn.c | 5 +- libc/calls/onntconsoleevent.c | 8 +- libc/calls/open-nt.c | 98 ++++-- libc/calls/raise.c | 5 +- libc/calls/readlinkat-nt.c | 1 - libc/calls/sleep.c | 6 +- libc/intrin/asan.c | 2 +- libc/intrin/createfile.greg.c | 69 ++++ libc/intrin/createfilemappingnuma.greg.c | 51 +++ libc/intrin/describeflags.greg.c | 59 ++++ libc/intrin/describeflags.internal.h | 21 ++ libc/intrin/describentfileaccessflags.greg.c | 70 ++++ .../describentfileflagsandattributes.greg.c | 56 ++++ libc/intrin/describentfilemapflags.greg.c | 37 +++ libc/intrin/describentfileshareflags.greg.c | 34 ++ libc/intrin/describentpageflags.greg.c | 48 +++ libc/intrin/exit.greg.c | 13 +- libc/intrin/intrin.mk | 21 +- libc/intrin/kprintf.greg.c | 13 +- libc/intrin/mapviewoffileexnuma.greg.c | 52 +++ libc/{calls => intrin}/prot2nt.greg.c | 39 +-- libc/intrin/quick_exit.c | 7 - libc/intrin/virtualprotect.greg.c | 39 +++ libc/{calls => intrin}/winerr.greg.c | 0 libc/log/die.c | 2 +- libc/log/oncrash.c | 2 +- libc/nt/enum/accessmask.h | 80 ++--- libc/nt/enum/heap.h | 9 + libc/nt/enum/pageflags.h | 34 +- libc/nt/kernel32/CreateFileMappingNumaW.s | 4 +- libc/nt/kernel32/CreateFileW.s | 4 +- libc/nt/kernel32/GetProcessHeap.s | 12 + libc/nt/kernel32/GetProcessHeaps.s | 10 + libc/nt/kernel32/HeapAlloc.s | 12 + libc/nt/kernel32/HeapCompact.s | 10 + libc/nt/kernel32/HeapCreate.s | 10 + libc/nt/kernel32/HeapDestroy.s | 13 + libc/nt/kernel32/HeapFree.s | 10 + libc/nt/kernel32/HeapReAlloc.s | 12 + libc/nt/kernel32/MapViewOfFileExNuma.s | 4 +- libc/nt/kernel32/VirtualProtect.s | 4 +- libc/nt/master.sh | 22 +- libc/nt/memory.h | 6 + libc/nt/thunk/memory.inc | 10 +- libc/runtime/fork-nt.c | 313 ++++++++++++++---- libc/runtime/memtrack.c | 5 +- libc/runtime/memtrack.internal.h | 14 +- libc/runtime/mmap.c | 16 +- libc/runtime/mremap.c | 4 +- libc/runtime/runtime.h | 1 + libc/runtime/runtime.mk | 10 + libc/runtime/winmain.greg.c | 3 + libc/sock/kntwsadata.c | 12 + libc/str/longsort.c | 2 +- libc/stubs/ld.S | 12 + libc/sysv/consts.sh | 46 ++- libc/sysv/consts/O_ACCMODE.S | 2 +- libc/sysv/consts/O_APPEND.S | 2 +- libc/sysv/consts/O_COMPRESSED.S | 2 + libc/sysv/consts/O_DIRECT.S | 2 +- libc/sysv/consts/O_DIRECTORY.S | 2 +- libc/sysv/consts/O_INDEXED.S | 2 + libc/sysv/consts/O_RANDOM.S | 2 +- libc/sysv/consts/O_RDONLY.S | 2 +- libc/sysv/consts/O_RDWR.S | 2 +- libc/sysv/consts/O_SEQUENTIAL.S | 2 +- libc/sysv/consts/O_SPARSE.S | 2 +- libc/sysv/consts/O_TMPFILE.S | 2 +- libc/sysv/consts/O_WRONLY.S | 2 +- libc/sysv/consts/o.h | 13 +- libc/sysv/systemfive.S | 10 +- test/libc/calls/mkntcmdline_test.c | 10 +- test/libc/intrin/describeflags_test.c | 40 +++ test/libc/intrin/kprintf_test.c | 3 + test/libc/runtime/memtrack_test.c | 6 +- tool/build/blinkenlights.c | 2 +- tool/net/redbean.c | 1 - 84 files changed, 1340 insertions(+), 338 deletions(-) create mode 100644 libc/intrin/createfile.greg.c create mode 100644 libc/intrin/createfilemappingnuma.greg.c create mode 100644 libc/intrin/describeflags.greg.c create mode 100644 libc/intrin/describeflags.internal.h create mode 100644 libc/intrin/describentfileaccessflags.greg.c create mode 100644 libc/intrin/describentfileflagsandattributes.greg.c create mode 100644 libc/intrin/describentfilemapflags.greg.c create mode 100644 libc/intrin/describentfileshareflags.greg.c create mode 100644 libc/intrin/describentpageflags.greg.c create mode 100644 libc/intrin/mapviewoffileexnuma.greg.c rename libc/{calls => intrin}/prot2nt.greg.c (62%) create mode 100644 libc/intrin/virtualprotect.greg.c rename libc/{calls => intrin}/winerr.greg.c (100%) create mode 100644 libc/nt/enum/heap.h create mode 100644 libc/nt/kernel32/HeapAlloc.s create mode 100644 libc/nt/kernel32/HeapReAlloc.s create mode 100644 libc/sysv/consts/O_COMPRESSED.S create mode 100644 libc/sysv/consts/O_INDEXED.S create mode 100644 test/libc/intrin/describeflags_test.c diff --git a/ape/ape.S b/ape/ape.S index 83dd7c7dd..a7f525644 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -1605,5 +1605,26 @@ ape_idata_ro: __data_start: .previous + .section .dataepilogue,"aw",@progbits + .type __data_end,@object + .globl __data_end + .hidden __data_end +__data_end: + .previous + + .section .bssprologue,"aw",@nobits + .type __bss_start,@object + .globl __bss_start + .hidden __bss_start +__bss_start: + .previous + + .section .bssepilogue,"aw",@nobits + .type __bss_end,@object + .globl __bss_end + .hidden __bss_end +__bss_end: + .previous + .end  \ No newline at end of file diff --git a/ape/ape.lds b/ape/ape.lds index ac41b1bc5..d55007773 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -342,7 +342,7 @@ SECTIONS { /*END: Read Only Data (only needed for initialization) */ /*END: Read Only Data */ } :Rom - + .tdata . : { _tdata_start = .; *(SORT_BY_ALIGNMENT(.tdata)) @@ -358,6 +358,8 @@ SECTIONS { .data . : { /*BEGIN: Read/Write Data */ + KEEP(*(SORT_BY_NAME(.piro.data.sort.iat.*))) +/*BEGIN: NT FORK COPYING */ KEEP(*(.dataprologue)) *(.data .data.*) KEEP(*(SORT_BY_NAME(.sort.data.*))) @@ -378,6 +380,8 @@ SECTIONS { . = ALIGN(__SIZEOF_POINTER__); KEEP(*(SORT_BY_NAME(.piro.data.sort.*))) KEEP(*(.piro.pad.data)) + KEEP(*(.dataepilogue)) +/*END: NT FORK COPYING */ . = ALIGN(PAGESIZE); HIDDEN(_edata = .); PROVIDE_HIDDEN(edata = .); @@ -404,6 +408,8 @@ SECTIONS { /*BEGIN: bss memory that's addressable */ .bss ALIGN(64) : { +/*BEGIN: NT FORK COPYING */ + KEEP(*(.bssprologue)) KEEP(*(SORT_BY_NAME(.piro.bss.init.*))) *(.piro.bss) KEEP(*(SORT_BY_NAME(.piro.bss.sort.*))) @@ -418,6 +424,8 @@ SECTIONS { KEEP(*(SORT_BY_NAME(.sort.bss.*))) + KEEP(*(.bssepilogue)) +/*END: NT FORK COPYING */ . = ALIGN(FRAMESIZE); /* for brk()/sbrk() allocation */ HIDDEN(_end = .); PROVIDE_HIDDEN(end = .); @@ -477,9 +485,9 @@ PFSTUB4(ape_elf_phnum, (ape_phdrs_end - ape_phdrs) / 56); PFSTUB4(ape_elf_shnum, 0); PFSTUB4(ape_elf_shstrndx, 0); -HIDDEN(__privileged_addr = ROUNDDOWN(__privileged_start, PAGESIZE)); +HIDDEN(__privileged_addr = ROUNDDOWN(__privileged_start, PAGESIZE)); HIDDEN(__privileged_size = (ROUNDUP(__privileged_end, PAGESIZE) - - ROUNDDOWN(__privileged_start, PAGESIZE))); + ROUNDDOWN(__privileged_start, PAGESIZE))); HIDDEN(ape_rom_offset = 0); HIDDEN(ape_rom_vaddr = ADDR(.head)); diff --git a/examples/forkrand.c b/examples/forkrand.c index 971eff04b..0eaec9e8c 100644 --- a/examples/forkrand.c +++ b/examples/forkrand.c @@ -12,9 +12,12 @@ #include "libc/log/log.h" #include "libc/nt/nt/process.h" #include "libc/rand/rand.h" +#include "libc/runtime/gc.h" +#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/time/time.h" +#include "libc/x/x.h" dontinline void dostuff(const char *s) { int i, us; @@ -29,6 +32,8 @@ dontinline void dostuff(const char *s) { int main(int argc, char *argv[]) { int rc, child, wstatus; + /* puts(_gc(xiso8601ts(NULL))); */ + PrintMemoryIntervals(2, &_mmi); CHECK_NE(-1, (child = fork())); if (!child) { /* child process */ diff --git a/libc/calls/calls.mk b/libc/calls/calls.mk index f95d5df86..e81419499 100644 --- a/libc/calls/calls.mk +++ b/libc/calls/calls.mk @@ -96,6 +96,7 @@ o//libc/calls/fcntl.o: \ OVERRIDE_CFLAGS += \ -Os +# must use alloca() o/$(MODE)/libc/calls/execl.o \ o/$(MODE)/libc/calls/execle.o \ o/$(MODE)/libc/calls/execlp.o \ diff --git a/libc/calls/directmap-nt.c b/libc/calls/directmap-nt.c index dab963446..65df866ff 100644 --- a/libc/calls/directmap-nt.c +++ b/libc/calls/directmap-nt.c @@ -23,6 +23,7 @@ #include "libc/nt/enum/filemapflags.h" #include "libc/nt/enum/pageflags.h" #include "libc/nt/memory.h" +#include "libc/nt/process.h" #include "libc/nt/runtime.h" #include "libc/nt/struct/overlapped.h" #include "libc/runtime/directmap.internal.h" @@ -33,7 +34,6 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot, int flags, int64_t handle, int64_t off) { /* asan runtime depends on this function */ - bool32 rc; uint32_t got; size_t i, upsize; struct DirectMap dm; @@ -44,18 +44,12 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size, * combination of flags, that'll cause Windows to actually do this! */ upsize = ROUNDUP(size, FRAMESIZE); - dm.maphandle = CreateFileMappingNuma(-1, &kNtIsInheritable, - kNtPageExecuteReadwrite, upsize >> 32, - upsize, NULL, kNtNumaNoPreferredNode); - STRACE( - "CreateFileMappingNuma(-1, kNtPageExecuteReadwrite, %'zu/%'zu) -> %p", - upsize, size, dm.maphandle); - if (dm.maphandle) { - dm.addr = - MapViewOfFileExNuma(dm.maphandle, kNtFileMapWrite | kNtFileMapExecute, - 0, 0, upsize, addr, kNtNumaNoPreferredNode); - STRACE("MapViewOfFileExNuma(WX, %p) → addr:%p", addr, dm.addr); - if (dm.addr) { + if ((dm.maphandle = CreateFileMappingNuma( + -1, &kNtIsInheritable, kNtPageExecuteReadwrite, upsize >> 32, + upsize, NULL, kNtNumaNoPreferredNode))) { + if ((dm.addr = MapViewOfFileExNuma( + dm.maphandle, kNtFileMapWrite | kNtFileMapExecute, 0, 0, upsize, + addr, kNtNumaNoPreferredNode))) { for (i = 0; i < size; i += got) { got = 0; op.Internal = 0; @@ -69,37 +63,27 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size, if (i == size) { return dm; } - rc = UnmapViewOfFile(dm.addr); - STRACE("%s(addr:%p) → %hhhd% m", "UnmapViewOfFile", dm.maphandle, rc); + UnmapViewOfFile(dm.addr); } - rc = CloseHandle(dm.maphandle); - STRACE("%s(%p) → %hhhd% m", "CloseHandle", dm.maphandle, rc); + CloseHandle(dm.maphandle); } } else { - dm.maphandle = CreateFileMappingNuma( - handle, &kNtIsInheritable, - (prot & PROT_WRITE) ? kNtPageExecuteReadwrite : kNtPageExecuteRead, - handle != -1 ? 0 : size >> 32, handle != -1 ? 0 : size, NULL, - kNtNumaNoPreferredNode); - STRACE("CreateFileMappingNuma(fhand:%ld, prot:%s, size:%'zu) → %p", handle, - (prot & PROT_WRITE) ? "XRW" : "XR", handle != -1 ? 0 : size); - if (dm.maphandle) { - dm.addr = MapViewOfFileExNuma( - dm.maphandle, - (prot & PROT_WRITE) ? kNtFileMapWrite | kNtFileMapExecute - : kNtFileMapRead | kNtFileMapExecute, - off >> 32, off, size, addr, kNtNumaNoPreferredNode); - STRACE("MapViewOfFileExNuma(prot:%s, off:%'ld, size:%'zu, addr:%p) → %p", - (prot & PROT_WRITE) ? "WX" : "RX", off, size, addr, dm.addr); - if (dm.addr) { + if ((dm.maphandle = CreateFileMappingNuma( + handle, &kNtIsInheritable, + (prot & PROT_WRITE) ? kNtPageExecuteReadwrite : kNtPageExecuteRead, + handle != -1 ? 0 : size >> 32, handle != -1 ? 0 : size, NULL, + kNtNumaNoPreferredNode))) { + if ((dm.addr = MapViewOfFileExNuma( + dm.maphandle, + (prot & PROT_WRITE) ? kNtFileMapWrite | kNtFileMapExecute + : kNtFileMapRead | kNtFileMapExecute, + off >> 32, off, size, addr, kNtNumaNoPreferredNode))) { return dm; - } else { - rc = CloseHandle(dm.maphandle); - STRACE("%s(%p) → %d% m", "CloseHandle", dm.maphandle, rc); } + CloseHandle(dm.maphandle); } } dm.maphandle = kNtInvalidHandleValue; - dm.addr = (void *)(intptr_t)__winerr(); + dm.addr = (void *)(intptr_t)-1; return dm; } diff --git a/libc/calls/execve-nt.c b/libc/calls/execve-nt.c index 8a8887e0e..44261bf45 100644 --- a/libc/calls/execve-nt.c +++ b/libc/calls/execve-nt.c @@ -27,6 +27,7 @@ #include "libc/nt/struct/processinformation.h" #include "libc/nt/struct/startupinfo.h" #include "libc/nt/synchronization.h" +#include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "libc/sysv/consts/o.h" @@ -54,5 +55,5 @@ textwindows int sys_execve_nt(const char *program, char *const argv[], GetExitCodeProcess(procinfo.hProcess, &dwExitCode); } while (dwExitCode == kNtStillActive); CloseHandle(procinfo.hProcess); - ExitProcess(dwExitCode); + _Exit(dwExitCode); } diff --git a/libc/calls/mprotect.greg.c b/libc/calls/mprotect.greg.c index 3a446fcba..ba55de0d2 100644 --- a/libc/calls/mprotect.greg.c +++ b/libc/calls/mprotect.greg.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#define ShouldUseMsabiAttribute() 1 #include "libc/bits/bits.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" @@ -52,7 +51,7 @@ noasan noubsan privileged int mprotect(void *addr, size_t len, int prot) { rc = -1; } } else { - if (__imp_VirtualProtect(addr, len, __prot2nt(prot, 0), &oldprot)) { + if (VirtualProtect(addr, len, __prot2nt(prot, 0), &oldprot)) { rc = 0; } else { rc = __winerr(); diff --git a/libc/calls/ntspawn.c b/libc/calls/ntspawn.c index 6f53b38d1..403b4866c 100644 --- a/libc/calls/ntspawn.c +++ b/libc/calls/ntspawn.c @@ -84,7 +84,7 @@ textwindows int ntspawn( (block = MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0, blocksize, NULL, kNtNumaNoPreferredNode))) { - if (mkntcmdline(block->cmdline, prog, argv + 1) != -1 && + if (mkntcmdline(block->cmdline, prog, argv) != -1 && mkntenvblock(block->envvars, envp, extravar) != -1) { if (CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes, opt_lpThreadAttributes, bInheritHandles, @@ -95,10 +95,11 @@ textwindows int ntspawn( } else { __winerr(); } - STRACE("CreateProcess(%#hs, %#hs) → %d% m", prog16, block->cmdline, rc); + STRACE("CreateProcess(%#hs, %!#hs) → %d% m", prog16, block->cmdline, rc); } } else { __winerr(); + STRACE("ntspawn() alloc failed %m"); } if (block) UnmapViewOfFile(block); if (handle) CloseHandle(handle); diff --git a/libc/calls/onntconsoleevent.c b/libc/calls/onntconsoleevent.c index 7626b632d..0b822d974 100644 --- a/libc/calls/onntconsoleevent.c +++ b/libc/calls/onntconsoleevent.c @@ -18,10 +18,12 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/pushpop.h" #include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" #include "libc/calls/struct/siginfo.h" #include "libc/calls/typedef/sigaction_f.h" #include "libc/nt/enum/ctrlevent.h" #include "libc/nt/runtime.h" +#include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "libc/sysv/consts/sig.h" @@ -31,16 +33,20 @@ textwindows bool32 __onntconsoleevent(uint32_t CtrlType) { siginfo_t info; switch (CtrlType) { case kNtCtrlCEvent: + STRACE("kNtCtrlCEvent"); sig = pushpop(SIGINT); break; case kNtCtrlBreakEvent: + STRACE("kNtCtrlBreakEvent"); sig = pushpop(SIGQUIT); break; case kNtCtrlCloseEvent: + STRACE("kNtCtrlCloseEvent"); sig = pushpop(SIGHUP); break; case kNtCtrlLogoffEvent: // only received by services so hack hack hack case kNtCtrlShutdownEvent: // only received by services so hack hack hack + STRACE("kNtCtrlLogoffEvent"); sig = pushpop(SIGALRM); break; default: @@ -48,7 +54,7 @@ textwindows bool32 __onntconsoleevent(uint32_t CtrlType) { } switch ((rva = __sighandrvas[sig])) { case (uintptr_t)SIG_DFL: - ExitProcess(128 + sig); + _Exit(128 + sig); case (uintptr_t)SIG_IGN: return true; default: diff --git a/libc/calls/open-nt.c b/libc/calls/open-nt.c index 7457ff719..5a1b0f707 100644 --- a/libc/calls/open-nt.c +++ b/libc/calls/open-nt.c @@ -36,42 +36,82 @@ #include "libc/sysv/consts/o.h" #include "libc/sysv/errfuns.h" +#define _O_APPEND 0x00000400 /* kNtFileAppendData */ +#define _O_CREAT 0x00000040 /* kNtOpenAlways */ +#define _O_EXCL 0x00000080 /* kNtCreateNew */ +#define _O_TRUNC 0x00000200 /* kNtCreateAlways */ +#define _O_DIRECTORY 0x00010000 /* kNtFileFlagBackupSemantics */ +#define _O_TMPFILE 0x00410000 /* AttributeTemporary|FlagDeleteOnClose */ +#define _O_DIRECT 0x00004000 /* kNtFileFlagNoBuffering */ +#define _O_NDELAY 0x00000800 /* kNtFileFlagWriteThrough */ +#define _O_RANDOM 0x80000000 /* kNtFileFlagRandomAccess */ +#define _O_SEQUENTIAL 0x40000000 /* kNtFileFlagSequentialScan */ +#define _O_COMPRESSED 0x20000000 /* kNtFileAttributeCompressed */ +#define _O_INDEXED 0x10000000 /* !kNtFileAttributeNotContentIndexed */ +#define _O_NONBLOCK 0x00000800 +#define _O_CLOEXEC 0x00080000 + static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path, uint32_t flags, int32_t mode) { uint32_t br; int64_t handle; char16_t path16[PATH_MAX]; + uint32_t perm, share, disp, attr; if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1; - if ((handle = CreateFile( - path16, flags & 0xf000000f, /* see consts.sh */ - (flags & O_EXCL) - ? kNtFileShareExclusive - : kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, - &kNtIsInheritable, - (flags & O_CREAT) && (flags & O_EXCL) ? kNtCreateNew - : (flags & O_CREAT) && (flags & O_TRUNC) ? kNtCreateAlways - : (flags & O_CREAT) ? kNtOpenAlways - : (flags & O_TRUNC) ? kNtTruncateExisting - : kNtOpenExisting, - /* TODO(jart): Should we just always set overlapped? */ - (/* note: content indexer demolishes unix-ey i/o performance */ - kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal | - (((flags & ((kNtFileFlagWriteThrough | kNtFileFlagOverlapped | - kNtFileFlagNoBuffering | kNtFileFlagRandomAccess) >> - 8)) - << 8) | - (flags & (kNtFileFlagSequentialScan | kNtFileFlagDeleteOnClose | - kNtFileFlagBackupSemantics | kNtFileFlagPosixSemantics | - kNtFileAttributeTemporary)))), - 0)) != -1) { - } else if (GetLastError() == kNtErrorFileExists && - ((flags & O_CREAT) && - (flags & O_TRUNC))) { /* TODO(jart): What was this? */ - handle = eisdir(); - } else { - handle = __winerr(); + + switch (flags & O_ACCMODE) { + case O_RDONLY: + perm = kNtFileGenericRead | kNtGenericExecute; + break; + case O_WRONLY: + perm = kNtFileGenericWrite | kNtGenericExecute; + break; + case O_RDWR: + perm = kNtFileGenericRead | kNtFileGenericWrite | kNtGenericExecute; + break; + default: + unreachable; + } + + if (flags & _O_EXCL) { + share = kNtFileShareExclusive; + } else { + share = kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete; + } + + if ((flags & _O_CREAT) && (flags & _O_EXCL)) { + disp = kNtCreateNew; + } else if ((flags & _O_CREAT) && (flags & _O_TRUNC)) { + disp = kNtCreateAlways; + } else if (flags & _O_CREAT) { + disp = kNtOpenAlways; + } else if (flags & _O_TRUNC) { + disp = kNtTruncateExisting; + } else { + disp = kNtOpenExisting; + } + + if ((flags & _O_TMPFILE) == _O_TMPFILE) { + attr = kNtFileAttributeTemporary | kNtFileFlagDeleteOnClose; + } else { + attr = kNtFileAttributeNormal; + if (flags & _O_DIRECTORY) attr |= kNtFileFlagBackupSemantics; + } + flags |= kNtFileFlagOverlapped; + if (~flags & _O_INDEXED) attr |= kNtFileAttributeNotContentIndexed; + if (flags & _O_COMPRESSED) attr |= kNtFileAttributeCompressed; + if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan; + if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess; + if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering; + if (flags & _O_NDELAY) attr |= kNtFileFlagWriteThrough; + + if ((handle = CreateFile(path16, perm, share, &kNtIsInheritable, disp, attr, + 0)) != -1) { + } else if (GetLastError() == kNtErrorFileExists && + ((flags & _O_CREAT) && + (flags & _O_TRUNC))) { /* TODO(jart): What was this? */ + handle = eisdir(); } - STRACE("CreateFile() → %ld% m", handle); return handle; } diff --git a/libc/calls/raise.c b/libc/calls/raise.c index 70683b910..33cec2088 100644 --- a/libc/calls/raise.c +++ b/libc/calls/raise.c @@ -19,8 +19,10 @@ #include "libc/calls/calls.h" #include "libc/calls/getconsolectrlevent.h" #include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" #include "libc/nt/console.h" #include "libc/nt/runtime.h" +#include "libc/runtime/runtime.h" #include "libc/sysv/consts/sig.h" /** @@ -32,6 +34,7 @@ */ int raise(int sig) { int event; + STRACE("raise(%d)", sig); if (sig == SIGTRAP) { DebugBreak(); return 0; @@ -50,6 +53,6 @@ int raise(int sig) { return __winerr(); } } else { - ExitProcess(128 + sig); + _Exit(128 + sig); } } diff --git a/libc/calls/readlinkat-nt.c b/libc/calls/readlinkat-nt.c index ade680471..566bba449 100644 --- a/libc/calls/readlinkat-nt.c +++ b/libc/calls/readlinkat-nt.c @@ -126,7 +126,6 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf, } CloseHandle(h); } else { - STRACE("%s failed %m", "CreateFile(kNtFileFlagOpenReparsePoint)"); rc = sys_readlinkat_nt_error(); } if (freeme && weaken(free)) { diff --git a/libc/calls/sleep.c b/libc/calls/sleep.c index b843b9183..4c12adadf 100644 --- a/libc/calls/sleep.c +++ b/libc/calls/sleep.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/strace.internal.h" #include "libc/calls/struct/timespec.h" #include "libc/time/time.h" @@ -24,5 +25,8 @@ * @asyncsignalsafe */ int sleep(uint32_t seconds) { - return nanosleep(&(struct timespec){seconds, 0}, NULL); + int rc; + rc = nanosleep(&(struct timespec){seconds, 0}, NULL); + STRACE("sleep(%u) → %d% m", seconds, rc); + return rc; } diff --git a/libc/intrin/asan.c b/libc/intrin/asan.c index 3ce36c7ef..c9458327c 100644 --- a/libc/intrin/asan.c +++ b/libc/intrin/asan.c @@ -1296,7 +1296,7 @@ void __asan_map_shadow(uintptr_t p, size_t n) { if (sm.addr == MAP_FAILED || weaken(TrackMemoryInterval)( m, a, a + i - 1, sm.maphandle, PROT_READ | PROT_WRITE, - MAP_PRIVATE | *weaken(MAP_ANONYMOUS) | MAP_FIXED) == -1) { + MAP_PRIVATE | *weaken(MAP_ANONYMOUS) | MAP_FIXED, 0, size) == -1) { kprintf("error: could not map asan shadow memory%n"); __asan_die()(); __asan_unreachable(); diff --git a/libc/intrin/createfile.greg.c b/libc/intrin/createfile.greg.c new file mode 100644 index 000000000..733fc4542 --- /dev/null +++ b/libc/intrin/createfile.greg.c @@ -0,0 +1,69 @@ +/*-*- 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 2022 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/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/intrin/describeflags.internal.h" +#include "libc/nt/createfile.h" +#include "libc/nt/enum/creationdisposition.h" +#include "libc/nt/thunk/msabi.h" + +extern typeof(CreateFile) *const __imp_CreateFileW __msabi; + +static const char *DescribeDisposition(int x) { + switch (x) { + case kNtCreateNew: + return "kNtCreateNew"; + case kNtCreateAlways: + return "kNtCreateAlways"; + case kNtOpenExisting: + return "kNtOpenExisting"; + case kNtOpenAlways: + return "kNtOpenAlways"; + case kNtTruncateExisting: + return "kNtTruncateExisting"; + default: + return "wut"; + } +} + +/** + * Opens file on the New Technology. + * + * @return handle, or -1 on failure + * @note this wrapper takes care of ABI, STRACE(), and __winerr() + * @see MapViewOfFileExNuma() + */ +int64_t CreateFile(const char16_t *lpFileName, uint32_t dwDesiredAccess, + uint32_t dwShareMode, + struct NtSecurityAttributes *opt_lpSecurityAttributes, + int dwCreationDisposition, uint32_t dwFlagsAndAttributes, + int64_t opt_hTemplateFile) { + int64_t hHandle; + hHandle = __imp_CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, + opt_lpSecurityAttributes, dwCreationDisposition, + dwFlagsAndAttributes, opt_hTemplateFile); + if (hHandle == -1) __winerr(); + STRACE("CreateFile(%#hs, %s, %s, %p, %s, %s, %ld) → %ld% m", lpFileName, + DescribeNtFileAccessFlags(dwDesiredAccess), + DescribeNtFileShareFlags(dwShareMode), opt_lpSecurityAttributes, + DescribeDisposition(dwCreationDisposition), + DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes), + opt_hTemplateFile, hHandle); + return hHandle; +} diff --git a/libc/intrin/createfilemappingnuma.greg.c b/libc/intrin/createfilemappingnuma.greg.c new file mode 100644 index 000000000..d4b45ecb2 --- /dev/null +++ b/libc/intrin/createfilemappingnuma.greg.c @@ -0,0 +1,51 @@ +/*-*- 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 2022 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/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/intrin/describeflags.internal.h" +#include "libc/nt/memory.h" +#include "libc/nt/struct/securityattributes.h" + +extern typeof(CreateFileMappingNuma) *const + __imp_CreateFileMappingNumaW __msabi; + +/** + * Creates file mapping object on the New Technology. + * + * @param opt_hFile may be -1 for MAP_ANONYMOUS behavior + * @return handle, or 0 on failure + * @note this wrapper takes care of ABI, STRACE(), and __winerr() + * @see MapViewOfFileExNuma() + */ +int64_t CreateFileMappingNuma( + int64_t opt_hFile, + const struct NtSecurityAttributes *opt_lpFileMappingAttributes, + uint32_t flProtect, uint32_t dwMaximumSizeHigh, uint32_t dwMaximumSizeLow, + const char16_t *opt_lpName, uint32_t nndDesiredNumaNode) { + int64_t hHandle; + hHandle = __imp_CreateFileMappingNumaW( + opt_hFile, opt_lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, + dwMaximumSizeLow, opt_lpName, nndDesiredNumaNode); + if (!hHandle) __winerr(); + STRACE("CreateFileMappingNuma(%ld, %s, max:%'zu, name:%#hs) → %ld% m", + opt_hFile, DescribeNtPageFlags(flProtect), + (uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName, + hHandle); + return hHandle; +} diff --git a/libc/intrin/describeflags.greg.c b/libc/intrin/describeflags.greg.c new file mode 100644 index 000000000..460c0512b --- /dev/null +++ b/libc/intrin/describeflags.greg.c @@ -0,0 +1,59 @@ +/*-*- 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 2022 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/intrin/describeflags.internal.h" +#include "libc/intrin/kprintf.h" + +const char *DescribeFlags(char *p, size_t n, struct DescribeFlags *d, size_t m, + const char *prefix, unsigned x) { + bool t; + char b[21]; + size_t i, j, k; + for (t = i = j = 0; j < m; ++j) { + if ((x & d[j].flag) == d[j].flag) { + x &= ~d[j].flag; + if (t) { + if (i + 1 < n) p[i++] = '|'; + } else { + t = true; + } + for (k = 0; prefix && prefix[k]; ++k) { + if (i + 1 < n) p[i++] = prefix[k]; + } + for (k = 0; d[j].name[k]; ++k) { + if (i + 1 < n) p[i++] = d[j].name[k]; + } + } + } + if (x || !t) { + if (t && i + 1 < n) p[i++] = '|'; + if (i + 1 < n) p[i++] = '0'; + if (x) { + if (i + 1 < n) p[i++] = 'x'; + k = 0; + do { + if (i + 1 < n) b[k++] = "0123456789abcdef"[x % 16]; + } while ((x /= 16)); + while (k--) { + if (i + 1 < n) p[i++] = b[k]; + } + } + } + if (i < n) p[i] = 0; + return p; +} diff --git a/libc/intrin/describeflags.internal.h b/libc/intrin/describeflags.internal.h new file mode 100644 index 000000000..aba4f3470 --- /dev/null +++ b/libc/intrin/describeflags.internal.h @@ -0,0 +1,21 @@ +#ifndef COSMOPOLITAN_LIBC_INTRIN_DESCRIBEFLAGS_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_INTRIN_DESCRIBEFLAGS_INTERNAL_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +struct thatispacked DescribeFlags { + unsigned flag; + const char *name; +}; + +const char *DescribeFlags(char *, size_t, struct DescribeFlags *, size_t, + const char *, unsigned); +const char *DescribeNtPageFlags(uint32_t); +const char *DescribeNtFileMapFlags(uint32_t); +const char *DescribeNtFileFlagsAndAttributes(uint32_t); +const char *DescribeNtFileShareFlags(uint32_t); +const char *DescribeNtFileAccessFlags(uint32_t); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_INTRIN_DESCRIBEFLAGS_INTERNAL_H_ */ diff --git a/libc/intrin/describentfileaccessflags.greg.c b/libc/intrin/describentfileaccessflags.greg.c new file mode 100644 index 000000000..a6f93b5be --- /dev/null +++ b/libc/intrin/describentfileaccessflags.greg.c @@ -0,0 +1,70 @@ +/*-*- 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 2022 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/intrin/describeflags.internal.h" +#include "libc/macros.internal.h" +#include "libc/nt/enum/accessmask.h" +#include "libc/nt/enum/filesharemode.h" + +static const struct DescribeFlags kFileAccessflags[] = { + {kNtFileAllAccess, "FileAllAccess"}, // order matters + {kNtFileGenericRead, "FileGenericRead"}, // order matters + {kNtFileGenericWrite, "FileGenericWrite"}, // order matters + {kNtFileGenericExecute, "FileGenericExecute"}, // order matters + {kNtGenericRead, "GenericRead"}, // + {kNtGenericWrite, "GenericWrite"}, // + {kNtGenericExecute, "GenericExecute"}, // + {kNtGenericAll, "GenericAll"}, // + {kNtDelete, "Delete"}, // + {kNtReadControl, "ReadControl"}, // + {kNtWriteDac, "WriteDac"}, // + {kNtWriteOwner, "WriteOwner"}, // + {kNtSynchronize, "Synchronize"}, // + {kNtStandardRightsRequired, "StandardRightsRequired"}, // + {kNtAccessSystemSecurity, "AccessSystemSecurity"}, // + {kNtMaximumAllowed, "MaximumAllowed"}, // + {kNtFileReadData, "FileReadData"}, // + {kNtFileListDirectory, "FileListDirectory"}, // + {kNtFileWriteData, "FileWriteData"}, // + {kNtFileAddFile, "FileAddFile"}, // + {kNtFileAppendData, "FileAppendData"}, // + {kNtFileAddSubdirectory, "FileAddSubdirectory"}, // + {kNtFileCreatePipeInstance, "FileCreatePipeInstance"}, // + {kNtFileReadEa, "FileReadEa"}, // + {kNtFileWriteEa, "FileWriteEa"}, // + {kNtFileExecute, "FileExecute"}, // + {kNtFileTraverse, "FileTraverse"}, // + {kNtFileDeleteChild, "FileDeleteChild"}, // + {kNtFileReadAttributes, "FileReadAttributes"}, // + {kNtFileWriteAttributes, "FileWriteAttributes"}, // + {kNtTokenAssignPrimary, "TokenAssignPrimary"}, // + {kNtTokenDuplicate, "TokenDuplicate"}, // + {kNtTokenImpersonate, "TokenImpersonate"}, // + {kNtTokenQuery, "TokenQuery"}, // + {kNtTokenQuerySource, "TokenQuerySource"}, // + {kNtTokenAdjustPrivileges, "TokenAdjustPrivileges"}, // + {kNtTokenAdjustGroups, "TokenAdjustGroups"}, // + {kNtTokenAdjustDefault, "TokenAdjustDefault"}, // + {kNtTokenAdjustSessionid, "TokenAdjustSessionid"}, // +}; + +const char *DescribeNtFileAccessFlags(uint32_t x) { + static char ntfileaccessflags[256]; + return DescribeFlags(ntfileaccessflags, sizeof(ntfileaccessflags), + kFileAccessflags, ARRAYLEN(kFileAccessflags), "kNt", x); +} diff --git a/libc/intrin/describentfileflagsandattributes.greg.c b/libc/intrin/describentfileflagsandattributes.greg.c new file mode 100644 index 000000000..374bc486d --- /dev/null +++ b/libc/intrin/describentfileflagsandattributes.greg.c @@ -0,0 +1,56 @@ +/*-*- 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 2022 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/intrin/describeflags.internal.h" +#include "libc/macros.internal.h" +#include "libc/nt/enum/fileflagandattributes.h" + +static const struct DescribeFlags kFileFlags[] = { + {kNtFileAttributeReadonly, "AttributeReadonly"}, // + {kNtFileAttributeHidden, "AttributeHidden"}, // + {kNtFileAttributeSystem, "AttributeSystem"}, // + {kNtFileAttributeVolumelabel, "AttributeVolumelabel"}, // + {kNtFileAttributeDirectory, "AttributeDirectory"}, // + {kNtFileAttributeArchive, "AttributeArchive"}, // + {kNtFileAttributeDevice, "AttributeDevice"}, // + {kNtFileAttributeNormal, "AttributeNormal"}, // + {kNtFileAttributeTemporary, "AttributeTemporary"}, // + {kNtFileAttributeSparseFile, "AttributeSparseFile"}, // + {kNtFileAttributeReparsePoint, "AttributeReparsePoint"}, // + {kNtFileAttributeCompressed, "AttributeCompressed"}, // + {kNtFileAttributeOffline, "AttributeOffline"}, // + {kNtFileAttributeNotContentIndexed, "AttributeNotContentIndexed"}, // + {kNtFileAttributeEncrypted, "AttributeEncrypted"}, // + {kNtFileFlagWriteThrough, "FlagWriteThrough"}, // + {kNtFileFlagOverlapped, "FlagOverlapped"}, // + {kNtFileFlagNoBuffering, "FlagNoBuffering"}, // + {kNtFileFlagRandomAccess, "FlagRandomAccess"}, // + {kNtFileFlagSequentialScan, "FlagSequentialScan"}, // + {kNtFileFlagDeleteOnClose, "FlagDeleteOnClose"}, // + {kNtFileFlagBackupSemantics, "FlagBackupSemantics"}, // + {kNtFileFlagPosixSemantics, "FlagPosixSemantics"}, // + {kNtFileFlagOpenReparsePoint, "FlagOpenReparsePoint"}, // + {kNtFileFlagOpenNoRecall, "FlagOpenNoRecall"}, // + {kNtFileFlagFirstPipeInstance, "FlagFirstPipeInstance"}, // +}; + +const char *DescribeNtFileFlagsAndAttributes(uint32_t x) { + static char ntfileflags[256]; + return DescribeFlags(ntfileflags, sizeof(ntfileflags), kFileFlags, + ARRAYLEN(kFileFlags), "kNtFile", x); +} diff --git a/libc/intrin/describentfilemapflags.greg.c b/libc/intrin/describentfilemapflags.greg.c new file mode 100644 index 000000000..5ab201575 --- /dev/null +++ b/libc/intrin/describentfilemapflags.greg.c @@ -0,0 +1,37 @@ +/*-*- 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 2022 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/intrin/describeflags.internal.h" +#include "libc/macros.internal.h" +#include "libc/nt/enum/filemapflags.h" + +static const struct DescribeFlags kFileMapFlags[] = { + {kNtFileMapCopy, "Copy"}, // + {kNtFileMapWrite, "Write"}, // + {kNtFileMapRead, "Read"}, // + {kNtFileMapExecute, "Execute"}, // + {kNtFileMapReserve, "Reserve"}, // + {kNtFileMapTargetsInvalid, "TargetsInvalid"}, // + {kNtFileMapLargePages, "LargePages"}, // +}; + +const char *DescribeNtFileMapFlags(uint32_t x) { + static char filemapflags[64]; + return DescribeFlags(filemapflags, sizeof(filemapflags), kFileMapFlags, + ARRAYLEN(kFileMapFlags), "kNtFileMap", x); +} diff --git a/libc/intrin/describentfileshareflags.greg.c b/libc/intrin/describentfileshareflags.greg.c new file mode 100644 index 000000000..a5e6d1b29 --- /dev/null +++ b/libc/intrin/describentfileshareflags.greg.c @@ -0,0 +1,34 @@ +/*-*- 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 2022 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/intrin/describeflags.internal.h" +#include "libc/macros.internal.h" +#include "libc/nt/enum/filesharemode.h" + +static const struct DescribeFlags kFileShareflags[] = { + {kNtFileShareRead, "Read"}, // + {kNtFileShareWrite, "Write"}, // + {kNtFileShareDelete, "Delete"}, // +}; + +const char *DescribeNtFileShareFlags(uint32_t x) { + static char ntfileshareflags[64]; + return DescribeFlags(ntfileshareflags, sizeof(ntfileshareflags), + kFileShareflags, ARRAYLEN(kFileShareflags), + "kNtFileShare", x); +} diff --git a/libc/intrin/describentpageflags.greg.c b/libc/intrin/describentpageflags.greg.c new file mode 100644 index 000000000..8c37a622a --- /dev/null +++ b/libc/intrin/describentpageflags.greg.c @@ -0,0 +1,48 @@ +/*-*- 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 2022 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/intrin/describeflags.internal.h" +#include "libc/macros.internal.h" +#include "libc/nt/enum/pageflags.h" + +static const struct DescribeFlags kPageFlags[] = { + {kNtPageNoaccess, "PageNoaccess"}, // + {kNtPageReadonly, "PageReadonly"}, // + {kNtPageReadwrite, "PageReadwrite"}, // + {kNtPageWritecopy, "PageWritecopy"}, // + {kNtPageExecute, "PageExecute"}, // + {kNtPageExecuteRead, "PageExecuteRead"}, // + {kNtPageExecuteReadwrite, "PageExecuteReadwrite"}, // + {kNtPageExecuteWritecopy, "PageExecuteWritecopy"}, // + {kNtPageGuard, "PageGuard"}, // + {kNtPageNocache, "PageNocache"}, // + {kNtPageWritecombine, "PageWritecombine"}, // + {kNtSecReserve, "SecReserve"}, // + {kNtSecCommit, "SecCommit"}, // + {kNtSecImageNoExecute, "SecImageNoExecute"}, // order matters + {kNtSecImage, "SecImage"}, // + {kNtSecLargePages, "SecLargePages"}, // + {kNtSecNocache, "SecNocache"}, // + {kNtSecWritecombine, "SecWritecombine"}, // +}; + +const char *DescribeNtPageFlags(uint32_t x) { + static char pageflags[64]; + return DescribeFlags(pageflags, sizeof(pageflags), kPageFlags, + ARRAYLEN(kPageFlags), "kNt", x); +} diff --git a/libc/intrin/exit.greg.c b/libc/intrin/exit.greg.c index 86ca692bb..caa199ee9 100644 --- a/libc/intrin/exit.greg.c +++ b/libc/intrin/exit.greg.c @@ -20,12 +20,17 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" -#include "libc/intrin/kprintf.h" #include "libc/nexgen32e/vendor.internal.h" +#include "libc/nt/console.h" +#include "libc/nt/process.h" #include "libc/nt/runtime.h" #include "libc/nt/thunk/msabi.h" +#include "libc/runtime/internal.h" #include "libc/sysv/consts/nr.h" +uint32_t __winmainpid; +const char kConsoleHandles[2] = {kNtStdInputHandle, kNtStdOutputHandle}; + /** * Terminates process, ignoring destructors and atexit() handlers. * @@ -38,7 +43,13 @@ * @noreturn */ privileged noinstrument noasan noubsan wontreturn void _Exit(int exitcode) { + int i; STRACE("_Exit(%d)", exitcode); + if (SupportsWindows() && GetCurrentProcessId() == __winmainpid) { + for (i = 0; i < 2; ++i) { + SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]); + } + } if ((!IsWindows() && !IsMetal()) || (IsMetal() && IsGenuineCosmo())) { asm volatile("syscall" : /* no outputs */ diff --git a/libc/intrin/intrin.mk b/libc/intrin/intrin.mk index 4e6fae5af..adce82aff 100644 --- a/libc/intrin/intrin.mk +++ b/libc/intrin/intrin.mk @@ -57,11 +57,23 @@ o/$(MODE)/libc/intrin/asan.o: \ -finline \ -finline-functions +o/$(MODE)/libc/intrin/kprintf.greg.o: \ + OVERRIDE_CFLAGS += \ + -fpie \ + -ffreestanding \ + $(NO_MAGIC) + +o/$(MODE)/libc/intrin/createfile.greg.o \ +o/$(MODE)/libc/intrin/describeflags.greg.o \ +o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \ +o/$(MODE)/libc/intrin/createfilemappingnuma.greg.o \ o/$(MODE)/libc/intrin/kstarttsc.o \ o/$(MODE)/libc/intrin/nomultics.o \ o/$(MODE)/libc/intrin/ntconsolemode.o: \ OVERRIDE_CFLAGS += \ - -fno-sanitize=all + -Os \ + -ffreestanding \ + $(NO_MAGIC) o/$(MODE)/libc/intrin/asan.o \ o/$(MODE)/libc/intrin/ubsan.o: \ @@ -86,13 +98,6 @@ o/$(MODE)/libc/intrin/memmove.o: \ OVERRIDE_CFLAGS += \ -fpie -o/$(MODE)/libc/intrin/kprintf.greg.o: \ - OVERRIDE_CFLAGS += \ - -fpie \ - -fwrapv \ - -fno-sanitize=all \ - -fschedule-insns2 - LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x))) LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS)) LIBC_INTRIN_SRCS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_SRCS)) diff --git a/libc/intrin/kprintf.greg.c b/libc/intrin/kprintf.greg.c index bf483fa9c..c4928e447 100644 --- a/libc/intrin/kprintf.greg.c +++ b/libc/intrin/kprintf.greg.c @@ -54,16 +54,16 @@ struct Timestamps { extern int __pid; extern bool __replmode; extern bool __nomultics; -static volatile unsigned long long kbirth; +volatile unsigned long long __kbirth; privileged static struct Timestamps kenter(void) { struct Timestamps ts; ts.start = rdtsc(); - ts.birth = kbirth; + ts.birth = __kbirth; if (!ts.birth) { ts.birth = kStartTsc; if (!ts.birth) ts.birth = 1; - cmpxchg(&kbirth, 0, ts.birth); + cmpxchg(&__kbirth, 0, ts.birth); } return ts; } @@ -74,7 +74,7 @@ privileged static void kleave(struct Timestamps ts) { elapse = unsignedsubtract(finish, ts.start); adjust = ts.birth + elapse; if (!adjust) adjust = 1; - cmpxchg(&kbirth, ts.birth, adjust); /* ignore overlapping time intervals */ + cmpxchg(&__kbirth, ts.birth, adjust); /* ignore overlapping time intervals */ } privileged static inline char *kadvance(char *p, char *e, long n) { @@ -465,7 +465,8 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va, } goto EmitChar; case 'm': - if (!(x = errno) && sign == ' ') { + if (!(x = errno) && sign == ' ' && + (!IsWindows() || !__imp_GetLastError())) { break; } else if (weaken(strerror_r) && !weaken(strerror_r)(x, z, sizeof(z))) { @@ -572,7 +573,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va, goto EmitChar; } } else if (type < -1) { - if ((t = *s++ & 255)) { + if ((t = *s++ & 255) || prec) { t = kCp437[t]; } } else if (type < 0) { diff --git a/libc/intrin/mapviewoffileexnuma.greg.c b/libc/intrin/mapviewoffileexnuma.greg.c new file mode 100644 index 000000000..ef914824b --- /dev/null +++ b/libc/intrin/mapviewoffileexnuma.greg.c @@ -0,0 +1,52 @@ +/*-*- 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 2022 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/assert.h" +#include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/intrin/describeflags.internal.h" +#include "libc/nt/enum/filemapflags.h" +#include "libc/nt/memory.h" + +extern typeof(MapViewOfFileExNuma) *const __imp_MapViewOfFileExNuma __msabi; + +/** + * Maps view of file mapping into memory on the New Technology. + * + * @param hFileMappingObject was returned by CreateFileMapping() + * @param dwDesiredAccess has kNtFileMap... flags + * @param opt_lpDesiredBaseAddress may be NULL to let o/s choose + * @return base address, or NULL on failure + * @note this wrapper takes care of ABI, STRACE(), and __winerr() + */ +void *MapViewOfFileExNuma(int64_t hFileMappingObject, uint32_t dwDesiredAccess, + uint32_t dwFileOffsetHigh, uint32_t dwFileOffsetLow, + size_t dwNumberOfBytesToMap, + void *opt_lpDesiredBaseAddress, + uint32_t nndDesiredNumaNode) { + void *pStartingAddress; + pStartingAddress = __imp_MapViewOfFileExNuma( + hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, + dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, nndDesiredNumaNode); + if (!pStartingAddress) __winerr(); + STRACE("MapViewOfFileExNuma(%ld, %s, off:%'ld, size:%'zu, %p) → %p% m", + hFileMappingObject, DescribeNtFileMapFlags(dwDesiredAccess), + (uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow, + dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress); + return pStartingAddress; +} diff --git a/libc/calls/prot2nt.greg.c b/libc/intrin/prot2nt.greg.c similarity index 62% rename from libc/calls/prot2nt.greg.c rename to libc/intrin/prot2nt.greg.c index ab53d9663..0bcdb56be 100644 --- a/libc/calls/prot2nt.greg.c +++ b/libc/intrin/prot2nt.greg.c @@ -18,32 +18,21 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" #include "libc/nt/enum/pageflags.h" -#include "libc/nt/memory.h" -#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/prot.h" -#define HAS(X, BITS) (((X) & (BITS)) == (BITS)) - -/** - * Converts System Five memory protection flags to Windows NT, Part 1. - * @see libc/sysv/consts.sh - */ privileged uint32_t __prot2nt(int prot, int flags) { - return (HAS(prot, PROT_READ | PROT_WRITE | PROT_EXEC) - ? (HAS(flags, MAP_SHARED) || HAS(flags, MAP_ANONYMOUS)) - ? kNtPageExecuteReadwrite - : kNtPageExecuteWritecopy - : HAS(prot, PROT_READ | PROT_WRITE) - ? (HAS(flags, MAP_SHARED) || HAS(flags, MAP_ANONYMOUS)) - ? kNtPageReadwrite - : kNtPageReadwrite /* kNtPageWritecopy */ - : HAS(prot, PROT_READ | PROT_EXEC) - ? kNtPageExecuteRead - : HAS(prot, PROT_EXEC) - ? kNtPageExecute - : HAS(prot, PROT_READ) ? kNtPageReadonly - : kNtPageNoaccess) | - ((prot | flags) & - (kNtSecReserve | kNtSecCommit | kNtSecImage | kNtSecImageNoExecute | - kNtSecLargePages | kNtSecNocache | kNtSecWritecombine)); + switch (prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) { + case PROT_READ: + return kNtPageReadonly; + case PROT_WRITE: + case PROT_READ | PROT_WRITE: + return kNtPageReadwrite; + case PROT_READ | PROT_EXEC: + return kNtPageExecuteRead; + case PROT_WRITE | PROT_EXEC: + case PROT_READ | PROT_WRITE | PROT_EXEC: + return kNtPageExecuteReadwrite; + default: + return kNtPageNoaccess; + } } diff --git a/libc/intrin/quick_exit.c b/libc/intrin/quick_exit.c index 1970c534c..820664cc8 100644 --- a/libc/intrin/quick_exit.c +++ b/libc/intrin/quick_exit.c @@ -25,8 +25,6 @@ #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" -const char kConsoleHandles[2] = {kNtStdInputHandle, kNtStdOutputHandle}; - /** * Exits process faster. * @@ -40,11 +38,6 @@ wontreturn void quick_exit(int exitcode) { if (weaken(fflush)) { weaken(fflush)(0); } - if (SupportsWindows() && __ntconsolemode[0]) { - for (i = 0; i < 2; ++i) { - SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]); - } - } for (p = __fini_array_end; p > __fini_array_start;) { ((void (*)(void))(*--p))(); } diff --git a/libc/intrin/virtualprotect.greg.c b/libc/intrin/virtualprotect.greg.c new file mode 100644 index 000000000..fc1ca7459 --- /dev/null +++ b/libc/intrin/virtualprotect.greg.c @@ -0,0 +1,39 @@ +/*-*- 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 2022 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/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/intrin/describeflags.internal.h" +#include "libc/nt/memory.h" + +extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi; + +/** + * Protects memory on the New Technology. + * @note this wrapper takes care of ABI, STRACE(), and __winerr() + */ +bool32 VirtualProtect(void *lpAddress, uint64_t dwSize, uint32_t flNewProtect, + uint32_t *lpflOldProtect) { + bool32 bOk; + bOk = __imp_VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); + if (!bOk) __winerr(); + STRACE("VirtualProtect(%p, %'zu, %s, [%s]) → %hhhd% m", lpAddress, dwSize, + DescribeNtPageFlags(flNewProtect), + DescribeNtPageFlags(*lpflOldProtect), bOk); + return bOk; +} diff --git a/libc/calls/winerr.greg.c b/libc/intrin/winerr.greg.c similarity index 100% rename from libc/calls/winerr.greg.c rename to libc/intrin/winerr.greg.c diff --git a/libc/log/die.c b/libc/log/die.c index 8893584a6..e895728cf 100644 --- a/libc/log/die.c +++ b/libc/log/die.c @@ -38,7 +38,7 @@ relegated wontreturn void __die(void) { DebugBreak(); } ShowBacktrace(2, NULL); - quick_exit(77); + _Exit(77); } __write_str("PANIC: __DIE() DIED\r\n"); _Exit(78); diff --git a/libc/log/oncrash.c b/libc/log/oncrash.c index 02fc8ab38..b19a7e8fd 100644 --- a/libc/log/oncrash.c +++ b/libc/log/oncrash.c @@ -316,7 +316,7 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si, if (!(gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT))) { __restore_tty(1); ShowCrashReport(err, sig, si, ctx); - quick_exit(128 + sig); + _Exit(128 + sig); } } else { __minicrash(sig, si, ctx, "WHILE VFORKED"); diff --git a/libc/nt/enum/accessmask.h b/libc/nt/enum/accessmask.h index 44cfeb019..da67f0682 100644 --- a/libc/nt/enum/accessmask.h +++ b/libc/nt/enum/accessmask.h @@ -20,38 +20,38 @@ * }; * }; */ -#define kNtGenericRead 0x80000000u -#define kNtGenericWrite 0x40000000u -#define kNtGenericExecute 0x20000000u -#define kNtGenericAll 0x10000000u -#define kNtDelete 0x00010000u -#define kNtReadControl 0x00020000u -#define kNtWriteDac 0x00040000u -#define kNtWriteOwner 0x00080000u -#define kNtSynchronize 0x00100000u +#define kNtGenericRead 0x80000000u +#define kNtGenericWrite 0x40000000u +#define kNtGenericExecute 0x20000000u +#define kNtGenericAll 0x10000000u +#define kNtDelete 0x00010000u +#define kNtReadControl 0x00020000u +#define kNtWriteDac 0x00040000u +#define kNtWriteOwner 0x00080000u +#define kNtSynchronize 0x00100000u #define kNtStandardRightsRequired 0x000F0000u -#define kNtStandardRightsRead kNtReadControl -#define kNtStandardRightsWrite kNtReadControl -#define kNtStandardRightsExecute kNtReadControl -#define kNtStandardRightsAll 0x001F0000u -#define kNtSpecificRightsAll 0x0000FFFFu -#define kNtAccessSystemSecurity 0x01000000u -#define kNtMaximumAllowed 0x02000000u -#define kNtFileReadData 0x0001u -#define kNtFileListDirectory 0x0001u -#define kNtFileWriteData 0x0002u -#define kNtFileAddFile 0x0002u -#define kNtFileAppendData 0x0004u -#define kNtFileAddSubdirectory 0x0004u +#define kNtStandardRightsRead kNtReadControl +#define kNtStandardRightsWrite kNtReadControl +#define kNtStandardRightsExecute kNtReadControl +#define kNtStandardRightsAll 0x001F0000u +#define kNtSpecificRightsAll 0x0000FFFFu +#define kNtAccessSystemSecurity 0x01000000u +#define kNtMaximumAllowed 0x02000000u +#define kNtFileReadData 0x0001u +#define kNtFileListDirectory 0x0001u +#define kNtFileWriteData 0x0002u +#define kNtFileAddFile 0x0002u +#define kNtFileAppendData 0x0004u +#define kNtFileAddSubdirectory 0x0004u #define kNtFileCreatePipeInstance 0x0004u -#define kNtFileReadEa 0x0008u -#define kNtFileWriteEa 0x0010u -#define kNtFileExecute 0x0020u -#define kNtFileTraverse 0x0020u -#define kNtFileDeleteChild 0x0040u -#define kNtFileReadAttributes 0x0080u -#define kNtFileWriteAttributes 0x0100u -#define kNtFileAllAccess (kNtStandardRightsRequired | kNtSynchronize | 0x1FFu) +#define kNtFileReadEa 0x0008u +#define kNtFileWriteEa 0x0010u +#define kNtFileExecute 0x0020u +#define kNtFileTraverse 0x0020u +#define kNtFileDeleteChild 0x0040u +#define kNtFileReadAttributes 0x0080u +#define kNtFileWriteAttributes 0x0100u +#define kNtFileAllAccess (kNtStandardRightsRequired | kNtSynchronize | 0x1FFu) #define kNtFileGenericRead \ (kNtStandardRightsRead | kNtFileReadData | kNtFileReadAttributes | \ kNtFileReadEa | kNtSynchronize) @@ -61,21 +61,21 @@ #define kNtFileGenericExecute \ (kNtStandardRightsExecute | kNtFileReadAttributes | kNtFileExecute | \ kNtSynchronize) -#define kNtTokenAssignPrimary 0x0001u -#define kNtTokenDuplicate 0x0002u -#define kNtTokenImpersonate 0x0004u -#define kNtTokenQuery 0x0008u -#define kNtTokenQuerySource 0x0010u +#define kNtTokenAssignPrimary 0x0001u +#define kNtTokenDuplicate 0x0002u +#define kNtTokenImpersonate 0x0004u +#define kNtTokenQuery 0x0008u +#define kNtTokenQuerySource 0x0010u #define kNtTokenAdjustPrivileges 0x0020u -#define kNtTokenAdjustGroups 0x0040u -#define kNtTokenAdjustDefault 0x0080u -#define kNtTokenAdjustSessionid 0x0100u +#define kNtTokenAdjustGroups 0x0040u +#define kNtTokenAdjustDefault 0x0080u +#define kNtTokenAdjustSessionid 0x0100u #define kNtTokenAllAccessP \ (kNtStandardRightsRequired | kNtTokenAssignPrimary | kNtTokenDuplicate | \ kNtTokenImpersonate | kNtTokenQuery | kNtTokenQuerySource | \ kNtTokenAdjustPrivileges | kNtTokenAdjustGroups | kNtTokenAdjustDefault) #define kNtTokenAllAccess kNtTokenAllAccessP | kNtTokenAdjustSessionid -#define kNtTokenRead kNtStandardRightsRead | kNtTokenQuery +#define kNtTokenRead kNtStandardRightsRead | kNtTokenQuery #define kNtTokenWrite \ (kNtStandardRightsWrite | kNtTokenAdjustPrivileges | kNtTokenAdjustGroups | \ kNtTokenAdjustDefault) @@ -83,6 +83,6 @@ #define kNtTokenTrustConstraintMask \ (kNtStandardRightsRead | kNtTokenQuery | kNtTokenQuerySource) #define kNtTokenAccessPseudoHandleWin8 kNtTokenQuery | kNtTokenQuerySource -#define kNtTokenAccessPseudoHandle kNtTokenAccessPseudoHandleWin8 +#define kNtTokenAccessPseudoHandle kNtTokenAccessPseudoHandleWin8 #endif /* COSMOPOLITAN_LIBC_NT_ENUM_ACCESSMASK_H_ */ diff --git a/libc/nt/enum/heap.h b/libc/nt/enum/heap.h new file mode 100644 index 000000000..f7ccc0915 --- /dev/null +++ b/libc/nt/enum/heap.h @@ -0,0 +1,9 @@ +#ifndef COSMOPOLITAN_LIBC_NT_ENUM_HEAP_H_ +#define COSMOPOLITAN_LIBC_NT_ENUM_HEAP_H_ + +#define kNtHeapNoSerialize 1 +#define kNtHeapGenerateExceptions 4 +#define kNtHeapZeroMemory 8 +#define kNtHeapReallocInPlaceOnly 16 + +#endif /* COSMOPOLITAN_LIBC_NT_ENUM_HEAP_H_ */ diff --git a/libc/nt/enum/pageflags.h b/libc/nt/enum/pageflags.h index ba76a0db4..5cef3a2fa 100644 --- a/libc/nt/enum/pageflags.h +++ b/libc/nt/enum/pageflags.h @@ -2,25 +2,25 @@ #define COSMOPOLITAN_LIBC_NT_ENUM_PAGEFLAGS_H_ /* Pick One */ -#define kNtPageNoaccess 0x01 -#define kNtPageReadonly 0x02 -#define kNtPageReadwrite 0x04 -#define kNtPageWritecopy 0x08 -#define kNtPageExecute 0x10 -#define kNtPageExecuteRead 0x20 -#define kNtPageExecuteReadwrite 0x40 -#define kNtPageExecuteWritecopy 0x80 -#define kNtPageGuard 0x100 -#define kNtPageNocache 0x200 -#define kNtPageWritecombine 0x400 +#define kNtPageNoaccess 0x001 +#define kNtPageReadonly 0x002 +#define kNtPageReadwrite 0x004 +#define kNtPageWritecopy 0x008 +#define kNtPageExecute 0x010 +#define kNtPageExecuteRead 0x020 +#define kNtPageExecuteReadwrite 0x040 +#define kNtPageExecuteWritecopy 0x080 +#define kNtPageGuard 0x100 +#define kNtPageNocache 0x200 +#define kNtPageWritecombine 0x400 /* These may be OR'd */ -#define kNtSecReserve 0x4000000 -#define kNtSecCommit 0x8000000 /* ←default */ -#define kNtSecImage 0x1000000 +#define kNtSecReserve 0x04000000 +#define kNtSecCommit 0x08000000 /* default */ #define kNtSecImageNoExecute 0x11000000 -#define kNtSecLargePages 0x80000000 -#define kNtSecNocache 0x10000000 -#define kNtSecWritecombine 0x40000000 +#define kNtSecImage 0x01000000 +#define kNtSecNocache 0x10000000 +#define kNtSecLargePages 0x80000000 +#define kNtSecWritecombine 0x40000000 #endif /* COSMOPOLITAN_LIBC_NT_ENUM_PAGEFLAGS_H_ */ diff --git a/libc/nt/kernel32/CreateFileMappingNumaW.s b/libc/nt/kernel32/CreateFileMappingNumaW.s index 19f542339..3ce9ae334 100644 --- a/libc/nt/kernel32/CreateFileMappingNumaW.s +++ b/libc/nt/kernel32/CreateFileMappingNumaW.s @@ -2,11 +2,11 @@ .imp kernel32,__imp_CreateFileMappingNumaW,CreateFileMappingNumaW,0 .text.windows -CreateFileMappingNuma: +__CreateFileMappingNuma: push %rbp mov %rsp,%rbp .profilable mov __imp_CreateFileMappingNumaW(%rip),%rax jmp __sysv2nt8 - .endfn CreateFileMappingNuma,globl + .endfn __CreateFileMappingNuma,globl .previous diff --git a/libc/nt/kernel32/CreateFileW.s b/libc/nt/kernel32/CreateFileW.s index 078ba1aff..ce8e9938d 100644 --- a/libc/nt/kernel32/CreateFileW.s +++ b/libc/nt/kernel32/CreateFileW.s @@ -2,11 +2,11 @@ .imp kernel32,__imp_CreateFileW,CreateFileW,0 .text.windows -CreateFile: +__CreateFile: push %rbp mov %rsp,%rbp .profilable mov __imp_CreateFileW(%rip),%rax jmp __sysv2nt8 - .endfn CreateFile,globl + .endfn __CreateFile,globl .previous diff --git a/libc/nt/kernel32/GetProcessHeap.s b/libc/nt/kernel32/GetProcessHeap.s index 4aa7b0b00..582ffd2ee 100644 --- a/libc/nt/kernel32/GetProcessHeap.s +++ b/libc/nt/kernel32/GetProcessHeap.s @@ -1,2 +1,14 @@ .include "o/libc/nt/codegen.inc" .imp kernel32,__imp_GetProcessHeap,GetProcessHeap,0 + + .text.windows +GetProcessHeap: + push %rbp + mov %rsp,%rbp + .profilable + sub $32,%rsp + call *__imp_GetProcessHeap(%rip) + leave + ret + .endfn GetProcessHeap,globl + .previous diff --git a/libc/nt/kernel32/GetProcessHeaps.s b/libc/nt/kernel32/GetProcessHeaps.s index ce5308cfa..7c5bd6ab6 100644 --- a/libc/nt/kernel32/GetProcessHeaps.s +++ b/libc/nt/kernel32/GetProcessHeaps.s @@ -1,2 +1,12 @@ .include "o/libc/nt/codegen.inc" .imp kernel32,__imp_GetProcessHeaps,GetProcessHeaps,0 + + .text.windows +GetProcessHeaps: + push %rbp + mov %rsp,%rbp + .profilable + mov __imp_GetProcessHeaps(%rip),%rax + jmp __sysv2nt + .endfn GetProcessHeaps,globl + .previous diff --git a/libc/nt/kernel32/HeapAlloc.s b/libc/nt/kernel32/HeapAlloc.s new file mode 100644 index 000000000..5d71b53ba --- /dev/null +++ b/libc/nt/kernel32/HeapAlloc.s @@ -0,0 +1,12 @@ +.include "o/libc/nt/codegen.inc" +.imp kernel32,__imp_HeapAlloc,HeapAlloc,0 + + .text.windows +HeapAlloc: + push %rbp + mov %rsp,%rbp + .profilable + mov __imp_HeapAlloc(%rip),%rax + jmp __sysv2nt + .endfn HeapAlloc,globl + .previous diff --git a/libc/nt/kernel32/HeapCompact.s b/libc/nt/kernel32/HeapCompact.s index 6322c22c0..b557f6886 100644 --- a/libc/nt/kernel32/HeapCompact.s +++ b/libc/nt/kernel32/HeapCompact.s @@ -1,2 +1,12 @@ .include "o/libc/nt/codegen.inc" .imp kernel32,__imp_HeapCompact,HeapCompact,0 + + .text.windows +HeapCompact: + push %rbp + mov %rsp,%rbp + .profilable + mov __imp_HeapCompact(%rip),%rax + jmp __sysv2nt + .endfn HeapCompact,globl + .previous diff --git a/libc/nt/kernel32/HeapCreate.s b/libc/nt/kernel32/HeapCreate.s index bf8db4cdf..cbdfff932 100644 --- a/libc/nt/kernel32/HeapCreate.s +++ b/libc/nt/kernel32/HeapCreate.s @@ -1,2 +1,12 @@ .include "o/libc/nt/codegen.inc" .imp kernel32,__imp_HeapCreate,HeapCreate,0 + + .text.windows +HeapCreate: + push %rbp + mov %rsp,%rbp + .profilable + mov __imp_HeapCreate(%rip),%rax + jmp __sysv2nt + .endfn HeapCreate,globl + .previous diff --git a/libc/nt/kernel32/HeapDestroy.s b/libc/nt/kernel32/HeapDestroy.s index 02d78182f..9cf8b76f4 100644 --- a/libc/nt/kernel32/HeapDestroy.s +++ b/libc/nt/kernel32/HeapDestroy.s @@ -1,2 +1,15 @@ .include "o/libc/nt/codegen.inc" .imp kernel32,__imp_HeapDestroy,HeapDestroy,0 + + .text.windows +HeapDestroy: + push %rbp + mov %rsp,%rbp + .profilable + mov %rdi,%rcx + sub $32,%rsp + call *__imp_HeapDestroy(%rip) + leave + ret + .endfn HeapDestroy,globl + .previous diff --git a/libc/nt/kernel32/HeapFree.s b/libc/nt/kernel32/HeapFree.s index 138e1927c..e7bf59084 100644 --- a/libc/nt/kernel32/HeapFree.s +++ b/libc/nt/kernel32/HeapFree.s @@ -1,2 +1,12 @@ .include "o/libc/nt/codegen.inc" .imp kernel32,__imp_HeapFree,HeapFree,847 + + .text.windows +HeapFree: + push %rbp + mov %rsp,%rbp + .profilable + mov __imp_HeapFree(%rip),%rax + jmp __sysv2nt + .endfn HeapFree,globl + .previous diff --git a/libc/nt/kernel32/HeapReAlloc.s b/libc/nt/kernel32/HeapReAlloc.s new file mode 100644 index 000000000..f775d27b0 --- /dev/null +++ b/libc/nt/kernel32/HeapReAlloc.s @@ -0,0 +1,12 @@ +.include "o/libc/nt/codegen.inc" +.imp kernel32,__imp_HeapReAlloc,HeapReAlloc,0 + + .text.windows +HeapReAlloc: + push %rbp + mov %rsp,%rbp + .profilable + mov __imp_HeapReAlloc(%rip),%rax + jmp __sysv2nt + .endfn HeapReAlloc,globl + .previous diff --git a/libc/nt/kernel32/MapViewOfFileExNuma.s b/libc/nt/kernel32/MapViewOfFileExNuma.s index b28d08586..b74a7b956 100644 --- a/libc/nt/kernel32/MapViewOfFileExNuma.s +++ b/libc/nt/kernel32/MapViewOfFileExNuma.s @@ -2,11 +2,11 @@ .imp kernel32,__imp_MapViewOfFileExNuma,MapViewOfFileExNuma,0 .text.windows -MapViewOfFileExNuma: +__MapViewOfFileExNuma: push %rbp mov %rsp,%rbp .profilable mov __imp_MapViewOfFileExNuma(%rip),%rax jmp __sysv2nt8 - .endfn MapViewOfFileExNuma,globl + .endfn __MapViewOfFileExNuma,globl .previous diff --git a/libc/nt/kernel32/VirtualProtect.s b/libc/nt/kernel32/VirtualProtect.s index 706c74aa3..0acf070a5 100644 --- a/libc/nt/kernel32/VirtualProtect.s +++ b/libc/nt/kernel32/VirtualProtect.s @@ -2,11 +2,11 @@ .imp kernel32,__imp_VirtualProtect,VirtualProtect,0 .text.windows -VirtualProtect: +__VirtualProtect: push %rbp mov %rsp,%rbp .profilable mov __imp_VirtualProtect(%rip),%rax jmp __sysv2nt - .endfn VirtualProtect,globl + .endfn __VirtualProtect,globl .previous diff --git a/libc/nt/master.sh b/libc/nt/master.sh index d77d8942f..9830809ee 100755 --- a/libc/nt/master.sh +++ b/libc/nt/master.sh @@ -593,9 +593,10 @@ imp 'CreateEventEx' CreateEventExW kernel32 0 4 # KernelBase imp 'CreateEvent' CreateEventW kernel32 0 4 # KernelBase imp 'CreateFiber' CreateFiber kernel32 0 # KernelBase imp 'CreateFiberEx' CreateFiberEx kernel32 0 # KernelBase -imp 'CreateFile' CreateFileW kernel32 0 7 # KernelBase imp 'CreateFileA' CreateFileA kernel32 0 7 # KernelBase -imp 'CreateFileMappingNuma' CreateFileMappingNumaW kernel32 0 7 # Kernelbase +imp '__CreateFile' CreateFileW kernel32 0 7 # KernelBase +imp '__CreateFileMappingNuma' CreateFileMappingNumaW kernel32 0 7 # Kernelbase +imp '__MapViewOfFileExNuma' MapViewOfFileExNuma kernel32 0 7 # KernelBase imp 'CreateFileMappingNumaA' CreateFileMappingNumaA kernel32 198 7 imp 'CreateFileMapping' CreateFileMappingW kernel32 0 7 # KernelBase imp 'CreateFileMappingA' CreateFileMappingA kernel32 196 7 @@ -2474,8 +2475,8 @@ imp 'GetProcessDefaultLayout' GetProcessDefaultLayout user32 1930 imp 'GetProcessDpiAwarenessInternal' GetProcessDpiAwarenessInternal user32 1931 imp 'GetProcessGroupAffinity' GetProcessGroupAffinity kernel32 0 # KernelBase imp 'GetProcessHandleCount' GetProcessHandleCount kernel32 0 2 # KernelBase -imp 'GetProcessHeap' GetProcessHeap kernel32 0 # KernelBase -imp 'GetProcessHeaps' GetProcessHeaps kernel32 0 # KernelBase +imp 'GetProcessHeap' GetProcessHeap kernel32 0 0 # KernelBase +imp 'GetProcessHeaps' GetProcessHeaps kernel32 0 2 # KernelBase imp 'GetProcessId' GetProcessId kernel32 0 1 # KernelBase imp 'GetProcessIdOfThread' GetProcessIdOfThread kernel32 0 1 # KernelBase imp 'GetProcessImageFileNameA' GetProcessImageFileNameA kernel32 676 3 @@ -2817,10 +2818,12 @@ imp 'Heap32First' Heap32First kernel32 839 imp 'Heap32ListFirst' Heap32ListFirst kernel32 840 imp 'Heap32ListNext' Heap32ListNext kernel32 841 imp 'Heap32Next' Heap32Next kernel32 842 -imp 'HeapCompact' HeapCompact kernel32 0 # KernelBase -imp 'HeapCreate' HeapCreate kernel32 0 # KernelBase -imp 'HeapDestroy' HeapDestroy kernel32 0 # KernelBase -imp 'HeapFree' HeapFree kernel32 847 +imp 'HeapCompact' HeapCompact kernel32 0 2 # KernelBase +imp 'HeapAlloc' HeapAlloc kernel32 0 3 +imp 'HeapReAlloc' HeapReAlloc kernel32 0 4 +imp 'HeapCreate' HeapCreate kernel32 0 3 # KernelBase +imp 'HeapDestroy' HeapDestroy kernel32 0 1 # KernelBase +imp 'HeapFree' HeapFree kernel32 847 3 imp 'HeapLock' HeapLock kernel32 0 # KernelBase imp 'HeapQueryInformation' HeapQueryInformation kernel32 0 # KernelBase imp 'HeapSetInformation' HeapSetInformation kernel32 0 # KernelBase @@ -3380,7 +3383,6 @@ imp 'MapViewOfFile' MapViewOfFile kernel32 0 # KernelBase imp 'MapViewOfFile3' MapViewOfFile3 KernelBase 1003 imp 'MapViewOfFile3FromApp' MapViewOfFile3FromApp KernelBase 1004 imp 'MapViewOfFileEx' MapViewOfFileEx kernel32 0 # KernelBase -imp 'MapViewOfFileExNuma' MapViewOfFileExNuma kernel32 0 7 # KernelBase imp 'MapViewOfFileFromApp' MapViewOfFileFromApp kernel32 0 # KernelBase imp 'MapViewOfFileNuma2' MapViewOfFileNuma2 KernelBase 1008 imp 'MapVirtualKeyA' MapVirtualKeyA user32 2153 @@ -6879,7 +6881,7 @@ imp 'VirtualAllocFromApp' VirtualAllocFromApp KernelBase 1760 imp 'VirtualFree' VirtualFree kernel32 0 3 # KernelBase imp 'VirtualFreeEx' VirtualFreeEx kernel32 0 # KernelBase imp 'VirtualLock' VirtualLock kernel32 0 # KernelBase -imp 'VirtualProtect' VirtualProtect kernel32 0 4 # KernelBase +imp '__VirtualProtect' VirtualProtect kernel32 0 4 # KernelBase imp 'VirtualProtectEx' VirtualProtectEx kernel32 0 # KernelBase imp 'VirtualProtectFromApp' VirtualProtectFromApp KernelBase 1766 imp 'VirtualQuery' VirtualQuery kernel32 0 3 # KernelBase diff --git a/libc/nt/memory.h b/libc/nt/memory.h index c729f9726..c17d37185 100644 --- a/libc/nt/memory.h +++ b/libc/nt/memory.h @@ -70,6 +70,12 @@ bool32 PrefetchVirtualMemory(int64_t hProcess, const uint32_t *NumberOfEntries, bool32 OfferVirtualMemory(void *inout_VirtualAddress, size_t Size, int Priority); +int64_t GetProcessHeap(void); +void *HeapAlloc(int64_t hHeap, uint32_t dwFlags, size_t dwBytes) nodiscard; +bool32 HeapFree(int64_t hHeap, uint32_t dwFlags, void *opt_lpMem); +void *HeapReAlloc(int64_t hHeap, uint32_t dwFlags, void *lpMem, + size_t dwBytes) nodiscard; + void *GlobalAlloc(uint32_t uFlags, uint64_t dwBytes) nodiscard; void *GlobalFree(void *hMem); diff --git a/libc/nt/thunk/memory.inc b/libc/nt/thunk/memory.inc index cf2941299..599b35468 100644 --- a/libc/nt/thunk/memory.inc +++ b/libc/nt/thunk/memory.inc @@ -1,12 +1,6 @@ -#define CreateFileMappingNuma(...) __imp_CreateFileMappingNumaW(__VA_ARGS__) -#define MapViewOfFileExNuma(...) __imp_MapViewOfFileExNuma(__VA_ARGS__) -#define FlushViewOfFile(...) __imp_FlushViewOfFile(__VA_ARGS__) -#define UnmapViewOfFile(...) __imp_UnmapViewOfFile(__VA_ARGS__) +#define FlushViewOfFile(...) __imp_FlushViewOfFile(__VA_ARGS__) +#define UnmapViewOfFile(...) __imp_UnmapViewOfFile(__VA_ARGS__) extern typeof(LocalFree) *const __imp_LocalFree __msabi; -extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi; extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile __msabi; extern typeof(FlushViewOfFile) *const __imp_FlushViewOfFile __msabi; -extern typeof(MapViewOfFileExNuma) *const __imp_MapViewOfFileExNuma __msabi; -extern typeof(CreateFileMappingNuma) *const - __imp_CreateFileMappingNumaW __msabi; diff --git a/libc/runtime/fork-nt.c b/libc/runtime/fork-nt.c index 7aefaa140..6424df3e1 100644 --- a/libc/runtime/fork-nt.c +++ b/libc/runtime/fork-nt.c @@ -22,20 +22,27 @@ #include "libc/calls/internal.h" #include "libc/calls/ntspawn.h" #include "libc/calls/strace.internal.h" +#include "libc/dce.h" #include "libc/fmt/itoa.h" +#include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" +#include "libc/mem/alloca.h" #include "libc/nexgen32e/nt2sysv.h" #include "libc/nt/dll.h" +#include "libc/nt/enum/exceptionhandleractions.h" #include "libc/nt/enum/filemapflags.h" #include "libc/nt/enum/memflags.h" #include "libc/nt/enum/pageflags.h" #include "libc/nt/enum/startf.h" #include "libc/nt/enum/wt.h" +#include "libc/nt/files.h" #include "libc/nt/ipc.h" #include "libc/nt/memory.h" #include "libc/nt/process.h" #include "libc/nt/runtime.h" #include "libc/nt/signals.h" +#include "libc/nt/struct/context.h" +#include "libc/nt/struct/ntexceptionpointers.h" #include "libc/nt/synchronization.h" #include "libc/nt/thread.h" #include "libc/runtime/directmap.internal.h" @@ -49,7 +56,14 @@ #include "libc/sysv/consts/sig.h" #include "libc/sysv/errfuns.h" -static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) { +extern int __pid; +extern unsigned long long __kbirth; +extern unsigned char __data_start[]; /* αpε */ +extern unsigned char __data_end[]; /* αpε */ +extern unsigned char __bss_start[]; /* αpε */ +extern unsigned char __bss_end[]; /* αpε */ + +static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) { *x = 0; while (*p == ' ') p++; while ('0' <= *p && *p <= '9') { @@ -59,89 +73,211 @@ static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) { return p; } -static dontinline textwindows noasan bool ForkIo(int64_t h, void *buf, size_t n, - bool32 (*f)()) { - char *p; +static inline textwindows ssize_t ForkIo(int64_t h, char *p, size_t n, + bool32 (*f)()) { size_t i; uint32_t x; - for (p = buf, i = 0; i < n; i += x) { + for (i = 0; i < n; i += x) { if (!f(h, p + i, n - i, &x, NULL)) { - return false; + return -1; } } - return true; + return i; } -static dontinline textwindows noasan void WriteAll(int64_t h, void *buf, - size_t n) { - bool rc = ForkIo(h, buf, n, WriteFile); - STRACE("%s(%ld, %'zu) %d% m", "WriteFile", h, n); +static dontinline textwindows bool ForkIo2(int64_t h, void *buf, size_t n, + bool32 (*fn)(), const char *sf) { + ssize_t rc = ForkIo(h, buf, n, fn); + STRACE("%s(%ld, %'zu) → %'zd% m", sf, h, n, rc); + return rc != -1; } -static textwindows dontinline noasan void ReadAll(int64_t h, void *buf, - size_t n) { - bool rc = ForkIo(h, buf, n, ReadFile); - STRACE("%s(%ld, %'zu) %d% m", "ReadFile", h, n); +static dontinline textwindows bool WriteAll(int64_t h, void *buf, size_t n) { + return ForkIo2(h, buf, n, WriteFile, "WriteFile"); } -textwindows noasan noinstrument void WinMainForked(void) { - void *addr; +static textwindows dontinline bool ReadAll(int64_t h, void *buf, size_t n) { + return ForkIo2(h, buf, n, ReadFile, "ReadFile"); +} + +static textwindows int OnForkCrash(struct NtExceptionPointers *ep) { + kprintf("error: fork() child crashed!%n" + "\tExceptionCode = %#x%n" + "\tRip = %x%n" + "\tRax = %.16x R8 = %.16x%n" + "\tRbx = %.16x R9 = %.16x%n" + "\tRcx = %.16x R10 = %.16x%n" + "\tRdx = %.16x R11 = %.16x%n" + "\tRdi = %.16x R12 = %.16x%n" + "\tRsi = %.16x R13 = %.16x%n" + "\tRbp = %.16x R14 = %.16x%n" + "\tRsp = %.16x R15 = %.16x%n", + ep->ExceptionRecord->ExceptionCode, + ep->ContextRecord ? ep->ContextRecord->Rip : -1, + ep->ContextRecord ? ep->ContextRecord->Rax : -1, + ep->ContextRecord ? ep->ContextRecord->R8 : -1, + ep->ContextRecord ? ep->ContextRecord->Rbx : -1, + ep->ContextRecord ? ep->ContextRecord->R9 : -1, + ep->ContextRecord ? ep->ContextRecord->Rcx : -1, + ep->ContextRecord ? ep->ContextRecord->R10 : -1, + ep->ContextRecord ? ep->ContextRecord->Rdx : -1, + ep->ContextRecord ? ep->ContextRecord->R11 : -1, + ep->ContextRecord ? ep->ContextRecord->Rdi : -1, + ep->ContextRecord ? ep->ContextRecord->R12 : -1, + ep->ContextRecord ? ep->ContextRecord->Rsi : -1, + ep->ContextRecord ? ep->ContextRecord->R13 : -1, + ep->ContextRecord ? ep->ContextRecord->Rbp : -1, + ep->ContextRecord ? ep->ContextRecord->R14 : -1, + ep->ContextRecord ? ep->ContextRecord->Rsp : -1, + ep->ContextRecord ? ep->ContextRecord->R15 : -1); + ExitProcess(73); +} + +textwindows void WinMainForked(void) { jmp_buf jb; - long mapcount; - uint64_t size; - uint32_t i, varlen; + char *addr, *shad; struct DirectMap dm; + uint64_t size, upsize; int64_t reader, writer; struct MemoryInterval *maps; - char16_t var[21 + 1 + 21 + 1]; - varlen = GetEnvironmentVariable(u"_FORK", var, ARRAYLEN(var)); - if (!varlen) return; - if (varlen >= ARRAYLEN(var)) ExitProcess(123); + char16_t fvar[21 + 1 + 21 + 1]; + int64_t oncrash, savetsc, savebir; + uint32_t i, varlen, oldprot, savepid; + long mapcount, mapcapacity, specialz; + extern uint64_t ts asm("kStartTsc"); + + /* + * check to see if the process was actually forked + * this variable should have the pipe handle numba + */ + varlen = GetEnvironmentVariable(u"_FORK", fvar, ARRAYLEN(fvar)); + if (!varlen || varlen >= ARRAYLEN(fvar)) return; STRACE("WinMainForked()"); SetEnvironmentVariable(u"_FORK", NULL); - ParseInt(ParseInt(var, &reader), &writer); +#ifdef SYSDEBUG + oncrash = AddVectoredExceptionHandler(1, NT2SYSV(OnForkCrash)); +#endif + ParseInt(ParseInt(fvar, &reader), &writer); + + /* + * read the cpu state from the parent process + */ ReadAll(reader, jb, sizeof(jb)); + + /* + * read the list of mappings from the parent process + * this is stored in a special secretive memory map! + * read ExtendMemoryIntervals for further details :| + */ + maps = (void *)kMemtrackStart; ReadAll(reader, &mapcount, sizeof(_mmi.i)); - maps = GlobalAlloc(0, mapcount * sizeof(*_mmi.p)); - ReadAll(reader, maps, mapcount * sizeof(*_mmi.p)); + ReadAll(reader, &mapcapacity, sizeof(_mmi.n)); + specialz = ROUNDUP(mapcapacity * sizeof(_mmi.p[0]), kMemtrackGran); + MapViewOfFileExNuma(CreateFileMappingNuma( + -1, &kNtIsInheritable, kNtPageReadwrite, + specialz >> 32, specialz, 0, kNtNumaNoPreferredNode), + kNtFileMapWrite, 0, 0, specialz, maps, + kNtNumaNoPreferredNode); + ReadAll(reader, maps, mapcount * sizeof(_mmi.p[0])); + if (IsAsan()) { + shad = (char *)(((intptr_t)maps >> 3) + 0x7fff8000); + size = ROUNDUP(specialz >> 3, FRAMESIZE); + MapViewOfFileExNuma( + CreateFileMappingNuma(-1, &kNtIsInheritable, kNtPageReadwrite, + size >> 32, size, 0, kNtNumaNoPreferredNode), + kNtFileMapWrite, 0, 0, size, maps, kNtNumaNoPreferredNode); +#if 0 + ReadAll(reader, shad, (mapcount * sizeof(_mmi.p[0])) >> 3); +#endif + } + + /* + * read the heap mappings from the parent process + * we can avoid copying via pipe for shared maps! + */ for (i = 0; i < mapcount; ++i) { - addr = (void *)((uint64_t)maps[i].x << 16); - size = ((uint64_t)(maps[i].y - maps[i].x) << 16) + FRAMESIZE; + addr = (char *)((uint64_t)maps[i].x << 16); + size = maps[i].size; if (maps[i].flags & MAP_PRIVATE) { - CloseHandle(maps[i].h); - maps[i].h = - sys_mmap_nt(addr, size, maps[i].prot, maps[i].flags, -1, 0).maphandle; + STRACE("fork() child %p %'zu copying private map", addr, size); + if (!CloseHandle(maps[i].h)) { + STRACE("fork() child CloseHandle(%ld) ~~~FAILED~~~ %m", maps[i].h); + } + upsize = ROUNDUP(size, FRAMESIZE); + maps[i].h = CreateFileMappingNuma(-1, &kNtIsInheritable, + kNtPageExecuteReadwrite, upsize >> 32, + upsize, NULL, kNtNumaNoPreferredNode); + MapViewOfFileExNuma(maps[i].h, kNtFileMapWrite | kNtFileMapExecute, 0, 0, + upsize, addr, kNtNumaNoPreferredNode); ReadAll(reader, addr, size); } else { - MapViewOfFileExNuma( - maps[i].h, - (maps[i].prot & PROT_WRITE) - ? kNtFileMapWrite | kNtFileMapExecute | kNtFileMapRead - : kNtFileMapExecute | kNtFileMapRead, - 0, 0, size, addr, kNtNumaNoPreferredNode); + STRACE("fork() child %p %'zu mapping shared hand:%ld offset:%'lu", addr, + size, maps[i].h, maps[i].offset); + MapViewOfFileExNuma(maps[i].h, + (maps[i].prot & PROT_WRITE) + ? kNtFileMapWrite | kNtFileMapExecute + : kNtFileMapRead | kNtFileMapExecute, + maps[i].offset >> 32, maps[i].offset, size, addr, + kNtNumaNoPreferredNode); } } - ReadAll(reader, _etext, _end - _etext); + + /* + * read the .data and .bss program image sections + */ + savepid = __pid; + savebir = __kbirth; + savetsc = ts; + STRACE("fork() child reading %'zu bytes of .data to %p", + __data_end - __data_start, __data_start); + ReadAll(reader, __data_start, __data_end - __data_start); + STRACE("fork() child reading %'zu bytes of .bss to %p", + __bss_end - __bss_start, __bss_start); + ReadAll(reader, __bss_start, __bss_end - __bss_start); + __pid = savepid; + __kbirth = savebir; + ts = savetsc; + + /* + * apply fixups and reapply memory protections + */ + STRACE("fork() child applying fixups to _mmi.p"); + _mmi.p = maps; + _mmi.n = specialz / sizeof(_mmi.p[0]); for (i = 0; i < mapcount; ++i) { - _mmi.p[i].h = maps[i].h; + if ((maps[i].flags & MAP_PRIVATE) && (~maps[i].prot & PROT_WRITE)) { + VirtualProtect((void *)((uint64_t)maps[i].x << 16), + ROUNDUP(maps[i].size, FRAMESIZE), + __prot2nt(maps[i].prot, 0), &oldprot); + } } + + /* + * clean up and restore old processor state + */ + STRACE("fork() child almost done!"); CloseHandle(reader); CloseHandle(writer); - GlobalFree(maps); +#ifdef SYSDEBUG + RemoveVectoredExceptionHandler(oncrash); +#endif if (weaken(__wincrash_nt)) { AddVectoredExceptionHandler(1, (void *)weaken(__wincrash_nt)); } + STRACE("fork() child it's time for the big jump (>'.')>"); longjmp(jb, 1); } textwindows int sys_fork_nt(void) { + bool ok; jmp_buf jb; + char **args, **args2; int64_t reader, writer; - int i, rc, pid, releaseme; + int i, n, rc, pid, untrackpid; char *p, forkvar[6 + 21 + 1 + 21 + 1]; struct NtStartupInfo startinfo; struct NtProcessInformation procinfo; - if ((pid = releaseme = __reservefd()) == -1) return -1; + if ((pid = untrackpid = __reservefd()) == -1) return -1; if (!setjmp(jb)) { if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) { p = stpcpy(forkvar, "_FORK="); @@ -153,43 +289,94 @@ textwindows int sys_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(program_executable_name, __argv, environ, forkvar, + args = __argv; +#ifdef SYSDEBUG + /* + * If --strace was passed to this program, then propagate it the + * forked process since the flag was removed by __intercept_flag + */ + if (__strace > 0) { + for (n = 0; args[n];) ++n; + args2 = alloca((n + 2) * sizeof(char *)); + for (i = 0; i < n; ++i) args2[i] = args[i]; + args2[i++] = "--strace"; + args2[i] = 0; + args = args2; + } +#endif + if (ntspawn(program_executable_name, args, environ, forkvar, &kNtIsInheritable, NULL, true, 0, NULL, &startinfo, &procinfo) != -1) { CloseHandle(reader); CloseHandle(procinfo.hThread); - if (weaken(__sighandrvas) && - weaken(__sighandrvas)[SIGCHLD] == SIG_IGN) { - CloseHandle(procinfo.hProcess); - } else { - g_fds.p[pid].kind = kFdProcess; - g_fds.p[pid].handle = procinfo.hProcess; - g_fds.p[pid].flags = O_CLOEXEC; - releaseme = -1; + ok = WriteAll(writer, jb, sizeof(jb)) && + WriteAll(writer, &_mmi.i, sizeof(_mmi.i)) && + WriteAll(writer, &_mmi.n, sizeof(_mmi.n)) && + WriteAll(writer, _mmi.p, _mmi.i * sizeof(_mmi.p[0])); +#if 0 + if (IsAsan() && ok) { + ok = WriteAll(writer, (char *)(((intptr_t)_mmi.p >> 3) + 0x7fff8000), + (_mmi.i * sizeof(_mmi.p[0])) >> 3); } - WriteAll(writer, jb, sizeof(jb)); - WriteAll(writer, &_mmi.i, sizeof(_mmi.i)); - WriteAll(writer, _mmi.p, _mmi.i * sizeof(*_mmi.p)); - for (i = 0; i < _mmi.i; ++i) { +#endif + for (i = 0; i < _mmi.i && ok; ++i) { if (_mmi.p[i].flags & MAP_PRIVATE) { - WriteAll(writer, (void *)((uint64_t)_mmi.p[i].x << 16), - ((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE); + ok = WriteAll(writer, (void *)((uint64_t)_mmi.p[i].x << 16), + _mmi.p[i].size); } } - WriteAll(writer, _etext, _end - _etext); - CloseHandle(writer); + if (ok) { + STRACE("fork() parent writing %'zu bytes of .data", + __data_end - __data_start); + ok = WriteAll(writer, __data_start, __data_end - __data_start); + } + if (ok) { + STRACE("fork() parent writing %'zu bytes of .bss", + __bss_end - __bss_start); + ok = WriteAll(writer, __bss_start, __bss_end - __bss_start); + } + ok = ok & !!CloseHandle(writer); + if (ok) { + if (!weaken(__sighandrvas) || + weaken(__sighandrvas)[SIGCHLD] != SIG_IGN) { + g_fds.p[pid].kind = kFdProcess; + g_fds.p[pid].handle = procinfo.hProcess; + g_fds.p[pid].flags = O_CLOEXEC; + untrackpid = -1; + } else { + /* + * XXX: Ignoring SIGCHLD should track the process information. + * What we need to do instead, is periodically check if a + * process has exited and remove it automatically via i/o + * functions like poll() so it doesn't get zombdied. + */ + STRACE("fork() parent closing process handle b/c SIGCHLD=SIG_IGN"); + CloseHandle(procinfo.hProcess); + } + STRACE("fork() parent everything looks good"); + rc = pid; + } else { + STRACE("fork() parent ~~failed~~ because writing failed"); + rc = __winerr(); + TerminateProcess(procinfo.hProcess, 127); + CloseHandle(procinfo.hProcess); + } } else { + STRACE("fork() parent ~~failed~~ because ntspawn failed"); + CloseHandle(writer); rc = -1; } - rc = pid; } else { + STRACE("fork() parent ~~failed~~ because CreatePipe() failed %m"); rc = __winerr(); + CloseHandle(writer); } } else { + STRACE("fork() child welcome back <('.'<)"); rc = 0; } - if (releaseme != -1) { - __releasefd(releaseme); + if (untrackpid != -1) { + __releasefd(untrackpid); } return rc; } diff --git a/libc/runtime/memtrack.c b/libc/runtime/memtrack.c index a3b2783f9..5a546f2c9 100644 --- a/libc/runtime/memtrack.c +++ b/libc/runtime/memtrack.c @@ -71,6 +71,7 @@ static noasan bool ExtendMemoryIntervals(struct MemoryIntervals *mm) { base = (char *)kMemtrackStart; prot = PROT_READ | PROT_WRITE; flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED; + /* TODO(jart): These map handles should not leak across NT fork() */ if (mm->p == mm->s) { if (IsAsan()) { shad = (char *)(((intptr_t)base >> 3) + 0x7fff8000); @@ -170,7 +171,7 @@ noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y, } noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h, - int prot, int flags) { + int prot, int flags, long offset, long size) { /* asan runtime depends on this function */ unsigned i; assert(y >= x); @@ -194,6 +195,8 @@ noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h, mm->p[i].h = h; mm->p[i].prot = prot; mm->p[i].flags = flags; + mm->p[i].offset = offset; + mm->p[i].size = size; } return 0; } diff --git a/libc/runtime/memtrack.internal.h b/libc/runtime/memtrack.internal.h index eed644c5b..a25352559 100644 --- a/libc/runtime/memtrack.internal.h +++ b/libc/runtime/memtrack.internal.h @@ -14,9 +14,11 @@ COSMOPOLITAN_C_START_ #define kAutomapSize \ _kMem(0x200000000000 - 0x100080000000 - _kMmi(0x800000000000), \ 0x000040000000 - 0x000010000000 - _kMmi(0x000080000000)) -#define kMemtrackStart \ - _kMem(0x200000000000 - _kMmi(0x800000000000), \ - 0x000040000000 - _kMmi(0x000080000000)) +#define kMemtrackStart \ + (ROUNDDOWN(_kMem(0x200000000000 - _kMmi(0x800000000000), \ + 0x000040000000 - _kMmi(0x000080000000)), \ + FRAMESIZE * 8) - \ + 0x8000 * 8 /* so frame aligned after adding 0x7fff8000 */) #define kMemtrackSize _kMem(_kMmi(0x800000000000), _kMmi(0x000080000000)) #define kMemtrackGran (!IsAsan() ? FRAMESIZE : FRAMESIZE * 8) #define kFixedmapStart _kMem(0x300000000000, 0x000040000000) @@ -34,6 +36,8 @@ struct MemoryInterval { long h; int prot; int flags; + long offset; + long size; }; struct MemoryIntervals { @@ -50,8 +54,8 @@ char *DescribeProt(int, char[hasatleast 4]); char *DescribeMapping(int, int, char[hasatleast 8]) hidden; bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect hidden; void PrintMemoryIntervals(int, const struct MemoryIntervals *) hidden; -int TrackMemoryInterval(struct MemoryIntervals *, int, int, long, int, - int) hidden; +int TrackMemoryInterval(struct MemoryIntervals *, int, int, long, int, int, + long, long) hidden; int ReleaseMemoryIntervals(struct MemoryIntervals *, int, int, void (*)(struct MemoryIntervals *, int, int)) hidden; void ReleaseMemoryNt(struct MemoryIntervals *, int, int) hidden; diff --git a/libc/runtime/mmap.c b/libc/runtime/mmap.c index 714f82130..7778519e4 100644 --- a/libc/runtime/mmap.c +++ b/libc/runtime/mmap.c @@ -128,7 +128,8 @@ static noasan void *MapMemory(void *addr, size_t size, int prot, int flags, Die(); } } - if (TrackMemoryInterval(&_mmi, x, x + (n - 1), dm.maphandle, prot, flags)) { + if (TrackMemoryInterval(&_mmi, x, x + (n - 1), dm.maphandle, prot, flags, off, + size)) { if (sys_munmap(addr, n) == -1) { STRACE("TRACK MUNMAP FAILED %m"); assert(!"MapMemory() failed"); @@ -152,26 +153,31 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size, int prot, int flags, int fd, int64_t off, int f, int x, size_t n) { + int64_t oi, sz; struct DirectMap dm; size_t i, m = (n - 1) * FRAMESIZE; assert(m < size && m + FRAMESIZE >= size); - dm = sys_mmap(addr + m, size - m, prot, f, fd, fd == -1 ? 0 : off + m); + oi = fd == -1 ? 0 : off + m; + sz = size - m; + dm = sys_mmap(addr + m, sz, prot, f, fd, oi); if (dm.addr == MAP_FAILED) { STRACE("MapMemories(%.12p+%lx/%lx) %m", addr, m, size); return MAP_FAILED; } if (TrackMemoryInterval(&_mmi, x + (n - 1), x + (n - 1), dm.maphandle, prot, - flags) == -1) { + flags, oi, sz) == -1) { STRACE("MapMemories(%.12p+%lx/%lx) unrecoverable failure #1 %m", addr, m, size); assert(!"MapMemories() failed"); Die(); } for (i = 0; i < m; i += FRAMESIZE) { - dm = sys_mmap(addr + i, FRAMESIZE, prot, f, fd, fd == -1 ? 0 : off + i); + oi = fd == -1 ? 0 : off + i; + sz = FRAMESIZE; + dm = sys_mmap(addr + i, sz, prot, f, fd, oi); if (dm.addr == MAP_FAILED || TrackMemoryInterval(&_mmi, x + i / FRAMESIZE, x + i / FRAMESIZE, - dm.maphandle, prot, flags) == -1) { + dm.maphandle, prot, flags, oi, sz) == -1) { STRACE("MapMemories(%p+%x/%x) unrecoverable failure #2 %m", addr, i, size); assert(!"MapMemories() failed"); diff --git a/libc/runtime/mremap.c b/libc/runtime/mremap.c index 82dad601e..9a6fd9c25 100644 --- a/libc/runtime/mremap.c +++ b/libc/runtime/mremap.c @@ -145,7 +145,7 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) { if (dm.addr == MAP_FAILED) return 0; if (TrackMemoryInterval(&_mmi, ((uintptr_t)p + n) >> 16, ((uintptr_t)p + m - FRAMESIZE) >> 16, dm.maphandle, - prot, flags) != -1) { + prot, flags, 0, m - n) != -1) { if (weaken(__asan_map_shadow)) { weaken(__asan_map_shadow)((uintptr_t)dm.addr, m - n); } @@ -178,7 +178,7 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) { if (q == MAP_FAILED) return 0; if (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16, ((uintptr_t)p + n - FRAMESIZE) >> 16, 0) != -1 && - TrackMemoryInterval(&_mmi, a, b, -1, prot, flags) != -1) { + TrackMemoryInterval(&_mmi, a, b, -1, prot, flags, 0, m) != -1) { if (weaken(__asan_poison)) { if (!OverlapsShadowSpace(p, n)) { weaken(__asan_poison)((intptr_t)p, n, kAsanUnmapped); diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index d1ad71ead..9de2108f4 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -27,6 +27,7 @@ extern unsigned char _base[] forcealign(PAGESIZE); /* αpε */ extern unsigned char _ehead[] forcealign(PAGESIZE); /* αpε */ extern unsigned char _etext[] forcealign(PAGESIZE); /* αpε */ extern unsigned char _edata[] forcealign(PAGESIZE); /* αpε */ +extern unsigned char _ezip[]; /* αpε */ extern unsigned char _end[] forcealign(FRAMESIZE); /* αpε */ extern unsigned char _ereal; /* αpε */ extern unsigned char __privileged_start; /* αpε */ diff --git a/libc/runtime/runtime.mk b/libc/runtime/runtime.mk index e012c0de1..6afc6be9a 100644 --- a/libc/runtime/runtime.mk +++ b/libc/runtime/runtime.mk @@ -59,6 +59,7 @@ $(LIBC_RUNTIME_A).pkg: \ o/$(MODE)/libc/runtime/printf.o \ o/$(MODE)/libc/runtime/abort-nt.o \ +o/$(MODE)/libc/runtime/printmemoryintervals.o \ o/$(MODE)/libc/runtime/arememoryintervalsok.o \ o/$(MODE)/libc/runtime/assertfail.o \ o/$(MODE)/libc/runtime/directmap.o \ @@ -81,6 +82,15 @@ o/$(MODE)/libc/runtime/winmain.greg.o: \ OVERRIDE_CFLAGS += \ $(NO_MAGIC) +# must use alloca() +# can't use asan or any runtime services +o/$(MODE)/libc/runtime/fork-nt.o: \ + OVERRIDE_CPPFLAGS += \ + -DSTACK_FRAME_UNLIMITED +o/$(MODE)/libc/runtime/fork-nt.o: \ + OVERRIDE_CFLAGS += \ + $(NO_MAGIC) + o/$(MODE)/libc/runtime/printf.o \ o/$(MODE)/libc/runtime/memtrack.o \ o/$(MODE)/libc/runtime/mman.greg.o: \ diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 91b43ab14..e42a2cd63 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -72,6 +72,7 @@ struct WinArgs { extern int __pid; extern bool __nomultics; +extern uint32_t __winmainpid; extern const char kConsoleHandles[2]; static const short kConsoleModes[2] = { @@ -115,6 +116,7 @@ static noasan textwindows wontreturn noinstrument void WinMainNew( version = NtGetPeb()->OSMajorVersion; __oldstack = (intptr_t)__builtin_frame_address(0); if ((intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui && version >= 10) { + __winmainpid = __pid; rc = SetConsoleCP(kNtCpUtf8); STRACE("SetConsoleCP(kNtCpUtf8) → %hhhd", rc); rc = SetConsoleOutputCP(kNtCpUtf8); @@ -147,6 +149,7 @@ static noasan textwindows wontreturn noinstrument void WinMainNew( _mmi.p[0].y = (allocaddr >> 16) + ((allocsize >> 16) - 1); _mmi.p[0].prot = PROT_READ | PROT_WRITE | PROT_EXEC; _mmi.p[0].flags = MAP_PRIVATE | MAP_ANONYMOUS; + _mmi.p[0].size = allocsize; _mmi.i = 1; wa = (struct WinArgs *)allocaddr; STRACE("WinMainNew() loading arg block"); diff --git a/libc/sock/kntwsadata.c b/libc/sock/kntwsadata.c index 5e907e62a..74fb4144b 100644 --- a/libc/sock/kntwsadata.c +++ b/libc/sock/kntwsadata.c @@ -16,8 +16,10 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/weaken.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" +#include "libc/mem/mem.h" #include "libc/nt/runtime.h" #include "libc/nt/winsock.h" #include "libc/runtime/runtime.h" @@ -35,7 +37,17 @@ hidden struct NtWsaData kNtWsaData; static textwindows void WinSockCleanup(void) { + size_t i; + STRACE("WSACleanup()"); WSACleanup(); + for (i = 0; i < g_fds.n; ++i) { + if (g_fds.p[i].kind == kFdSocket) { + if (weaken(free)) { + weaken(free)((struct SockFd *)g_fds.p[i].extra); + g_fds.p[i].extra = 0; + } + } + } } textwindows noasan void WinSockInit(void) { diff --git a/libc/str/longsort.c b/libc/str/longsort.c index 6235485d3..bdf420b81 100644 --- a/libc/str/longsort.c +++ b/libc/str/longsort.c @@ -74,7 +74,7 @@ void longsort(long *x, size_t n) { } if (n > 1) { t = 1ul << bsrl(n - 1); - if (X86_HAVE(AVX2)) { + if (!IsTiny() && X86_HAVE(AVX2)) { longsort_avx2(x, n, t); } else { longsort_pure(x, n, t); diff --git a/libc/stubs/ld.S b/libc/stubs/ld.S index 23d78e6db..195e33c71 100644 --- a/libc/stubs/ld.S +++ b/libc/stubs/ld.S @@ -35,6 +35,10 @@ __ro = 0 __relo_start = 0 __relo_end = 0 + __data_start = 0 + __data_end = 0 + __bss_start = 0 + __bss_end = 0 // Thread local boundaries defined by linker script // @see ape/ape.lds @@ -59,6 +63,10 @@ .globl _tbss_end .globl _tdata_start .globl _tdata_end + .globl __data_start + .globl __data_end + .globl __bss_start + .globl __bss_end .weak _base .weak ape_xlm @@ -76,3 +84,7 @@ .weak _tbss_end .weak _tdata_start .weak _tdata_end + .weak __data_start + .weak __data_end + .weak __bss_start + .weak __bss_end diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index f9782ce88..df6726506 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -175,30 +175,28 @@ syscon compat SIGPOLL 29 23 23 23 23 29 # same as SIGIO syscon compat SIGIOT 6 6 6 6 6 6 # PDP-11 feature; same as SIGABRT syscon compat SIGPWR 30 30 30 30 32 30 # not implemented in most community editions of system five; consider doing this using SIGUSR1 or SIGUSR2 instead -# open() flags ┌──────hoo boy -# ┌──────┐ -# │┌─<<8─┴───dwFlagsAndAttributes -# ┌││─────┐ -# │││ │ ┌┴───dwDesiredAccess -# N │││ │ │ -# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD T │││┌─┴┐│ Commentary -syscon open O_RDONLY 0 0 0 0 0 0xA0000000 # unix consensus & kNtGenericRead|kNtGenericExecute -syscon open O_WRONLY 1 1 1 1 1 0x40000000 # unix consensus & kNtGenericWrite -syscon open O_RDWR 2 2 2 2 2 0xE0000000 # unix consensus & kNtGenericRead|kNtGenericWrite|kNtGenericExecute -syscon open O_ACCMODE 3 3 3 3 3 0xE0000000 # O_RDONLY|O_WRONLY|O_RDWR -syscon open O_APPEND 0x00000400 8 8 8 8 0x00000004 # bsd consensus & kNtFileAppendData; won't pose issues w/ mknod(S_IFIFO) -syscon open O_CREAT 0x00000040 0x00000200 0x00000200 0x00000200 0x00000200 0x00000040 # bsd consensus & NT faked as Linux -syscon open O_EXCL 0x00000080 0x00000800 0x00000800 0x00000800 0x00000800 0x00000080 # bsd consensus & NT faked as Linux -syscon open O_TRUNC 0x00000200 0x00000400 0x00000400 0x00000400 0x00000400 0x00000200 # bsd consensus & NT faked as Linux -syscon open O_DIRECTORY 0x00010000 0x00100000 0x00020000 0x00020000 0x00200000 0x02000000 # useful hint on UNIX, but required on NT (see kNtFileFlagBackupSemantics) -syscon open O_RANDOM 0 0 0 0 0 0x10000000 # kNtFileFlagRandomAccess -syscon open O_SEQUENTIAL 0 0 0 0 0 0x08000000 # kNtFileFlagSequentialScan -syscon open O_DIRECT 0x00004000 0 0x00010000 0 0x00080000 0x00200000 # kNtFileFlagNoBuffering>>8 -syscon open O_CLOEXEC 0x00080000 0x01000000 0x00100000 0x00010000 0x00400000 0x00080000 # NT faked as Linux -syscon open O_TMPFILE 0x00410000 0 0 0 0 0x00000000 # Linux 3.11+ (c. 2013) & kNtFileAttributeTemporary|kNtFileFlagDeleteOnClose -syscon open O_SPARSE 0 0 0 0 0 0x00040000 # we invented it -syscon open O_NDELAY 0x00000800 0x00000004 0x00000004 0x00000004 0x00000004 0x00000800 # bsd consensus & kNtFileFlagWriteThrough>>8 → 0x00800000 (???) -syscon open O_NONBLOCK 0x00000800 0x00000004 0x00000004 0x00000004 0x00000004 0x00000800 # bsd consensus & faked on nt to be same as linux +# open() flags +# +# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD Windoze Commentary +syscon open O_RDONLY 0 0 0 0 0 0 # consensus +syscon open O_WRONLY 1 1 1 1 1 1 # consensus +syscon open O_RDWR 2 2 2 2 2 2 # consensus +syscon open O_ACCMODE 3 3 3 3 3 3 # O_RDONLY|O_WRONLY|O_RDWR +syscon open O_APPEND 0x00000400 8 8 8 8 0x00000400 # bsd consensus & kNtFileAppendData; won't pose issues w/ mknod(S_IFIFO) [SYNC libc/calls/open-nt.c] +syscon open O_CREAT 0x00000040 0x00000200 0x00000200 0x00000200 0x00000200 0x00000040 # bsd consensus & NT faked as Linux [SYNC libc/calls/open-nt.c] +syscon open O_EXCL 0x00000080 0x00000800 0x00000800 0x00000800 0x00000800 0x00000080 # bsd consensus & NT faked as Linux [SYNC libc/calls/open-nt.c] +syscon open O_TRUNC 0x00000200 0x00000400 0x00000400 0x00000400 0x00000400 0x00000200 # bsd consensus & NT faked as Linux [SYNC libc/calls/open-nt.c] +syscon open O_DIRECTORY 0x00010000 0x00100000 0x00020000 0x00020000 0x00200000 0x00010000 # useful hint on UNIX, but required on NT (see kNtFileFlagBackupSemantics) [SYNC libc/calls/open-nt.c] +syscon open O_DIRECT 0x00004000 0 0x00010000 0 0x00080000 0x00004000 # kNtFileFlagNoBuffering [SYNC libc/calls/open-nt.c] +syscon open O_NDELAY 0x00000800 0x00000004 0x00000004 0x00000004 0x00000004 0x00000800 # kNtFileFlagWriteThrough [SYNC libc/calls/open-nt.c] +syscon open O_RANDOM 0 0 0 0 0 0x80000000 # kNtFileFlagRandomAccess [SYNC libc/calls/open-nt.c] +syscon open O_SEQUENTIAL 0 0 0 0 0 0x40000000 # kNtFileFlagSequentialScan [SYNC libc/calls/open-nt.c] +syscon open O_COMPRESSED 0 0 0 0 0 0x20000000 # kNtFileAttributeCompressed [SYNC libc/calls/open-nt.c] +syscon open O_INDEXED 0 0 0 0 0 0x10000000 # !kNtFileAttributeNotContentIndexed [SYNC libc/calls/open-nt.c] +syscon open O_CLOEXEC 0x00080000 0x01000000 0x00100000 0x00010000 0x00400000 0x00080000 # NT faked as Linux [SYNC libc/calls/open-nt.c] +syscon open O_TMPFILE 0x00410000 0 0 0 0 0x00410000 # Linux 3.11+ (c. 2013) & kNtFileAttributeTemporary|kNtFileFlagDeleteOnClose [SYNC libc/calls/open-nt.c] +syscon open O_SPARSE 0 0 0 0 0 0 # wut +syscon open O_NONBLOCK 0x00000800 0x00000004 0x00000004 0x00000004 0x00000004 0x00000800 # bsd consensus syscon open O_ASYNC 0x00002000 0x00000040 0x00000040 0x00000040 0x00000040 0 # bsd consensus syscon open O_NOFOLLOW 0x00020000 0x00000100 0x00000100 0x00000100 0x00000100 0 # bsd consensus syscon open O_NOFOLLOW_ANY 0 0x20000000 0 0 0 0 # diff --git a/libc/sysv/consts/O_ACCMODE.S b/libc/sysv/consts/O_ACCMODE.S index a3fc04fc4..975af5e22 100644 --- a/libc/sysv/consts/O_ACCMODE.S +++ b/libc/sysv/consts/O_ACCMODE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon open,O_ACCMODE,3,3,3,3,3,0xE0000000 +.syscon open,O_ACCMODE,3,3,3,3,3,3 diff --git a/libc/sysv/consts/O_APPEND.S b/libc/sysv/consts/O_APPEND.S index ee7a00db2..3a0bab7d5 100644 --- a/libc/sysv/consts/O_APPEND.S +++ b/libc/sysv/consts/O_APPEND.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon open,O_APPEND,0x00000400,8,8,8,8,0x00000004 +.syscon open,O_APPEND,0x00000400,8,8,8,8,0x00000400 diff --git a/libc/sysv/consts/O_COMPRESSED.S b/libc/sysv/consts/O_COMPRESSED.S new file mode 100644 index 000000000..251563818 --- /dev/null +++ b/libc/sysv/consts/O_COMPRESSED.S @@ -0,0 +1,2 @@ +#include "libc/sysv/consts/syscon.internal.h" +.syscon open,O_COMPRESSED,0,0,0,0,0,0x20000000 diff --git a/libc/sysv/consts/O_DIRECT.S b/libc/sysv/consts/O_DIRECT.S index f9be1eb9c..8a205a29f 100644 --- a/libc/sysv/consts/O_DIRECT.S +++ b/libc/sysv/consts/O_DIRECT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon open,O_DIRECT,0x00004000,0,0x00010000,0,0x00080000,0x00200000 +.syscon open,O_DIRECT,0x00004000,0,0x00010000,0,0x00080000,0x00004000 diff --git a/libc/sysv/consts/O_DIRECTORY.S b/libc/sysv/consts/O_DIRECTORY.S index 00fcac4dd..8a41b6e27 100644 --- a/libc/sysv/consts/O_DIRECTORY.S +++ b/libc/sysv/consts/O_DIRECTORY.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon open,O_DIRECTORY,0x00010000,0x00100000,0x00020000,0x00020000,0x00200000,0x02000000 +.syscon open,O_DIRECTORY,0x00010000,0x00100000,0x00020000,0x00020000,0x00200000,0x00010000 diff --git a/libc/sysv/consts/O_INDEXED.S b/libc/sysv/consts/O_INDEXED.S new file mode 100644 index 000000000..3bcd6320a --- /dev/null +++ b/libc/sysv/consts/O_INDEXED.S @@ -0,0 +1,2 @@ +#include "libc/sysv/consts/syscon.internal.h" +.syscon open,O_INDEXED,0,0,0,0,0,0x10000000 diff --git a/libc/sysv/consts/O_RANDOM.S b/libc/sysv/consts/O_RANDOM.S index 88e3552b2..f7cb69d59 100644 --- a/libc/sysv/consts/O_RANDOM.S +++ b/libc/sysv/consts/O_RANDOM.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon open,O_RANDOM,0,0,0,0,0,0x10000000 +.syscon open,O_RANDOM,0,0,0,0,0,0x80000000 diff --git a/libc/sysv/consts/O_RDONLY.S b/libc/sysv/consts/O_RDONLY.S index b239e4466..0db270eb7 100644 --- a/libc/sysv/consts/O_RDONLY.S +++ b/libc/sysv/consts/O_RDONLY.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon open,O_RDONLY,0,0,0,0,0,0xA0000000 +.syscon open,O_RDONLY,0,0,0,0,0,0 diff --git a/libc/sysv/consts/O_RDWR.S b/libc/sysv/consts/O_RDWR.S index 786c1c138..87de21ff9 100644 --- a/libc/sysv/consts/O_RDWR.S +++ b/libc/sysv/consts/O_RDWR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon open,O_RDWR,2,2,2,2,2,0xE0000000 +.syscon open,O_RDWR,2,2,2,2,2,2 diff --git a/libc/sysv/consts/O_SEQUENTIAL.S b/libc/sysv/consts/O_SEQUENTIAL.S index c0f64b8d5..3a0be8664 100644 --- a/libc/sysv/consts/O_SEQUENTIAL.S +++ b/libc/sysv/consts/O_SEQUENTIAL.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon open,O_SEQUENTIAL,0,0,0,0,0,0x08000000 +.syscon open,O_SEQUENTIAL,0,0,0,0,0,0x40000000 diff --git a/libc/sysv/consts/O_SPARSE.S b/libc/sysv/consts/O_SPARSE.S index f135a0219..7b17bfe52 100644 --- a/libc/sysv/consts/O_SPARSE.S +++ b/libc/sysv/consts/O_SPARSE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon open,O_SPARSE,0,0,0,0,0,0x00040000 +.syscon open,O_SPARSE,0,0,0,0,0,0 diff --git a/libc/sysv/consts/O_TMPFILE.S b/libc/sysv/consts/O_TMPFILE.S index 4627550ab..bbff30e4a 100644 --- a/libc/sysv/consts/O_TMPFILE.S +++ b/libc/sysv/consts/O_TMPFILE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon open,O_TMPFILE,0x00410000,0,0,0,0,0x00000000 +.syscon open,O_TMPFILE,0x00410000,0,0,0,0,0x00410000 diff --git a/libc/sysv/consts/O_WRONLY.S b/libc/sysv/consts/O_WRONLY.S index 7dd4a3830..0188a8b58 100644 --- a/libc/sysv/consts/O_WRONLY.S +++ b/libc/sysv/consts/O_WRONLY.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon open,O_WRONLY,1,1,1,1,1,0x40000000 +.syscon open,O_WRONLY,1,1,1,1,1,1 diff --git a/libc/sysv/consts/o.h b/libc/sysv/consts/o.h index 6d5d61ebf..175209255 100644 --- a/libc/sysv/consts/o.h +++ b/libc/sysv/consts/o.h @@ -8,6 +8,7 @@ extern const unsigned O_ACCMODE; extern const unsigned O_APPEND; extern const unsigned O_ASYNC; extern const unsigned O_CLOEXEC; +extern const unsigned O_COMPRESSED; extern const unsigned O_CREAT; extern const unsigned O_DIRECT; extern const unsigned O_DIRECTORY; @@ -15,6 +16,7 @@ extern const unsigned O_DSYNC; extern const unsigned O_EXCL; extern const unsigned O_EXEC; extern const unsigned O_EXLOCK; +extern const unsigned O_INDEXED; extern const unsigned O_LARGEFILE; extern const unsigned O_NDELAY; extern const unsigned O_NOATIME; @@ -41,10 +43,15 @@ extern const unsigned O_WRONLY; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#define O_ACCMODE SYMBOLIC(O_ACCMODE) +#define O_RDONLY LITERALLY(0) +#define O_WRONLY LITERALLY(1) +#define O_RDWR LITERALLY(2) +#define O_ACCMODE LITERALLY(3) + #define O_APPEND SYMBOLIC(O_APPEND) #define O_ASYNC SYMBOLIC(O_ASYNC) #define O_CLOEXEC SYMBOLIC(O_CLOEXEC) +#define O_COMPRESSED SYMBOLIC(O_COMPRESSED) #define O_CREAT SYMBOLIC(O_CREAT) #define O_DIRECT SYMBOLIC(O_DIRECT) #define O_DIRECTORY SYMBOLIC(O_DIRECTORY) @@ -52,6 +59,7 @@ COSMOPOLITAN_C_END_ #define O_EXCL SYMBOLIC(O_EXCL) #define O_EXEC SYMBOLIC(O_EXEC) #define O_EXLOCK SYMBOLIC(O_EXLOCK) +#define O_INDEXED SYMBOLIC(O_INDEXED) #define O_LARGEFILE SYMBOLIC(O_LARGEFILE) #define O_NDELAY SYMBOLIC(O_NDELAY) #define O_NOATIME SYMBOLIC(O_NOATIME) @@ -61,8 +69,6 @@ COSMOPOLITAN_C_END_ #define O_NONBLOCK SYMBOLIC(O_NONBLOCK) #define O_PATH SYMBOLIC(O_PATH) #define O_RANDOM SYMBOLIC(O_RANDOM) -#define O_RDONLY SYMBOLIC(O_RDONLY) -#define O_RDWR SYMBOLIC(O_RDWR) #define O_RSYNC SYMBOLIC(O_RSYNC) #define O_SEARCH SYMBOLIC(O_SEARCH) #define O_SEQUENTIAL SYMBOLIC(O_SEQUENTIAL) @@ -73,6 +79,5 @@ COSMOPOLITAN_C_END_ #define O_TRUNC SYMBOLIC(O_TRUNC) #define O_TTY_INIT SYMBOLIC(O_TTY_INIT) #define O_VERIFY SYMBOLIC(O_VERIFY) -#define O_WRONLY SYMBOLIC(O_WRONLY) #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_O_H_ */ diff --git a/libc/sysv/systemfive.S b/libc/sysv/systemfive.S index 8a8995720..fd8b07ee0 100644 --- a/libc/sysv/systemfive.S +++ b/libc/sysv/systemfive.S @@ -23,7 +23,6 @@ #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/prot.h" -#include "libc/sysv/consts/prot.h" /* ▄▄▄ ▄▄▄ ▀▓▓▒▄ @@ -418,11 +417,13 @@ _init_systemfive_stack: // m.p[0].h 32 8 // m.p[0].prot 40 4 // m.p[0].flags 44 4 +// m.p[0].offset 48 8 +// m.p[0].size 56 8 .weak _mmi ezlea _mmi,cx test %rcx,%rcx - push %r9 # save the stack size jz 3f + push %r9 # save the stack size lea -1(%r11,%r9),%r9 # need incl. interval shr $16,%r11 # for the stack range shr $16,%r9 @@ -432,8 +433,9 @@ _init_systemfive_stack: orq $-1,32(%rcx) # _mmi.s[0].h mov %edx,40(%rcx) # _mmi.s[0].prot mov %r10d,44(%rcx) # _mmi.s[0].flags -3: pop %r9 # restore stack size - pop %rsi + pop %r9 # restore stack size + mov %r9,56(%rcx) # _mmi.s[0].size +3: pop %rsi pop %rdi leave // switch stacks diff --git a/test/libc/calls/mkntcmdline_test.c b/test/libc/calls/mkntcmdline_test.c index bd373fd76..4cb9b99e2 100644 --- a/test/libc/calls/mkntcmdline_test.c +++ b/test/libc/calls/mkntcmdline_test.c @@ -76,11 +76,17 @@ TEST(mkntcmdline, fix) { char *argv1[] = { "C:/WINDOWS/system32/cmd.exe", "/C", - "more < \"C:\\Users\\jtunn\\AppData\\Local\\Temp\\tmplquaa_d6\"", + "more < \"C:\\Users\\jart\\AppData\\Local\\Temp\\tmplquaa_d6\"", NULL, }; EXPECT_NE(-1, mkntcmdline(cmdline, argv1[0], argv1)); EXPECT_STREQ(u"C:\\WINDOWS\\system32\\cmd.exe /C \"more < " - u"\\\"C:\\Users\\jtunn\\AppData\\Local\\Temp\\tmplquaa_d6\\\"\"", + u"\\\"C:\\Users\\jart\\AppData\\Local\\Temp\\tmplquaa_d6\\\"\"", cmdline); } + +TEST(mkntcmdline, testWut) { + char *argv[] = {"redbean.com", "--strace", NULL}; + EXPECT_NE(-1, mkntcmdline(cmdline, "C:\\Users\\jart\\redbean.com", argv)); + EXPECT_STREQ(u"C:\\Users\\jart\\redbean.com --strace", cmdline); +} diff --git a/test/libc/intrin/describeflags_test.c b/test/libc/intrin/describeflags_test.c new file mode 100644 index 000000000..f23a33b35 --- /dev/null +++ b/test/libc/intrin/describeflags_test.c @@ -0,0 +1,40 @@ +/*-*- 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 2022 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/intrin/describeflags.internal.h" +#include "libc/intrin/kprintf.h" +#include "libc/macros.internal.h" +#include "libc/testlib/testlib.h" + +static const struct DescribeFlags kFlags[] = { + {1, "hi"}, // + {2, "there"}, // +}; + +const char *DescribeIt(uint32_t x) { + static char s[64]; + return DescribeFlags(s, ARRAYLEN(s), kFlags, ARRAYLEN(kFlags), "x", x); +} + +TEST(describeflags, test) { + EXPECT_STREQ("0", DescribeIt(0)); + EXPECT_STREQ("xhi", DescribeIt(1)); + EXPECT_STREQ("xthere", DescribeIt(2)); + EXPECT_STREQ("xhi|xthere", DescribeIt(3)); + EXPECT_STREQ("xhi|xthere|0x14", DescribeIt(0x17)); +} diff --git a/test/libc/intrin/kprintf_test.c b/test/libc/intrin/kprintf_test.c index d9192a101..9aa5d6e92 100644 --- a/test/libc/intrin/kprintf_test.c +++ b/test/libc/intrin/kprintf_test.c @@ -155,6 +155,9 @@ static const struct { {"\"\\001\"", "%#s", S("\1")}, // {"", "%.*s", 0}, // {"☺☻♥♦♣♠!", "%hhs", S("\1\2\3\4\5\6!")}, // + {"☺☻", "%.*hhs", 2, S("\1\2\3\4\5\6!")}, // + {"u\"☺☻\"", "%#.*hhs", 2, S("\1\2\3\4\5\6!")}, // + {"u\" ☻\"", "%#.*hhs", 2, S("\0\2\3\4\5\6!")}, // {"", "% s", S("")}, // {" a", "% s", S("a")}, // {"", "% .*s", 0, S("a")}, // diff --git a/test/libc/runtime/memtrack_test.c b/test/libc/runtime/memtrack_test.c index a69fd6dbe..6cca95b51 100644 --- a/test/libc/runtime/memtrack_test.c +++ b/test/libc/runtime/memtrack_test.c @@ -65,7 +65,7 @@ static void RunTrackMemoryIntervalTest(const struct MemoryIntervals t[2], int x, struct MemoryIntervals *mm; mm = memcpy(malloc(sizeof(*t)), t, sizeof(*t)); CheckMemoryIntervalsAreOk(mm); - CHECK_NE(-1, TrackMemoryInterval(mm, x, y, h, 0, 0)); + CHECK_NE(-1, TrackMemoryInterval(mm, x, y, h, 0, 0, 0, 0)); CheckMemoryIntervalsAreOk(mm); CheckMemoryIntervalsEqual(mm, t + 1); free(mm); @@ -102,10 +102,10 @@ TEST(TrackMemoryInterval, TestFull) { mm = calloc(1, sizeof(struct MemoryIntervals)); for (i = 0; i < mm->n; ++i) { CheckMemoryIntervalsAreOk(mm); - CHECK_NE(-1, TrackMemoryInterval(mm, i, i, i, 0, 0)); + CHECK_NE(-1, TrackMemoryInterval(mm, i, i, i, 0, 0, 0, 0)); CheckMemoryIntervalsAreOk(mm); } - CHECK_EQ(-1, TrackMemoryInterval(mm, i, i, i, 0, 0)); + CHECK_EQ(-1, TrackMemoryInterval(mm, i, i, i, 0, 0, 0, 0)); CHECK_EQ(ENOMEM, errno); CheckMemoryIntervalsAreOk(mm); free(mm); diff --git a/tool/build/blinkenlights.c b/tool/build/blinkenlights.c index 4f261d35c..584922e06 100644 --- a/tool/build/blinkenlights.c +++ b/tool/build/blinkenlights.c @@ -3112,7 +3112,7 @@ int main(int argc, char *argv[]) { m->mode = XED_MACHINE_MODE_LONG_64; m->onbinbase = OnBinbase; m->onlongbranch = OnLongBranch; - speed = 32; + speed = 4; SetXmmSize(2); SetXmmDisp(kXmmHex); if ((colorize = !__nocolor)) { diff --git a/tool/net/redbean.c b/tool/net/redbean.c index aefb0f9b7..94349998e 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -914,7 +914,6 @@ static void SetDefaults(void) { ProgramTimeout(60 * 1000); ProgramSslTicketLifetime(24 * 60 * 60); sslfetchverify = true; - if (IsWindows()) uniprocess = true; } static void AddString(struct Strings *l, const char *s, size_t n) {