Get Redbean fork() working on the New Technology

Now that we have understandable system call tracing on Windows, this
change rewrites many of the polyfill internals for that platform, to
help things get closer to tip top shape. Support for complex forking
scenarios had been in a regressed state for quite some time. Now, it
works! Subsequent changes should be able to address the performance.
This commit is contained in:
Justine Tunney 2022-03-20 08:01:14 -07:00
parent efedef6e65
commit 0cb6b6ff4b
84 changed files with 1340 additions and 338 deletions

View file

@ -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


View file

@ -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));

View file

@ -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 */

View file

@ -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 \

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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();

View file

@ -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);

View file

@ -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:

View file

@ -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;
}

View file

@ -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);
}
}

View file

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

View file

@ -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;
}

View file

@ -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();

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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_ */

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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 */

View file

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

View file

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

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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))();
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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");

View file

@ -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_ */

9
libc/nt/enum/heap.h Normal file
View file

@ -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_ */

View file

@ -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_ */

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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");

View file

@ -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);

View file

@ -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ε */

View file

@ -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: \

View file

@ -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");

View file

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

View file

@ -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);

View file

@ -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

View file

@ -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 #

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon open,O_COMPRESSED,0,0,0,0,0,0x20000000

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon open,O_INDEXED,0,0,0,0,0,0x10000000

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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_ */

View file

@ -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

View file

@ -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);
}

View file

@ -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));
}

View file

@ -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")}, //

View file

@ -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);

View file

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

View file

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