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) {