mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +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 =
|
||||
|
||||
-include ~/.cosmo.mk #──No.1
|
||||
-include ~/.cosmo.mk
|
||||
include build/functions.mk #─┐
|
||||
include build/definitions.mk # ├──meta
|
||||
include build/config.mk # │
|
||||
include build/rules.mk # │
|
||||
include build/definitions.mk # ├──META
|
||||
include build/config.mk # │ You can build
|
||||
include build/rules.mk # │ You can topologically order
|
||||
include build/online.mk # │
|
||||
include libc/stubs/stubs.mk #─┘
|
||||
include libc/nexgen32e/nexgen32e.mk #─┐
|
||||
include libc/intrin/intrin.mk # │
|
||||
include libc/linux/linux.mk # │
|
||||
include libc/tinymath/tinymath.mk # ├──metal
|
||||
include libc/sysv/sysv.mk # ├──SYSTEM SUPPORT
|
||||
include libc/nt/nt.mk # │ You can do math
|
||||
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 libc/bits/bits.mk # │
|
||||
include libc/str/str.mk # │
|
||||
|
@ -100,20 +102,18 @@ include third_party/xed/xed.mk # │
|
|||
include third_party/zlib/zlib.mk # │
|
||||
include libc/elf/elf.mk # │
|
||||
include ape/lib/apelib.mk # │
|
||||
include ape/ape.mk #─┘
|
||||
include libc/sysv/sysv.mk #─┐
|
||||
include libc/nt/nt.mk # ├──system
|
||||
include libc/fmt/fmt.mk # │
|
||||
include libc/rand/rand.mk #─┘
|
||||
include ape/ape.mk # │
|
||||
include libc/fmt/fmt.mk #─┘
|
||||
include libc/calls/calls.mk #─┐
|
||||
include libc/runtime/runtime.mk # ├──systems
|
||||
include libc/crt/crt.mk # │
|
||||
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
|
||||
include libc/crt/crt.mk # │ You can issue system calls
|
||||
include libc/rand/rand.mk # │
|
||||
include libc/unicode/unicode.mk # │
|
||||
include third_party/dlmalloc/dlmalloc.mk # │
|
||||
include libc/mem/mem.mk # │
|
||||
include libc/ohmyplus/ohmyplus.mk # │
|
||||
include libc/zipos/zipos.mk # │
|
||||
include third_party/gdtoa/gdtoa.mk # │
|
||||
include third_party/dlmalloc/dlmalloc.mk #─┘
|
||||
include libc/mem/mem.mk #─┐
|
||||
include libc/ohmyplus/ohmyplus.mk # ├──DYNAMIC RUNTIME
|
||||
include libc/zipos/zipos.mk # │ You can now use stdio
|
||||
include third_party/gdtoa/gdtoa.mk # │ You can finally call malloc()
|
||||
include libc/time/time.mk # │
|
||||
include libc/alg/alg.mk # │
|
||||
include libc/stdio/stdio.mk # │
|
||||
|
@ -131,8 +131,8 @@ include third_party/musl/musl.mk # │
|
|||
include third_party/getopt/getopt.mk # │
|
||||
include libc/libc.mk #─┘
|
||||
include libc/sock/sock.mk #─┐
|
||||
include dsp/tty/tty.mk # ├──online
|
||||
include libc/dns/dns.mk # │
|
||||
include dsp/tty/tty.mk # ├──ONLINE RUNTIME
|
||||
include libc/dns/dns.mk # │ You can communicate with the network
|
||||
include libc/crypto/crypto.mk # │
|
||||
include net/http/http.mk #─┘
|
||||
include third_party/lemon/lemon.mk
|
||||
|
|
|
@ -44,7 +44,6 @@ LIBC_CALLS_A_DIRECTDEPS = \
|
|||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_RAND \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV_CALLS \
|
||||
|
|
|
@ -17,13 +17,15 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int close$nt(int fd) {
|
||||
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
|
||||
* 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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -53,8 +53,7 @@ int close(int fd) {
|
|||
rc = ebadf();
|
||||
}
|
||||
if (!__vforked && fd < g_fds.n) {
|
||||
g_fds.p[fd].kind = kFdEmpty;
|
||||
g_fds.f = MIN(g_fds.f, fd);
|
||||
__releasefd(fd);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -30,17 +30,18 @@
|
|||
*/
|
||||
textwindows int dup$nt(int oldfd, int newfd, int flags) {
|
||||
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 = __getemptyfd()) == -1) {
|
||||
return -1;
|
||||
}
|
||||
} else if (__ensurefds(newfd) != -1) {
|
||||
if (g_fds.p[newfd].kind != kFdEmpty) {
|
||||
close(newfd);
|
||||
}
|
||||
if ((newfd = __reservefd()) == -1) return -1;
|
||||
} 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();
|
||||
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;
|
||||
return newfd;
|
||||
} else {
|
||||
__releasefd(newfd);
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
@ -24,24 +25,29 @@
|
|||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int __ensurefds(int fd) {
|
||||
size_t n;
|
||||
struct Fd *p;
|
||||
if (fd < g_fds.n) return fd;
|
||||
if (weaken(malloc)) {
|
||||
n = MAX(fd + 1, g_fds.n + (g_fds.n << 1));
|
||||
if ((p = weaken(malloc)(n * sizeof(*p)))) {
|
||||
memcpy(p, g_fds.p, g_fds.n * sizeof(*p));
|
||||
memset(p + g_fds.n, 0, (n - g_fds.n) * sizeof(*p));
|
||||
if (g_fds.p != g_fds.__init_p && weaken(free)) {
|
||||
weaken(free)(g_fds.p);
|
||||
size_t n1, n2;
|
||||
struct Fd *p1, *p2;
|
||||
for (;;) {
|
||||
p1 = g_fds.p;
|
||||
n1 = g_fds.n;
|
||||
if (fd < n1) return fd;
|
||||
if (weaken(malloc)) {
|
||||
n2 = MAX(fd + 1, n1 + (n1 << 1));
|
||||
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
|
||||
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 {
|
||||
return enomem();
|
||||
return emfile();
|
||||
}
|
||||
} else {
|
||||
return emfile();
|
||||
}
|
||||
}
|
|
@ -52,6 +52,7 @@ struct Fds {
|
|||
kFdSerial,
|
||||
kFdZip,
|
||||
kFdEpoll,
|
||||
kFdReserved,
|
||||
} kind;
|
||||
unsigned flags;
|
||||
} * p;
|
||||
|
@ -68,7 +69,8 @@ hidden extern struct NtSystemInfo g_ntsysteminfo;
|
|||
hidden extern struct NtStartupInfo g_ntstartupinfo;
|
||||
hidden extern const struct NtSecurityAttributes kNtIsInheritable;
|
||||
|
||||
ssize_t __getemptyfd(void) hidden;
|
||||
int __reservefd(void) hidden;
|
||||
void __releasefd(int) hidden;
|
||||
int __ensurefds(int) hidden;
|
||||
void __removefd(int) hidden;
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/enum/consolemodeflags.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
|
|
@ -32,7 +32,11 @@
|
|||
|
||||
#define kBufSize 1024
|
||||
#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.
|
||||
|
@ -42,19 +46,18 @@ int IsDebuggerPresent(bool force) {
|
|||
int fd, res;
|
||||
ssize_t got;
|
||||
char buf[1024];
|
||||
res = 0;
|
||||
res = false;
|
||||
if (!force) {
|
||||
if (getenv("HEISENDEBUG")) return false;
|
||||
if (IsGenuineCosmo()) return false;
|
||||
}
|
||||
if (IsWindows()) {
|
||||
res = NtGetPeb()->BeingDebugged;
|
||||
res = NtBeingDebugged();
|
||||
} else if (IsLinux()) {
|
||||
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';
|
||||
res =
|
||||
atoi(firstnonnull(strstr(buf, kGdbPid), kGdbPid) + strlen(kGdbPid));
|
||||
res = atoi(firstnonnull(strstr(buf, kPid), kPid) + strlen(kPid));
|
||||
}
|
||||
close$sysv(fd);
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
* @kudos Daniel Colascione for teaching how to quote
|
||||
* @see libc/runtime/dosargv.c
|
||||
*/
|
||||
textwindows int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
|
||||
char *const argv[]) {
|
||||
textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
|
||||
char *const argv[]) {
|
||||
char *arg;
|
||||
uint64_t w;
|
||||
wint_t x, y;
|
||||
|
|
|
@ -29,21 +29,18 @@
|
|||
#include "libc/str/utf16.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;
|
||||
while (l[i] == r[i] && r[i]) ++i;
|
||||
return (l[i] & 0xff) - (r[i] & 0xff);
|
||||
}
|
||||
|
||||
static void SortStrings(char **a, size_t n) {
|
||||
char *t;
|
||||
size_t i, j;
|
||||
for (i = 1; i < n; ++i) {
|
||||
for (t = a[i], j = i; j > 0 && CompareStrings(t, a[j - 1]) < 0; --j) {
|
||||
a[j] = a[j - 1];
|
||||
}
|
||||
a[j] = t;
|
||||
static noasan void InsertString(char **a, size_t i, char *s) {
|
||||
size_t j;
|
||||
for (j = i; j > 0 && CompareStrings(s, a[j - 1]) < 0; --j) {
|
||||
a[j] = a[j - 1];
|
||||
}
|
||||
a[j] = s;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,8 +54,9 @@ static void SortStrings(char **a, size_t n) {
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @error E2BIG if total number of shorts exceeded ARG_MAX (0x8000)
|
||||
*/
|
||||
textwindows int mkntenvblock(char16_t envvars[ARG_MAX], char *const envp[],
|
||||
const char *extravar) {
|
||||
textwindows noasan int mkntenvblock(char16_t envvars[ARG_MAX],
|
||||
char *const envp[], const char *extravar) {
|
||||
char *t;
|
||||
axdx_t rc;
|
||||
uint64_t w;
|
||||
char **vars;
|
||||
|
@ -66,9 +64,8 @@ textwindows int mkntenvblock(char16_t envvars[ARG_MAX], char *const envp[],
|
|||
size_t i, j, k, n, m;
|
||||
for (n = 0; envp[n];) n++;
|
||||
vars = alloca((n + 1) * sizeof(char *));
|
||||
memcpy(vars, envp, n * sizeof(char *));
|
||||
if (extravar) vars[n++] = extravar;
|
||||
SortStrings(vars, n);
|
||||
for (i = 0; i < n; ++i) InsertString(vars, i, envp[i]);
|
||||
if (extravar) InsertString(vars, n++, extravar);
|
||||
for (k = i = 0; i < n; ++i) {
|
||||
j = 0;
|
||||
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,
|
||||
int32_t mode) {
|
||||
size_t fd;
|
||||
if ((fd = __getemptyfd()) == -1) return -1;
|
||||
int fd;
|
||||
ssize_t rc;
|
||||
if ((fd = __reservefd()) == -1) return -1;
|
||||
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 {
|
||||
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
|
||||
* @vforksafe
|
||||
*/
|
||||
nodiscard int open(const char *file, int flags, ...) {
|
||||
int open(const char *file, int flags, ...) {
|
||||
va_list va;
|
||||
unsigned mode;
|
||||
va_start(va, flags);
|
||||
|
|
|
@ -67,8 +67,8 @@ static int openanon$impl(const char *name, unsigned flags,
|
|||
}
|
||||
return fd;
|
||||
} else {
|
||||
if ((fd = __getemptyfd()) != -1 &&
|
||||
(g_fds.p[fd].handle = CreateFileA(
|
||||
if ((fd = __reservefd()) == -1) return -1;
|
||||
if ((g_fds.p[fd].handle = CreateFileA(
|
||||
pathbuf, kNtGenericRead | kNtGenericWrite, kNtFileShareExclusive,
|
||||
&kNtIsInheritable, kNtCreateAlways,
|
||||
(kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal |
|
||||
|
@ -78,6 +78,7 @@ static int openanon$impl(const char *name, unsigned flags,
|
|||
g_fds.p[fd].flags = flags;
|
||||
return fd;
|
||||
} else {
|
||||
__releasefd(fd);
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,16 +58,19 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) {
|
|||
int reader, writer;
|
||||
char16_t pipename[64];
|
||||
CreatePipeName(pipename);
|
||||
if ((reader = __reservefd()) == -1) return -1;
|
||||
if ((writer = __reservefd()) == -1) {
|
||||
__releasefd(reader);
|
||||
return -1;
|
||||
}
|
||||
if ((hin = CreateNamedPipe(pipename, kNtPipeAccessInbound,
|
||||
kNtPipeWait | kNtPipeReadmodeByte, 1, 65536, 65536,
|
||||
0, &kNtIsInheritable)) != -1) {
|
||||
if ((hout = CreateFile(pipename, kNtGenericWrite, kNtFileShareWrite,
|
||||
&kNtIsInheritable, kNtOpenExisting, 0, 0)) != -1) {
|
||||
reader = __getemptyfd();
|
||||
g_fds.p[reader].kind = kFdFile;
|
||||
g_fds.p[reader].flags = flags;
|
||||
g_fds.p[reader].handle = hin;
|
||||
writer = __getemptyfd();
|
||||
g_fds.p[writer].kind = kFdFile;
|
||||
g_fds.p[writer].flags = flags;
|
||||
g_fds.p[writer].handle = hout;
|
||||
|
@ -78,5 +81,6 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) {
|
|||
CloseHandle(hin);
|
||||
}
|
||||
}
|
||||
__releasefd(reader);
|
||||
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.
|
||||
*/
|
||||
ssize_t __getemptyfd(void) {
|
||||
for (; g_fds.f < g_fds.n; ++g_fds.f) {
|
||||
if (g_fds.p[g_fds.f].kind == kFdEmpty) {
|
||||
return g_fds.f;
|
||||
int __reservefd(void) {
|
||||
int fd;
|
||||
for (;;) {
|
||||
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/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/sigaction-freebsd.internal.h"
|
||||
#include "libc/calls/struct/sigaction-linux.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));
|
||||
int rc, rva, oldrva;
|
||||
struct sigaction *ap, copy;
|
||||
if (!(0 < sig && sig < NSIG) || sig == SIGKILL || sig == SIGSTOP) {
|
||||
return einval();
|
||||
}
|
||||
if (!(0 < sig && sig < NSIG)) return einval();
|
||||
if (sig == SIGKILL || sig == SIGSTOP) return einval();
|
||||
if (!act) {
|
||||
rva = (int32_t)(intptr_t)SIG_DFL;
|
||||
} else if ((intptr_t)act->sa_handler < kSigactionMinRva) {
|
||||
|
@ -141,6 +141,9 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
} else {
|
||||
return efault();
|
||||
}
|
||||
if (__vforked && rva != (intptr_t)SIG_DFL && rva != (intptr_t)SIG_IGN) {
|
||||
return einval();
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
if (!IsMetal()) {
|
||||
if (act) {
|
||||
|
@ -149,16 +152,13 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
if (IsXnu()) {
|
||||
ap->sa_restorer = (void *)&xnutrampoline;
|
||||
ap->sa_handler = (void *)&xnutrampoline;
|
||||
} else {
|
||||
if (IsLinux()) {
|
||||
if (!(ap->sa_flags & SA_RESTORER)) {
|
||||
ap->sa_flags |= SA_RESTORER;
|
||||
ap->sa_restorer = &__restore_rt;
|
||||
}
|
||||
}
|
||||
if (rva >= kSigactionMinRva) {
|
||||
ap->sa_sigaction = (sigaction_f)__sigenter;
|
||||
} else if (IsLinux()) {
|
||||
if (!(ap->sa_flags & SA_RESTORER)) {
|
||||
ap->sa_flags |= SA_RESTORER;
|
||||
ap->sa_restorer = &__restore_rt;
|
||||
}
|
||||
} else if (rva >= kSigactionMinRva) {
|
||||
ap->sa_sigaction = (sigaction_f)__sigenter;
|
||||
}
|
||||
sigaction$cosmo2native((union metasigaction *)ap);
|
||||
} else {
|
||||
|
@ -178,7 +178,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
}
|
||||
rc = 0;
|
||||
}
|
||||
if (rc != -1) {
|
||||
if (rc != -1 && !__vforked) {
|
||||
if (oldact) {
|
||||
oldrva = __sighandrvas[sig];
|
||||
oldact->sa_sigaction = (sigaction_f)(
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
/ System Five signal handler.
|
||||
/ BSD signal handler.
|
||||
/
|
||||
/ This is needed because (1) a signal is allowed to trigger at
|
||||
/ just about any time, and leaf functions (e.g. memcpy) aren't
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
* @return -1 w/ few exceptions
|
||||
* @note this is a code-size saving device
|
||||
*/
|
||||
privileged int64_t __winerr(void) {
|
||||
privileged noasan int64_t __winerr(void) {
|
||||
if (IsWindows()) {
|
||||
errno = GetLastError();
|
||||
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,
|
||||
offset2overlap(opt_offset, &overlap))) {
|
||||
if (!wrote) assert(!SumIovecLen(iov, iovlen));
|
||||
FlushFileBuffers(fd->handle);
|
||||
return wrote;
|
||||
} else {
|
||||
return __winerr();
|
||||
|
|
|
@ -618,7 +618,7 @@ typedef uint64_t uintmax_t;
|
|||
#define textexit _Section(".text.exit") noinstrument
|
||||
#define textreal _Section(".text.real")
|
||||
#define textwindows _Section(".text.windows")
|
||||
#define textsyscall _Section(".text.syscall")
|
||||
#define textsyscall _Section(".text.syscall") noinline
|
||||
#define antiquity _Section(".text.antiquity")
|
||||
#else
|
||||
#define testonly
|
||||
|
|
|
@ -20,17 +20,19 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/linux/exit.h"
|
||||
#include "libc/linux/write.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.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/memtrack.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/prot.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) {
|
||||
ssize_t rc;
|
||||
if (weaken(write)) {
|
||||
if ((rc = weaken(write)(2, data, size)) != -1) {
|
||||
return 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;
|
||||
}
|
||||
}
|
||||
return LinuxWrite(2, data, size);
|
||||
}
|
||||
|
||||
static ssize_t __asan_write_string(const char *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) {
|
||||
if (weaken(__die)) weaken(__die)();
|
||||
if (weaken(abort)) weaken(abort)();
|
||||
|
@ -640,7 +653,9 @@ void __asan_stack_free(char *p, size_t size, int classid) {
|
|||
__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);
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
@ -790,6 +805,10 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
|
|||
intptr_t *auxv) {
|
||||
static bool once;
|
||||
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(__mmap);
|
||||
REQUIRE(MAP_ANONYMOUS);
|
||||
|
|
|
@ -25,7 +25,9 @@ LIBC_INTRIN_A_CHECKS = \
|
|||
|
||||
LIBC_INTRIN_A_DIRECTDEPS = \
|
||||
LIBC_STUBS \
|
||||
LIBC_NEXGEN32E
|
||||
LIBC_SYSV \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_KERNEL32
|
||||
|
||||
LIBC_INTRIN_A_DEPS := \
|
||||
$(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.
|
||||
/ 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:
|
||||
push $1
|
||||
jmp OnReportLoad
|
||||
|
@ -43,14 +55,18 @@ __asan_report_load8:
|
|||
.endfn __asan_report_load8,globl
|
||||
__asan_report_load16:
|
||||
push $16
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
jmp OnReportLoad
|
||||
.endfn __asan_report_load16,globl
|
||||
__asan_report_load32:
|
||||
push $32
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn __asan_report_load32,globl
|
||||
OnReportLoad:
|
||||
pop %rsi
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn OnReportLoad
|
||||
__asan_report_load_n:
|
||||
lea __asan_report_load_impl(%rip),%r11
|
||||
lea __asan_report_load(%rip),%r11
|
||||
jmp __asan_report_noreentry
|
||||
.endfn __asan_report_load_n,globl
|
||||
|
||||
|
@ -83,7 +99,7 @@ ReportStore:
|
|||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn ReportStore
|
||||
__asan_report_store_n:
|
||||
lea __asan_report_store_impl(%rip),%r11
|
||||
lea __asan_report_store(%rip),%r11
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn __asan_report_store_n,globl
|
||||
|
||||
|
@ -198,31 +214,6 @@ OnStackMalloc:
|
|||
jmp __asan_stack_malloc
|
||||
.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:
|
||||
ret
|
||||
.endfn __asan_version_mismatch_check_v8,globl
|
||||
|
@ -240,14 +231,76 @@ __asan_version_mismatch_check_v8:
|
|||
pop %rdi
|
||||
.init.end 301,_init_asan
|
||||
|
||||
.rodata.cst4
|
||||
__asan_option_detect_stack_use_after_return:
|
||||
.long 0
|
||||
.endobj __asan_option_detect_stack_use_after_return,globl
|
||||
.previous
|
||||
__asan_before_dynamic_init:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
ud2
|
||||
.endfn __asan_before_dynamic_init,globl
|
||||
|
||||
.bss
|
||||
__asan_noreentry:
|
||||
.byte 0
|
||||
.endobj __asan_noreentry
|
||||
.previous
|
||||
__asan_after_dynamic_init:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
ud2
|
||||
.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"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/* These macros address directly into NT's TEB a.k.a. TIB */
|
||||
#define NtGetPeb() gs((struct NtPeb **)(0x60ULL))
|
||||
#define NtGetTeb() gs((void **)(0x30)) /* %gs:0 linear address */
|
||||
#define NtGetPid() gs((uint32_t *)(0x40)) /* GetCurrentProcessId() */
|
||||
#define NtGetTid() gs((uint32_t *)(0x48)) /* GetCurrentThreadId() */
|
||||
#define NtGetErr() gs((int *)(0x68))
|
||||
#define NtGetVersion() \
|
||||
((NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion)
|
||||
/*
|
||||
* These macros address directly into NT's TEB a.k.a. TIB
|
||||
* Any function that does this needs the `noasan` keyword
|
||||
*/
|
||||
#define NtGetPeb() gs((struct NtPeb **)(0x60ULL))
|
||||
#define NtGetTeb() gs((void **)(0x30)) /* %gs:0 linear address */
|
||||
#define NtGetPid() gs((uint32_t *)(0x40)) /* GetCurrentProcessId() */
|
||||
#define NtGetTid() gs((uint32_t *)(0x48)) /* GetCurrentThreadId() */
|
||||
#define NtGetErr() gs((int *)(0x68))
|
||||
#define _NtGetSeh() gs((void **)(0x00))
|
||||
#define _NtGetStackHigh() gs((void **)(0x08))
|
||||
#define _NtGetStackLow() gs((void **)(0x10))
|
||||
|
|
|
@ -24,14 +24,14 @@ LIBC_RAND_A_CHECKS = \
|
|||
$(LIBC_RAND_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
LIBC_RAND_A_DIRECTDEPS = \
|
||||
LIBC_STUBS \
|
||||
LIBC_INTRIN \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_CALLS \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_SYSV
|
||||
LIBC_TINYMATH
|
||||
|
||||
LIBC_RAND_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_RAND_A_DIRECTDEPS),$($(x))))
|
||||
|
|
|
@ -33,7 +33,7 @@ hidden extern uint64_t g_rando64;
|
|||
*
|
||||
* @see rngset()
|
||||
*/
|
||||
nodebuginfo uint64_t(rand64)(void) {
|
||||
nodebuginfo uint64_t rand64(void) {
|
||||
uint64_t res;
|
||||
if (X86_HAVE(RDRND)) {
|
||||
res = rdrand();
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nt/dll.h"
|
||||
#include "libc/nt/events.h"
|
||||
#include "libc/nt/struct/point.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/rand/rand.h"
|
||||
|
||||
/**
|
||||
|
@ -29,7 +29,7 @@
|
|||
textwindows int64_t winrandish(void) {
|
||||
int64_t res;
|
||||
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
|
||||
* 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/runtime.h"
|
||||
|
||||
bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
|
||||
noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
|
||||
int i;
|
||||
for (i = 0; i < mm->i; ++i) {
|
||||
if (mm->p[i].y < mm->p[i].x) return false;
|
||||
|
|
|
@ -17,38 +17,83 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/nr.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.
|
||||
*/
|
||||
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;
|
||||
char *msg, *p, linebuf[16];
|
||||
unsigned i, exprlen, filelen;
|
||||
if (!once) {
|
||||
once = true;
|
||||
exprlen = expr ? strlen(expr) : 0;
|
||||
filelen = file ? strlen(file) : 0;
|
||||
if (cmpxchg(&once, false, true)) {
|
||||
exprlen = expr ? __assert_strlen(expr) : 0;
|
||||
filelen = file ? __assert_strlen(file) : 0;
|
||||
p = msg = alloca(MIN(512, exprlen + filelen + 64));
|
||||
p = mempcpy(p, file, filelen);
|
||||
p = stpcpy(p, ":");
|
||||
p = __assert_stpcpy(p, file);
|
||||
p = __assert_stpcpy(p, ":");
|
||||
if (line < 1) line = 1;
|
||||
for (i = 0; line; line /= 10) linebuf[i++] = '0' + line % 10;
|
||||
while (i) *p++ = linebuf[--i];
|
||||
p = stpcpy(p, ":");
|
||||
p = mempcpy(p, expr, exprlen);
|
||||
p = stpcpy(p, "\r\n");
|
||||
write(STDERR_FILENO, msg, p - msg);
|
||||
p = __assert_stpcpy(p, ":");
|
||||
p = __assert_stpcpy(p, expr);
|
||||
p = __assert_stpcpy(p, "\r\n");
|
||||
__assert_write(msg, p - msg);
|
||||
if (weaken(__die)) weaken(__die)();
|
||||
}
|
||||
abort();
|
||||
unreachable;
|
||||
__assert_exit(23);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ static struct CxaAtexitBlocks {
|
|||
* @return 0 on success or nonzero w/ errno
|
||||
* @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;
|
||||
struct CxaAtexitBlock *b, *b2;
|
||||
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
|
||||
*/
|
||||
void __cxa_finalize(void *pred) {
|
||||
noasan void __cxa_finalize(void *pred) {
|
||||
unsigned i;
|
||||
unsigned long mask;
|
||||
struct CxaAtexitBlock *b, *b2;
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
* bypassed by calling this function. However the caller is responsible
|
||||
* for passing the magic memory handle on Windows NT to CloseHandle().
|
||||
*/
|
||||
struct DirectMap __mmap(void *addr, size_t size, unsigned prot, unsigned flags,
|
||||
int fd, int64_t off) {
|
||||
noasan struct DirectMap __mmap(void *addr, size_t size, unsigned prot,
|
||||
unsigned flags, int fd, int64_t off) {
|
||||
if (!IsWindows()) {
|
||||
return (struct DirectMap){mmap$sysv(addr, size, prot, flags, fd, off),
|
||||
kNtInvalidHandleValue};
|
||||
|
|
|
@ -25,8 +25,9 @@
|
|||
#include "libc/runtime/directmap.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
textwindows struct DirectMap __mmap$nt(void *addr, size_t size, unsigned prot,
|
||||
int64_t handle, int64_t off) {
|
||||
textwindows noasan struct DirectMap __mmap$nt(void *addr, size_t size,
|
||||
unsigned prot, int64_t handle,
|
||||
int64_t off) {
|
||||
struct DirectMap dm;
|
||||
if ((dm.maphandle = CreateFileMappingNuma(
|
||||
handle, &kNtIsInheritable,
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#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;
|
||||
l = 0;
|
||||
r = mm->i;
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
#include "libc/sysv/consts/sig.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;
|
||||
while (*p == ' ') p++;
|
||||
while ('0' <= *p && *p <= '9') {
|
||||
|
@ -56,8 +56,8 @@ static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) {
|
|||
return p;
|
||||
}
|
||||
|
||||
static noinline textwindows void ForkIo(int64_t h, void *buf, size_t n,
|
||||
bool32 (*f)()) {
|
||||
static noinline textwindows noasan void ForkIo(int64_t h, void *buf, size_t n,
|
||||
bool32 (*f)()) {
|
||||
char *p;
|
||||
size_t i;
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
textwindows void WinMainForked(void) {
|
||||
textwindows noasan void WinMainForked(void) {
|
||||
void *addr;
|
||||
jmp_buf jb;
|
||||
uint64_t size;
|
||||
|
@ -117,13 +119,13 @@ textwindows void WinMainForked(void) {
|
|||
|
||||
textwindows int fork$nt(void) {
|
||||
jmp_buf jb;
|
||||
int i, rc, pid;
|
||||
char exe[PATH_MAX];
|
||||
int64_t reader, writer;
|
||||
int i, rc, pid, releaseme;
|
||||
char *p, forkvar[6 + 21 + 1 + 21 + 1];
|
||||
struct NtStartupInfo startinfo;
|
||||
struct NtProcessInformation procinfo;
|
||||
if ((pid = __getemptyfd()) == -1) return -1;
|
||||
if ((pid = releaseme = __reservefd()) == -1) return -1;
|
||||
if (!setjmp(jb)) {
|
||||
if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) {
|
||||
p = stpcpy(forkvar, "_FORK=");
|
||||
|
@ -148,6 +150,7 @@ textwindows int fork$nt(void) {
|
|||
g_fds.p[pid].kind = kFdProcess;
|
||||
g_fds.p[pid].handle = procinfo.hProcess;
|
||||
g_fds.p[pid].flags = O_CLOEXEC;
|
||||
releaseme = -1;
|
||||
}
|
||||
WriteAll(writer, jb, sizeof(jb));
|
||||
WriteAll(writer, &_mmi.i, sizeof(_mmi.i));
|
||||
|
@ -170,5 +173,8 @@ textwindows int fork$nt(void) {
|
|||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
if (releaseme != -1) {
|
||||
__releasefd(releaseme);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ struct DosArgv {
|
|||
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;
|
||||
for (;;) {
|
||||
if (!(x = *(*s)++)) break;
|
||||
|
@ -50,7 +50,7 @@ static textwindows wint_t DecodeDosArgv(const char16_t **s) {
|
|||
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;
|
||||
w = tpenc(wc);
|
||||
do {
|
||||
|
@ -78,8 +78,8 @@ static textwindows void AppendDosArgv(struct DosArgv *st, wint_t wc) {
|
|||
* @see libc/runtime/ntspawn.c
|
||||
* @note kudos to Simon Tatham for figuring out quoting behavior
|
||||
*/
|
||||
textwindows int GetDosArgv(const char16_t *cmdline, char *buf, size_t size,
|
||||
char **argv, size_t max) {
|
||||
textwindows noasan int GetDosArgv(const char16_t *cmdline, char *buf,
|
||||
size_t size, char **argv, size_t max) {
|
||||
bool inquote;
|
||||
size_t i, argc, slashes, quotes;
|
||||
struct DosArgv st;
|
||||
|
|
|
@ -18,6 +18,30 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/runtime.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.
|
||||
|
@ -29,8 +53,8 @@
|
|||
* @param max is the pointer count capacity of envp
|
||||
* @return number of variables decoded, excluding NULL-terminator
|
||||
*/
|
||||
textwindows int GetDosEnviron(const char16_t *env, char *buf, size_t size,
|
||||
char **envp, size_t max) {
|
||||
textwindows noasan int GetDosEnviron(const char16_t *env, char *buf,
|
||||
size_t size, char **envp, size_t max) {
|
||||
int i;
|
||||
axdx_t r;
|
||||
i = 0;
|
||||
|
@ -38,7 +62,7 @@ textwindows int GetDosEnviron(const char16_t *env, char *buf, size_t size,
|
|||
--size;
|
||||
while (*env) {
|
||||
if (i + 1 < max) envp[i++] = buf;
|
||||
r = tprecode16to8(buf, size, env);
|
||||
r = Recode16to8(buf, size, env);
|
||||
size -= r.ax + 1;
|
||||
buf += r.ax + 1;
|
||||
env += r.dx;
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
#include "libc/str/str.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 + n <= mm->i);
|
||||
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;
|
||||
}
|
||||
|
||||
static void CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
||||
static noasan void CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
||||
assert(i >= 0);
|
||||
assert(i <= mm->i);
|
||||
assert(mm->i < ARRAYLEN(mm->p));
|
||||
|
@ -41,7 +42,7 @@ static void CreateMemoryInterval(struct MemoryIntervals *mm, int 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();
|
||||
CreateMemoryInterval(mm, i);
|
||||
mm->p[i].y = x - 1;
|
||||
|
@ -49,8 +50,8 @@ static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
||||
void wincb(struct MemoryIntervals *, int, int)) {
|
||||
noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
||||
void wf(struct MemoryIntervals *, int, int)) {
|
||||
unsigned l, r;
|
||||
assert(y >= x);
|
||||
assert(AreMemoryIntervalsOk(mm));
|
||||
|
@ -81,16 +82,16 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
|||
--r;
|
||||
}
|
||||
if (l <= r) {
|
||||
if (IsWindows() && wincb) {
|
||||
wincb(mm, l, r);
|
||||
if (IsWindows() && wf) {
|
||||
wf(mm, l, r);
|
||||
}
|
||||
RemoveMemoryIntervals(mm, l, r - l + 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
|
||||
int prot, int flags) {
|
||||
noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
|
||||
int prot, int flags) {
|
||||
unsigned i;
|
||||
assert(y >= x);
|
||||
assert(AreMemoryIntervalsOk(mm));
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
|
|
@ -22,14 +22,14 @@
|
|||
#include "libc/runtime/memtrack.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
static void *GetFrameAddr(int f) {
|
||||
static noasan void *GetFrameAddr(int f) {
|
||||
intptr_t a;
|
||||
a = f;
|
||||
a *= FRAMESIZE;
|
||||
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;
|
||||
for (i = l; i <= r; ++i) {
|
||||
ok = UnmapViewOfFile(GetFrameAddr(mm->p[i].x));
|
||||
|
|
|
@ -35,7 +35,6 @@ static void __print$nt(const void *data, size_t len) {
|
|||
savexmm(xmm + 128);
|
||||
hand = __imp_GetStdHandle(kNtStdErrorHandle);
|
||||
__imp_WriteFile(hand, data, len, &wrote, NULL);
|
||||
__imp_FlushFileBuffers(hand);
|
||||
loadxmm(xmm + 128);
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ void __print_string(const char *);
|
|||
void __fast_math(void);
|
||||
void *sbrk(intptr_t);
|
||||
int brk(void *);
|
||||
int NtGetVersion(void);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § runtime » optimizations ─╬─│┼
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "libc/bits/pushpop.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
|
@ -29,7 +28,7 @@
|
|||
/**
|
||||
* 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;
|
||||
const char *msg;
|
||||
int64_t ax, cx, si;
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "libc/nt/pedef.internal.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/runtime/directmap.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.h"
|
||||
|
@ -56,16 +55,16 @@ struct WinArgs {
|
|||
char envblock[ARG_MAX];
|
||||
};
|
||||
|
||||
static textwindows void SetTrueColor(void) {
|
||||
static noasan textwindows void SetTrueColor(void) {
|
||||
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 */
|
||||
asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw));
|
||||
}
|
||||
|
||||
static textwindows void NormalizeCmdExe(void) {
|
||||
static noasan textwindows void NormalizeCmdExe(void) {
|
||||
uint32_t mode;
|
||||
int64_t handle, hstdin, hstdout, hstderr;
|
||||
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;
|
||||
size_t size;
|
||||
int i, count;
|
||||
|
@ -165,8 +164,8 @@ static textwindows wontreturn void WinMainNew(void) {
|
|||
*
|
||||
* @param hInstance call GetModuleHandle(NULL) from main if you need it
|
||||
*/
|
||||
textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
||||
const char *lpCmdLine, int nCmdShow) {
|
||||
noasan textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
||||
const char *lpCmdLine, int nCmdShow) {
|
||||
MakeLongDoubleLongAgain();
|
||||
if (weaken(winsockinit)) weaken(winsockinit)();
|
||||
if (weaken(WinMainForked)) weaken(WinMainForked)();
|
||||
|
|
|
@ -34,12 +34,13 @@ textwindows int accept$nt(struct Fd *fd, void *addr, uint32_t *addrsize,
|
|||
uint32_t yes;
|
||||
for (;;) {
|
||||
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 (flags & SOCK_NONBLOCK) {
|
||||
yes = 1;
|
||||
if (__ioctlsocket$nt(g_fds.p[client].handle, FIONBIO, &yes) == -1) {
|
||||
__closesocket$nt(g_fds.p[client].handle);
|
||||
__releasefd(client);
|
||||
return __winsockerr();
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +49,7 @@ textwindows int accept$nt(struct Fd *fd, void *addr, uint32_t *addrsize,
|
|||
g_fds.p[client].handle = h;
|
||||
return client;
|
||||
} else {
|
||||
__releasefd(client);
|
||||
return __winsockerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1323,15 +1323,20 @@ static textwindows noinline int epoll_create1$nt(uint32_t flags) {
|
|||
int64_t ephnd;
|
||||
struct PortState *port_state;
|
||||
struct TsTreeNode *tree_node;
|
||||
if ((fd = __getemptyfd()) == -1) return -1;
|
||||
if (wepoll_init() < 0) return -1;
|
||||
if ((fd = __reservefd()) == -1) return -1;
|
||||
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);
|
||||
if (ts_tree_add(&epoll__handle_tree, tree_node, (uintptr_t)ephnd) < 0) {
|
||||
/* This should never happen. */
|
||||
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].handle = ephnd;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/internal.h"
|
||||
|
@ -32,15 +33,15 @@
|
|||
*/
|
||||
hidden struct NtWsaData kNtWsaData;
|
||||
|
||||
textwindows static void winsockfini(void) {
|
||||
static textwindows void winsockfini(void) {
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
textwindows void winsockinit(void) {
|
||||
textwindows noasan void winsockinit(void) {
|
||||
int rc;
|
||||
atexit(winsockfini);
|
||||
if ((rc = WSAStartup(VERSION, &kNtWsaData)) != 0 ||
|
||||
kNtWsaData.wVersion != VERSION) {
|
||||
abort();
|
||||
ExitProcess(123);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
textwindows int socket$nt(int family, int type, int protocol) {
|
||||
int fd;
|
||||
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),
|
||||
protocol, NULL, 0, 0)) != -1) {
|
||||
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_LT(C, X) _TEST2("EXPECT_LT", C, <, (X), #C, " < ", #X, 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)
|
||||
/**
|
||||
* Enables setup and teardown of test directories.
|
||||
*
|
||||
* If the linker says this symbol exists then, regardless of its value,
|
||||
* a unique test directory will be created at the start of each test,
|
||||
* the test will be run with that directory as its working directory,
|
||||
* and if the test succeeds it'll be removed along with any contents.
|
||||
*/
|
||||
extern char testlib_enable_tmp_setup_teardown;
|
||||
|
||||
/**
|
||||
* 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 ─╬─│┼
|
||||
|
@ -87,39 +102,12 @@ COSMOPOLITAN_C_START_
|
|||
__TEST_EQ(expect, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \
|
||||
__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, ...) \
|
||||
__TEST_NE(assert, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \
|
||||
__VA_ARGS__)
|
||||
#define EXPECT_NE(WANT, GOT, ...) \
|
||||
__TEST_NE(expect, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \
|
||||
__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) \
|
||||
assertBetween(FILIFU _I(BEG), _I(END), _I(GOT), \
|
||||
|
@ -245,6 +233,53 @@ COSMOPOLITAN_C_START_
|
|||
const char *file; \
|
||||
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);
|
||||
|
||||
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 __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,
|
||||
char *FREED_want, char *FREED_got, const char *fmt,
|
||||
...) relegated;
|
||||
|
|
|
@ -17,15 +17,17 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
void SetUp(void);
|
||||
void TearDown(void);
|
||||
#include "libc/x/x.h"
|
||||
|
||||
void testlib_finish(void) {
|
||||
if (g_testlib_failed) {
|
||||
|
@ -60,8 +62,18 @@ testonly void testlib_runtestcases(testfn_t *start, testfn_t *end,
|
|||
*
|
||||
* @see ape/ape.lds
|
||||
*/
|
||||
int x;
|
||||
char cwd[PATH_MAX];
|
||||
char tmp[PATH_MAX];
|
||||
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)();
|
||||
errno = 0;
|
||||
SetLastError(0);
|
||||
|
@ -71,5 +83,9 @@ testonly void testlib_runtestcases(testfn_t *start, testfn_t *end,
|
|||
(*fn)();
|
||||
getpid$sysv();
|
||||
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"
|
||||
|
||||
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) {
|
||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
||||
makedirs(testdir, 0755);
|
||||
CHECK_NE(-1, chdir(testdir));
|
||||
static int x;
|
||||
mkdir("bin", 0755);
|
||||
mkdir("home", 0755);
|
||||
oldpath = strdup(nulltoempty(getenv("PATH")));
|
||||
|
@ -48,8 +49,6 @@ void SetUp(void) {
|
|||
|
||||
void TearDown(void) {
|
||||
CHECK_NE(-1, setenv("PATH", oldpath, true));
|
||||
CHECK_NE(-1, chdir("../../.."));
|
||||
CHECK_NE(-1, rmrf(testdir));
|
||||
}
|
||||
|
||||
TEST(commandv, testPathSearch) {
|
||||
|
|
|
@ -26,20 +26,7 @@
|
|||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
char basedir[PATH_MAX];
|
||||
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));
|
||||
}
|
||||
char testlib_enable_tmp_setup_teardown;
|
||||
|
||||
TEST(fcntl_getfl, testRemembersAccessMode) {
|
||||
int fd;
|
||||
|
|
|
@ -26,20 +26,7 @@
|
|||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
char basedir[PATH_MAX];
|
||||
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));
|
||||
}
|
||||
char testlib_enable_tmp_setup_teardown;
|
||||
|
||||
TEST(getcwd, test) {
|
||||
char buf[PATH_MAX];
|
||||
|
|
|
@ -25,18 +25,7 @@
|
|||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
char testdir[PATH_MAX];
|
||||
|
||||
void SetUp(void) {
|
||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
||||
makedirs(testdir, 0755);
|
||||
CHECK_NE(-1, chdir(testdir));
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
CHECK_NE(-1, chdir("../../.."));
|
||||
CHECK_NE(-1, rmrf(testdir));
|
||||
}
|
||||
char testlib_enable_tmp_setup_teardown;
|
||||
|
||||
TEST(lseek, wat) {
|
||||
int fd, pid;
|
||||
|
|
|
@ -25,18 +25,7 @@
|
|||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
char testdir[PATH_MAX];
|
||||
|
||||
void SetUp(void) {
|
||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
||||
makedirs(testdir, 0755);
|
||||
CHECK_NE(-1, chdir(testdir));
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
CHECK_NE(-1, chdir("../../.."));
|
||||
CHECK_NE(-1, rmrf(testdir));
|
||||
}
|
||||
char testlib_enable_tmp_setup_teardown;
|
||||
|
||||
TEST(mkdir, testNothingExists_ENOENT) {
|
||||
EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755));
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
char testlib_enable_tmp_setup_teardown;
|
||||
|
||||
TEST(mmap, testMapFile) {
|
||||
int fd;
|
||||
char *p;
|
||||
|
@ -107,10 +109,6 @@ TEST(mmap, customStackMemory_isAuthorized) {
|
|||
TEST(mmap, fileOffset) {
|
||||
int fd;
|
||||
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)));
|
||||
EXPECT_NE(-1, ftruncate(fd, FRAMESIZE * 2));
|
||||
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_NE(-1, munmap(map, FRAMESIZE));
|
||||
EXPECT_NE(-1, close(fd));
|
||||
ASSERT_NE(-1, chdir("../../.."));
|
||||
ASSERT_NE(-1, rmrf(testdir));
|
||||
}
|
||||
|
||||
TEST(isheap, nullPtr) {
|
||||
|
|
|
@ -80,7 +80,7 @@ const struct IdName kNtStartfFlagNames[] = {
|
|||
{0, 0},
|
||||
};
|
||||
|
||||
void PrintStartupInfo(void) {
|
||||
noasan void PrintStartupInfo(void) {
|
||||
printf("\n\
|
||||
╔──────────────────────────────────────────────────────────────────────────────╗\n\
|
||||
│ new technology § startup info │\n\
|
||||
|
@ -155,7 +155,7 @@ void PrintStdioInfo(void) {
|
|||
ft2str(GetFileType(g_fds.p[2].handle)));
|
||||
}
|
||||
|
||||
void PrintTeb(void) {
|
||||
noasan void PrintTeb(void) {
|
||||
GetCurrentProcessId();
|
||||
SetLastError(0x1234);
|
||||
printf("\n\
|
||||
|
|
Loading…
Reference in a new issue