mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Eliminate some flakes
- Get ASAN working on Windows. - Deleting directories and then recreating them with the same name in a short period of time appears to be a no-no on Windows. - There's no reason to call FlushFileBuffers on close() for pipes, and it's harmful since it might block indefinitely for no good reason.
This commit is contained in:
parent
27c899af56
commit
4e56d89dcd
60 changed files with 588 additions and 751 deletions
42
Makefile
42
Makefile
|
@ -82,17 +82,19 @@ o: o/$(MODE)/ape \
|
||||||
|
|
||||||
PKGS =
|
PKGS =
|
||||||
|
|
||||||
-include ~/.cosmo.mk #──No.1
|
-include ~/.cosmo.mk
|
||||||
include build/functions.mk #─┐
|
include build/functions.mk #─┐
|
||||||
include build/definitions.mk # ├──meta
|
include build/definitions.mk # ├──META
|
||||||
include build/config.mk # │
|
include build/config.mk # │ You can build
|
||||||
include build/rules.mk # │
|
include build/rules.mk # │ You can topologically order
|
||||||
include build/online.mk # │
|
include build/online.mk # │
|
||||||
include libc/stubs/stubs.mk #─┘
|
include libc/stubs/stubs.mk #─┘
|
||||||
include libc/nexgen32e/nexgen32e.mk #─┐
|
include libc/nexgen32e/nexgen32e.mk #─┐
|
||||||
include libc/intrin/intrin.mk # │
|
include libc/sysv/sysv.mk # ├──SYSTEM SUPPORT
|
||||||
include libc/linux/linux.mk # │
|
include libc/nt/nt.mk # │ You can do math
|
||||||
include libc/tinymath/tinymath.mk # ├──metal
|
include libc/intrin/intrin.mk # │ You can use the stack
|
||||||
|
include libc/linux/linux.mk # │ You can manipulate arrays
|
||||||
|
include libc/tinymath/tinymath.mk # │ You can issue raw system calls
|
||||||
include third_party/compiler_rt/compiler_rt.mk # │
|
include third_party/compiler_rt/compiler_rt.mk # │
|
||||||
include libc/bits/bits.mk # │
|
include libc/bits/bits.mk # │
|
||||||
include libc/str/str.mk # │
|
include libc/str/str.mk # │
|
||||||
|
@ -100,20 +102,18 @@ include third_party/xed/xed.mk # │
|
||||||
include third_party/zlib/zlib.mk # │
|
include third_party/zlib/zlib.mk # │
|
||||||
include libc/elf/elf.mk # │
|
include libc/elf/elf.mk # │
|
||||||
include ape/lib/apelib.mk # │
|
include ape/lib/apelib.mk # │
|
||||||
include ape/ape.mk #─┘
|
include ape/ape.mk # │
|
||||||
include libc/sysv/sysv.mk #─┐
|
include libc/fmt/fmt.mk #─┘
|
||||||
include libc/nt/nt.mk # ├──system
|
|
||||||
include libc/fmt/fmt.mk # │
|
|
||||||
include libc/rand/rand.mk #─┘
|
|
||||||
include libc/calls/calls.mk #─┐
|
include libc/calls/calls.mk #─┐
|
||||||
include libc/runtime/runtime.mk # ├──systems
|
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
|
||||||
include libc/crt/crt.mk # │
|
include libc/crt/crt.mk # │ You can issue system calls
|
||||||
|
include libc/rand/rand.mk # │
|
||||||
include libc/unicode/unicode.mk # │
|
include libc/unicode/unicode.mk # │
|
||||||
include third_party/dlmalloc/dlmalloc.mk # │
|
include third_party/dlmalloc/dlmalloc.mk #─┘
|
||||||
include libc/mem/mem.mk # │
|
include libc/mem/mem.mk #─┐
|
||||||
include libc/ohmyplus/ohmyplus.mk # │
|
include libc/ohmyplus/ohmyplus.mk # ├──DYNAMIC RUNTIME
|
||||||
include libc/zipos/zipos.mk # │
|
include libc/zipos/zipos.mk # │ You can now use stdio
|
||||||
include third_party/gdtoa/gdtoa.mk # │
|
include third_party/gdtoa/gdtoa.mk # │ You can finally call malloc()
|
||||||
include libc/time/time.mk # │
|
include libc/time/time.mk # │
|
||||||
include libc/alg/alg.mk # │
|
include libc/alg/alg.mk # │
|
||||||
include libc/stdio/stdio.mk # │
|
include libc/stdio/stdio.mk # │
|
||||||
|
@ -131,8 +131,8 @@ include third_party/musl/musl.mk # │
|
||||||
include third_party/getopt/getopt.mk # │
|
include third_party/getopt/getopt.mk # │
|
||||||
include libc/libc.mk #─┘
|
include libc/libc.mk #─┘
|
||||||
include libc/sock/sock.mk #─┐
|
include libc/sock/sock.mk #─┐
|
||||||
include dsp/tty/tty.mk # ├──online
|
include dsp/tty/tty.mk # ├──ONLINE RUNTIME
|
||||||
include libc/dns/dns.mk # │
|
include libc/dns/dns.mk # │ You can communicate with the network
|
||||||
include libc/crypto/crypto.mk # │
|
include libc/crypto/crypto.mk # │
|
||||||
include net/http/http.mk #─┘
|
include net/http/http.mk #─┘
|
||||||
include third_party/lemon/lemon.mk
|
include third_party/lemon/lemon.mk
|
||||||
|
|
|
@ -44,7 +44,6 @@ LIBC_CALLS_A_DIRECTDEPS = \
|
||||||
LIBC_NT_ADVAPI32 \
|
LIBC_NT_ADVAPI32 \
|
||||||
LIBC_NT_KERNEL32 \
|
LIBC_NT_KERNEL32 \
|
||||||
LIBC_NT_NTDLL \
|
LIBC_NT_NTDLL \
|
||||||
LIBC_RAND \
|
|
||||||
LIBC_STR \
|
LIBC_STR \
|
||||||
LIBC_STUBS \
|
LIBC_STUBS \
|
||||||
LIBC_SYSV_CALLS \
|
LIBC_SYSV_CALLS \
|
||||||
|
|
|
@ -17,13 +17,15 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/nt/enum/filetype.h"
|
||||||
#include "libc/nt/files.h"
|
#include "libc/nt/files.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
textwindows int close$nt(int fd) {
|
textwindows int close$nt(int fd) {
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
if (g_fds.p[fd].kind == kFdFile) {
|
if (g_fds.p[fd].kind == kFdFile &&
|
||||||
|
GetFileType(g_fds.p[fd].handle) == kNtFileTypeDisk) {
|
||||||
/*
|
/*
|
||||||
* Like Linux, closing a file on Windows doesn't guarantee it's
|
* Like Linux, closing a file on Windows doesn't guarantee it's
|
||||||
* immediately synced to disk. But unlike Linux, this could cause
|
* immediately synced to disk. But unlike Linux, this could cause
|
||||||
|
@ -32,6 +34,8 @@ textwindows int close$nt(int fd) {
|
||||||
FlushFileBuffers(g_fds.p[fd].handle);
|
FlushFileBuffers(g_fds.p[fd].handle);
|
||||||
}
|
}
|
||||||
ok = CloseHandle(g_fds.p[fd].handle);
|
ok = CloseHandle(g_fds.p[fd].handle);
|
||||||
if (g_fds.p[fd].kind == kFdConsole) ok &= CloseHandle(g_fds.p[fd].extra);
|
if (g_fds.p[fd].kind == kFdConsole) {
|
||||||
|
ok &= CloseHandle(g_fds.p[fd].extra);
|
||||||
|
}
|
||||||
return ok ? 0 : __winerr();
|
return ok ? 0 : __winerr();
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,8 +53,7 @@ int close(int fd) {
|
||||||
rc = ebadf();
|
rc = ebadf();
|
||||||
}
|
}
|
||||||
if (!__vforked && fd < g_fds.n) {
|
if (!__vforked && fd < g_fds.n) {
|
||||||
g_fds.p[fd].kind = kFdEmpty;
|
__releasefd(fd);
|
||||||
g_fds.f = MIN(g_fds.f, fd);
|
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,17 +30,18 @@
|
||||||
*/
|
*/
|
||||||
textwindows int dup$nt(int oldfd, int newfd, int flags) {
|
textwindows int dup$nt(int oldfd, int newfd, int flags) {
|
||||||
int64_t proc;
|
int64_t proc;
|
||||||
if (!__isfdkind(oldfd, kFdFile)) return ebadf();
|
if (oldfd < 0) return einval();
|
||||||
|
if (oldfd >= g_fds.n ||
|
||||||
|
(g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket &&
|
||||||
|
g_fds.p[oldfd].kind != kFdConsole)) {
|
||||||
|
return ebadf();
|
||||||
|
}
|
||||||
if (newfd == -1) {
|
if (newfd == -1) {
|
||||||
if ((newfd = __getemptyfd()) == -1) {
|
if ((newfd = __reservefd()) == -1) return -1;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else if (__ensurefds(newfd) != -1) {
|
|
||||||
if (g_fds.p[newfd].kind != kFdEmpty) {
|
|
||||||
close(newfd);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
if (__ensurefds(newfd) == -1) return -1;
|
||||||
|
if (g_fds.p[newfd].kind) close(newfd);
|
||||||
|
g_fds.p[newfd].kind = kFdReserved;
|
||||||
}
|
}
|
||||||
proc = GetCurrentProcess();
|
proc = GetCurrentProcess();
|
||||||
if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc, &g_fds.p[newfd].handle,
|
if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc, &g_fds.p[newfd].handle,
|
||||||
|
@ -49,6 +50,7 @@ textwindows int dup$nt(int oldfd, int newfd, int flags) {
|
||||||
g_fds.p[newfd].flags = flags;
|
g_fds.p[newfd].flags = flags;
|
||||||
return newfd;
|
return newfd;
|
||||||
} else {
|
} else {
|
||||||
|
__releasefd(newfd);
|
||||||
return __winerr();
|
return __winerr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
@ -24,24 +25,29 @@
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
int __ensurefds(int fd) {
|
int __ensurefds(int fd) {
|
||||||
size_t n;
|
size_t n1, n2;
|
||||||
struct Fd *p;
|
struct Fd *p1, *p2;
|
||||||
if (fd < g_fds.n) return fd;
|
for (;;) {
|
||||||
if (weaken(malloc)) {
|
p1 = g_fds.p;
|
||||||
n = MAX(fd + 1, g_fds.n + (g_fds.n << 1));
|
n1 = g_fds.n;
|
||||||
if ((p = weaken(malloc)(n * sizeof(*p)))) {
|
if (fd < n1) return fd;
|
||||||
memcpy(p, g_fds.p, g_fds.n * sizeof(*p));
|
if (weaken(malloc)) {
|
||||||
memset(p + g_fds.n, 0, (n - g_fds.n) * sizeof(*p));
|
n2 = MAX(fd + 1, n1 + (n1 << 1));
|
||||||
if (g_fds.p != g_fds.__init_p && weaken(free)) {
|
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
|
||||||
weaken(free)(g_fds.p);
|
memcpy(p2, p1, n1 * sizeof(*p1));
|
||||||
|
memset(p2 + n1, 0, (n2 - n1) * sizeof(*p1));
|
||||||
|
if (p1 != g_fds.__init_p && weaken(free)) weaken(free)(p1);
|
||||||
|
if (cmpxchg(&g_fds.p, p1, p2)) {
|
||||||
|
g_fds.n = n2;
|
||||||
|
return fd;
|
||||||
|
} else if (weaken(free)) {
|
||||||
|
weaken(free)(p2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return enomem();
|
||||||
}
|
}
|
||||||
g_fds.p = p;
|
|
||||||
g_fds.n = n;
|
|
||||||
return fd;
|
|
||||||
} else {
|
} else {
|
||||||
return enomem();
|
return emfile();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return emfile();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -52,6 +52,7 @@ struct Fds {
|
||||||
kFdSerial,
|
kFdSerial,
|
||||||
kFdZip,
|
kFdZip,
|
||||||
kFdEpoll,
|
kFdEpoll,
|
||||||
|
kFdReserved,
|
||||||
} kind;
|
} kind;
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
} * p;
|
} * p;
|
||||||
|
@ -68,7 +69,8 @@ hidden extern struct NtSystemInfo g_ntsysteminfo;
|
||||||
hidden extern struct NtStartupInfo g_ntstartupinfo;
|
hidden extern struct NtStartupInfo g_ntstartupinfo;
|
||||||
hidden extern const struct NtSecurityAttributes kNtIsInheritable;
|
hidden extern const struct NtSecurityAttributes kNtIsInheritable;
|
||||||
|
|
||||||
ssize_t __getemptyfd(void) hidden;
|
int __reservefd(void) hidden;
|
||||||
|
void __releasefd(int) hidden;
|
||||||
int __ensurefds(int) hidden;
|
int __ensurefds(int) hidden;
|
||||||
void __removefd(int) hidden;
|
void __removefd(int) hidden;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include "libc/nt/console.h"
|
#include "libc/nt/console.h"
|
||||||
#include "libc/nt/enum/consolemodeflags.h"
|
#include "libc/nt/enum/consolemodeflags.h"
|
||||||
#include "libc/nt/enum/version.h"
|
#include "libc/nt/enum/version.h"
|
||||||
#include "libc/nt/struct/teb.h"
|
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/termios.h"
|
#include "libc/sysv/consts/termios.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
|
@ -32,7 +32,11 @@
|
||||||
|
|
||||||
#define kBufSize 1024
|
#define kBufSize 1024
|
||||||
#define kProcStatus "/proc/self/status"
|
#define kProcStatus "/proc/self/status"
|
||||||
_Alignas(16) static const char kGdbPid[] = "TracerPid:\t";
|
#define kPid "TracerPid:\t"
|
||||||
|
|
||||||
|
static noasan int NtBeingDebugged(void) {
|
||||||
|
return NtGetPeb()->BeingDebugged;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if gdb, strace, windbg, etc. is controlling process.
|
* Determines if gdb, strace, windbg, etc. is controlling process.
|
||||||
|
@ -42,19 +46,18 @@ int IsDebuggerPresent(bool force) {
|
||||||
int fd, res;
|
int fd, res;
|
||||||
ssize_t got;
|
ssize_t got;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
res = 0;
|
res = false;
|
||||||
if (!force) {
|
if (!force) {
|
||||||
if (getenv("HEISENDEBUG")) return false;
|
if (getenv("HEISENDEBUG")) return false;
|
||||||
if (IsGenuineCosmo()) return false;
|
if (IsGenuineCosmo()) return false;
|
||||||
}
|
}
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
res = NtGetPeb()->BeingDebugged;
|
res = NtBeingDebugged();
|
||||||
} else if (IsLinux()) {
|
} else if (IsLinux()) {
|
||||||
if ((fd = openat$sysv(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
|
if ((fd = openat$sysv(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
|
||||||
if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kGdbPid))) != -1) {
|
if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kPid))) != -1) {
|
||||||
buf[got] = '\0';
|
buf[got] = '\0';
|
||||||
res =
|
res = atoi(firstnonnull(strstr(buf, kPid), kPid) + strlen(kPid));
|
||||||
atoi(firstnonnull(strstr(buf, kGdbPid), kGdbPid) + strlen(kGdbPid));
|
|
||||||
}
|
}
|
||||||
close$sysv(fd);
|
close$sysv(fd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,8 @@
|
||||||
* @kudos Daniel Colascione for teaching how to quote
|
* @kudos Daniel Colascione for teaching how to quote
|
||||||
* @see libc/runtime/dosargv.c
|
* @see libc/runtime/dosargv.c
|
||||||
*/
|
*/
|
||||||
textwindows int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
|
textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
|
||||||
char *const argv[]) {
|
char *const argv[]) {
|
||||||
char *arg;
|
char *arg;
|
||||||
uint64_t w;
|
uint64_t w;
|
||||||
wint_t x, y;
|
wint_t x, y;
|
||||||
|
|
|
@ -29,21 +29,18 @@
|
||||||
#include "libc/str/utf16.h"
|
#include "libc/str/utf16.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
static int CompareStrings(const char *l, const char *r) {
|
static noasan int CompareStrings(const char *l, const char *r) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (l[i] == r[i] && r[i]) ++i;
|
while (l[i] == r[i] && r[i]) ++i;
|
||||||
return (l[i] & 0xff) - (r[i] & 0xff);
|
return (l[i] & 0xff) - (r[i] & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SortStrings(char **a, size_t n) {
|
static noasan void InsertString(char **a, size_t i, char *s) {
|
||||||
char *t;
|
size_t j;
|
||||||
size_t i, j;
|
for (j = i; j > 0 && CompareStrings(s, a[j - 1]) < 0; --j) {
|
||||||
for (i = 1; i < n; ++i) {
|
a[j] = a[j - 1];
|
||||||
for (t = a[i], j = i; j > 0 && CompareStrings(t, a[j - 1]) < 0; --j) {
|
|
||||||
a[j] = a[j - 1];
|
|
||||||
}
|
|
||||||
a[j] = t;
|
|
||||||
}
|
}
|
||||||
|
a[j] = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,8 +54,9 @@ static void SortStrings(char **a, size_t n) {
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
* @error E2BIG if total number of shorts exceeded ARG_MAX (0x8000)
|
* @error E2BIG if total number of shorts exceeded ARG_MAX (0x8000)
|
||||||
*/
|
*/
|
||||||
textwindows int mkntenvblock(char16_t envvars[ARG_MAX], char *const envp[],
|
textwindows noasan int mkntenvblock(char16_t envvars[ARG_MAX],
|
||||||
const char *extravar) {
|
char *const envp[], const char *extravar) {
|
||||||
|
char *t;
|
||||||
axdx_t rc;
|
axdx_t rc;
|
||||||
uint64_t w;
|
uint64_t w;
|
||||||
char **vars;
|
char **vars;
|
||||||
|
@ -66,9 +64,8 @@ textwindows int mkntenvblock(char16_t envvars[ARG_MAX], char *const envp[],
|
||||||
size_t i, j, k, n, m;
|
size_t i, j, k, n, m;
|
||||||
for (n = 0; envp[n];) n++;
|
for (n = 0; envp[n];) n++;
|
||||||
vars = alloca((n + 1) * sizeof(char *));
|
vars = alloca((n + 1) * sizeof(char *));
|
||||||
memcpy(vars, envp, n * sizeof(char *));
|
for (i = 0; i < n; ++i) InsertString(vars, i, envp[i]);
|
||||||
if (extravar) vars[n++] = extravar;
|
if (extravar) InsertString(vars, n++, extravar);
|
||||||
SortStrings(vars, n);
|
|
||||||
for (k = i = 0; i < n; ++i) {
|
for (k = i = 0; i < n; ++i) {
|
||||||
j = 0;
|
j = 0;
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -112,11 +112,16 @@ static textwindows ssize_t open$nt$file(int dirfd, const char *file,
|
||||||
|
|
||||||
textwindows ssize_t open$nt(int dirfd, const char *file, uint32_t flags,
|
textwindows ssize_t open$nt(int dirfd, const char *file, uint32_t flags,
|
||||||
int32_t mode) {
|
int32_t mode) {
|
||||||
size_t fd;
|
int fd;
|
||||||
if ((fd = __getemptyfd()) == -1) return -1;
|
ssize_t rc;
|
||||||
|
if ((fd = __reservefd()) == -1) return -1;
|
||||||
if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) {
|
if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) {
|
||||||
return open$nt$console(dirfd, &kNtMagicPaths, flags, mode, fd);
|
rc = open$nt$console(dirfd, &kNtMagicPaths, flags, mode, fd);
|
||||||
} else {
|
} else {
|
||||||
return open$nt$file(dirfd, file, flags, mode, fd);
|
rc = open$nt$file(dirfd, file, flags, mode, fd);
|
||||||
}
|
}
|
||||||
|
if (rc == -1) {
|
||||||
|
__releasefd(fd);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
* @vforksafe
|
* @vforksafe
|
||||||
*/
|
*/
|
||||||
nodiscard int open(const char *file, int flags, ...) {
|
int open(const char *file, int flags, ...) {
|
||||||
va_list va;
|
va_list va;
|
||||||
unsigned mode;
|
unsigned mode;
|
||||||
va_start(va, flags);
|
va_start(va, flags);
|
||||||
|
|
|
@ -67,8 +67,8 @@ static int openanon$impl(const char *name, unsigned flags,
|
||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
} else {
|
} else {
|
||||||
if ((fd = __getemptyfd()) != -1 &&
|
if ((fd = __reservefd()) == -1) return -1;
|
||||||
(g_fds.p[fd].handle = CreateFileA(
|
if ((g_fds.p[fd].handle = CreateFileA(
|
||||||
pathbuf, kNtGenericRead | kNtGenericWrite, kNtFileShareExclusive,
|
pathbuf, kNtGenericRead | kNtGenericWrite, kNtFileShareExclusive,
|
||||||
&kNtIsInheritable, kNtCreateAlways,
|
&kNtIsInheritable, kNtCreateAlways,
|
||||||
(kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal |
|
(kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal |
|
||||||
|
@ -78,6 +78,7 @@ static int openanon$impl(const char *name, unsigned flags,
|
||||||
g_fds.p[fd].flags = flags;
|
g_fds.p[fd].flags = flags;
|
||||||
return fd;
|
return fd;
|
||||||
} else {
|
} else {
|
||||||
|
__releasefd(fd);
|
||||||
return __winerr();
|
return __winerr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,16 +58,19 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) {
|
||||||
int reader, writer;
|
int reader, writer;
|
||||||
char16_t pipename[64];
|
char16_t pipename[64];
|
||||||
CreatePipeName(pipename);
|
CreatePipeName(pipename);
|
||||||
|
if ((reader = __reservefd()) == -1) return -1;
|
||||||
|
if ((writer = __reservefd()) == -1) {
|
||||||
|
__releasefd(reader);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if ((hin = CreateNamedPipe(pipename, kNtPipeAccessInbound,
|
if ((hin = CreateNamedPipe(pipename, kNtPipeAccessInbound,
|
||||||
kNtPipeWait | kNtPipeReadmodeByte, 1, 65536, 65536,
|
kNtPipeWait | kNtPipeReadmodeByte, 1, 65536, 65536,
|
||||||
0, &kNtIsInheritable)) != -1) {
|
0, &kNtIsInheritable)) != -1) {
|
||||||
if ((hout = CreateFile(pipename, kNtGenericWrite, kNtFileShareWrite,
|
if ((hout = CreateFile(pipename, kNtGenericWrite, kNtFileShareWrite,
|
||||||
&kNtIsInheritable, kNtOpenExisting, 0, 0)) != -1) {
|
&kNtIsInheritable, kNtOpenExisting, 0, 0)) != -1) {
|
||||||
reader = __getemptyfd();
|
|
||||||
g_fds.p[reader].kind = kFdFile;
|
g_fds.p[reader].kind = kFdFile;
|
||||||
g_fds.p[reader].flags = flags;
|
g_fds.p[reader].flags = flags;
|
||||||
g_fds.p[reader].handle = hin;
|
g_fds.p[reader].handle = hin;
|
||||||
writer = __getemptyfd();
|
|
||||||
g_fds.p[writer].kind = kFdFile;
|
g_fds.p[writer].kind = kFdFile;
|
||||||
g_fds.p[writer].flags = flags;
|
g_fds.p[writer].flags = flags;
|
||||||
g_fds.p[writer].handle = hout;
|
g_fds.p[writer].handle = hout;
|
||||||
|
@ -78,5 +81,6 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) {
|
||||||
CloseHandle(hin);
|
CloseHandle(hin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
__releasefd(reader);
|
||||||
return __winerr();
|
return __winerr();
|
||||||
}
|
}
|
||||||
|
|
29
libc/calls/releasefd.c
Normal file
29
libc/calls/releasefd.c
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
|
|
||||||
|
void __releasefd(int fd) {
|
||||||
|
int x;
|
||||||
|
g_fds.p[fd].kind = kFdEmpty;
|
||||||
|
do {
|
||||||
|
x = g_fds.f;
|
||||||
|
if (fd >= x) break;
|
||||||
|
} while (!cmpxchg(&g_fds.f, x, fd));
|
||||||
|
}
|
|
@ -24,11 +24,16 @@
|
||||||
/**
|
/**
|
||||||
* Finds open file descriptor slot.
|
* Finds open file descriptor slot.
|
||||||
*/
|
*/
|
||||||
ssize_t __getemptyfd(void) {
|
int __reservefd(void) {
|
||||||
for (; g_fds.f < g_fds.n; ++g_fds.f) {
|
int fd;
|
||||||
if (g_fds.p[g_fds.f].kind == kFdEmpty) {
|
for (;;) {
|
||||||
return g_fds.f;
|
fd = g_fds.f;
|
||||||
|
if (fd >= g_fds.n) {
|
||||||
|
if (__ensurefds(fd) == -1) return -1;
|
||||||
|
}
|
||||||
|
cmpxchg(&g_fds.f, fd, fd + 1);
|
||||||
|
if (cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
|
||||||
|
return fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return __ensurefds(g_fds.f);
|
|
||||||
}
|
}
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/calls/struct/sigaction-freebsd.internal.h"
|
#include "libc/calls/struct/sigaction-freebsd.internal.h"
|
||||||
#include "libc/calls/struct/sigaction-linux.internal.h"
|
#include "libc/calls/struct/sigaction-linux.internal.h"
|
||||||
#include "libc/calls/struct/sigaction-openbsd.internal.h"
|
#include "libc/calls/struct/sigaction-openbsd.internal.h"
|
||||||
|
@ -128,9 +129,8 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
||||||
sizeof(struct sigaction) > sizeof(struct sigaction$openbsd));
|
sizeof(struct sigaction) > sizeof(struct sigaction$openbsd));
|
||||||
int rc, rva, oldrva;
|
int rc, rva, oldrva;
|
||||||
struct sigaction *ap, copy;
|
struct sigaction *ap, copy;
|
||||||
if (!(0 < sig && sig < NSIG) || sig == SIGKILL || sig == SIGSTOP) {
|
if (!(0 < sig && sig < NSIG)) return einval();
|
||||||
return einval();
|
if (sig == SIGKILL || sig == SIGSTOP) return einval();
|
||||||
}
|
|
||||||
if (!act) {
|
if (!act) {
|
||||||
rva = (int32_t)(intptr_t)SIG_DFL;
|
rva = (int32_t)(intptr_t)SIG_DFL;
|
||||||
} else if ((intptr_t)act->sa_handler < kSigactionMinRva) {
|
} else if ((intptr_t)act->sa_handler < kSigactionMinRva) {
|
||||||
|
@ -141,6 +141,9 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
||||||
} else {
|
} else {
|
||||||
return efault();
|
return efault();
|
||||||
}
|
}
|
||||||
|
if (__vforked && rva != (intptr_t)SIG_DFL && rva != (intptr_t)SIG_IGN) {
|
||||||
|
return einval();
|
||||||
|
}
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
if (!IsMetal()) {
|
if (!IsMetal()) {
|
||||||
if (act) {
|
if (act) {
|
||||||
|
@ -149,16 +152,13 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
||||||
if (IsXnu()) {
|
if (IsXnu()) {
|
||||||
ap->sa_restorer = (void *)&xnutrampoline;
|
ap->sa_restorer = (void *)&xnutrampoline;
|
||||||
ap->sa_handler = (void *)&xnutrampoline;
|
ap->sa_handler = (void *)&xnutrampoline;
|
||||||
} else {
|
} else if (IsLinux()) {
|
||||||
if (IsLinux()) {
|
if (!(ap->sa_flags & SA_RESTORER)) {
|
||||||
if (!(ap->sa_flags & SA_RESTORER)) {
|
ap->sa_flags |= SA_RESTORER;
|
||||||
ap->sa_flags |= SA_RESTORER;
|
ap->sa_restorer = &__restore_rt;
|
||||||
ap->sa_restorer = &__restore_rt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rva >= kSigactionMinRva) {
|
|
||||||
ap->sa_sigaction = (sigaction_f)__sigenter;
|
|
||||||
}
|
}
|
||||||
|
} else if (rva >= kSigactionMinRva) {
|
||||||
|
ap->sa_sigaction = (sigaction_f)__sigenter;
|
||||||
}
|
}
|
||||||
sigaction$cosmo2native((union metasigaction *)ap);
|
sigaction$cosmo2native((union metasigaction *)ap);
|
||||||
} else {
|
} else {
|
||||||
|
@ -178,7 +178,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
||||||
}
|
}
|
||||||
rc = 0;
|
rc = 0;
|
||||||
}
|
}
|
||||||
if (rc != -1) {
|
if (rc != -1 && !__vforked) {
|
||||||
if (oldact) {
|
if (oldact) {
|
||||||
oldrva = __sighandrvas[sig];
|
oldrva = __sighandrvas[sig];
|
||||||
oldact->sa_sigaction = (sigaction_f)(
|
oldact->sa_sigaction = (sigaction_f)(
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "libc/macros.h"
|
#include "libc/macros.h"
|
||||||
.source __FILE__
|
.source __FILE__
|
||||||
|
|
||||||
/ System Five signal handler.
|
/ BSD signal handler.
|
||||||
/
|
/
|
||||||
/ This is needed because (1) a signal is allowed to trigger at
|
/ This is needed because (1) a signal is allowed to trigger at
|
||||||
/ just about any time, and leaf functions (e.g. memcpy) aren't
|
/ just about any time, and leaf functions (e.g. memcpy) aren't
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
* @return -1 w/ few exceptions
|
* @return -1 w/ few exceptions
|
||||||
* @note this is a code-size saving device
|
* @note this is a code-size saving device
|
||||||
*/
|
*/
|
||||||
privileged int64_t __winerr(void) {
|
privileged noasan int64_t __winerr(void) {
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
errno = GetLastError();
|
errno = GetLastError();
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -42,7 +42,6 @@ textwindows ssize_t write$nt(struct Fd *fd, const struct iovec *iov,
|
||||||
iovlen ? clampio(iov[0].iov_len) : 0, &wrote,
|
iovlen ? clampio(iov[0].iov_len) : 0, &wrote,
|
||||||
offset2overlap(opt_offset, &overlap))) {
|
offset2overlap(opt_offset, &overlap))) {
|
||||||
if (!wrote) assert(!SumIovecLen(iov, iovlen));
|
if (!wrote) assert(!SumIovecLen(iov, iovlen));
|
||||||
FlushFileBuffers(fd->handle);
|
|
||||||
return wrote;
|
return wrote;
|
||||||
} else {
|
} else {
|
||||||
return __winerr();
|
return __winerr();
|
||||||
|
|
|
@ -618,7 +618,7 @@ typedef uint64_t uintmax_t;
|
||||||
#define textexit _Section(".text.exit") noinstrument
|
#define textexit _Section(".text.exit") noinstrument
|
||||||
#define textreal _Section(".text.real")
|
#define textreal _Section(".text.real")
|
||||||
#define textwindows _Section(".text.windows")
|
#define textwindows _Section(".text.windows")
|
||||||
#define textsyscall _Section(".text.syscall")
|
#define textsyscall _Section(".text.syscall") noinline
|
||||||
#define antiquity _Section(".text.antiquity")
|
#define antiquity _Section(".text.antiquity")
|
||||||
#else
|
#else
|
||||||
#define testonly
|
#define testonly
|
||||||
|
|
|
@ -20,17 +20,19 @@
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
#include "libc/linux/exit.h"
|
|
||||||
#include "libc/linux/write.h"
|
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/macros.h"
|
#include "libc/macros.h"
|
||||||
#include "libc/mem/hook/hook.h"
|
#include "libc/mem/hook/hook.h"
|
||||||
|
#include "libc/nt/enum/version.h"
|
||||||
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/runtime/directmap.h"
|
#include "libc/runtime/directmap.h"
|
||||||
#include "libc/runtime/memtrack.h"
|
#include "libc/runtime/memtrack.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/consts/auxv.h"
|
#include "libc/sysv/consts/auxv.h"
|
||||||
#include "libc/sysv/consts/map.h"
|
#include "libc/sysv/consts/map.h"
|
||||||
|
#include "libc/sysv/consts/nr.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
#include "third_party/dlmalloc/dlmalloc.internal.h"
|
#include "third_party/dlmalloc/dlmalloc.internal.h"
|
||||||
|
|
||||||
|
@ -409,29 +411,40 @@ static const char *__asan_describe_access_poison(char *p) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static textsyscall wontreturn void __asan_exit(int rc) {
|
||||||
|
if (!IsWindows()) {
|
||||||
|
asm volatile("syscall"
|
||||||
|
: /* no outputs */
|
||||||
|
: "a"(__NR_exit_group), "D"(rc)
|
||||||
|
: "memory");
|
||||||
|
unreachable;
|
||||||
|
} else {
|
||||||
|
ExitProcess(rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static textsyscall ssize_t __asan_write(const void *data, size_t size) {
|
static textsyscall ssize_t __asan_write(const void *data, size_t size) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
if (weaken(write)) {
|
uint32_t wrote;
|
||||||
if ((rc = weaken(write)(2, data, size)) != -1) {
|
if (!IsWindows()) {
|
||||||
return rc;
|
asm volatile("syscall"
|
||||||
|
: "=a"(rc)
|
||||||
|
: "0"(__NR_write), "D"(2), "S"(data), "d"(size)
|
||||||
|
: "rcx", "r11", "memory");
|
||||||
|
return rc;
|
||||||
|
} else {
|
||||||
|
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
|
||||||
|
return wrote;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return LinuxWrite(2, data, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t __asan_write_string(const char *s) {
|
static ssize_t __asan_write_string(const char *s) {
|
||||||
return __asan_write(s, __asan_strlen(s));
|
return __asan_write(s, __asan_strlen(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
static textsyscall wontreturn void __asan_exit(int rc) {
|
|
||||||
if (weaken(_Exit)) {
|
|
||||||
weaken(_Exit)(rc);
|
|
||||||
} else {
|
|
||||||
LinuxExit(rc);
|
|
||||||
}
|
|
||||||
for (;;) asm("hlt");
|
|
||||||
}
|
|
||||||
|
|
||||||
static wontreturn void __asan_abort(void) {
|
static wontreturn void __asan_abort(void) {
|
||||||
if (weaken(__die)) weaken(__die)();
|
if (weaken(__die)) weaken(__die)();
|
||||||
if (weaken(abort)) weaken(abort)();
|
if (weaken(abort)) weaken(abort)();
|
||||||
|
@ -640,7 +653,9 @@ void __asan_stack_free(char *p, size_t size, int classid) {
|
||||||
__asan_deallocate(p, kAsanStackFree);
|
__asan_deallocate(p, kAsanStackFree);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __asan_handle_no_return_impl(uintptr_t rsp) {
|
void __asan_handle_no_return(void) {
|
||||||
|
uintptr_t rsp;
|
||||||
|
rsp = (uintptr_t)__builtin_frame_address(0);
|
||||||
__asan_unpoison(rsp, ROUNDUP(rsp, STACKSIZE) - rsp);
|
__asan_unpoison(rsp, ROUNDUP(rsp, STACKSIZE) - rsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -660,11 +675,11 @@ void __asan_unregister_globals(struct AsanGlobal g[], int n) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __asan_report_load_impl(uint8_t *addr, int size) {
|
void __asan_report_load(uint8_t *addr, int size) {
|
||||||
__asan_report_memory_fault(addr, size, "load");
|
__asan_report_memory_fault(addr, size, "load");
|
||||||
}
|
}
|
||||||
|
|
||||||
void __asan_report_store_impl(uint8_t *addr, int size) {
|
void __asan_report_store(uint8_t *addr, int size) {
|
||||||
__asan_report_memory_fault(addr, size, "store");
|
__asan_report_memory_fault(addr, size, "store");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,6 +805,10 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
|
||||||
intptr_t *auxv) {
|
intptr_t *auxv) {
|
||||||
static bool once;
|
static bool once;
|
||||||
if (!cmpxchg(&once, false, true)) return;
|
if (!cmpxchg(&once, false, true)) return;
|
||||||
|
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
|
||||||
|
__asan_write_string("error: asan binaries require windows10\n");
|
||||||
|
__asan_exit(0); /* So `make MODE=dbg test` passes w/ Windows7 */
|
||||||
|
}
|
||||||
REQUIRE(_mmi);
|
REQUIRE(_mmi);
|
||||||
REQUIRE(__mmap);
|
REQUIRE(__mmap);
|
||||||
REQUIRE(MAP_ANONYMOUS);
|
REQUIRE(MAP_ANONYMOUS);
|
||||||
|
|
|
@ -25,7 +25,9 @@ LIBC_INTRIN_A_CHECKS = \
|
||||||
|
|
||||||
LIBC_INTRIN_A_DIRECTDEPS = \
|
LIBC_INTRIN_A_DIRECTDEPS = \
|
||||||
LIBC_STUBS \
|
LIBC_STUBS \
|
||||||
LIBC_NEXGEN32E
|
LIBC_SYSV \
|
||||||
|
LIBC_NEXGEN32E \
|
||||||
|
LIBC_NT_KERNEL32
|
||||||
|
|
||||||
LIBC_INTRIN_A_DEPS := \
|
LIBC_INTRIN_A_DEPS := \
|
||||||
$(call uniq,$(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x))))
|
$(call uniq,$(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x))))
|
||||||
|
|
24
libc/intrin/ntgetversion.c
Normal file
24
libc/intrin/ntgetversion.c
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/nt/struct/teb.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
|
textwindows noasan int NtGetVersion(void) {
|
||||||
|
return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion;
|
||||||
|
}
|
|
@ -25,6 +25,18 @@
|
||||||
/ since ASAN has the same stylistic hugeness as UBSAN.
|
/ since ASAN has the same stylistic hugeness as UBSAN.
|
||||||
/ We also guard all the functions, against reentrancy.
|
/ We also guard all the functions, against reentrancy.
|
||||||
|
|
||||||
|
.rodata.cst4
|
||||||
|
__asan_option_detect_stack_use_after_return:
|
||||||
|
.long 0
|
||||||
|
.endobj __asan_option_detect_stack_use_after_return,globl
|
||||||
|
.previous
|
||||||
|
|
||||||
|
.bss
|
||||||
|
__asan_noreentry:
|
||||||
|
.byte 0
|
||||||
|
.endobj __asan_noreentry
|
||||||
|
.previous
|
||||||
|
|
||||||
__asan_report_load1:
|
__asan_report_load1:
|
||||||
push $1
|
push $1
|
||||||
jmp OnReportLoad
|
jmp OnReportLoad
|
||||||
|
@ -43,14 +55,18 @@ __asan_report_load8:
|
||||||
.endfn __asan_report_load8,globl
|
.endfn __asan_report_load8,globl
|
||||||
__asan_report_load16:
|
__asan_report_load16:
|
||||||
push $16
|
push $16
|
||||||
/ 𝑠𝑙𝑖𝑑𝑒
|
jmp OnReportLoad
|
||||||
.endfn __asan_report_load16,globl
|
.endfn __asan_report_load16,globl
|
||||||
|
__asan_report_load32:
|
||||||
|
push $32
|
||||||
|
/ 𝑠𝑙𝑖𝑑𝑒
|
||||||
|
.endfn __asan_report_load32,globl
|
||||||
OnReportLoad:
|
OnReportLoad:
|
||||||
pop %rsi
|
pop %rsi
|
||||||
/ 𝑠𝑙𝑖𝑑𝑒
|
/ 𝑠𝑙𝑖𝑑𝑒
|
||||||
.endfn OnReportLoad
|
.endfn OnReportLoad
|
||||||
__asan_report_load_n:
|
__asan_report_load_n:
|
||||||
lea __asan_report_load_impl(%rip),%r11
|
lea __asan_report_load(%rip),%r11
|
||||||
jmp __asan_report_noreentry
|
jmp __asan_report_noreentry
|
||||||
.endfn __asan_report_load_n,globl
|
.endfn __asan_report_load_n,globl
|
||||||
|
|
||||||
|
@ -83,7 +99,7 @@ ReportStore:
|
||||||
/ 𝑠𝑙𝑖𝑑𝑒
|
/ 𝑠𝑙𝑖𝑑𝑒
|
||||||
.endfn ReportStore
|
.endfn ReportStore
|
||||||
__asan_report_store_n:
|
__asan_report_store_n:
|
||||||
lea __asan_report_store_impl(%rip),%r11
|
lea __asan_report_store(%rip),%r11
|
||||||
/ 𝑠𝑙𝑖𝑑𝑒
|
/ 𝑠𝑙𝑖𝑑𝑒
|
||||||
.endfn __asan_report_store_n,globl
|
.endfn __asan_report_store_n,globl
|
||||||
|
|
||||||
|
@ -198,31 +214,6 @@ OnStackMalloc:
|
||||||
jmp __asan_stack_malloc
|
jmp __asan_stack_malloc
|
||||||
.endfn OnStackMalloc
|
.endfn OnStackMalloc
|
||||||
|
|
||||||
__asan_handle_no_return:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
lea 8(%rsp),%rdi
|
|
||||||
call __asan_handle_no_return_impl
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_handle_no_return,globl
|
|
||||||
|
|
||||||
__asan_before_dynamic_init:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_before_dynamic_init,globl
|
|
||||||
|
|
||||||
__asan_after_dynamic_init:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_after_dynamic_init,globl
|
|
||||||
|
|
||||||
__asan_version_mismatch_check_v8:
|
__asan_version_mismatch_check_v8:
|
||||||
ret
|
ret
|
||||||
.endfn __asan_version_mismatch_check_v8,globl
|
.endfn __asan_version_mismatch_check_v8,globl
|
||||||
|
@ -240,14 +231,76 @@ __asan_version_mismatch_check_v8:
|
||||||
pop %rdi
|
pop %rdi
|
||||||
.init.end 301,_init_asan
|
.init.end 301,_init_asan
|
||||||
|
|
||||||
.rodata.cst4
|
__asan_before_dynamic_init:
|
||||||
__asan_option_detect_stack_use_after_return:
|
push %rbp
|
||||||
.long 0
|
mov %rsp,%rbp
|
||||||
.endobj __asan_option_detect_stack_use_after_return,globl
|
ud2
|
||||||
.previous
|
.endfn __asan_before_dynamic_init,globl
|
||||||
|
|
||||||
.bss
|
__asan_after_dynamic_init:
|
||||||
__asan_noreentry:
|
push %rbp
|
||||||
.byte 0
|
mov %rsp,%rbp
|
||||||
.endobj __asan_noreentry
|
ud2
|
||||||
.previous
|
.endfn __asan_after_dynamic_init,globl
|
||||||
|
|
||||||
|
__asan_load1:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
ud2
|
||||||
|
.endfn __asan_load1,globl
|
||||||
|
__asan_load2:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
ud2
|
||||||
|
.endfn __asan_load2,globl
|
||||||
|
__asan_load4:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
ud2
|
||||||
|
.endfn __asan_load4,globl
|
||||||
|
__asan_load8:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
ud2
|
||||||
|
.endfn __asan_load8,globl
|
||||||
|
__asan_load16:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
ud2
|
||||||
|
.endfn __asan_load16,globl
|
||||||
|
__asan_load32:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
ud2
|
||||||
|
.endfn __asan_load32,globl
|
||||||
|
|
||||||
|
__asan_store1:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
ud2
|
||||||
|
.endfn __asan_store1,globl
|
||||||
|
__asan_store2:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
ud2
|
||||||
|
.endfn __asan_store2,globl
|
||||||
|
__asan_store4:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
ud2
|
||||||
|
.endfn __asan_store4,globl
|
||||||
|
__asan_store8:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
ud2
|
||||||
|
.endfn __asan_store8,globl
|
||||||
|
__asan_store16:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
ud2
|
||||||
|
.endfn __asan_store16,globl
|
||||||
|
__asan_store32:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
ud2
|
||||||
|
.endfn __asan_store32,globl
|
||||||
|
|
|
@ -4,14 +4,15 @@
|
||||||
#include "libc/nt/struct/peb.h"
|
#include "libc/nt/struct/peb.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
|
||||||
/* These macros address directly into NT's TEB a.k.a. TIB */
|
/*
|
||||||
#define NtGetPeb() gs((struct NtPeb **)(0x60ULL))
|
* These macros address directly into NT's TEB a.k.a. TIB
|
||||||
#define NtGetTeb() gs((void **)(0x30)) /* %gs:0 linear address */
|
* Any function that does this needs the `noasan` keyword
|
||||||
#define NtGetPid() gs((uint32_t *)(0x40)) /* GetCurrentProcessId() */
|
*/
|
||||||
#define NtGetTid() gs((uint32_t *)(0x48)) /* GetCurrentThreadId() */
|
#define NtGetPeb() gs((struct NtPeb **)(0x60ULL))
|
||||||
#define NtGetErr() gs((int *)(0x68))
|
#define NtGetTeb() gs((void **)(0x30)) /* %gs:0 linear address */
|
||||||
#define NtGetVersion() \
|
#define NtGetPid() gs((uint32_t *)(0x40)) /* GetCurrentProcessId() */
|
||||||
((NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion)
|
#define NtGetTid() gs((uint32_t *)(0x48)) /* GetCurrentThreadId() */
|
||||||
|
#define NtGetErr() gs((int *)(0x68))
|
||||||
#define _NtGetSeh() gs((void **)(0x00))
|
#define _NtGetSeh() gs((void **)(0x00))
|
||||||
#define _NtGetStackHigh() gs((void **)(0x08))
|
#define _NtGetStackHigh() gs((void **)(0x08))
|
||||||
#define _NtGetStackLow() gs((void **)(0x10))
|
#define _NtGetStackLow() gs((void **)(0x10))
|
||||||
|
|
|
@ -24,14 +24,14 @@ LIBC_RAND_A_CHECKS = \
|
||||||
$(LIBC_RAND_A_HDRS:%=o/$(MODE)/%.ok)
|
$(LIBC_RAND_A_HDRS:%=o/$(MODE)/%.ok)
|
||||||
|
|
||||||
LIBC_RAND_A_DIRECTDEPS = \
|
LIBC_RAND_A_DIRECTDEPS = \
|
||||||
LIBC_STUBS \
|
LIBC_CALLS \
|
||||||
LIBC_INTRIN \
|
|
||||||
LIBC_TINYMATH \
|
|
||||||
LIBC_NEXGEN32E \
|
LIBC_NEXGEN32E \
|
||||||
LIBC_NT_KERNEL32 \
|
LIBC_NT_KERNEL32 \
|
||||||
LIBC_STR \
|
LIBC_STR \
|
||||||
|
LIBC_STUBS \
|
||||||
|
LIBC_SYSV \
|
||||||
LIBC_SYSV_CALLS \
|
LIBC_SYSV_CALLS \
|
||||||
LIBC_SYSV
|
LIBC_TINYMATH
|
||||||
|
|
||||||
LIBC_RAND_A_DEPS := \
|
LIBC_RAND_A_DEPS := \
|
||||||
$(call uniq,$(foreach x,$(LIBC_RAND_A_DIRECTDEPS),$($(x))))
|
$(call uniq,$(foreach x,$(LIBC_RAND_A_DIRECTDEPS),$($(x))))
|
||||||
|
|
|
@ -33,7 +33,7 @@ hidden extern uint64_t g_rando64;
|
||||||
*
|
*
|
||||||
* @see rngset()
|
* @see rngset()
|
||||||
*/
|
*/
|
||||||
nodebuginfo uint64_t(rand64)(void) {
|
nodebuginfo uint64_t rand64(void) {
|
||||||
uint64_t res;
|
uint64_t res;
|
||||||
if (X86_HAVE(RDRND)) {
|
if (X86_HAVE(RDRND)) {
|
||||||
res = rdrand();
|
res = rdrand();
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/nexgen32e/rdtsc.h"
|
#include "libc/nexgen32e/rdtsc.h"
|
||||||
#include "libc/nt/dll.h"
|
#include "libc/nt/dll.h"
|
||||||
#include "libc/nt/events.h"
|
#include "libc/nt/events.h"
|
||||||
#include "libc/nt/struct/point.h"
|
#include "libc/nt/struct/point.h"
|
||||||
#include "libc/nt/struct/teb.h"
|
|
||||||
#include "libc/rand/rand.h"
|
#include "libc/rand/rand.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
textwindows int64_t winrandish(void) {
|
textwindows int64_t winrandish(void) {
|
||||||
int64_t res;
|
int64_t res;
|
||||||
struct NtPoint point;
|
struct NtPoint point;
|
||||||
res = ((int64_t)NtGetPid() << 17) ^ NtGetTid() ^ rdtsc();
|
res = ((int64_t)getpid() << 17) ^ gettid() ^ rdtsc();
|
||||||
/*
|
/*
|
||||||
* This function is intended for older CPUs built before 2012, so
|
* This function is intended for older CPUs built before 2012, so
|
||||||
* let's avoid having our CUI apps yoink USER32.DLL until we're
|
* let's avoid having our CUI apps yoink USER32.DLL until we're
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "libc/runtime/memtrack.h"
|
#include "libc/runtime/memtrack.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
|
noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < mm->i; ++i) {
|
for (i = 0; i < mm->i; ++i) {
|
||||||
if (mm->p[i].y < mm->p[i].x) return false;
|
if (mm->p[i].y < mm->p[i].x) return false;
|
||||||
|
|
|
@ -17,38 +17,83 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/macros.h"
|
#include "libc/macros.h"
|
||||||
#include "libc/mem/alloca.h"
|
#include "libc/mem/alloca.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
#include "libc/sysv/consts/fileno.h"
|
|
||||||
|
static noasan size_t __assert_strlen(const char *s) {
|
||||||
|
size_t i = 0;
|
||||||
|
while (s[i]) ++i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static noasan char *__assert_stpcpy(char *d, const char *s) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0;; ++i) {
|
||||||
|
if (!(d[i] = s[i])) {
|
||||||
|
return d + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static textsyscall noasan wontreturn void __assert_exit(int rc) {
|
||||||
|
if (!IsWindows()) {
|
||||||
|
asm volatile("syscall"
|
||||||
|
: /* no outputs */
|
||||||
|
: "a"(__NR_exit_group), "D"(rc)
|
||||||
|
: "memory");
|
||||||
|
unreachable;
|
||||||
|
} else {
|
||||||
|
ExitProcess(rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static textsyscall noasan ssize_t __assert_write(const void *data,
|
||||||
|
size_t size) {
|
||||||
|
ssize_t rc;
|
||||||
|
uint32_t wrote;
|
||||||
|
if (!IsWindows()) {
|
||||||
|
asm volatile("syscall"
|
||||||
|
: "=a"(rc)
|
||||||
|
: "0"(__NR_write), "D"(2), "S"(data), "d"(size)
|
||||||
|
: "rcx", "r11", "memory");
|
||||||
|
return rc;
|
||||||
|
} else {
|
||||||
|
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
|
||||||
|
return wrote;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles failure of assert() macro.
|
* Handles failure of assert() macro.
|
||||||
*/
|
*/
|
||||||
relegated void __assert_fail(const char *expr, const char *file, int line) {
|
relegated wontreturn noasan void __assert_fail(const char *expr,
|
||||||
|
const char *file, int line) {
|
||||||
static bool once;
|
static bool once;
|
||||||
char *msg, *p, linebuf[16];
|
char *msg, *p, linebuf[16];
|
||||||
unsigned i, exprlen, filelen;
|
unsigned i, exprlen, filelen;
|
||||||
if (!once) {
|
if (cmpxchg(&once, false, true)) {
|
||||||
once = true;
|
exprlen = expr ? __assert_strlen(expr) : 0;
|
||||||
exprlen = expr ? strlen(expr) : 0;
|
filelen = file ? __assert_strlen(file) : 0;
|
||||||
filelen = file ? strlen(file) : 0;
|
|
||||||
p = msg = alloca(MIN(512, exprlen + filelen + 64));
|
p = msg = alloca(MIN(512, exprlen + filelen + 64));
|
||||||
p = mempcpy(p, file, filelen);
|
p = __assert_stpcpy(p, file);
|
||||||
p = stpcpy(p, ":");
|
p = __assert_stpcpy(p, ":");
|
||||||
if (line < 1) line = 1;
|
if (line < 1) line = 1;
|
||||||
for (i = 0; line; line /= 10) linebuf[i++] = '0' + line % 10;
|
for (i = 0; line; line /= 10) linebuf[i++] = '0' + line % 10;
|
||||||
while (i) *p++ = linebuf[--i];
|
while (i) *p++ = linebuf[--i];
|
||||||
p = stpcpy(p, ":");
|
p = __assert_stpcpy(p, ":");
|
||||||
p = mempcpy(p, expr, exprlen);
|
p = __assert_stpcpy(p, expr);
|
||||||
p = stpcpy(p, "\r\n");
|
p = __assert_stpcpy(p, "\r\n");
|
||||||
write(STDERR_FILENO, msg, p - msg);
|
__assert_write(msg, p - msg);
|
||||||
if (weaken(__die)) weaken(__die)();
|
if (weaken(__die)) weaken(__die)();
|
||||||
}
|
}
|
||||||
abort();
|
__assert_exit(23);
|
||||||
unreachable;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ static struct CxaAtexitBlocks {
|
||||||
* @return 0 on success or nonzero w/ errno
|
* @return 0 on success or nonzero w/ errno
|
||||||
* @note folks have forked libc in past just to unbloat atexit()
|
* @note folks have forked libc in past just to unbloat atexit()
|
||||||
*/
|
*/
|
||||||
int __cxa_atexit(void *fp, void *arg, void *pred) {
|
noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||||
unsigned i;
|
unsigned i;
|
||||||
struct CxaAtexitBlock *b, *b2;
|
struct CxaAtexitBlock *b, *b2;
|
||||||
b = __cxa_blocks.p;
|
b = __cxa_blocks.p;
|
||||||
|
@ -83,7 +83,7 @@ int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||||
*
|
*
|
||||||
* @param pred can be null to match all
|
* @param pred can be null to match all
|
||||||
*/
|
*/
|
||||||
void __cxa_finalize(void *pred) {
|
noasan void __cxa_finalize(void *pred) {
|
||||||
unsigned i;
|
unsigned i;
|
||||||
unsigned long mask;
|
unsigned long mask;
|
||||||
struct CxaAtexitBlock *b, *b2;
|
struct CxaAtexitBlock *b, *b2;
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
* bypassed by calling this function. However the caller is responsible
|
* bypassed by calling this function. However the caller is responsible
|
||||||
* for passing the magic memory handle on Windows NT to CloseHandle().
|
* for passing the magic memory handle on Windows NT to CloseHandle().
|
||||||
*/
|
*/
|
||||||
struct DirectMap __mmap(void *addr, size_t size, unsigned prot, unsigned flags,
|
noasan struct DirectMap __mmap(void *addr, size_t size, unsigned prot,
|
||||||
int fd, int64_t off) {
|
unsigned flags, int fd, int64_t off) {
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
return (struct DirectMap){mmap$sysv(addr, size, prot, flags, fd, off),
|
return (struct DirectMap){mmap$sysv(addr, size, prot, flags, fd, off),
|
||||||
kNtInvalidHandleValue};
|
kNtInvalidHandleValue};
|
||||||
|
|
|
@ -25,8 +25,9 @@
|
||||||
#include "libc/runtime/directmap.h"
|
#include "libc/runtime/directmap.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
|
||||||
textwindows struct DirectMap __mmap$nt(void *addr, size_t size, unsigned prot,
|
textwindows noasan struct DirectMap __mmap$nt(void *addr, size_t size,
|
||||||
int64_t handle, int64_t off) {
|
unsigned prot, int64_t handle,
|
||||||
|
int64_t off) {
|
||||||
struct DirectMap dm;
|
struct DirectMap dm;
|
||||||
if ((dm.maphandle = CreateFileMappingNuma(
|
if ((dm.maphandle = CreateFileMappingNuma(
|
||||||
handle, &kNtIsInheritable,
|
handle, &kNtIsInheritable,
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/runtime/memtrack.h"
|
#include "libc/runtime/memtrack.h"
|
||||||
|
|
||||||
unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) {
|
noasan unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) {
|
||||||
unsigned l, m, r;
|
unsigned l, m, r;
|
||||||
l = 0;
|
l = 0;
|
||||||
r = mm->i;
|
r = mm->i;
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) {
|
static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) {
|
||||||
*x = 0;
|
*x = 0;
|
||||||
while (*p == ' ') p++;
|
while (*p == ' ') p++;
|
||||||
while ('0' <= *p && *p <= '9') {
|
while ('0' <= *p && *p <= '9') {
|
||||||
|
@ -56,8 +56,8 @@ static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinline textwindows void ForkIo(int64_t h, void *buf, size_t n,
|
static noinline textwindows noasan void ForkIo(int64_t h, void *buf, size_t n,
|
||||||
bool32 (*f)()) {
|
bool32 (*f)()) {
|
||||||
char *p;
|
char *p;
|
||||||
size_t i;
|
size_t i;
|
||||||
uint32_t x;
|
uint32_t x;
|
||||||
|
@ -66,15 +66,17 @@ static noinline textwindows void ForkIo(int64_t h, void *buf, size_t n,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinline textwindows void WriteAll(int64_t h, void *buf, size_t n) {
|
static noinline textwindows noasan void WriteAll(int64_t h, void *buf,
|
||||||
|
size_t n) {
|
||||||
ForkIo(h, buf, n, WriteFile);
|
ForkIo(h, buf, n, WriteFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinline textwindows void ReadAll(int64_t h, void *buf, size_t n) {
|
static textwindows noinline noasan void ReadAll(int64_t h, void *buf,
|
||||||
|
size_t n) {
|
||||||
ForkIo(h, buf, n, ReadFile);
|
ForkIo(h, buf, n, ReadFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
textwindows void WinMainForked(void) {
|
textwindows noasan void WinMainForked(void) {
|
||||||
void *addr;
|
void *addr;
|
||||||
jmp_buf jb;
|
jmp_buf jb;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
|
@ -117,13 +119,13 @@ textwindows void WinMainForked(void) {
|
||||||
|
|
||||||
textwindows int fork$nt(void) {
|
textwindows int fork$nt(void) {
|
||||||
jmp_buf jb;
|
jmp_buf jb;
|
||||||
int i, rc, pid;
|
|
||||||
char exe[PATH_MAX];
|
char exe[PATH_MAX];
|
||||||
int64_t reader, writer;
|
int64_t reader, writer;
|
||||||
|
int i, rc, pid, releaseme;
|
||||||
char *p, forkvar[6 + 21 + 1 + 21 + 1];
|
char *p, forkvar[6 + 21 + 1 + 21 + 1];
|
||||||
struct NtStartupInfo startinfo;
|
struct NtStartupInfo startinfo;
|
||||||
struct NtProcessInformation procinfo;
|
struct NtProcessInformation procinfo;
|
||||||
if ((pid = __getemptyfd()) == -1) return -1;
|
if ((pid = releaseme = __reservefd()) == -1) return -1;
|
||||||
if (!setjmp(jb)) {
|
if (!setjmp(jb)) {
|
||||||
if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) {
|
if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) {
|
||||||
p = stpcpy(forkvar, "_FORK=");
|
p = stpcpy(forkvar, "_FORK=");
|
||||||
|
@ -148,6 +150,7 @@ textwindows int fork$nt(void) {
|
||||||
g_fds.p[pid].kind = kFdProcess;
|
g_fds.p[pid].kind = kFdProcess;
|
||||||
g_fds.p[pid].handle = procinfo.hProcess;
|
g_fds.p[pid].handle = procinfo.hProcess;
|
||||||
g_fds.p[pid].flags = O_CLOEXEC;
|
g_fds.p[pid].flags = O_CLOEXEC;
|
||||||
|
releaseme = -1;
|
||||||
}
|
}
|
||||||
WriteAll(writer, jb, sizeof(jb));
|
WriteAll(writer, jb, sizeof(jb));
|
||||||
WriteAll(writer, &_mmi.i, sizeof(_mmi.i));
|
WriteAll(writer, &_mmi.i, sizeof(_mmi.i));
|
||||||
|
@ -170,5 +173,8 @@ textwindows int fork$nt(void) {
|
||||||
} else {
|
} else {
|
||||||
rc = 0;
|
rc = 0;
|
||||||
}
|
}
|
||||||
|
if (releaseme != -1) {
|
||||||
|
__releasefd(releaseme);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ struct DosArgv {
|
||||||
wint_t wc;
|
wint_t wc;
|
||||||
};
|
};
|
||||||
|
|
||||||
static textwindows wint_t DecodeDosArgv(const char16_t **s) {
|
static textwindows noasan wint_t DecodeDosArgv(const char16_t **s) {
|
||||||
wint_t x, y;
|
wint_t x, y;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!(x = *(*s)++)) break;
|
if (!(x = *(*s)++)) break;
|
||||||
|
@ -50,7 +50,7 @@ static textwindows wint_t DecodeDosArgv(const char16_t **s) {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static textwindows void AppendDosArgv(struct DosArgv *st, wint_t wc) {
|
static textwindows noasan void AppendDosArgv(struct DosArgv *st, wint_t wc) {
|
||||||
uint64_t w;
|
uint64_t w;
|
||||||
w = tpenc(wc);
|
w = tpenc(wc);
|
||||||
do {
|
do {
|
||||||
|
@ -78,8 +78,8 @@ static textwindows void AppendDosArgv(struct DosArgv *st, wint_t wc) {
|
||||||
* @see libc/runtime/ntspawn.c
|
* @see libc/runtime/ntspawn.c
|
||||||
* @note kudos to Simon Tatham for figuring out quoting behavior
|
* @note kudos to Simon Tatham for figuring out quoting behavior
|
||||||
*/
|
*/
|
||||||
textwindows int GetDosArgv(const char16_t *cmdline, char *buf, size_t size,
|
textwindows noasan int GetDosArgv(const char16_t *cmdline, char *buf,
|
||||||
char **argv, size_t max) {
|
size_t size, char **argv, size_t max) {
|
||||||
bool inquote;
|
bool inquote;
|
||||||
size_t i, argc, slashes, quotes;
|
size_t i, argc, slashes, quotes;
|
||||||
struct DosArgv st;
|
struct DosArgv st;
|
||||||
|
|
|
@ -18,6 +18,30 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/str/tpenc.h"
|
||||||
|
#include "libc/str/utf16.h"
|
||||||
|
|
||||||
|
static textwindows noasan axdx_t Recode16to8(char *dst, size_t dstsize,
|
||||||
|
const char16_t *src) {
|
||||||
|
axdx_t r;
|
||||||
|
uint64_t w;
|
||||||
|
wint_t x, y;
|
||||||
|
for (r.ax = 0, r.dx = 0;;) {
|
||||||
|
if (!(x = src[r.dx++])) break;
|
||||||
|
if (IsUtf16Cont(x)) continue;
|
||||||
|
if (!IsUcs2(x)) {
|
||||||
|
if (!(y = src[r.dx++])) break;
|
||||||
|
x = MergeUtf16(x, y);
|
||||||
|
}
|
||||||
|
for (w = tpenc(x); w && r.ax + 1 < dstsize; w >>= 8) {
|
||||||
|
dst[r.ax++] = w & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (r.ax < dstsize) {
|
||||||
|
dst[r.ax] = 0;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transcodes NT environment variable block from UTF-16 to UTF-8.
|
* Transcodes NT environment variable block from UTF-16 to UTF-8.
|
||||||
|
@ -29,8 +53,8 @@
|
||||||
* @param max is the pointer count capacity of envp
|
* @param max is the pointer count capacity of envp
|
||||||
* @return number of variables decoded, excluding NULL-terminator
|
* @return number of variables decoded, excluding NULL-terminator
|
||||||
*/
|
*/
|
||||||
textwindows int GetDosEnviron(const char16_t *env, char *buf, size_t size,
|
textwindows noasan int GetDosEnviron(const char16_t *env, char *buf,
|
||||||
char **envp, size_t max) {
|
size_t size, char **envp, size_t max) {
|
||||||
int i;
|
int i;
|
||||||
axdx_t r;
|
axdx_t r;
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -38,7 +62,7 @@ textwindows int GetDosEnviron(const char16_t *env, char *buf, size_t size,
|
||||||
--size;
|
--size;
|
||||||
while (*env) {
|
while (*env) {
|
||||||
if (i + 1 < max) envp[i++] = buf;
|
if (i + 1 < max) envp[i++] = buf;
|
||||||
r = tprecode16to8(buf, size, env);
|
r = Recode16to8(buf, size, env);
|
||||||
size -= r.ax + 1;
|
size -= r.ax + 1;
|
||||||
buf += r.ax + 1;
|
buf += r.ax + 1;
|
||||||
env += r.dx;
|
env += r.dx;
|
||||||
|
|
|
@ -24,7 +24,8 @@
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) {
|
static noasan void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i,
|
||||||
|
int n) {
|
||||||
assert(i >= 0);
|
assert(i >= 0);
|
||||||
assert(i + n <= mm->i);
|
assert(i + n <= mm->i);
|
||||||
memcpy(mm->p + i, mm->p + i + n,
|
memcpy(mm->p + i, mm->p + i + n,
|
||||||
|
@ -32,7 +33,7 @@ static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) {
|
||||||
mm->i -= n;
|
mm->i -= n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
static noasan void CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
||||||
assert(i >= 0);
|
assert(i >= 0);
|
||||||
assert(i <= mm->i);
|
assert(i <= mm->i);
|
||||||
assert(mm->i < ARRAYLEN(mm->p));
|
assert(mm->i < ARRAYLEN(mm->p));
|
||||||
|
@ -41,7 +42,7 @@ static void CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
||||||
++mm->i;
|
++mm->i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
|
static noasan int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
|
||||||
if (mm->i == ARRAYLEN(mm->p)) return enomem();
|
if (mm->i == ARRAYLEN(mm->p)) return enomem();
|
||||||
CreateMemoryInterval(mm, i);
|
CreateMemoryInterval(mm, i);
|
||||||
mm->p[i].y = x - 1;
|
mm->p[i].y = x - 1;
|
||||||
|
@ -49,8 +50,8 @@ static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
||||||
void wincb(struct MemoryIntervals *, int, int)) {
|
void wf(struct MemoryIntervals *, int, int)) {
|
||||||
unsigned l, r;
|
unsigned l, r;
|
||||||
assert(y >= x);
|
assert(y >= x);
|
||||||
assert(AreMemoryIntervalsOk(mm));
|
assert(AreMemoryIntervalsOk(mm));
|
||||||
|
@ -81,16 +82,16 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
||||||
--r;
|
--r;
|
||||||
}
|
}
|
||||||
if (l <= r) {
|
if (l <= r) {
|
||||||
if (IsWindows() && wincb) {
|
if (IsWindows() && wf) {
|
||||||
wincb(mm, l, r);
|
wf(mm, l, r);
|
||||||
}
|
}
|
||||||
RemoveMemoryIntervals(mm, l, r - l + 1);
|
RemoveMemoryIntervals(mm, l, r - l + 1);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
|
noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
|
||||||
int prot, int flags) {
|
int prot, int flags) {
|
||||||
unsigned i;
|
unsigned i;
|
||||||
assert(y >= x);
|
assert(y >= x);
|
||||||
assert(AreMemoryIntervalsOk(mm));
|
assert(AreMemoryIntervalsOk(mm));
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/macros.h"
|
#include "libc/macros.h"
|
||||||
#include "libc/nt/enum/version.h"
|
#include "libc/nt/enum/version.h"
|
||||||
#include "libc/nt/struct/teb.h"
|
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
|
@ -22,14 +22,14 @@
|
||||||
#include "libc/runtime/memtrack.h"
|
#include "libc/runtime/memtrack.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
static void *GetFrameAddr(int f) {
|
static noasan void *GetFrameAddr(int f) {
|
||||||
intptr_t a;
|
intptr_t a;
|
||||||
a = f;
|
a = f;
|
||||||
a *= FRAMESIZE;
|
a *= FRAMESIZE;
|
||||||
return (void *)a;
|
return (void *)a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReleaseMemoryNt(struct MemoryIntervals *mm, int l, int r) {
|
noasan void ReleaseMemoryNt(struct MemoryIntervals *mm, int l, int r) {
|
||||||
int i, ok;
|
int i, ok;
|
||||||
for (i = l; i <= r; ++i) {
|
for (i = l; i <= r; ++i) {
|
||||||
ok = UnmapViewOfFile(GetFrameAddr(mm->p[i].x));
|
ok = UnmapViewOfFile(GetFrameAddr(mm->p[i].x));
|
||||||
|
|
|
@ -35,7 +35,6 @@ static void __print$nt(const void *data, size_t len) {
|
||||||
savexmm(xmm + 128);
|
savexmm(xmm + 128);
|
||||||
hand = __imp_GetStdHandle(kNtStdErrorHandle);
|
hand = __imp_GetStdHandle(kNtStdErrorHandle);
|
||||||
__imp_WriteFile(hand, data, len, &wrote, NULL);
|
__imp_WriteFile(hand, data, len, &wrote, NULL);
|
||||||
__imp_FlushFileBuffers(hand);
|
|
||||||
loadxmm(xmm + 128);
|
loadxmm(xmm + 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@ void __print_string(const char *);
|
||||||
void __fast_math(void);
|
void __fast_math(void);
|
||||||
void *sbrk(intptr_t);
|
void *sbrk(intptr_t);
|
||||||
int brk(void *);
|
int brk(void *);
|
||||||
|
int NtGetVersion(void);
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § runtime » optimizations ─╬─│┼
|
│ cosmopolitan § runtime » optimizations ─╬─│┼
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "libc/bits/pushpop.h"
|
#include "libc/bits/pushpop.h"
|
||||||
#include "libc/nt/enum/version.h"
|
#include "libc/nt/enum/version.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/nt/struct/teb.h"
|
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/sysv/consts/fileno.h"
|
#include "libc/sysv/consts/fileno.h"
|
||||||
#include "libc/sysv/consts/nr.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
|
@ -29,7 +28,7 @@
|
||||||
/**
|
/**
|
||||||
* Aborts program under enemy fire to avoid being taken alive.
|
* Aborts program under enemy fire to avoid being taken alive.
|
||||||
*/
|
*/
|
||||||
textsyscall void __stack_chk_fail(void) {
|
textsyscall noasan void __stack_chk_fail(void) {
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *msg;
|
const char *msg;
|
||||||
int64_t ax, cx, si;
|
int64_t ax, cx, si;
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
#include "libc/nt/pedef.internal.h"
|
#include "libc/nt/pedef.internal.h"
|
||||||
#include "libc/nt/process.h"
|
#include "libc/nt/process.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/nt/struct/teb.h"
|
|
||||||
#include "libc/runtime/directmap.h"
|
#include "libc/runtime/directmap.h"
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/runtime/memtrack.h"
|
#include "libc/runtime/memtrack.h"
|
||||||
|
@ -56,16 +55,16 @@ struct WinArgs {
|
||||||
char envblock[ARG_MAX];
|
char envblock[ARG_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
static textwindows void SetTrueColor(void) {
|
static noasan textwindows void SetTrueColor(void) {
|
||||||
SetEnvironmentVariable(u"TERM", u"xterm-truecolor");
|
SetEnvironmentVariable(u"TERM", u"xterm-truecolor");
|
||||||
}
|
}
|
||||||
|
|
||||||
static textwindows void MakeLongDoubleLongAgain(void) {
|
static noasan textwindows void MakeLongDoubleLongAgain(void) {
|
||||||
int x87cw = 0x037f; /* let's hope win32 won't undo this */
|
int x87cw = 0x037f; /* let's hope win32 won't undo this */
|
||||||
asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw));
|
asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw));
|
||||||
}
|
}
|
||||||
|
|
||||||
static textwindows void NormalizeCmdExe(void) {
|
static noasan textwindows void NormalizeCmdExe(void) {
|
||||||
uint32_t mode;
|
uint32_t mode;
|
||||||
int64_t handle, hstdin, hstdout, hstderr;
|
int64_t handle, hstdin, hstdout, hstderr;
|
||||||
if ((int)weakaddr("v_ntsubsystem") == kNtImageSubsystemWindowsCui &&
|
if ((int)weakaddr("v_ntsubsystem") == kNtImageSubsystemWindowsCui &&
|
||||||
|
@ -96,7 +95,7 @@ static textwindows void NormalizeCmdExe(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static textwindows wontreturn void WinMainNew(void) {
|
static noasan textwindows wontreturn void WinMainNew(void) {
|
||||||
int64_t h;
|
int64_t h;
|
||||||
size_t size;
|
size_t size;
|
||||||
int i, count;
|
int i, count;
|
||||||
|
@ -165,8 +164,8 @@ static textwindows wontreturn void WinMainNew(void) {
|
||||||
*
|
*
|
||||||
* @param hInstance call GetModuleHandle(NULL) from main if you need it
|
* @param hInstance call GetModuleHandle(NULL) from main if you need it
|
||||||
*/
|
*/
|
||||||
textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
noasan textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
||||||
const char *lpCmdLine, int nCmdShow) {
|
const char *lpCmdLine, int nCmdShow) {
|
||||||
MakeLongDoubleLongAgain();
|
MakeLongDoubleLongAgain();
|
||||||
if (weaken(winsockinit)) weaken(winsockinit)();
|
if (weaken(winsockinit)) weaken(winsockinit)();
|
||||||
if (weaken(WinMainForked)) weaken(WinMainForked)();
|
if (weaken(WinMainForked)) weaken(WinMainForked)();
|
||||||
|
|
|
@ -34,12 +34,13 @@ textwindows int accept$nt(struct Fd *fd, void *addr, uint32_t *addrsize,
|
||||||
uint32_t yes;
|
uint32_t yes;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!WSAPoll(&(struct pollfd$nt){fd->handle, POLLIN}, 1, 1000)) continue;
|
if (!WSAPoll(&(struct pollfd$nt){fd->handle, POLLIN}, 1, 1000)) continue;
|
||||||
if ((client = __getemptyfd()) == -1) return -1;
|
if ((client = __reservefd()) == -1) return -1;
|
||||||
if ((h = WSAAccept(fd->handle, addr, (int32_t *)addrsize, 0, 0)) != -1) {
|
if ((h = WSAAccept(fd->handle, addr, (int32_t *)addrsize, 0, 0)) != -1) {
|
||||||
if (flags & SOCK_NONBLOCK) {
|
if (flags & SOCK_NONBLOCK) {
|
||||||
yes = 1;
|
yes = 1;
|
||||||
if (__ioctlsocket$nt(g_fds.p[client].handle, FIONBIO, &yes) == -1) {
|
if (__ioctlsocket$nt(g_fds.p[client].handle, FIONBIO, &yes) == -1) {
|
||||||
__closesocket$nt(g_fds.p[client].handle);
|
__closesocket$nt(g_fds.p[client].handle);
|
||||||
|
__releasefd(client);
|
||||||
return __winsockerr();
|
return __winsockerr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +49,7 @@ textwindows int accept$nt(struct Fd *fd, void *addr, uint32_t *addrsize,
|
||||||
g_fds.p[client].handle = h;
|
g_fds.p[client].handle = h;
|
||||||
return client;
|
return client;
|
||||||
} else {
|
} else {
|
||||||
|
__releasefd(client);
|
||||||
return __winsockerr();
|
return __winsockerr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1323,15 +1323,20 @@ static textwindows noinline int epoll_create1$nt(uint32_t flags) {
|
||||||
int64_t ephnd;
|
int64_t ephnd;
|
||||||
struct PortState *port_state;
|
struct PortState *port_state;
|
||||||
struct TsTreeNode *tree_node;
|
struct TsTreeNode *tree_node;
|
||||||
if ((fd = __getemptyfd()) == -1) return -1;
|
|
||||||
if (wepoll_init() < 0) return -1;
|
if (wepoll_init() < 0) return -1;
|
||||||
|
if ((fd = __reservefd()) == -1) return -1;
|
||||||
port_state = port_new(&ephnd);
|
port_state = port_new(&ephnd);
|
||||||
if (!port_state) return -1;
|
if (!port_state) {
|
||||||
|
__releasefd(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
tree_node = port_state_to_handle_tree_node(port_state);
|
tree_node = port_state_to_handle_tree_node(port_state);
|
||||||
if (ts_tree_add(&epoll__handle_tree, tree_node, (uintptr_t)ephnd) < 0) {
|
if (ts_tree_add(&epoll__handle_tree, tree_node, (uintptr_t)ephnd) < 0) {
|
||||||
/* This should never happen. */
|
/* This should never happen. */
|
||||||
port_delete(port_state);
|
port_delete(port_state);
|
||||||
RETURN_SET_ERROR(-1, kNtErrorAlreadyExists);
|
err_set_win_error(kNtErrorAlreadyExists);
|
||||||
|
__releasefd(fd);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
g_fds.p[fd].kind = kFdEpoll;
|
g_fds.p[fd].kind = kFdEpoll;
|
||||||
g_fds.p[fd].handle = ephnd;
|
g_fds.p[fd].handle = ephnd;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/nt/winsock.h"
|
#include "libc/nt/winsock.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
|
@ -32,15 +33,15 @@
|
||||||
*/
|
*/
|
||||||
hidden struct NtWsaData kNtWsaData;
|
hidden struct NtWsaData kNtWsaData;
|
||||||
|
|
||||||
textwindows static void winsockfini(void) {
|
static textwindows void winsockfini(void) {
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
textwindows void winsockinit(void) {
|
textwindows noasan void winsockinit(void) {
|
||||||
int rc;
|
int rc;
|
||||||
atexit(winsockfini);
|
atexit(winsockfini);
|
||||||
if ((rc = WSAStartup(VERSION, &kNtWsaData)) != 0 ||
|
if ((rc = WSAStartup(VERSION, &kNtWsaData)) != 0 ||
|
||||||
kNtWsaData.wVersion != VERSION) {
|
kNtWsaData.wVersion != VERSION) {
|
||||||
abort();
|
ExitProcess(123);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
textwindows int socket$nt(int family, int type, int protocol) {
|
textwindows int socket$nt(int family, int type, int protocol) {
|
||||||
int fd;
|
int fd;
|
||||||
uint32_t yes;
|
uint32_t yes;
|
||||||
if ((fd = __getemptyfd()) == -1) return -1;
|
if ((fd = __reservefd()) == -1) return -1;
|
||||||
if ((g_fds.p[fd].handle = WSASocket(family, type & ~(CLOEXEC | NONBLOCK),
|
if ((g_fds.p[fd].handle = WSASocket(family, type & ~(CLOEXEC | NONBLOCK),
|
||||||
protocol, NULL, 0, 0)) != -1) {
|
protocol, NULL, 0, 0)) != -1) {
|
||||||
if (type & NONBLOCK) {
|
if (type & NONBLOCK) {
|
||||||
|
|
|
@ -1,388 +0,0 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
||||||
│ Copyright 2020 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/macros.h"
|
|
||||||
.source __FILE__
|
|
||||||
|
|
||||||
/ @fileoverview Address Sanitizer Linker Poison
|
|
||||||
|
|
||||||
__asan_addr_is_in_fake_stack:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_addr_is_in_fake_stack,weak
|
|
||||||
|
|
||||||
__asan_after_dynamic_init:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_after_dynamic_init,weak
|
|
||||||
|
|
||||||
__asan_alloca_poison:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_alloca_poison,weak
|
|
||||||
|
|
||||||
__asan_allocas_unpoison:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_allocas_unpoison,weak
|
|
||||||
|
|
||||||
__asan_before_dynamic_init:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_before_dynamic_init,weak
|
|
||||||
|
|
||||||
__asan_get_current_fake_stack:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_get_current_fake_stack,weak
|
|
||||||
|
|
||||||
__asan_handle_no_return:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_handle_no_return,weak
|
|
||||||
|
|
||||||
__asan_init:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_init,weak
|
|
||||||
|
|
||||||
__asan_load1:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_load1,weak
|
|
||||||
|
|
||||||
__asan_load2:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_load2,weak
|
|
||||||
|
|
||||||
__asan_load4:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_load4,weak
|
|
||||||
|
|
||||||
__asan_load8:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_load8,weak
|
|
||||||
|
|
||||||
__asan_load16:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_load16,weak
|
|
||||||
|
|
||||||
__asan_load32:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_load32,weak
|
|
||||||
|
|
||||||
__asan_option_detect_stack_use_after_return:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_option_detect_stack_use_after_return,weak
|
|
||||||
|
|
||||||
__asan_register_globals:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_register_globals,weak
|
|
||||||
|
|
||||||
__asan_report_load1:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_report_load1,weak
|
|
||||||
|
|
||||||
__asan_report_load2:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_report_load2,weak
|
|
||||||
|
|
||||||
__asan_report_load4:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_report_load4,weak
|
|
||||||
|
|
||||||
__asan_report_load8:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_report_load8,weak
|
|
||||||
|
|
||||||
__asan_report_load16:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_report_load16,weak
|
|
||||||
|
|
||||||
__asan_report_load_n:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_report_load_n,weak
|
|
||||||
|
|
||||||
__asan_report_store1:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_report_store1,weak
|
|
||||||
|
|
||||||
__asan_report_store2:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_report_store2,weak
|
|
||||||
|
|
||||||
__asan_report_store4:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_report_store4,weak
|
|
||||||
|
|
||||||
__asan_report_store8:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_report_store8,weak
|
|
||||||
|
|
||||||
__asan_report_store16:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_report_store16,weak
|
|
||||||
|
|
||||||
__asan_report_store32:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_report_store32,weak
|
|
||||||
|
|
||||||
__asan_report_store_n:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_report_store_n,weak
|
|
||||||
|
|
||||||
__asan_stack_free:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_free,weak
|
|
||||||
|
|
||||||
__asan_stack_free_0:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_free_0,weak
|
|
||||||
|
|
||||||
__asan_stack_free_1:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_free_1,weak
|
|
||||||
|
|
||||||
__asan_stack_free_10:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_free_10,weak
|
|
||||||
|
|
||||||
__asan_stack_free_2:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_free_2,weak
|
|
||||||
|
|
||||||
__asan_stack_free_3:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_free_3,weak
|
|
||||||
|
|
||||||
__asan_stack_free_4:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_free_4,weak
|
|
||||||
|
|
||||||
__asan_stack_free_5:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_free_5,weak
|
|
||||||
|
|
||||||
__asan_stack_free_6:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_free_6,weak
|
|
||||||
|
|
||||||
__asan_stack_free_7:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_free_7,weak
|
|
||||||
|
|
||||||
__asan_stack_free_8:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_free_8,weak
|
|
||||||
|
|
||||||
__asan_stack_free_9:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_free_9,weak
|
|
||||||
|
|
||||||
__asan_stack_malloc:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_malloc,weak
|
|
||||||
|
|
||||||
__asan_stack_malloc_0:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_malloc_0,weak
|
|
||||||
|
|
||||||
__asan_stack_malloc_1:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_malloc_1,weak
|
|
||||||
|
|
||||||
__asan_stack_malloc_2:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_malloc_2,weak
|
|
||||||
|
|
||||||
__asan_stack_malloc_3:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_malloc_3,weak
|
|
||||||
|
|
||||||
__asan_stack_malloc_4:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_malloc_4,weak
|
|
||||||
|
|
||||||
__asan_stack_malloc_5:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_malloc_5,weak
|
|
||||||
|
|
||||||
__asan_stack_malloc_6:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_malloc_6,weak
|
|
||||||
|
|
||||||
__asan_stack_malloc_7:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_malloc_7,weak
|
|
||||||
|
|
||||||
__asan_stack_malloc_8:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_malloc_8,weak
|
|
||||||
|
|
||||||
__asan_stack_malloc_9:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_malloc_9,weak
|
|
||||||
|
|
||||||
__asan_stack_malloc_10:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_stack_malloc_10,weak
|
|
||||||
|
|
||||||
__asan_store1:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_store1,weak
|
|
||||||
|
|
||||||
__asan_store2:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_store2,weak
|
|
||||||
|
|
||||||
__asan_store4:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_store4,weak
|
|
||||||
|
|
||||||
__asan_store8:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_store8,weak
|
|
||||||
|
|
||||||
__asan_store16:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_store16,weak
|
|
||||||
|
|
||||||
__asan_store32:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_store32,weak
|
|
||||||
|
|
||||||
__asan_unregister_globals:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_unregister_globals,weak
|
|
||||||
|
|
||||||
__asan_version_mismatch_check_v8:
|
|
||||||
push %rbp
|
|
||||||
mov %rsp,%rbp
|
|
||||||
ud2
|
|
||||||
.endfn __asan_version_mismatch_check_v8,weak
|
|
|
@ -59,16 +59,31 @@ COSMOPOLITAN_C_START_
|
||||||
#define EXPECT_LE(C, X) _TEST2("EXPECT_LE", C, <=, (X), #C, " ≤ ", #X, 0)
|
#define EXPECT_LE(C, X) _TEST2("EXPECT_LE", C, <=, (X), #C, " ≤ ", #X, 0)
|
||||||
#define EXPECT_LT(C, X) _TEST2("EXPECT_LT", C, <, (X), #C, " < ", #X, 0)
|
#define EXPECT_LT(C, X) _TEST2("EXPECT_LT", C, <, (X), #C, " < ", #X, 0)
|
||||||
|
|
||||||
#define _TEST2(NAME, WANT, OP, GOT, WANTCODE, OPSTR, GOTCODE, ISFATAL) \
|
/**
|
||||||
do { \
|
* Enables setup and teardown of test directories.
|
||||||
autotype(WANT) Want = (WANT); \
|
*
|
||||||
autotype(GOT) Got = (GOT); \
|
* If the linker says this symbol exists then, regardless of its value,
|
||||||
if (!(Want OP Got)) { \
|
* a unique test directory will be created at the start of each test,
|
||||||
testlib_showerror(FILIFU NAME, OPSTR, WANTCODE OPSTR GOTCODE, \
|
* the test will be run with that directory as its working directory,
|
||||||
testlib_formatint(Want), testlib_formatint(Got)); \
|
* and if the test succeeds it'll be removed along with any contents.
|
||||||
testlib_onfail2(ISFATAL); \
|
*/
|
||||||
} \
|
extern char testlib_enable_tmp_setup_teardown;
|
||||||
} while (0)
|
|
||||||
|
/**
|
||||||
|
* User-defined test setup function.
|
||||||
|
*
|
||||||
|
* The test runner will call this function before each TEST() if it's
|
||||||
|
* defined by the linkage.
|
||||||
|
*/
|
||||||
|
void SetUp(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User-defined test cleanup function.
|
||||||
|
*
|
||||||
|
* The test runner will call this function after each TEST() if it's
|
||||||
|
* defined by the linkage.
|
||||||
|
*/
|
||||||
|
void TearDown(void);
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § testing library » assert or die ─╬─│┼
|
│ cosmopolitan § testing library » assert or die ─╬─│┼
|
||||||
|
@ -87,39 +102,12 @@ COSMOPOLITAN_C_START_
|
||||||
__TEST_EQ(expect, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \
|
__TEST_EQ(expect, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \
|
||||||
__VA_ARGS__)
|
__VA_ARGS__)
|
||||||
|
|
||||||
#define __TEST_EQ(KIND, FILE, LINE, FUNC, WANTCODE, GOTCODE, WANT, GOT, ...) \
|
|
||||||
({ \
|
|
||||||
autotype(GOT) Got = _I(GOT); \
|
|
||||||
typeof(Got) Want = _I(WANT); \
|
|
||||||
testlib_ontest(); \
|
|
||||||
if (Want != Got) { \
|
|
||||||
TESTLIB_ONFAIL(FILE, FUNC); \
|
|
||||||
TESTLIB_SHOWERROR(testlib_showerror_##KIND##_eq, LINE, WANTCODE, \
|
|
||||||
GOTCODE, testlib_formatint(_I(Want)), \
|
|
||||||
testlib_formatint(_I(Got)), "" __VA_ARGS__); \
|
|
||||||
} \
|
|
||||||
(void)0; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define ASSERT_NE(WANT, GOT, ...) \
|
#define ASSERT_NE(WANT, GOT, ...) \
|
||||||
__TEST_NE(assert, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \
|
__TEST_NE(assert, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \
|
||||||
__VA_ARGS__)
|
__VA_ARGS__)
|
||||||
#define EXPECT_NE(WANT, GOT, ...) \
|
#define EXPECT_NE(WANT, GOT, ...) \
|
||||||
__TEST_NE(expect, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \
|
__TEST_NE(expect, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \
|
||||||
__VA_ARGS__)
|
__VA_ARGS__)
|
||||||
#define __TEST_NE(KIND, FILE, LINE, FUNC, WANTCODE, GOTCODE, WANT, GOT, ...) \
|
|
||||||
({ \
|
|
||||||
autotype(GOT) Got = (GOT); \
|
|
||||||
typeof(Got) Want = (WANT); \
|
|
||||||
testlib_ontest(); \
|
|
||||||
if (Want == Got) { \
|
|
||||||
TESTLIB_ONFAIL(FILE, FUNC); \
|
|
||||||
TESTLIB_SHOWERROR(testlib_showerror_##KIND##_ne, LINE, WANTCODE, \
|
|
||||||
GOTCODE, testlib_formatint(_I(Want)), \
|
|
||||||
testlib_formatint(_I(Got)), "" __VA_ARGS__); \
|
|
||||||
} \
|
|
||||||
(void)0; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define ASSERT_BETWEEN(BEG, END, GOT) \
|
#define ASSERT_BETWEEN(BEG, END, GOT) \
|
||||||
assertBetween(FILIFU _I(BEG), _I(END), _I(GOT), \
|
assertBetween(FILIFU _I(BEG), _I(END), _I(GOT), \
|
||||||
|
@ -245,6 +233,53 @@ COSMOPOLITAN_C_START_
|
||||||
const char *file; \
|
const char *file; \
|
||||||
int line
|
int line
|
||||||
|
|
||||||
|
#define TESTLIB_ONFAIL(FILE, FUNC) \
|
||||||
|
if (g_testlib_shoulddebugbreak) DebugBreak(); \
|
||||||
|
testlib_showerror_file = FILE; \
|
||||||
|
testlib_showerror_func = FUNC
|
||||||
|
|
||||||
|
#define TESTLIB_SHOWERROR(THUNK, ...) \
|
||||||
|
(((typeof(&testlib_showerror_))strongaddr(#THUNK)))(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define __TEST_EQ(KIND, FILE, LINE, FUNC, WANTCODE, GOTCODE, WANT, GOT, ...) \
|
||||||
|
({ \
|
||||||
|
autotype(GOT) Got = _I(GOT); \
|
||||||
|
typeof(Got) Want = _I(WANT); \
|
||||||
|
testlib_ontest(); \
|
||||||
|
if (Want != Got) { \
|
||||||
|
TESTLIB_ONFAIL(FILE, FUNC); \
|
||||||
|
TESTLIB_SHOWERROR(testlib_showerror_##KIND##_eq, LINE, WANTCODE, \
|
||||||
|
GOTCODE, testlib_formatint(_I(Want)), \
|
||||||
|
testlib_formatint(_I(Got)), "" __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
(void)0; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define __TEST_NE(KIND, FILE, LINE, FUNC, WANTCODE, GOTCODE, WANT, GOT, ...) \
|
||||||
|
({ \
|
||||||
|
autotype(GOT) Got = (GOT); \
|
||||||
|
typeof(Got) Want = (WANT); \
|
||||||
|
testlib_ontest(); \
|
||||||
|
if (Want == Got) { \
|
||||||
|
TESTLIB_ONFAIL(FILE, FUNC); \
|
||||||
|
TESTLIB_SHOWERROR(testlib_showerror_##KIND##_ne, LINE, WANTCODE, \
|
||||||
|
GOTCODE, testlib_formatint(_I(Want)), \
|
||||||
|
testlib_formatint(_I(Got)), "" __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
(void)0; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define _TEST2(NAME, WANT, OP, GOT, WANTCODE, OPSTR, GOTCODE, ISFATAL) \
|
||||||
|
do { \
|
||||||
|
autotype(WANT) Want = (WANT); \
|
||||||
|
autotype(GOT) Got = (GOT); \
|
||||||
|
if (!(Want OP Got)) { \
|
||||||
|
testlib_showerror(FILIFU NAME, OPSTR, WANTCODE OPSTR GOTCODE, \
|
||||||
|
testlib_formatint(Want), testlib_formatint(Got)); \
|
||||||
|
testlib_onfail2(ISFATAL); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
typedef void (*testfn_t)(void);
|
typedef void (*testfn_t)(void);
|
||||||
|
|
||||||
struct TestFixture {
|
struct TestFixture {
|
||||||
|
@ -265,14 +300,6 @@ extern const testfn_t __testcase_start[], __testcase_end[];
|
||||||
extern const struct TestFixture __fixture_start[], __fixture_end[];
|
extern const struct TestFixture __fixture_start[], __fixture_end[];
|
||||||
extern const struct TestFixture __combo_start[], __combo_end[];
|
extern const struct TestFixture __combo_start[], __combo_end[];
|
||||||
|
|
||||||
#define TESTLIB_ONFAIL(FILE, FUNC) \
|
|
||||||
if (g_testlib_shoulddebugbreak) DebugBreak(); \
|
|
||||||
testlib_showerror_file = FILE; \
|
|
||||||
testlib_showerror_func = FUNC
|
|
||||||
|
|
||||||
#define TESTLIB_SHOWERROR(THUNK, ...) \
|
|
||||||
(((typeof(&testlib_showerror_))strongaddr(#THUNK)))(__VA_ARGS__)
|
|
||||||
|
|
||||||
void testlib_showerror_(int line, const char *wantcode, const char *gotcode,
|
void testlib_showerror_(int line, const char *wantcode, const char *gotcode,
|
||||||
char *FREED_want, char *FREED_got, const char *fmt,
|
char *FREED_want, char *FREED_got, const char *fmt,
|
||||||
...) relegated;
|
...) relegated;
|
||||||
|
|
|
@ -17,15 +17,17 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/fmt/fmt.h"
|
||||||
|
#include "libc/log/check.h"
|
||||||
#include "libc/macros.h"
|
#include "libc/macros.h"
|
||||||
#include "libc/nt/process.h"
|
#include "libc/nt/process.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
#include "libc/x/x.h"
|
||||||
void SetUp(void);
|
|
||||||
void TearDown(void);
|
|
||||||
|
|
||||||
void testlib_finish(void) {
|
void testlib_finish(void) {
|
||||||
if (g_testlib_failed) {
|
if (g_testlib_failed) {
|
||||||
|
@ -60,8 +62,18 @@ testonly void testlib_runtestcases(testfn_t *start, testfn_t *end,
|
||||||
*
|
*
|
||||||
* @see ape/ape.lds
|
* @see ape/ape.lds
|
||||||
*/
|
*/
|
||||||
|
int x;
|
||||||
|
char cwd[PATH_MAX];
|
||||||
|
char tmp[PATH_MAX];
|
||||||
const testfn_t *fn;
|
const testfn_t *fn;
|
||||||
for (fn = start; fn != end; ++fn) {
|
for (x = 0, fn = start; fn != end; ++fn) {
|
||||||
|
if (weaken(testlib_enable_tmp_setup_teardown)) {
|
||||||
|
CHECK_NOTNULL(getcwd(cwd, sizeof(cwd)));
|
||||||
|
snprintf(tmp, sizeof(tmp), "o/tmp/%s.%d.%d",
|
||||||
|
program_invocation_short_name, getpid(), x++);
|
||||||
|
CHECK_NE(-1, makedirs(tmp, 0755), "tmp=%s", tmp);
|
||||||
|
CHECK_NE(-1, chdir(tmp), "tmp=%s", tmp);
|
||||||
|
}
|
||||||
if (weaken(SetUp)) weaken(SetUp)();
|
if (weaken(SetUp)) weaken(SetUp)();
|
||||||
errno = 0;
|
errno = 0;
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
|
@ -71,5 +83,9 @@ testonly void testlib_runtestcases(testfn_t *start, testfn_t *end,
|
||||||
(*fn)();
|
(*fn)();
|
||||||
getpid$sysv();
|
getpid$sysv();
|
||||||
if (weaken(TearDown)) weaken(TearDown)();
|
if (weaken(TearDown)) weaken(TearDown)();
|
||||||
|
if (weaken(testlib_enable_tmp_setup_teardown)) {
|
||||||
|
CHECK_NE(-1, chdir(cwd));
|
||||||
|
CHECK_NE(-1, rmrf(tmp));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,12 +34,13 @@
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
uint64_t i;
|
uint64_t i;
|
||||||
char pathbuf[PATH_MAX], testdir[PATH_MAX], *oldpath;
|
char *oldpath;
|
||||||
|
char tmp[PATH_MAX];
|
||||||
|
char pathbuf[PATH_MAX];
|
||||||
|
char testlib_enable_tmp_setup_teardown;
|
||||||
|
|
||||||
void SetUp(void) {
|
void SetUp(void) {
|
||||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
static int x;
|
||||||
makedirs(testdir, 0755);
|
|
||||||
CHECK_NE(-1, chdir(testdir));
|
|
||||||
mkdir("bin", 0755);
|
mkdir("bin", 0755);
|
||||||
mkdir("home", 0755);
|
mkdir("home", 0755);
|
||||||
oldpath = strdup(nulltoempty(getenv("PATH")));
|
oldpath = strdup(nulltoempty(getenv("PATH")));
|
||||||
|
@ -48,8 +49,6 @@ void SetUp(void) {
|
||||||
|
|
||||||
void TearDown(void) {
|
void TearDown(void) {
|
||||||
CHECK_NE(-1, setenv("PATH", oldpath, true));
|
CHECK_NE(-1, setenv("PATH", oldpath, true));
|
||||||
CHECK_NE(-1, chdir("../../.."));
|
|
||||||
CHECK_NE(-1, rmrf(testdir));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(commandv, testPathSearch) {
|
TEST(commandv, testPathSearch) {
|
||||||
|
|
|
@ -26,20 +26,7 @@
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
char basedir[PATH_MAX];
|
char testlib_enable_tmp_setup_teardown;
|
||||||
char testdir[PATH_MAX];
|
|
||||||
|
|
||||||
void SetUp(void) {
|
|
||||||
getcwd(basedir, ARRAYLEN(basedir));
|
|
||||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
|
||||||
makedirs(testdir, 0755);
|
|
||||||
CHECK_NE(-1, chdir(testdir));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown(void) {
|
|
||||||
CHECK_NE(-1, chdir(basedir));
|
|
||||||
CHECK_NE(-1, rmrf(testdir));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(fcntl_getfl, testRemembersAccessMode) {
|
TEST(fcntl_getfl, testRemembersAccessMode) {
|
||||||
int fd;
|
int fd;
|
||||||
|
|
|
@ -26,20 +26,7 @@
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
char basedir[PATH_MAX];
|
char testlib_enable_tmp_setup_teardown;
|
||||||
char testdir[PATH_MAX];
|
|
||||||
|
|
||||||
void SetUp(void) {
|
|
||||||
getcwd(basedir, ARRAYLEN(basedir));
|
|
||||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
|
||||||
makedirs(testdir, 0755);
|
|
||||||
CHECK_NE(-1, chdir(testdir));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown(void) {
|
|
||||||
CHECK_NE(-1, chdir(basedir));
|
|
||||||
CHECK_NE(-1, rmrf(testdir));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(getcwd, test) {
|
TEST(getcwd, test) {
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
|
|
|
@ -25,18 +25,7 @@
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
char testdir[PATH_MAX];
|
char testlib_enable_tmp_setup_teardown;
|
||||||
|
|
||||||
void SetUp(void) {
|
|
||||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
|
||||||
makedirs(testdir, 0755);
|
|
||||||
CHECK_NE(-1, chdir(testdir));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown(void) {
|
|
||||||
CHECK_NE(-1, chdir("../../.."));
|
|
||||||
CHECK_NE(-1, rmrf(testdir));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(lseek, wat) {
|
TEST(lseek, wat) {
|
||||||
int fd, pid;
|
int fd, pid;
|
||||||
|
|
|
@ -25,18 +25,7 @@
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
char testdir[PATH_MAX];
|
char testlib_enable_tmp_setup_teardown;
|
||||||
|
|
||||||
void SetUp(void) {
|
|
||||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
|
||||||
makedirs(testdir, 0755);
|
|
||||||
CHECK_NE(-1, chdir(testdir));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown(void) {
|
|
||||||
CHECK_NE(-1, chdir("../../.."));
|
|
||||||
CHECK_NE(-1, rmrf(testdir));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(mkdir, testNothingExists_ENOENT) {
|
TEST(mkdir, testNothingExists_ENOENT) {
|
||||||
EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755));
|
EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755));
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
|
char testlib_enable_tmp_setup_teardown;
|
||||||
|
|
||||||
TEST(mmap, testMapFile) {
|
TEST(mmap, testMapFile) {
|
||||||
int fd;
|
int fd;
|
||||||
char *p;
|
char *p;
|
||||||
|
@ -107,10 +109,6 @@ TEST(mmap, customStackMemory_isAuthorized) {
|
||||||
TEST(mmap, fileOffset) {
|
TEST(mmap, fileOffset) {
|
||||||
int fd;
|
int fd;
|
||||||
char *map;
|
char *map;
|
||||||
char testdir[PATH_MAX];
|
|
||||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
|
||||||
ASSERT_NE(-1, makedirs(testdir, 0755));
|
|
||||||
ASSERT_NE(-1, chdir(testdir));
|
|
||||||
ASSERT_NE(-1, (fd = open("foo", O_CREAT | O_RDWR, 0644)));
|
ASSERT_NE(-1, (fd = open("foo", O_CREAT | O_RDWR, 0644)));
|
||||||
EXPECT_NE(-1, ftruncate(fd, FRAMESIZE * 2));
|
EXPECT_NE(-1, ftruncate(fd, FRAMESIZE * 2));
|
||||||
EXPECT_NE(-1, pwrite(fd, "hello", 5, FRAMESIZE * 0));
|
EXPECT_NE(-1, pwrite(fd, "hello", 5, FRAMESIZE * 0));
|
||||||
|
@ -120,8 +118,6 @@ TEST(mmap, fileOffset) {
|
||||||
EXPECT_EQ(0, memcmp(map, "there", 5), "%#.*s", 5, map);
|
EXPECT_EQ(0, memcmp(map, "there", 5), "%#.*s", 5, map);
|
||||||
EXPECT_NE(-1, munmap(map, FRAMESIZE));
|
EXPECT_NE(-1, munmap(map, FRAMESIZE));
|
||||||
EXPECT_NE(-1, close(fd));
|
EXPECT_NE(-1, close(fd));
|
||||||
ASSERT_NE(-1, chdir("../../.."));
|
|
||||||
ASSERT_NE(-1, rmrf(testdir));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(isheap, nullPtr) {
|
TEST(isheap, nullPtr) {
|
||||||
|
|
|
@ -80,7 +80,7 @@ const struct IdName kNtStartfFlagNames[] = {
|
||||||
{0, 0},
|
{0, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
void PrintStartupInfo(void) {
|
noasan void PrintStartupInfo(void) {
|
||||||
printf("\n\
|
printf("\n\
|
||||||
╔──────────────────────────────────────────────────────────────────────────────╗\n\
|
╔──────────────────────────────────────────────────────────────────────────────╗\n\
|
||||||
│ new technology § startup info │\n\
|
│ new technology § startup info │\n\
|
||||||
|
@ -155,7 +155,7 @@ void PrintStdioInfo(void) {
|
||||||
ft2str(GetFileType(g_fds.p[2].handle)));
|
ft2str(GetFileType(g_fds.p[2].handle)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintTeb(void) {
|
noasan void PrintTeb(void) {
|
||||||
GetCurrentProcessId();
|
GetCurrentProcessId();
|
||||||
SetLastError(0x1234);
|
SetLastError(0x1234);
|
||||||
printf("\n\
|
printf("\n\
|
||||||
|
|
Loading…
Reference in a new issue