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:
Justine Tunney 2021-02-03 06:22:51 -08:00
parent 27c899af56
commit 4e56d89dcd
60 changed files with 588 additions and 751 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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