diff --git a/libc/assert.h b/libc/assert.h index a0116cf34..502fa86ac 100644 --- a/libc/assert.h +++ b/libc/assert.h @@ -16,23 +16,60 @@ void __assert_fail(const char *, const char *, int) hidden relegated; #define static_assert _Static_assert #endif -#define _unassert(x) \ - do { \ - if (__builtin_expect(!(x), 0)) { \ - unreachable; \ - } \ - } while (0) - +#ifdef __GNUC__ #ifndef TINY +/** + * Specifies expression can't possibly be false. + * + * This macro uses the `notpossible` keyword and is intended for things + * like systems integration, where we know for a fact that something is + * never going to happen, but there's no proof. So we don't want to add + * extra bloat for filenames and line numbers, since `ShowCrashReports` + * can print a backtrace if we just embed the UD2 instruction to crash. + * That's useful for systems code, for the following reason. Invariants + * make sense with _unassert() since they usually get placed at the top + * of functions. But if you used _unassert() to test a system call does + * not fail, then check happens at the end of your function usually and + * is therefore likely to result in a failure condition where execution + * falls through into a different function, which is shocking to debug. + * + * In `MODE=tiny` these assertions are redefined as undefined behavior. + */ #define _npassert(x) \ - do { \ + ({ \ if (__builtin_expect(!(x), 0)) { \ notpossible; \ } \ - } while (0) + (void)0; \ + }) #else #define _npassert(x) _unassert(x) #endif +#endif + +#ifdef __GNUC__ +/** + * Specifies expression being false is undefined behavior. + * + * This is a good way to tell the compiler about your invariants, which + * leads to smaller faster programs. The expression is never removed by + * the preprocessor so it's recommended that it be free of side-effects + * if you intend for it to be removed. At the same time, this guarantee + * makes this assertion useful for things like system calls, since they + * won't be removed by `NDEBUG` mode. + * + * If this assertion fails, the worst possible things can happen unless + * you've built your binary in `MODE=dbg` since UBSAN is the only thing + * that's capable of debugging this macro. + */ +#define _unassert(x) \ + ({ \ + if (__builtin_expect(!(x), 0)) { \ + unreachable; \ + } \ + (void)0; \ + }) +#endif COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/calls/alarm.c b/libc/calls/alarm.c index 0a26ca372..17828d9be 100644 --- a/libc/calls/alarm.c +++ b/libc/calls/alarm.c @@ -32,12 +32,10 @@ * @asyncsignalsafe */ unsigned alarm(unsigned seconds) { - int rc; struct itimerval it; bzero(&it, sizeof(it)); it.it_value.tv_sec = seconds; - rc = setitimer(ITIMER_REAL, &it, &it); - assert(rc != -1); + _npassert(!setitimer(ITIMER_REAL, &it, &it)); if (!it.it_value.tv_sec && !it.it_value.tv_usec) { return 0; } else { diff --git a/libc/calls/getcwd.greg.c b/libc/calls/getcwd.greg.c index f9bf03eb2..8a2934d36 100644 --- a/libc/calls/getcwd.greg.c +++ b/libc/calls/getcwd.greg.c @@ -52,7 +52,7 @@ char *getcwd(char *buf, size_t size) { return 0; } } else if (_weaken(malloc)) { - assert(!__vforked); + _unassert(!__vforked); if (!size) size = PATH_MAX; if (!(p = _weaken(malloc)(size))) { STRACE("getcwd(%p, %'zu) %m", buf, size); diff --git a/libc/calls/ioctl_siocgifconf-nt.c b/libc/calls/ioctl_siocgifconf-nt.c index 09f5d7280..6762d018b 100644 --- a/libc/calls/ioctl_siocgifconf-nt.c +++ b/libc/calls/ioctl_siocgifconf-nt.c @@ -253,7 +253,7 @@ static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) { int count, i; /* __hostInfo must be empty */ - assert(__hostInfo == NULL); + _unassert(__hostInfo == NULL); for (aa = firstAdapter; aa; aa = aa->Next) { /* Skip all the interfaces with no address and the ones that are not AF_INET diff --git a/libc/calls/now.c b/libc/calls/now.c index 7d4cc5b0c..20fb37499 100644 --- a/libc/calls/now.c +++ b/libc/calls/now.c @@ -91,7 +91,7 @@ static long double nowl_art(void) { static long double nowl_vdso(void) { long double secs; struct timespec tv; - assert(__gettime); + _unassert(__gettime); __gettime(CLOCK_REALTIME_FAST, &tv); secs = tv.tv_nsec; secs *= 1 / 1e9L; diff --git a/libc/calls/open-nt.c b/libc/calls/open-nt.c index 32fc759e6..d1242f63c 100644 --- a/libc/calls/open-nt.c +++ b/libc/calls/open-nt.c @@ -53,7 +53,7 @@ static textwindows int sys_open_nt_console(int dirfd, -1) { g_fds.p[fd].extra = sys_open_nt_impl(dirfd, mp->conout, (flags & ~O_ACCMODE) | O_WRONLY, mode); - assert(g_fds.p[fd].extra != -1); + _npassert(g_fds.p[fd].extra != -1); } else { return -1; } diff --git a/libc/calls/readlinkat.c b/libc/calls/readlinkat.c index 885e196ac..a6ca90120 100644 --- a/libc/calls/readlinkat.c +++ b/libc/calls/readlinkat.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" #include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" @@ -52,7 +51,6 @@ ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) { (bytes = __zipos_notat(dirfd, path)) == -1) { STRACE("TODO: zipos support for readlinkat"); } else if (!IsWindows()) { - assert(bufsiz); bytes = sys_readlinkat(dirfd, path, buf, bufsiz); } else { bytes = sys_readlinkat_nt(dirfd, path, buf, bufsiz); diff --git a/libc/calls/realpath.c b/libc/calls/realpath.c index 510af0496..37d046dc1 100644 --- a/libc/calls/realpath.c +++ b/libc/calls/realpath.c @@ -181,7 +181,7 @@ skip_readlink: continue; } k = rc; - assert(k <= p); + _npassert(k <= p); if (k==p) goto toolong; if (!k) { diff --git a/libc/fmt/itoa64fixed16.greg.c b/libc/fmt/itoa64fixed16.greg.c index 9e10c6b5c..ace624ba7 100644 --- a/libc/fmt/itoa64fixed16.greg.c +++ b/libc/fmt/itoa64fixed16.greg.c @@ -21,7 +21,7 @@ size_t uint64toarray_fixed16(uint64_t x, char b[hasatleast 17], uint8_t k) { char *p; - assert(k <= 64 && !(k & 3)); + _unassert(k <= 64 && !(k & 3)); for (p = b; k > 0;) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15]; *p = '\0'; return p - b; diff --git a/libc/fmt/ntoa.c b/libc/fmt/ntoa.c index 87f6fe3e1..8bf081768 100644 --- a/libc/fmt/ntoa.c +++ b/libc/fmt/ntoa.c @@ -16,13 +16,13 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/mem/reverse.internal.h" #include "libc/assert.h" #include "libc/fmt/conv.h" #include "libc/fmt/divmod10.internal.h" #include "libc/fmt/fmt.internal.h" #include "libc/fmt/internal.h" #include "libc/limits.h" +#include "libc/mem/reverse.internal.h" #define BUFFER_SIZE 144 @@ -121,7 +121,7 @@ int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg, } buf[len++] = alphabet[digit]; } while (value); - assert(count <= BUFFER_SIZE); + _npassert(count <= BUFFER_SIZE); } return __fmt_ntoa_format(out, arg, buf, len, neg, log2base, prec, width, flags); diff --git a/libc/fmt/swprintf.c b/libc/fmt/swprintf.c index da14232d2..78b1cb39b 100644 --- a/libc/fmt/swprintf.c +++ b/libc/fmt/swprintf.c @@ -16,11 +16,10 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/fmt/fmt.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" int swprintf(wchar_t* ws, size_t n, const wchar_t* format, ...) { - assert(!"not implemented"); - abort(); + kprintf("error: swprintf() not supported yet by cosmo libc sorry!\n"); + _Exit(1); } diff --git a/libc/fmt/unhexbuf.c b/libc/fmt/unhexbuf.c index b83c9fc46..de02cbff8 100644 --- a/libc/fmt/unhexbuf.c +++ b/libc/fmt/unhexbuf.c @@ -23,10 +23,10 @@ void *unhexbuf(void *buf, size_t size, const char *hexdigs) { size_t i; unsigned char *p; - assert(size * 2 == strlen(hexdigs)); + _npassert(size * 2 == strlen(hexdigs)); p = buf; for (i = 0; i < size; ++i) { - assert(isxdigit(hexdigs[i / 2 + 0]) && isxdigit(hexdigs[i / 2 + 1])); + _npassert(isxdigit(hexdigs[i / 2 + 0]) && isxdigit(hexdigs[i / 2 + 1])); } for (i = 0; i < size; ++i) { p[i] = hextoint(hexdigs[i * 2 + 0]) * 16 + hextoint(hexdigs[i * 2 + 1]); diff --git a/libc/intrin/cxaatexit.c b/libc/intrin/cxaatexit.c index 0759d96af..589264d08 100644 --- a/libc/intrin/cxaatexit.c +++ b/libc/intrin/cxaatexit.c @@ -61,7 +61,7 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) { } } i = _bsr(~b->mask); - assert(i < ARRAYLEN(b->p)); + _unassert(i < ARRAYLEN(b->p)); b->mask |= 1u << i; b->p[i].fp = fp; b->p[i].arg = arg; diff --git a/libc/intrin/cxafinalize.c b/libc/intrin/cxafinalize.c index d43eae4f1..3e0b1ad26 100644 --- a/libc/intrin/cxafinalize.c +++ b/libc/intrin/cxafinalize.c @@ -60,7 +60,7 @@ StartOverLocked: if (!pred) { b2 = b->next; if (b2) { - assert(b != &__cxa_blocks.root); + _npassert(b != &__cxa_blocks.root); if (_weaken(free)) { _weaken(free)(b); } diff --git a/libc/intrin/describeflags.internal.h b/libc/intrin/describeflags.internal.h index 537c13246..93f3ca25b 100644 --- a/libc/intrin/describeflags.internal.h +++ b/libc/intrin/describeflags.internal.h @@ -56,6 +56,7 @@ const char *DescribeSockOptname(char[32], int, int); const char *DescribeSocketFamily(char[12], int); const char *DescribeSocketProtocol(char[12], int); const char *DescribeSocketType(char[64], int); +const char *DescribeStdioState(char[12], int); const char *DescribeWhence(char[12], int); #define DescribeArchPrctlCode(x) DescribeArchPrctlCode(alloca(12), x) @@ -99,6 +100,7 @@ const char *DescribeWhence(char[12], int); #define DescribeSocketFamily(x) DescribeSocketFamily(alloca(12), x) #define DescribeSocketProtocol(x) DescribeSocketProtocol(alloca(12), x) #define DescribeSocketType(x) DescribeSocketType(alloca(64), x) +#define DescribeStdioState(x) DescribeStdioState(alloca(12), x) #define DescribeWhence(x) DescribeWhence(alloca(12), x) COSMOPOLITAN_C_END_ diff --git a/libc/intrin/describeopenflags.c b/libc/intrin/describeopenflags.c index d1a3c840d..727871eae 100644 --- a/libc/intrin/describeopenflags.c +++ b/libc/intrin/describeopenflags.c @@ -34,10 +34,7 @@ const char *(DescribeOpenFlags)(char buf[128], int x) { struct DescribeFlags d[N]; // TODO(jart): unify DescribeFlags and MagnumStr data structures for (n = 0; kOpenFlags[n].x != MAGNUM_TERMINATOR; ++n) { - if (n == N) { - assert(!"too many open flags"); - break; - } + if (n == N) notpossible; } for (i = 0; i < n; ++i) { d[i].flag = MAGNUM_NUMBER(kOpenFlags, i); diff --git a/libc/intrin/describestdiostate.c b/libc/intrin/describestdiostate.c new file mode 100644 index 000000000..25013047a --- /dev/null +++ b/libc/intrin/describestdiostate.c @@ -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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/fmt/itoa.h" +#include "libc/intrin/describeflags.internal.h" +#include "libc/str/str.h" + +const char *(DescribeStdioState)(char buf[12], int x) { + if (!x) return ""; + if (x == -1) return "EOF"; + if (x > 0) return _strerrno(x); + FormatInt32(buf, x); + return buf; +} diff --git a/libc/intrin/directmap-nt.c b/libc/intrin/directmap-nt.c index 3b5f44f1e..650efd767 100644 --- a/libc/intrin/directmap-nt.c +++ b/libc/intrin/directmap-nt.c @@ -74,7 +74,7 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot, } } } else { - assert(flags & MAP_ANONYMOUS); + _unassert(flags & MAP_ANONYMOUS); fl = (struct ProtectNt){kNtPageExecuteReadwrite, kNtFileMapWrite | kNtFileMapExecute}; } diff --git a/libc/intrin/isatleastwindows10.greg.c b/libc/intrin/isatleastwindows10.greg.c index 1135ec56d..8829d14b1 100644 --- a/libc/intrin/isatleastwindows10.greg.c +++ b/libc/intrin/isatleastwindows10.greg.c @@ -26,6 +26,6 @@ * This function may only be called if IsWindows() is true. */ privileged bool(IsAtLeastWindows10)(void) { - assert(IsWindows()); + _unassert(IsWindows()); return IsAtLeastWindows10(); } diff --git a/libc/intrin/midpoint.h b/libc/intrin/midpoint.h index aa013453f..ce5e31078 100644 --- a/libc/intrin/midpoint.h +++ b/libc/intrin/midpoint.h @@ -13,8 +13,8 @@ ({ \ typeof((a) + (b)) a_ = (a); \ typeof(a_) b_ = (b); \ - assert(a_ >= 0); \ - assert(b_ >= 0); \ + _unassert(a_ >= 0); \ + _unassert(b_ >= 0); \ asm("add\t%1,%0\n\t" \ "rcr\t%0" \ : "+r"(a_) \ diff --git a/libc/intrin/pthread_once.c b/libc/intrin/pthread_once.c index 6805a0ce2..05e969f79 100644 --- a/libc/intrin/pthread_once.c +++ b/libc/intrin/pthread_once.c @@ -56,14 +56,14 @@ errno_t pthread_once(pthread_once_t *once, void init(void)) { memory_order_acquire, memory_order_relaxed)) { init(); - atomic_store(&once->_lock, FINISHED); + atomic_store_explicit(&once->_lock, FINISHED, memory_order_release); return 0; } // fallthrough case CALLING: do { pthread_yield(); - } while (atomic_load_explicit(&once->_lock, memory_order_relaxed) == + } while (atomic_load_explicit(&once->_lock, memory_order_acquire) == CALLING); return 0; case FINISHED: diff --git a/libc/intrin/strace.internal.h b/libc/intrin/strace.internal.h index a4355370d..b7136a55c 100644 --- a/libc/intrin/strace.internal.h +++ b/libc/intrin/strace.internal.h @@ -3,10 +3,11 @@ #include "libc/intrin/likely.h" #include "libc/runtime/runtime.h" -#define _KERNTRACE 0 /* not configurable w/ flag yet */ -#define _POLLTRACE 0 /* not configurable w/ flag yet */ -#define _DATATRACE 1 /* not configurable w/ flag yet */ -#define _NTTRACE 0 /* not configurable w/ flag yet */ +#define _KERNTRACE 0 /* not configurable w/ flag yet */ +#define _POLLTRACE 0 /* not configurable w/ flag yet */ +#define _DATATRACE 1 /* not configurable w/ flag yet */ +#define _STDIOTRACE 0 /* not configurable w/ flag yet */ +#define _NTTRACE 0 /* not configurable w/ flag yet */ #define STRACE_PROLOGUE "%rSYS %6P %'18T " @@ -42,6 +43,12 @@ COSMOPOLITAN_C_START_ #define KERNTRACE(FMT, ...) (void)0 #endif +#if defined(SYSDEBUG) && _STDIOTRACE +#define STDIOTRACE(FMT, ...) STRACE(FMT, ##__VA_ARGS__) +#else +#define STDIOTRACE(FMT, ...) (void)0 +#endif + #if defined(SYSDEBUG) && _NTTRACE #define NTTRACE(FMT, ...) STRACE(FMT, ##__VA_ARGS__) #else diff --git a/libc/log/countexpr_report.c b/libc/log/countexpr_report.c index 96d07ff94..800eb7319 100644 --- a/libc/log/countexpr_report.c +++ b/libc/log/countexpr_report.c @@ -16,13 +16,13 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/mem/alg.h" #include "libc/assert.h" #include "libc/calls/calls.h" #include "libc/intrin/kprintf.h" #include "libc/limits.h" #include "libc/log/countexpr.h" #include "libc/macros.internal.h" +#include "libc/mem/alg.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" @@ -50,7 +50,7 @@ static void PrintHistogram(const long *h, size_t n, long t) { unsigned long logos; for (i = 0; i < n; ++i) { p = (h[i] * 10000 + (t >> 1)) / t; - assert(0 <= p && p <= 10000); + _unassert(0 <= p && p <= 10000); if (p) { for (j = 0; j < p / 100; ++j) s[j] = '#'; s[j] = 0; diff --git a/libc/log/memlog.c b/libc/log/memlog.c index af7017072..be4240430 100644 --- a/libc/log/memlog.c +++ b/libc/log/memlog.c @@ -145,11 +145,11 @@ static void __memlog_update(void *p2, void *p) { __memlog.usage += n - __memlog.allocs.p[i].size; __memlog.allocs.p[i].addr = p2; __memlog.allocs.p[i].size = n; - assert(__memlog.usage >= 0); + _unassert(__memlog.usage >= 0); return; } } - assert(!"this corruption"); + unreachable; } static void __memlog_log(struct StackFrame *frame, const char *op, void *res, @@ -169,21 +169,20 @@ static void __memlog_free(void *p) { __memlog.allocs.p[i].addr = 0; __memlog.usage -= __memlog.allocs.p[i].size; __memlog.allocs.f = MIN(__memlog.allocs.f, i); - assert(__memlog.usage >= 0); + _unassert(__memlog.usage >= 0); } else { kprintf("memlog could not find %p\n", p); - assert(!"this corruption"); - n = -1; + notpossible; } __memlog_unlock(); - assert(__memlog.free); + _unassert(__memlog.free); __memlog.free(p); __memlog_log(__builtin_frame_address(0), "free", 0, p, n); } static void *__memlog_malloc(size_t n) { void *res; - assert(__memlog.malloc); + _unassert(__memlog.malloc); if ((res = __memlog.malloc(n))) { __memlog_lock(); __memlog_insert(res); @@ -195,7 +194,7 @@ static void *__memlog_malloc(size_t n) { static void *__memlog_calloc(size_t n, size_t z) { void *res; - assert(__memlog.calloc); + _unassert(__memlog.calloc); if ((res = __memlog.calloc(n, z))) { __memlog_lock(); __memlog_insert(res); @@ -207,7 +206,7 @@ static void *__memlog_calloc(size_t n, size_t z) { static void *__memlog_memalign(size_t l, size_t n) { void *res; - assert(__memlog.memalign); + _unassert(__memlog.memalign); if ((res = __memlog.memalign(l, n))) { __memlog_lock(); __memlog_insert(res); @@ -221,7 +220,7 @@ static void *__memlog_realloc_impl(void *p, size_t n, void *(*f)(void *, size_t), struct StackFrame *frame) { void *res; - assert(f); + _unassert(f); if ((res = f(p, n))) { __memlog_lock(); if (p) { diff --git a/libc/mem/arena.c b/libc/mem/arena.c index bc2c9c14e..c0a148801 100644 --- a/libc/mem/arena.c +++ b/libc/mem/arena.c @@ -62,18 +62,13 @@ static wontreturn void __arena_die(void) { _exit(83); } -static wontreturn void __arena_not_implemented(void) { - assert(!"not implemented"); - __arena_die(); -} - forceinline void __arena_check(void) { - assert(__arena.depth); + _unassert(__arena.depth); } forceinline void __arena_check_pointer(void *p) { - assert(BASE + __arena.offset[__arena.depth - 1] <= (uintptr_t)p && - (uintptr_t)p < BASE + __arena.offset[__arena.depth]); + _unassert(BASE + __arena.offset[__arena.depth - 1] <= (uintptr_t)p && + (uintptr_t)p < BASE + __arena.offset[__arena.depth]); } forceinline bool __arena_is_arena_pointer(void *p) { @@ -326,7 +321,7 @@ void __arena_push(void) { if (!__arena.depth) { __arena_install(); } else { - assert(__arena.depth < ARRAYLEN(__arena.offset) - 1); + _unassert(__arena.depth < ARRAYLEN(__arena.offset) - 1); } __arena.offset[__arena.depth + 1] = __arena.offset[__arena.depth]; ++__arena.depth; diff --git a/libc/mem/gc.c b/libc/mem/gc.c index 96e493c53..ab0c2697b 100644 --- a/libc/mem/gc.c +++ b/libc/mem/gc.c @@ -25,9 +25,9 @@ #include "libc/str/str.h" #include "libc/thread/tls.h" -static inline bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame, - struct StackFrame *parent, - void *ptr) { +forceinline bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame, + struct StackFrame *parent, + void *ptr) { return !(((intptr_t)ptr > (intptr_t)frame) && ((intptr_t)ptr < (intptr_t)parent)); } @@ -93,8 +93,8 @@ static void DeferFunction(struct StackFrame *frame, void *fn, void *arg) { void __defer(void *rbp, void *fn, void *arg) { struct StackFrame *f, *frame = rbp; f = __builtin_frame_address(0); - assert(f->next == frame); - assert(PointerNotOwnedByParentStackFrame(f, frame, arg)); + _unassert(f->next == frame); + _unassert(PointerNotOwnedByParentStackFrame(f, frame, arg)); DeferFunction(frame, fn, arg); } diff --git a/libc/mem/tarjan.c b/libc/mem/tarjan.c index 2ec19588e..7a6b895b3 100644 --- a/libc/mem/tarjan.c +++ b/libc/mem/tarjan.c @@ -52,9 +52,9 @@ struct Tarjan { static bool TarjanPush(struct Tarjan *t, int v) { int *q; - assert(t->S.i >= 0); - assert(t->S.n >= 0); - assert(0 <= v && v < t->Vn); + _unassert(t->S.i >= 0); + _unassert(t->S.n >= 0); + _unassert(0 <= v && v < t->Vn); if (t->S.i == t->S.n) { if ((q = realloc(t->S.p, (t->S.n + (t->S.n >> 1) + 8) * sizeof(*t->S.p)))) { t->S.p = q; @@ -67,13 +67,13 @@ static bool TarjanPush(struct Tarjan *t, int v) { } static int TarjanPop(struct Tarjan *t) { - assert(t->S.i > 0); + _unassert(t->S.i > 0); return t->S.p[--t->S.i]; } static bool TarjanConnect(struct Tarjan *t, int v) { int fs, w, e; - assert(0 <= v && v < t->Vn); + _unassert(0 <= v && v < t->Vn); t->V[v].index = t->index; t->V[v].lowlink = t->index; t->V[v].onstack = true; @@ -135,12 +135,12 @@ int _tarjan(int vertex_count, const int (*edges)[2], int edge_count, int *out_opt_componentcount) { int i, rc, v, e; struct Tarjan *t; - assert(0 <= edge_count && edge_count <= INT_MAX); - assert(0 <= vertex_count && vertex_count <= INT_MAX); + _unassert(0 <= edge_count && edge_count <= INT_MAX); + _unassert(0 <= vertex_count && vertex_count <= INT_MAX); for (i = 0; i < edge_count; ++i) { - if (i) assert(edges[i - 1][0] <= edges[i][0]); - assert(edges[i][0] < vertex_count); - assert(edges[i][1] < vertex_count); + if (i) _unassert(edges[i - 1][0] <= edges[i][0]); + _unassert(edges[i][0] < vertex_count); + _unassert(edges[i][1] < vertex_count); } if (!(t = calloc(1, (sizeof(struct Tarjan) + sizeof(struct Vertex) * vertex_count)))) { @@ -175,7 +175,7 @@ int _tarjan(int vertex_count, const int (*edges)[2], int edge_count, if (out_opt_components) { *out_opt_componentcount = t->Ci; } - assert(t->Ri == vertex_count); + _unassert(t->Ri == vertex_count); free(t->S.p); free(t); return rc; diff --git a/libc/mem/unhexstr.c b/libc/mem/unhexstr.c index 82499ddef..dc245fe38 100644 --- a/libc/mem/unhexstr.c +++ b/libc/mem/unhexstr.c @@ -22,6 +22,6 @@ #include "libc/str/str.h" dontdiscard void *unhexstr(const char *hexdigs) { - assert(strlen(hexdigs) % 2 == 0); + _unassert(strlen(hexdigs) % 2 == 0); return unhexbuf(malloc(strlen(hexdigs) / 2), strlen(hexdigs) / 2, hexdigs); } diff --git a/libc/mem/vasprintf.c b/libc/mem/vasprintf.c index b002c8a34..4b3c3462f 100644 --- a/libc/mem/vasprintf.c +++ b/libc/mem/vasprintf.c @@ -43,7 +43,7 @@ int(vasprintf)(char **strp, const char *fmt, va_list va) { if ((p2 = realloc(p, size))) { p = p2; wrote = (vsnprintf)(p, size, fmt, vb); - assert(wrote == size - 1); + _unassert(wrote == size - 1); rc = wrote; } } diff --git a/libc/runtime/exit.c b/libc/runtime/exit.c index 6b4ded62c..80e58a8ea 100644 --- a/libc/runtime/exit.c +++ b/libc/runtime/exit.c @@ -26,7 +26,10 @@ * * This calls functions registered by atexit() before terminating * the current process, and any associated threads. It also calls - * all the legacy linker registered destructors in reeverse order + * all the legacy linker registered destructors in reversed order + * + * This implementation allows exit() to be called recursively via + * atexit() handlers. * * @param exitcode is masked with 255 * @see _Exit() diff --git a/libc/runtime/grow.c b/libc/runtime/grow.c index 9dbe8e578..ef33e9f5b 100644 --- a/libc/runtime/grow.c +++ b/libc/runtime/grow.c @@ -41,9 +41,9 @@ bool __grow(void *pp, size_t *capacity, size_t itemsize, size_t extra) { size_t t1, t2; extra += GUARANTEE_TERMINATOR; p = (void **)pp; - assert(itemsize); - assert((*p && *capacity) || (!*p && !*capacity)); - assert(!_isheap(*p) || ((intptr_t)*p & 15) == 0); + _unassert(itemsize); + _unassert((*p && *capacity) || (!*p && !*capacity)); + _unassert(!_isheap(*p) || ((intptr_t)*p & 15) == 0); p1 = _isheap(*p) ? *p : NULL; p2 = NULL; n1 = *capacity; diff --git a/libc/runtime/mmap.c b/libc/runtime/mmap.c index c4fae0c47..4652ef88d 100644 --- a/libc/runtime/mmap.c +++ b/libc/runtime/mmap.c @@ -25,6 +25,7 @@ #include "libc/intrin/asan.internal.h" #include "libc/intrin/asancodes.h" #include "libc/intrin/bits.h" +#include "libc/intrin/bsr.h" #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/likely.h" #include "libc/intrin/safemacros.internal.h" @@ -63,6 +64,10 @@ #define SHADE(x) (((intptr_t)(x) >> 3) + 0x7fff8000) #define FRAME(x) ((int)((intptr_t)(x) >> 16)) +static unsigned long RoundDownTwoPow(unsigned long x) { + return x ? 1ul << _bsrl(x) : 0; +} + static wontreturn void OnUnrecoverableMmapError(const char *s) { if (_weaken(__die)) _weaken(__die)(); STRACE("%s %m", s); @@ -322,7 +327,7 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags, return VIP(einval()); } - a = max(1, _rounddown2pow(size) >> 16); + a = max(1, RoundDownTwoPow(size) >> 16); f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED; if (flags & MAP_FIXED) { diff --git a/libc/runtime/mremap.c b/libc/runtime/mremap.c index 4170291c0..02d04a0cf 100644 --- a/libc/runtime/mremap.c +++ b/libc/runtime/mremap.c @@ -91,7 +91,7 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) { size_t i, j, k; struct DirectMap dm; int a, b, prot, flags; - assert(!__vforked); + _unassert(!__vforked); if (UNLIKELY(!m)) { STRACE("m=0"); return VIP(einval()); diff --git a/libc/runtime/msync.c b/libc/runtime/msync.c index 71e75672c..0f7c34e1f 100644 --- a/libc/runtime/msync.c +++ b/libc/runtime/msync.c @@ -18,10 +18,10 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" -#include "libc/intrin/strace.internal.h" #include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" +#include "libc/intrin/strace.internal.h" #include "libc/macros.internal.h" #include "libc/sysv/consts/msync.h" @@ -37,7 +37,7 @@ */ int msync(void *addr, size_t size, int flags) { int rc; - assert(((flags & MS_SYNC) ^ (flags & MS_ASYNC)) || !(MS_SYNC && MS_ASYNC)); + _unassert(((flags & MS_SYNC) ^ (flags & MS_ASYNC)) || !(MS_SYNC && MS_ASYNC)); if (!IsWindows()) { rc = sys_msync(addr, size, flags); } else { diff --git a/libc/runtime/munmap.c b/libc/runtime/munmap.c index a3f8d0b44..12cb19c93 100644 --- a/libc/runtime/munmap.c +++ b/libc/runtime/munmap.c @@ -95,9 +95,7 @@ static noasan void MunmapImpl(char *p, size_t n) { beg = MAX(_mmi.p[i].x, l); end = _mmi.p[i].y; } else { - // shouldn't be possible - assert(!"binary search panic"); - continue; + unreachable; } // openbsd even requires that if we mapped, for instance a 5 byte // file, that we be sure to call munmap(file, 5). let's abstract! @@ -107,8 +105,7 @@ static noasan void MunmapImpl(char *p, size_t n) { q = (char *)a; m = MIN(b, c) - a; if (!IsWindows()) { - rc = sys_munmap(q, m); - assert(!rc); + _npassert(!sys_munmap(q, m)); } else { // Handled by UntrackMemoryIntervals() on Windows } @@ -122,7 +119,7 @@ static noasan int Munmap(char *p, size_t n) { unsigned i; char poison; intptr_t a, b, x, y; - assert(!__vforked); + _unassert(!__vforked); if (UNLIKELY(!n)) { STRACE("n=0"); return einval(); diff --git a/libc/runtime/stackuse.c b/libc/runtime/stackuse.c index 8b8217f4f..651d081d4 100644 --- a/libc/runtime/stackuse.c +++ b/libc/runtime/stackuse.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/dce.h" +#include "libc/errno.h" #include "libc/fmt/itoa.h" #include "libc/intrin/atomic.h" #include "libc/intrin/promises.internal.h" @@ -48,30 +49,33 @@ size_t GetStackUsage(char *s, size_t n) { } static textexit void LogStackUse(void) { - int i, fd; bool quote; char *p, *q; + int i, e, fd; size_t n, usage; if (!PLEDGED(STDIO) || !PLEDGED(WPATH) || !PLEDGED(CPATH)) return; usage = GetStackUsage((char *)GetStackAddr(), GetStackSize()); - fd = open(stacklog, O_APPEND | O_CREAT | O_WRONLY, 0644); - p = FormatUint64(stacklog, usage); - for (i = 0; i < __argc; ++i) { - n = strlen(__argv[i]); - if ((q = memchr(__argv[i], '\n', n))) n = q - __argv[i]; - if (p - stacklog + 1 + 1 + n + 1 + 1 < sizeof(stacklog)) { - quote = !!memchr(__argv[i], ' ', n); - *p++ = ' '; - if (quote) *p++ = '\''; - p = mempcpy(p, __argv[i], n); - if (quote) *p++ = '\''; - } else { - break; + e = errno; + if ((fd = open(stacklog, O_APPEND | O_CREAT | O_WRONLY, 0644)) != -1) { + p = FormatUint64(stacklog, usage); + for (i = 0; i < __argc; ++i) { + n = strlen(__argv[i]); + if ((q = memchr(__argv[i], '\n', n))) n = q - __argv[i]; + if (p - stacklog + 1 + 1 + n + 1 + 1 < sizeof(stacklog)) { + quote = !!memchr(__argv[i], ' ', n); + *p++ = ' '; + if (quote) *p++ = '\''; + p = mempcpy(p, __argv[i], n); + if (quote) *p++ = '\''; + } else { + break; + } } + *p++ = '\n'; + write(fd, stacklog, p - stacklog); + close(fd); } - *p++ = '\n'; - write(fd, stacklog, p - stacklog); - close(fd); + errno = e; } static textstartup void LogStackUseInit(void) { diff --git a/libc/runtime/untrackmemoryintervals.c b/libc/runtime/untrackmemoryintervals.c index 16ccca652..dfca2efe6 100644 --- a/libc/runtime/untrackmemoryintervals.c +++ b/libc/runtime/untrackmemoryintervals.c @@ -23,7 +23,7 @@ int UntrackMemoryIntervals(void *addr, size_t size) { int a, b; - assert(size > 0); + _unassert(size > 0); a = ROUNDDOWN((intptr_t)addr, FRAMESIZE) >> 16; b = ROUNDDOWN((intptr_t)addr + size - 1, FRAMESIZE) >> 16; return ReleaseMemoryIntervals(&_mmi, a, b, diff --git a/libc/sock/bind-nt.c b/libc/sock/bind-nt.c index d48c7a38a..2add613dc 100644 --- a/libc/sock/bind-nt.c +++ b/libc/sock/bind-nt.c @@ -25,7 +25,7 @@ textwindows int sys_bind_nt(struct Fd *fd, const void *addr, uint32_t addrsize) { - assert(fd->kind == kFdSocket); + _npassert(fd->kind == kFdSocket); if (__sys_bind_nt(fd->handle, addr, addrsize) != -1) { return 0; } else { diff --git a/libc/sock/connect-nt.c b/libc/sock/connect-nt.c index 8142fed29..a5ee60734 100644 --- a/libc/sock/connect-nt.c +++ b/libc/sock/connect-nt.c @@ -27,7 +27,7 @@ textwindows int sys_connect_nt(struct Fd *fd, const void *addr, uint32_t addrsize) { struct SockFd *sockfd; sockfd = (struct SockFd *)fd->extra; - assert(fd->kind == kFdSocket); + _npassert(fd->kind == kFdSocket); return __winsockblock( fd->handle, FD_CONNECT_BIT, WSAConnect(fd->handle, addr, addrsize, NULL, NULL, NULL, NULL), diff --git a/libc/sock/epoll.c b/libc/sock/epoll.c index a7e99521e..596b6f87e 100644 --- a/libc/sock/epoll.c +++ b/libc/sock/epoll.c @@ -378,7 +378,7 @@ static textwindows int afd_poll(int64_t afd_device_handle, struct NtIoStatusBlock *io_status_block) { NtStatus status; /* Blocking operation is not supported.*/ - assert(io_status_block); + _npassert(io_status_block); io_status_block->Status = kNtStatusPending; status = NtDeviceIoControlFile(afd_device_handle, 0, NULL, io_status_block, @@ -425,11 +425,11 @@ static textwindows void queue__detach_node(struct QueueNode *node) { node->next->prev = node->prev; } -static textwindows bool queue_is_enqueued(const struct QueueNode *node) { +forceinline bool queue_is_enqueued(const struct QueueNode *node) { return node->prev != node; } -static textwindows bool queue_is_empty(const struct Queue *queue) { +forceinline bool queue_is_empty(const struct Queue *queue) { return !queue_is_enqueued(&queue->head); } @@ -558,7 +558,7 @@ static textwindows int ts_tree_add(struct TsTree *ts_tree, } static textwindows void port__free(struct PortState *port) { - assert(port != NULL); + _npassert(port); free(port); } @@ -586,7 +586,7 @@ err1: } static textwindows int sock__cancel_poll(struct SockState *sock_state) { - assert(sock_state->poll_status == kPollPending); + _npassert(sock_state->poll_status == kPollPending); if (afd_cancel_poll(poll_group_get_afd_device_handle(sock_state->poll_group), &sock_state->io_status_block) < 0) { return -1; @@ -702,13 +702,13 @@ static textwindows void reflock__await_event(void *address) { static textwindows void reflock_ref(struct RefLock *reflock) { long state = InterlockedAdd(&reflock->state, REFLOCK__REF); /* Verify that the counter didn 't overflow and the lock isn' t destroyed.*/ - assert((state & REFLOCK__DESTROY_MASK) == 0); + _npassert((state & REFLOCK__DESTROY_MASK) == 0); } static textwindows void reflock_unref(struct RefLock *reflock) { long state = InterlockedAdd(&reflock->state, -REFLOCK__REF); /* Verify that the lock was referenced and not already destroyed.*/ - assert((state & REFLOCK__DESTROY_MASK & ~REFLOCK__DESTROY) == 0); + _npassert((state & REFLOCK__DESTROY_MASK & ~REFLOCK__DESTROY) == 0); if (state == REFLOCK__DESTROY) reflock__signal_event(reflock); } @@ -744,10 +744,10 @@ static textwindows void reflock_unref_and_destroy(struct RefLock *reflock) { state = InterlockedAdd(&reflock->state, REFLOCK__DESTROY - REFLOCK__REF); ref_count = state & REFLOCK__REF_MASK; /* Verify that the lock was referenced and not already destroyed. */ - assert((state & REFLOCK__DESTROY_MASK) == REFLOCK__DESTROY); + _npassert((state & REFLOCK__DESTROY_MASK) == REFLOCK__DESTROY); if (ref_count != 0) reflock__await_event(reflock); state = InterlockedExchange(&reflock->state, REFLOCK__POISON); - assert(state == REFLOCK__DESTROY); + _npassert(state == REFLOCK__DESTROY); } static textwindows void ts_tree_node_unref_and_destroy( @@ -775,13 +775,13 @@ static textwindows void poll_group_release(struct PollGroup *poll_group) { struct PortState *port_state = poll_group->port_state; struct Queue *poll_group_queue = port_get_poll_group_queue(port_state); poll_group->group_size--; - assert(poll_group->group_size < MAX_GROUP_SIZE); + _npassert(poll_group->group_size < MAX_GROUP_SIZE); queue_move_to_end(poll_group_queue, &poll_group->queue_node); /* Poll groups are currently only freed when the epoll port is closed. */ } static textwindows void sock__free(struct SockState *sock_state) { - assert(sock_state != NULL); + _npassert(sock_state != NULL); free(sock_state); } @@ -827,7 +827,7 @@ static textwindows void sock_force_delete(struct PortState *port_state, } static textwindows void poll_group_delete(struct PollGroup *poll_group) { - assert(poll_group->group_size == 0); + _npassert(poll_group->group_size == 0); CloseHandle(poll_group->afd_device_handle); queue_remove(&poll_group->queue_node); free(poll_group); @@ -839,7 +839,7 @@ static textwindows int port_delete(struct PortState *port_state) { struct SockState *sock_state; struct PollGroup *poll_group; /* At this point the IOCP port should have been closed.*/ - assert(!port_state->iocp_handle); + _npassert(!port_state->iocp_handle); while ((tree_node = tree_root(&port_state->sock_tree)) != NULL) { sock_state = sock_state_from_tree_node(tree_node); sock_force_delete(port_state, sock_state); @@ -852,14 +852,14 @@ static textwindows int port_delete(struct PortState *port_state) { poll_group = poll_group_from_queue_node(queue_node); poll_group_delete(poll_group); } - assert(queue_is_empty(&port_state->sock_update_queue)); + _npassert(queue_is_empty(&port_state->sock_update_queue)); DeleteCriticalSection(&port_state->lock); port__free(port_state); return 0; } static textwindows int64_t port_get_iocp_handle(struct PortState *port_state) { - assert(port_state->iocp_handle); + _npassert(port_state->iocp_handle); return port_state->iocp_handle; } @@ -933,7 +933,7 @@ static textwindows uint32_t sock__afd_events_to_epoll_events(uint32_t a) { static textwindows int sock_update(struct PortState *port_state, struct SockState *sock_state) { - assert(!sock_state->delete_pending); + _npassert(!sock_state->delete_pending); if ((sock_state->poll_status == kPollPending) && !(sock_state->user_events & KNOWN_EVENTS & ~sock_state->pending_events)) { /* All the events the user is interested in are already being diff --git a/libc/sock/getpeername-nt.c b/libc/sock/getpeername-nt.c index 8ed54e952..b0e3ec2ad 100644 --- a/libc/sock/getpeername-nt.c +++ b/libc/sock/getpeername-nt.c @@ -26,7 +26,7 @@ textwindows int sys_getpeername_nt(struct Fd *fd, void *out_addr, uint32_t *out_addrsize) { - assert(fd->kind == kFdSocket); + _npassert(fd->kind == kFdSocket); if (__sys_getpeername_nt(fd->handle, out_addr, out_addrsize) != -1) { return 0; } else { diff --git a/libc/sock/getsockname-nt.c b/libc/sock/getsockname-nt.c index 569b377bc..8051ff288 100644 --- a/libc/sock/getsockname-nt.c +++ b/libc/sock/getsockname-nt.c @@ -24,7 +24,7 @@ textwindows int sys_getsockname_nt(struct Fd *fd, void *out_addr, uint32_t *out_addrsize) { - assert(fd->kind == kFdSocket); + _npassert(fd->kind == kFdSocket); if (__sys_getsockname_nt(fd->handle, out_addr, out_addrsize) != -1) { return 0; } else { diff --git a/libc/sock/getsockopt-nt.c b/libc/sock/getsockopt-nt.c index ddfd644b2..d85115b04 100644 --- a/libc/sock/getsockopt-nt.c +++ b/libc/sock/getsockopt-nt.c @@ -36,7 +36,7 @@ textwindows int sys_getsockopt_nt(struct Fd *fd, int level, int optname, uint32_t in_optlen; struct SockFd *sockfd; struct linger_nt linger; - assert(fd->kind == kFdSocket); + _npassert(fd->kind == kFdSocket); sockfd = (struct SockFd *)fd->extra; if (out_opt_optval && inout_optlen) { diff --git a/libc/sock/listen-nt.c b/libc/sock/listen-nt.c index bb6fbf5d1..c899f97ef 100644 --- a/libc/sock/listen-nt.c +++ b/libc/sock/listen-nt.c @@ -22,7 +22,7 @@ #include "libc/sock/syscall_fd.internal.h" textwindows int sys_listen_nt(struct Fd *fd, int backlog) { - assert(fd->kind == kFdSocket); + _npassert(fd->kind == kFdSocket); if (__sys_listen_nt(fd->handle, backlog) != -1) { return 0; } else { diff --git a/libc/sock/nointernet.c b/libc/sock/nointernet.c index 7b4257010..40f320b52 100644 --- a/libc/sock/nointernet.c +++ b/libc/sock/nointernet.c @@ -274,6 +274,11 @@ static int WaitForTrace(int main) { /** * Disables internet access. + * + * Warning: This function uses ptrace to react to seccomp filter events. + * This approach is effective, but it's not bulletproof, since a highly + * motivated attacker could theoretically use threads to modify sockaddr + * in the short time between it being monitored and the actual syscall. */ int nointernet(void) { int ws, act, main; @@ -317,7 +322,7 @@ int nointernet(void) { sigprocmask(SIG_SETMASK, &old, 0); return eperm(); } - assert(WIFSTOPPED(ws)); + _npassert(WIFSTOPPED(ws)); // parent process becomes monitor of subprocess tree. all signals // continue to be blocked since we assume they'll also be sent to diff --git a/libc/stdio/appendd.c b/libc/stdio/appendd.c index 4c727aa0d..31cde43d5 100644 --- a/libc/stdio/appendd.c +++ b/libc/stdio/appendd.c @@ -53,7 +53,7 @@ ssize_t appendd(char **b, const void *s, size_t l) { z.n = ROUNDUP(z.n, W); if ((p = realloc(p, z.n))) { z.n = malloc_usable_size(p); - assert(!(z.n & (W - 1))); + _unassert(!(z.n & (W - 1))); *b = p; } else { return -1; diff --git a/libc/stdio/appendr.c b/libc/stdio/appendr.c index 902a25821..13128f920 100644 --- a/libc/stdio/appendr.c +++ b/libc/stdio/appendr.c @@ -51,14 +51,14 @@ ssize_t appendr(char **b, size_t i) { char *p; size_t n; struct appendz z; - assert(b); + _unassert(b); z = appendz((p = *b)); if (i != z.i || !p) { n = ROUNDUP(i + 1, 8) + W; if (n > z.n || _bsrl(n) < _bsrl(z.n)) { if ((p = realloc(p, n))) { z.n = malloc_usable_size(p); - assert(!(z.n & (W - 1))); + _unassert(!(z.n & (W - 1))); *b = p; } else { return -1; diff --git a/libc/stdio/appendw.c b/libc/stdio/appendw.c index 9513eeeaf..c13db27f8 100644 --- a/libc/stdio/appendw.c +++ b/libc/stdio/appendw.c @@ -67,7 +67,7 @@ ssize_t appendw(char **b, uint64_t w) { z.n = ROUNDUP(z.n, W); if ((p = realloc(p, z.n))) { z.n = malloc_usable_size(p); - assert(!(z.n & (W - 1))); + _unassert(!(z.n & (W - 1))); *b = p; } else { return -1; diff --git a/libc/stdio/appendz.c b/libc/stdio/appendz.c index 2d6cc7571..936908a28 100644 --- a/libc/stdio/appendz.c +++ b/libc/stdio/appendz.c @@ -34,7 +34,7 @@ struct appendz appendz(char *p) { struct appendz z; if (p) { z.n = malloc_usable_size(p); - assert(z.n >= W * 2 && !(z.n & (W - 1))); + _unassert(z.n >= W * 2 && !(z.n & (W - 1))); z.i = *(size_t *)(p + z.n - W); if (!IsTiny() && W == 8) { /* @@ -43,10 +43,10 @@ struct appendz appendz(char *p) { * can be free()'d safely, but they need to be allocated by the * append library, because we write a special value to the end. */ - assert((z.i >> 48) == APPEND_COOKIE); + _unassert((z.i >> 48) == APPEND_COOKIE); z.i &= 0x0000ffffffffffff; } - assert(z.n >= z.i); + _unassert(z.n >= z.i); } else { z.i = 0; z.n = 0; diff --git a/libc/stdio/clearerr.c b/libc/stdio/clearerr.c index 1ff0ae2b6..02eab7b0a 100644 --- a/libc/stdio/clearerr.c +++ b/libc/stdio/clearerr.c @@ -20,7 +20,7 @@ #include "libc/stdio/stdio.h" /** - * Clears error state on stream. + * Clears eof and error state indicators on stream. * * @param f is file object stream pointer * @see clearerr_unlocked() diff --git a/libc/stdio/clearerr_unlocked.c b/libc/stdio/clearerr_unlocked.c index d06719d15..3214dadc0 100644 --- a/libc/stdio/clearerr_unlocked.c +++ b/libc/stdio/clearerr_unlocked.c @@ -18,6 +18,13 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/stdio/stdio.h" +/** + * Clears eof and error state indicators on stream. + * + * @param f is file object stream pointer + * @see clearerr() + * @threadsafe + */ void clearerr_unlocked(FILE *f) { f->state = 0; } diff --git a/libc/stdio/dirstream.c b/libc/stdio/dirstream.c index 4bad33ccc..4e0ac0d22 100644 --- a/libc/stdio/dirstream.c +++ b/libc/stdio/dirstream.c @@ -336,7 +336,8 @@ static struct dirent *readdir_impl(DIR *dir) { ent = 0; zip = _weaken(__zipos_get)(); while (!ent && dir->tell < dir->zip.records) { - assert(ZIP_CFILE_MAGIC(zip->map + dir->zip.offset) == kZipCfileHdrMagic); + _npassert(ZIP_CFILE_MAGIC(zip->map + dir->zip.offset) == + kZipCfileHdrMagic); s = ZIP_CFILE_NAME(zip->map + dir->zip.offset); n = ZIP_CFILE_NAMESIZE(zip->map + dir->zip.offset); if (dir->zip.prefixlen < n && diff --git a/libc/stdio/fread.c b/libc/stdio/fread.c index f5f96007a..67ee940f4 100644 --- a/libc/stdio/fread.c +++ b/libc/stdio/fread.c @@ -16,6 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/describeflags.internal.h" +#include "libc/intrin/strace.internal.h" #include "libc/stdio/lock.internal.h" #include "libc/stdio/stdio.h" @@ -31,6 +33,8 @@ size_t fread(void *buf, size_t stride, size_t count, FILE *f) { size_t rc; flockfile(f); rc = fread_unlocked(buf, stride, count, f); + STDIOTRACE("fread(%p, %'zu, %'zu, %p) → %'zu %s", buf, stride, count, f, rc, + DescribeStdioState(f->state)); funlockfile(f); return rc; } diff --git a/libc/stdio/fread_unlocked.c b/libc/stdio/fread_unlocked.c index d3b121d4b..c36f8d80e 100644 --- a/libc/stdio/fread_unlocked.c +++ b/libc/stdio/fread_unlocked.c @@ -42,6 +42,9 @@ size_t fread_unlocked(void *buf, size_t stride, size_t count, FILE *f) { ssize_t rc; size_t n, m; struct iovec iov[2]; + if (f->state) { + return 0; + } if ((f->iomode & O_ACCMODE) == O_WRONLY) { f->state = errno = EBADF; return 0; diff --git a/libc/stdio/fseeko.c b/libc/stdio/fseeko.c index d0d8d265f..c20380c31 100644 --- a/libc/stdio/fseeko.c +++ b/libc/stdio/fseeko.c @@ -16,6 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/describeflags.internal.h" +#include "libc/intrin/strace.internal.h" #include "libc/stdio/lock.internal.h" #include "libc/stdio/stdio.h" @@ -37,6 +39,8 @@ int fseeko(FILE *f, int64_t offset, int whence) { int rc; flockfile(f); rc = fseeko_unlocked(f, offset, whence); + STDIOTRACE("fseeko(%p, %'ld, %s) → %d %s", f, offset, DescribeWhence(whence), + rc, DescribeStdioState(f->state)); funlockfile(f); return rc; } diff --git a/libc/stdio/fseeko_unlocked.c b/libc/stdio/fseeko_unlocked.c index 0a7c08bdb..2bcac84e0 100644 --- a/libc/stdio/fseeko_unlocked.c +++ b/libc/stdio/fseeko_unlocked.c @@ -47,6 +47,7 @@ int fseeko_unlocked(FILE *f, int64_t offset, int whence) { if (lseek(f->fd, offset, whence) != -1) { f->beg = 0; f->end = 0; + f->state = 0; res = 0; } else { f->state = errno == ESPIPE ? EBADF : errno; @@ -69,6 +70,7 @@ int fseeko_unlocked(FILE *f, int64_t offset, int whence) { } if (0 <= pos && pos <= f->end) { f->beg = pos; + f->state = 0; res = 0; } else { f->state = errno = EINVAL; diff --git a/libc/stdio/fwrite.c b/libc/stdio/fwrite.c index 915b0a21c..3db05c335 100644 --- a/libc/stdio/fwrite.c +++ b/libc/stdio/fwrite.c @@ -16,6 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/describeflags.internal.h" +#include "libc/intrin/strace.internal.h" #include "libc/stdio/lock.internal.h" #include "libc/stdio/stdio.h" @@ -31,6 +33,8 @@ size_t fwrite(const void *data, size_t stride, size_t count, FILE *f) { size_t rc; flockfile(f); rc = fwrite_unlocked(data, stride, count, f); + STDIOTRACE("fwrite(%p, %'zu, %'zu, %p) → %'zu %s", data, stride, count, f, rc, + DescribeStdioState(f->state)); funlockfile(f); return rc; } diff --git a/libc/stdio/fwrite_unlocked.c b/libc/stdio/fwrite_unlocked.c index 927411a58..d3e22aa1b 100644 --- a/libc/stdio/fwrite_unlocked.c +++ b/libc/stdio/fwrite_unlocked.c @@ -44,6 +44,9 @@ size_t fwrite_unlocked(const void *data, size_t stride, size_t count, FILE *f) { size_t n, m; const char *p; struct iovec iov[2]; + if (f->state) { + return 0; + } if ((f->iomode & O_ACCMODE) == O_RDONLY) { f->state = errno = EBADF; return 0; diff --git a/libc/stdio/kvappendf.c b/libc/stdio/kvappendf.c index b54c3dabf..b0fc5dce5 100644 --- a/libc/stdio/kvappendf.c +++ b/libc/stdio/kvappendf.c @@ -51,9 +51,9 @@ ssize_t kvappendf(char **b, const char *f, va_list v) { z.n = ROUNDUP(z.n, W); if ((p = realloc(p, z.n))) { z.n = malloc_usable_size(p); - assert(!(z.n & (W - 1))); + _unassert(!(z.n & (W - 1))); s = kvsnprintf(p + z.i, z.n - W - z.i, f, w); - assert(s == r); + _unassert(s == r); *b = p; } else { va_end(w); diff --git a/libc/stdio/mkostempsm.c b/libc/stdio/mkostempsm.c index 0b85ce1a5..8b74f47a2 100644 --- a/libc/stdio/mkostempsm.c +++ b/libc/stdio/mkostempsm.c @@ -18,11 +18,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" -#include "libc/intrin/strace.internal.h" #include "libc/errno.h" +#include "libc/intrin/strace.internal.h" +#include "libc/runtime/runtime.h" #include "libc/stdio/lcg.internal.h" #include "libc/stdio/rand.h" -#include "libc/runtime/runtime.h" #include "libc/stdio/temp.h" #include "libc/str/str.h" #include "libc/sysv/consts/o.h" @@ -38,7 +38,7 @@ int mkostempsmi(char *tpl, int slen, unsigned flags, uint64_t *rando, int mode, size_t wildlen = strlen(WILDCARD); if (len < wildlen || slen > len - wildlen) return einval(); char *ss = tpl + len - wildlen - slen; - assert(memcmp(ss, WILDCARD, wildlen) == 0); + _npassert(memcmp(ss, WILDCARD, wildlen) == 0); flags = (flags & ~(flags & O_ACCMODE)) | O_RDWR | O_CREAT | O_EXCL; unsigned attempts = ATTEMPTS; do { diff --git a/libc/stdio/pclose.c b/libc/stdio/pclose.c index e9047cd1a..380c66221 100644 --- a/libc/stdio/pclose.c +++ b/libc/stdio/pclose.c @@ -31,7 +31,6 @@ int pclose(FILE *f) { int ws, pid; pid = f->pid; fclose(f); - assert(pid); if (!pid) return 0; TryAgain: if (wait4(pid, &ws, 0, 0) != -1) { diff --git a/libc/stdio/vappendf.c b/libc/stdio/vappendf.c index eae9a4293..a8ac2873b 100644 --- a/libc/stdio/vappendf.c +++ b/libc/stdio/vappendf.c @@ -44,9 +44,9 @@ ssize_t(vappendf)(char **b, const char *f, va_list v) { z.n = ROUNDUP(z.n, W); if ((p = realloc(p, z.n))) { z.n = malloc_usable_size(p); - assert(!(z.n & (W - 1))); + _unassert(!(z.n & (W - 1))); s = (vsnprintf)(p + z.i, z.n - W - z.i, f, w); - assert(s == r); + _unassert(s == r); *b = p; } else { va_end(w); diff --git a/libc/str/blake2.c b/libc/str/blake2.c index f00443dea..551f81f19 100644 --- a/libc/str/blake2.c +++ b/libc/str/blake2.c @@ -126,7 +126,7 @@ int BLAKE2B256_Update(struct Blake2b *b2b, const void *in_data, size_t len) { return 0; } // More input remains therefore we must have filled |b2b->block|. - assert(b2b->block_used == BLAKE2B_CBLOCK); + _unassert(b2b->block_used == BLAKE2B_CBLOCK); Blake2bTransform(b2b, b2b->block.words, BLAKE2B_CBLOCK, /*is_final_block=*/0); b2b->block_used = 0; diff --git a/libc/str/getcachesize.c b/libc/str/getcachesize.c index 3902ad639..586f913f6 100644 --- a/libc/str/getcachesize.c +++ b/libc/str/getcachesize.c @@ -51,7 +51,7 @@ static unsigned _getcachesize_cpuid4(int type, int level) { * @return size in bytes, or 0 if unknown */ unsigned _getcachesize(int type, int level) { - assert(1 <= type && type <= 3); - assert(level >= 1); + _unassert(1 <= type && type <= 3); + _unassert(level >= 1); return _getcachesize_cpuid4(type, level); } diff --git a/libc/str/strchr.c b/libc/str/strchr.c index 32d96e6a9..99cd2f4eb 100644 --- a/libc/str/strchr.c +++ b/libc/str/strchr.c @@ -70,6 +70,6 @@ char *strchr(const char *s, int c) { } else { r = strchr_pure(s, c); } - assert(!r || *r || !(c & 255)); + _unassert(!r || *r || !(c & 255)); return (char *)r; } diff --git a/libc/str/strchrnul.c b/libc/str/strchrnul.c index 3a3125442..aea39e049 100644 --- a/libc/str/strchrnul.c +++ b/libc/str/strchrnul.c @@ -68,6 +68,6 @@ char *strchrnul(const char *s, int c) { } else { r = strchrnul_pure(s, c); } - assert((*r & 255) == (c & 255) || !*r); + _unassert((*r & 255) == (c & 255) || !*r); return (char *)r; } diff --git a/libc/str/strnlen.c b/libc/str/strnlen.c index a48b23432..2229e286d 100644 --- a/libc/str/strnlen.c +++ b/libc/str/strnlen.c @@ -17,9 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" -#include "libc/intrin/bits.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" +#include "libc/intrin/bits.h" #include "libc/str/str.h" static noasan size_t strnlen_x64(const char *s, size_t n, size_t i) { @@ -52,7 +52,7 @@ noasan size_t strnlen(const char *s, size_t n) { for (;; ++i) { if (i == n || !s[i]) break; } - assert(i == n || (i < n && !s[i])); + _unassert(i == n || (i < n && !s[i])); if (IsAsan()) __asan_verify(s, i); return i; } diff --git a/libc/str/strnlen16.c b/libc/str/strnlen16.c index 1a1429ee6..4e59b1c0c 100644 --- a/libc/str/strnlen16.c +++ b/libc/str/strnlen16.c @@ -32,6 +32,6 @@ noasan size_t strnlen16(const char16_t *s, size_t n) { for (i = 0;; ++i) { if (i == n || !s[i]) break; } - assert(i == n || (i < n && !s[i])); + _unassert(i == n || (i < n && !s[i])); return i; } diff --git a/libc/str/strnlen_s.c b/libc/str/strnlen_s.c index 7c6351d8a..d04084ea9 100644 --- a/libc/str/strnlen_s.c +++ b/libc/str/strnlen_s.c @@ -56,6 +56,6 @@ noasan size_t strnlen_s(const char *s, size_t n) { for (;; ++i) { if (i == n || !s[i]) break; } - assert(i == n || (i < n && !s[i])); + _unassert(i == n || (i < n && !s[i])); return i; } diff --git a/libc/str/strxfrm.c b/libc/str/strxfrm.c index bea74ee14..1a28b2610 100644 --- a/libc/str/strxfrm.c +++ b/libc/str/strxfrm.c @@ -42,6 +42,6 @@ * @note if dest is NULL, count has to be zero */ size_t strxfrm(char *dest, const char *src, size_t count) { - assert(dest == NULL ? count == 0 : 1); + _unassert(dest == NULL ? count == 0 : 1); return strlcpy(dest, src, count); } diff --git a/libc/testlib/testrunner.c b/libc/testlib/testrunner.c index 0955a2929..bb30f8a4c 100644 --- a/libc/testlib/testrunner.c +++ b/libc/testlib/testrunner.c @@ -120,7 +120,7 @@ static void CheckSignalHandler(int sig) { #if 0 int i; struct sigaction sa = {0}; - assert(0 <= sig - 1 && sig - 1 < ARRAYLEN(wanthandlers)); + _unassert(0 <= sig - 1 && sig - 1 < ARRAYLEN(wanthandlers)); CHECK_EQ(0, sigaction(sig, 0, &sa)); CHECK_EQ(0, memcmp(wanthandlers + sig - 1, &sa, sizeof(sa)), "signal handler for %s was %p/%#x/%#x:%x " diff --git a/libc/thread/pthread_attr_setinheritsched.c b/libc/thread/pthread_attr_setinheritsched.c index feacb979b..0978d33cb 100644 --- a/libc/thread/pthread_attr_setinheritsched.c +++ b/libc/thread/pthread_attr_setinheritsched.c @@ -47,7 +47,6 @@ errno_t pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched) { attr->__inheritsched = inheritsched; return 0; default: - assert(!"badval"); return EINVAL; } } diff --git a/libc/x/rmrf.c b/libc/x/rmrf.c index 257920356..b59560e53 100644 --- a/libc/x/rmrf.c +++ b/libc/x/rmrf.c @@ -38,7 +38,7 @@ static int rmrfdir(const char *dirpath) { while ((e = readdir(d))) { if (!strcmp(e->d_name, ".")) continue; if (!strcmp(e->d_name, "..")) continue; - assert(!strchr(e->d_name, '/')); + _npassert(!strchr(e->d_name, '/')); path = xjoinpaths(dirpath, e->d_name); if (e->d_type == DT_DIR) { rc = rmrfdir(path); diff --git a/libc/x/xloadzd.c b/libc/x/xloadzd.c index 557268bc0..588638019 100644 --- a/libc/x/xloadzd.c +++ b/libc/x/xloadzd.c @@ -47,7 +47,7 @@ void *xloadzd(bool *o, void **t, const void *p, size_t n, size_t m, size_t c, z_stream zs; char *q, *b; int64_t x, y; - assert(z == 2 || z == 4); + _unassert(z == 2 || z == 4); b = q = malloc(m); __inflate(q, m, p, n); r = memalign(z, c * z); @@ -61,7 +61,7 @@ void *xloadzd(bool *o, void **t, const void *p, size_t n, size_t m, size_t c, } } free(q); - assert(crc32_z(0, r, c * z) == s); + _npassert(crc32_z(0, r, c * z) == s); if (_lockcmpxchg(t, 0, r)) { __cxa_atexit(free, r, 0); } else { diff --git a/libc/zipos/find.c b/libc/zipos/find.c index 48cbb9820..a64c3499c 100644 --- a/libc/zipos/find.c +++ b/libc/zipos/find.c @@ -34,7 +34,7 @@ ssize_t __zipos_find(struct Zipos *zipos, const struct ZiposUri *name) { c = GetZipCdirOffset(zipos->cdir); n = GetZipCdirRecords(zipos->cdir); for (i = 0; i < n; ++i, c += ZIP_CFILE_HDRSIZE(zipos->map + c)) { - assert(ZIP_CFILE_MAGIC(zipos->map + c) == kZipCfileHdrMagic); + _npassert(ZIP_CFILE_MAGIC(zipos->map + c) == kZipCfileHdrMagic); zname = ZIP_CFILE_NAME(zipos->map + c); znamesize = ZIP_CFILE_NAMESIZE(zipos->map + c); if ((name->len == znamesize && !memcmp(name->path, zname, name->len)) || diff --git a/libc/zipos/open.c b/libc/zipos/open.c index a7b4d0eb4..333fe9814 100644 --- a/libc/zipos/open.c +++ b/libc/zipos/open.c @@ -49,7 +49,7 @@ static size_t maptotal; static void *__zipos_mmap(size_t mapsize) { char *start; size_t offset; - assert(mapsize); + _unassert(mapsize); offset = maptotal; maptotal += mapsize; start = (char *)kMemtrackZiposStart; @@ -131,7 +131,7 @@ static int __zipos_load(struct Zipos *zipos, size_t cf, unsigned flags, int rc, fd, minfd; struct ZiposHandle *h; lf = GetZipCfileOffset(zipos->map + cf); - assert((ZIP_LFILE_MAGIC(zipos->map + lf) == kZipLfileHdrMagic)); + _npassert((ZIP_LFILE_MAGIC(zipos->map + lf) == kZipLfileHdrMagic)); size = GetZipLfileUncompressedSize(zipos->map + lf); switch (ZIP_LFILE_COMPRESSIONMETHOD(zipos->map + lf)) { case kZipCompressionNone: diff --git a/net/http/headerhassubstring.c b/net/http/headerhassubstring.c index f45298aae..a07010b92 100644 --- a/net/http/headerhassubstring.c +++ b/net/http/headerhassubstring.c @@ -33,7 +33,7 @@ bool HeaderHas(struct HttpMessage *m, const char *b, int h, const char *s, size_t n) { size_t i; - assert(0 <= h && h < kHttpHeadersMax); + _unassert(0 <= h && h < kHttpHeadersMax); if (n == -1) n = s ? strlen(s) : 0; if (m->headers[h].a) { if (memmem(b + m->headers[h].a, m->headers[h].b - m->headers[h].a, s, n)) { diff --git a/net/http/parsehttpmessage.c b/net/http/parsehttpmessage.c index 98ed671e6..c7b560dbe 100644 --- a/net/http/parsehttpmessage.c +++ b/net/http/parsehttpmessage.c @@ -35,7 +35,7 @@ * Initializes HTTP message parser. */ void InitHttpMessage(struct HttpMessage *r, int type) { - assert(type == kHttpRequest || type == kHttpResponse); + _unassert(type == kHttpRequest || type == kHttpResponse); bzero(r, sizeof(*r)); r->type = type; } diff --git a/test/libc/calls/read_test.c b/test/libc/calls/read_test.c index 5f5a66897..26e462da1 100644 --- a/test/libc/calls/read_test.c +++ b/test/libc/calls/read_test.c @@ -27,6 +27,22 @@ #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" +char testlib_enable_tmp_setup_teardown; + +TEST(read, eof) { + char b[8] = "hello"; + ASSERT_SYS(0, 3, creat("foo", 0644)); + ASSERT_SYS(0, 4, open("foo", O_RDONLY)); + ASSERT_SYS(0, 0, read(4, b, 8)); + ASSERT_SYS(0, 8, write(3, b, 8)); + ASSERT_SYS(0, 8, read(4, b, 8)); + ASSERT_SYS(0, 0, read(4, b, 8)); + ASSERT_SYS(0, 0, close(4)); + ASSERT_SYS(0, 0, close(3)); +} + +//////////////////////////////////////////////////////////////////////////////// + static long Read(long fd, void *buf, unsigned long size) { long ax, di, si, dx; asm volatile("syscall" diff --git a/test/libc/calls/test.mk b/test/libc/calls/test.mk index 861f419aa..47cfc25f8 100644 --- a/test/libc/calls/test.mk +++ b/test/libc/calls/test.mk @@ -120,6 +120,9 @@ o/$(MODE)/test/libc/calls/lock_test.com.runs: \ o/$(MODE)/test/libc/calls/openbsd_test.com.runs: \ private .PLEDGE = stdio rpath wpath cpath fattr proc unveil +o/$(MODE)/test/libc/calls/read_test.com.runs: \ + private .UNVEIL += /dev/zero + # TODO(jart): Update nointernet() to allow AF_INET6 o/$(MODE)/test/libc/calls/pledge_test.com.runs: \ private .INTERNET = 1 diff --git a/test/libc/runtime/exit_test.c b/test/libc/runtime/exit_test.c new file mode 100644 index 000000000..085783a91 --- /dev/null +++ b/test/libc/runtime/exit_test.c @@ -0,0 +1,62 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/runtime/runtime.h" +#include "libc/testlib/subprocess.h" +#include "libc/testlib/testlib.h" + +int i, *p; + +void SetUp(void) { + p = _mapshared(FRAMESIZE); +} + +void TearDown(void) { + munmap(p, FRAMESIZE); +} + +void AtExit3(void) { + p[i++] = 3; +} + +void AtExit2(void) { + p[i++] = 2; + exit(2); +} + +void AtExit1(void) { + p[i++] = 1; + atexit(AtExit2); + exit(1); +} + +// consistent with glibc, musl, freebsd, openbsd & netbsd +// please note posix says recursion is undefined behavior +// however, fifo ordering of atexit handlers is specified +TEST(exit, test) { + SPAWN(fork); + atexit(AtExit3); + atexit(AtExit3); + atexit(AtExit1); + exit(0); + EXITS(2); + ASSERT_EQ(1, p[0]); + ASSERT_EQ(2, p[1]); + ASSERT_EQ(3, p[2]); + ASSERT_EQ(3, p[3]); +} diff --git a/test/libc/stdio/fread_test.c b/test/libc/stdio/fread_test.c new file mode 100644 index 000000000..b82ad97a0 --- /dev/null +++ b/test/libc/stdio/fread_test.c @@ -0,0 +1,60 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/stdio/stdio.h" +#include "libc/testlib/testlib.h" + +char testlib_enable_tmp_setup_teardown; + +TEST(fread, eofIsSticky) { + FILE *fo, *fi; + char b[10] = "hello"; + ASSERT_NE(NULL, (fo = fopen("foo", "w"))); + ASSERT_NE(NULL, (fi = fopen("foo", "r"))); + ASSERT_EQ(0, fread(b, 1, 8, fi)); + ASSERT_TRUE(feof(fi)); + ASSERT_EQ(8, fwrite(b, 1, 8, fo)); + ASSERT_EQ(0, fflush(fo)); + ASSERT_EQ(0, fread(b, 1, 8, fi)); + ASSERT_TRUE(feof(fi)); + clearerr(fi); + ASSERT_EQ(8, fread(b, 1, 10, fi)); + ASSERT_TRUE(feof(fi)); + ASSERT_EQ(0, fseek(fi, 0, SEEK_SET)); + ASSERT_FALSE(feof(fi)); + ASSERT_EQ(0, fclose(fi)); + ASSERT_EQ(0, fclose(fo)); +} + +TEST(fread, seekWithBuffer) { + FILE *f; + char b[8] = "hellosup"; + char c[8] = {0}; + char d[8] = {0}; + ASSERT_NE(NULL, (f = fopen("foo", "w"))); + ASSERT_EQ(8, fwrite(b, 1, 8, f)); + ASSERT_EQ(0, fclose(f)); + ASSERT_NE(NULL, (f = fopen("foo", "r"))); + ASSERT_EQ(5, fread(c, 1, 5, f)); + ASSERT_STREQ("hello", c); + ASSERT_EQ(0, fseek(f, 1, SEEK_SET)); + ASSERT_EQ(5, fread(d, 1, 5, f)); + ASSERT_STREQ("ellos", d); + ASSERT_EQ(0, fclose(f)); +} diff --git a/test/libc/stdio/fwrite_test.c b/test/libc/stdio/fwrite_test.c index 5c0717787..beeed09f0 100644 --- a/test/libc/stdio/fwrite_test.c +++ b/test/libc/stdio/fwrite_test.c @@ -20,10 +20,10 @@ #include "libc/calls/struct/sigaction.h" #include "libc/dce.h" #include "libc/errno.h" -#include "libc/mem/mem.h" -#include "libc/stdio/rand.h" #include "libc/mem/gc.internal.h" +#include "libc/mem/mem.h" #include "libc/runtime/runtime.h" +#include "libc/stdio/rand.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/sig.h" @@ -39,6 +39,10 @@ char testlib_enable_tmp_setup_teardown; TEST(fwrite, test) { ASSERT_NE(NULL, (f = fopen(PATH, "wb"))); EXPECT_EQ(-1, fgetc(f)); + ASSERT_FALSE(feof(f)); + ASSERT_EQ(EBADF, errno); + ASSERT_EQ(EBADF, ferror(f)); + clearerr(f); EXPECT_EQ(5, fwrite("hello", 1, 5, f)); EXPECT_EQ(5, ftell(f)); EXPECT_NE(-1, fclose(f)); @@ -60,6 +64,7 @@ TEST(fwrite, testSmallBuffer) { ASSERT_NE(NULL, (f = fopen(PATH, "wb"))); setbuffer(f, gc(malloc(1)), 1); EXPECT_EQ(-1, fgetc(f)); + clearerr(f); EXPECT_EQ(5, fwrite("hello", 1, 5, f)); EXPECT_EQ(5, ftell(f)); EXPECT_NE(-1, fclose(f)); @@ -84,6 +89,7 @@ TEST(fwrite, testLineBuffer) { ASSERT_NE(NULL, (f = fopen(PATH, "wb"))); setvbuf(f, NULL, _IOLBF, 64); EXPECT_EQ(-1, fgetc(f)); + clearerr(f); EXPECT_EQ(5, fwrite("heyy\n", 1, 5, f)); EXPECT_EQ(0, fread(buf, 0, 0, f)); EXPECT_FALSE(feof(f)); @@ -112,6 +118,7 @@ TEST(fwrite, testNoBuffer) { ASSERT_NE(NULL, (f = fopen(PATH, "wb"))); setvbuf(f, NULL, _IONBF, 64); EXPECT_EQ(-1, fgetc(f)); + clearerr(f); EXPECT_EQ(5, fwrite("heyy\n", 1, 5, f)); EXPECT_EQ(5, ftell(f)); EXPECT_NE(-1, fclose(f)); diff --git a/third_party/dlmalloc/dlmalloc.c b/third_party/dlmalloc/dlmalloc.c index bd8a58499..061301f1c 100644 --- a/third_party/dlmalloc/dlmalloc.c +++ b/third_party/dlmalloc/dlmalloc.c @@ -28,17 +28,20 @@ #define USE_LOCKS 2 #define MORECORE_CONTIGUOUS 0 #define MALLOC_INSPECT_ALL 1 +#define ABORT_ON_ASSERT_FAILURE 0 #if IsTiny() #define INSECURE 1 #define PROCEED_ON_ERROR 1 -#define ABORT_ON_ASSERT_FAILURE 0 #endif #if IsModeDbg() #define DEBUG 1 #endif +#undef assert +#define assert(x) _npassert(x) + #include "third_party/dlmalloc/platform.inc" #include "third_party/dlmalloc/locks.inc" #include "third_party/dlmalloc/chunks.inc" diff --git a/third_party/dlmalloc/platform.inc b/third_party/dlmalloc/platform.inc index d5c57893c..355d68eba 100644 --- a/third_party/dlmalloc/platform.inc +++ b/third_party/dlmalloc/platform.inc @@ -200,10 +200,6 @@ #endif /* LACKS_ERRNO_H */ #ifdef DEBUG #if ABORT_ON_ASSERT_FAILURE -#undef assert -#define assert(x) if(!(x)) ABORT -#else /* ABORT_ON_ASSERT_FAILURE */ -#include #endif /* ABORT_ON_ASSERT_FAILURE */ #else /* DEBUG */ #ifndef assert diff --git a/third_party/double-conversion/README.cosmo b/third_party/double-conversion/README.cosmo index f33a8066e..1d8a81cfd 100644 --- a/third_party/double-conversion/README.cosmo +++ b/third_party/double-conversion/README.cosmo @@ -11,3 +11,7 @@ ORIGIN LICENSE BSD 3-Clause License + +LOCAL CHANGES + + - Use _unassert() macro for undefined behavior on failed assertions diff --git a/third_party/double-conversion/double-conversion.mk b/third_party/double-conversion/double-conversion.mk index 358641f72..abaff4aa8 100644 --- a/third_party/double-conversion/double-conversion.mk +++ b/third_party/double-conversion/double-conversion.mk @@ -28,6 +28,8 @@ THIRD_PARTY_DOUBLECONVERSION_TEST_BINS = \ $(THIRD_PARTY_DOUBLECONVERSION_TEST_COMS) \ $(THIRD_PARTY_DOUBLECONVERSION_TEST_COMS:%=%.dbg) +THIRD_PARTY_DOUBLECONVERSION_ARTIFACTS += THIRD_PARTY_DOUBLECONVERSION_TEST_A + THIRD_PARTY_DOUBLECONVERSION_TEST_A_SRCS_CC = \ third_party/double-conversion/test/cctest.cc \ third_party/double-conversion/test/gay-fixed.cc \ @@ -52,6 +54,10 @@ THIRD_PARTY_DOUBLECONVERSION_TEST_A_HDRS = \ third_party/double-conversion/test/gay-shortest.h \ third_party/double-conversion/test/gay-shortest-single.h +THIRD_PARTY_DOUBLECONVERSION_TEST_A_SRCS = \ + $(THIRD_PARTY_DOUBLECONVERSION_TEST_A_SRCS_C) \ + $(THIRD_PARTY_DOUBLECONVERSION_TEST_A_SRCS_CC) + THIRD_PARTY_DOUBLECONVERSION_A_OBJS = \ $(THIRD_PARTY_DOUBLECONVERSION_A_SRCS_C:%.c=o/$(MODE)/%.o) \ $(THIRD_PARTY_DOUBLECONVERSION_A_SRCS_CC:%.cc=o/$(MODE)/%.o) diff --git a/third_party/double-conversion/test/cctest.cc b/third_party/double-conversion/test/cctest.cc index f1b333005..eaa696bf7 100644 --- a/third_party/double-conversion/test/cctest.cc +++ b/third_party/double-conversion/test/cctest.cc @@ -24,9 +24,6 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "libc/isystem/stdio.h" -#include "libc/isystem/stdlib.h" -#include "libc/isystem/string.h" #include "third_party/double-conversion/test/cctest.h" // clang-format off diff --git a/third_party/double-conversion/test/cctest.h b/third_party/double-conversion/test/cctest.h index 65dce0c22..a77473a36 100644 --- a/third_party/double-conversion/test/cctest.h +++ b/third_party/double-conversion/test/cctest.h @@ -26,8 +26,6 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef CCTEST_H_ #define CCTEST_H_ -#include "libc/isystem/stdio.h" -#include "libc/isystem/string.h" #include "third_party/double-conversion/utils.h" // clang-format off diff --git a/third_party/double-conversion/test/checks.h b/third_party/double-conversion/test/checks.h index cd0923de5..cbf90a43b 100644 --- a/third_party/double-conversion/test/checks.h +++ b/third_party/double-conversion/test/checks.h @@ -26,7 +26,6 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef V8_CHECKS_H_ #define V8_CHECKS_H_ -#include "libc/isystem/string.h" #include "third_party/double-conversion/test/flags.h" // clang-format off diff --git a/third_party/double-conversion/test/test-bignum-dtoa.cc b/third_party/double-conversion/test/test-bignum-dtoa.cc index ce14d0b54..0877a6d83 100644 --- a/third_party/double-conversion/test/test-bignum-dtoa.cc +++ b/third_party/double-conversion/test/test-bignum-dtoa.cc @@ -24,7 +24,6 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "libc/isystem/stdlib.h" #include "third_party/double-conversion/bignum-dtoa.h" #include "third_party/double-conversion/ieee.h" #include "third_party/double-conversion/test/cctest.h" diff --git a/third_party/double-conversion/test/test-bignum.cc b/third_party/double-conversion/test/test-bignum.cc index 443d30bb2..3b2642137 100644 --- a/third_party/double-conversion/test/test-bignum.cc +++ b/third_party/double-conversion/test/test-bignum.cc @@ -24,8 +24,6 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "libc/isystem/stdlib.h" -#include "libc/isystem/string.h" #include "third_party/double-conversion/bignum.h" #include "third_party/double-conversion/test/cctest.h" #include "third_party/double-conversion/utils.h" diff --git a/third_party/double-conversion/test/test-conversions.cc b/third_party/double-conversion/test/test-conversions.cc index a4e809ea4..9d229d71a 100644 --- a/third_party/double-conversion/test/test-conversions.cc +++ b/third_party/double-conversion/test/test-conversions.cc @@ -24,7 +24,6 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "libc/isystem/string.h" #include "third_party/double-conversion/double-conversion.h" #include "third_party/double-conversion/ieee.h" #include "third_party/double-conversion/test/cctest.h" diff --git a/third_party/double-conversion/test/test-diy-fp.cc b/third_party/double-conversion/test/test-diy-fp.cc index 27e90b094..3706e0e3c 100644 --- a/third_party/double-conversion/test/test-diy-fp.cc +++ b/third_party/double-conversion/test/test-diy-fp.cc @@ -24,7 +24,6 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "libc/isystem/stdlib.h" #include "third_party/double-conversion/diy-fp.h" #include "third_party/double-conversion/test/cctest.h" #include "third_party/double-conversion/utils.h" diff --git a/third_party/double-conversion/test/test-dtoa.cc b/third_party/double-conversion/test/test-dtoa.cc index 613dc3383..d8e7a6eac 100644 --- a/third_party/double-conversion/test/test-dtoa.cc +++ b/third_party/double-conversion/test/test-dtoa.cc @@ -24,7 +24,6 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "libc/isystem/stdlib.h" #include "third_party/double-conversion/double-conversion.h" #include "third_party/double-conversion/ieee.h" #include "third_party/double-conversion/test/cctest.h" diff --git a/third_party/double-conversion/test/test-fast-dtoa.cc b/third_party/double-conversion/test/test-fast-dtoa.cc index 19e17182c..9ad949e5e 100644 --- a/third_party/double-conversion/test/test-fast-dtoa.cc +++ b/third_party/double-conversion/test/test-fast-dtoa.cc @@ -24,7 +24,6 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "libc/isystem/stdlib.h" #include "third_party/double-conversion/diy-fp.h" #include "third_party/double-conversion/fast-dtoa.h" #include "third_party/double-conversion/ieee.h" diff --git a/third_party/double-conversion/test/test-fixed-dtoa.cc b/third_party/double-conversion/test/test-fixed-dtoa.cc index 785bed87b..cc6178186 100644 --- a/third_party/double-conversion/test/test-fixed-dtoa.cc +++ b/third_party/double-conversion/test/test-fixed-dtoa.cc @@ -24,7 +24,6 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "libc/isystem/stdlib.h" #include "third_party/double-conversion/fixed-dtoa.h" #include "third_party/double-conversion/ieee.h" #include "third_party/double-conversion/test/cctest.h" diff --git a/third_party/double-conversion/test/test-ieee.cc b/third_party/double-conversion/test/test-ieee.cc index 142915a76..5c6700fd9 100644 --- a/third_party/double-conversion/test/test-ieee.cc +++ b/third_party/double-conversion/test/test-ieee.cc @@ -24,7 +24,6 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "libc/isystem/stdlib.h" #include "third_party/double-conversion/diy-fp.h" #include "third_party/double-conversion/ieee.h" #include "third_party/double-conversion/test/cctest.h" diff --git a/third_party/double-conversion/test/test-strtod.cc b/third_party/double-conversion/test/test-strtod.cc index 94a92bc83..35e0bee45 100644 --- a/third_party/double-conversion/test/test-strtod.cc +++ b/third_party/double-conversion/test/test-strtod.cc @@ -24,7 +24,6 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "libc/isystem/stdlib.h" #include "third_party/double-conversion/bignum.h" #include "third_party/double-conversion/diy-fp.h" #include "third_party/double-conversion/ieee.h" diff --git a/third_party/double-conversion/utils.h b/third_party/double-conversion/utils.h index 85d7c47ca..9f3936dac 100644 --- a/third_party/double-conversion/utils.h +++ b/third_party/double-conversion/utils.h @@ -9,7 +9,11 @@ #include "third_party/libcxx/cstring" // clang-format off +// [jart] use undefined behaavior to make code tinier +// use ubsan build mode to troubleshoot errors +#define DOUBLE_CONVERSION_ASSERT(x) _unassert(x) #define DOUBLE_CONVERSION_UNREACHABLE() unreachable +#define DOUBLE_CONVERSION_UNIMPLEMENTED() notpossible // Use DOUBLE_CONVERSION_NON_PREFIXED_MACROS to get unprefixed macros as was // the case in double-conversion releases prior to 3.1.6 diff --git a/third_party/linenoise/linenoise.c b/third_party/linenoise/linenoise.c index f98e33a36..18e392d9a 100644 --- a/third_party/linenoise/linenoise.c +++ b/third_party/linenoise/linenoise.c @@ -588,7 +588,7 @@ static size_t GetMonospaceWidth(const char *p, size_t n, char *out_haswides) { } break; default: - assert(0); + unreachable; } } if (out_haswides) { @@ -1558,7 +1558,7 @@ static void linenoiseEditTranspose(struct linenoiseState *l) { p = q = malloc(c - a); p = mempcpy(p, l->buf + b, c - b); p = mempcpy(p, l->buf + a, b - a); - assert(p - q == c - a); + _unassert(p - q == c - a); memcpy(l->buf + a, q, p - q); l->pos = c; free(q); @@ -1579,7 +1579,7 @@ static void linenoiseEditTransposeWords(struct linenoiseState *l) { p = mempcpy(p, l->buf + yi, yj - yi); p = mempcpy(p, l->buf + xj, yi - xj); p = mempcpy(p, l->buf + xi, xj - xi); - assert(p - q == yj - xi); + _unassert(p - q == yj - xi); memcpy(l->buf + xi, q, p - q); l->pos = yj; free(q); diff --git a/third_party/lua/lauxlib.h b/third_party/lua/lauxlib.h index 859fe28de..062726617 100644 --- a/third_party/lua/lauxlib.h +++ b/third_party/lua/lauxlib.h @@ -1,5 +1,6 @@ #ifndef lauxlib_h #define lauxlib_h +#include "libc/assert.h" #include "libc/stdio/stdio.h" #include "third_party/lua/lua.h" #include "third_party/lua/luaconf.h" @@ -156,10 +157,9 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, #if !defined(lua_assert) #if defined LUAI_ASSERT - #include #define lua_assert(c) assert(c) #else - #define lua_assert(c) ((void)0) + #define lua_assert(c) _unassert(c) #endif #endif diff --git a/third_party/lua/lua.mk b/third_party/lua/lua.mk index fa98200da..45694a40c 100644 --- a/third_party/lua/lua.mk +++ b/third_party/lua/lua.mk @@ -250,7 +250,7 @@ o/$(MODE)/third_party/lua/lua.com.dbg: \ $(APE_NO_MODIFY_SELF) @$(APELINK) -o/$(MODE)/third_party/lua/lua.com: \ +o/$(MODE)/third_party/lua/lua2.com: \ o/$(MODE)/third_party/lua/lua.com.dbg \ o/$(MODE)/third_party/zip/zip.com \ o/$(MODE)/tool/build/symtab.com diff --git a/third_party/maxmind/maxminddb.c b/third_party/maxmind/maxminddb.c index 04d3df90c..900436956 100644 --- a/third_party/maxmind/maxminddb.c +++ b/third_party/maxmind/maxminddb.c @@ -16,13 +16,13 @@ │ limitations under the License. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" -#include "libc/intrin/bits.h" #include "libc/calls/calls.h" #include "libc/calls/struct/stat.h" #include "libc/calls/weirdtypes.h" #include "libc/errno.h" #include "libc/fmt/conv.h" #include "libc/fmt/fmt.h" +#include "libc/intrin/bits.h" #include "libc/inttypes.h" #include "libc/limits.h" #include "libc/mem/mem.h" @@ -686,7 +686,7 @@ static record_info_s record_info_for_database(const MMDB_s *const mmdb) { record_info.right_record_getter = &get_uint32; record_info.right_record_offset = 4; } else { - assert(false); + unreachable; } return record_info; } diff --git a/third_party/mbedtls/bignum.c b/third_party/mbedtls/bignum.c index 71f11a2ad..a682d977d 100644 --- a/third_party/mbedtls/bignum.c +++ b/third_party/mbedtls/bignum.c @@ -15,14 +15,10 @@ │ See the License for the specific language governing permissions and │ │ limitations under the License. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" #include "libc/intrin/bits.h" -#include "libc/intrin/bswap.h" -#include "libc/log/backtrace.internal.h" -#include "libc/log/check.h" -#include "libc/log/log.h" -#include "libc/macros.internal.h" #include "libc/intrin/bsf.h" +#include "libc/intrin/bswap.h" +#include "libc/macros.internal.h" #include "libc/nexgen32e/nexgen32e.h" #include "libc/nexgen32e/x86feature.h" #include "libc/runtime/runtime.h" diff --git a/third_party/mbedtls/bigshift.c b/third_party/mbedtls/bigshift.c index caf563274..ae7d34fc2 100644 --- a/third_party/mbedtls/bigshift.c +++ b/third_party/mbedtls/bigshift.c @@ -15,8 +15,6 @@ │ See the License for the specific language governing permissions and │ │ limitations under the License. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/log/log.h" #include "libc/macros.internal.h" #include "libc/str/str.h" #include "third_party/mbedtls/bignum.h" diff --git a/third_party/mbedtls/ecp256.c b/third_party/mbedtls/ecp256.c index b79c11cbb..f26047134 100644 --- a/third_party/mbedtls/ecp256.c +++ b/third_party/mbedtls/ecp256.c @@ -16,10 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/log/check.h" #include "libc/nexgen32e/x86feature.h" -#include "libc/mem/gc.internal.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "third_party/mbedtls/bignum_internal.h" @@ -261,7 +258,7 @@ mbedtls_p256_add( uint64_t X[5], ADC( X[3], A[3], B[3], c, X[4] ); #endif mbedtls_p256_rum( X ); - DCHECK_EQ( 0, X[4] ); + MBEDTLS_ASSERT( 0 == X[4] ); } static void @@ -298,7 +295,7 @@ mbedtls_p256_sub( uint64_t X[5], #endif while( (int64_t)X[4] < 0 ) mbedtls_p256_gro( X ); - DCHECK_EQ( 0, X[4] ); + MBEDTLS_ASSERT( 0 == X[4] ); } static void @@ -322,7 +319,7 @@ mbedtls_p256_hub( uint64_t A[5], : "rax", "rcx", "memory", "cc"); while( (int64_t)A[4] < 0 ) mbedtls_p256_gro( A ); - DCHECK_EQ( 0, A[4] ); + MBEDTLS_ASSERT( 0 == A[4] ); #else mbedtls_p256_sub( A, A, B ); #endif @@ -368,9 +365,9 @@ int mbedtls_p256_double_jac( const mbedtls_ecp_group *G, s.Xn = mbedtls_mpi_limbs( &P->X ); s.Yn = mbedtls_mpi_limbs( &P->Y ); s.Zn = mbedtls_mpi_limbs( &P->Z ); - CHECK_LE( s.Xn, 4 ); - CHECK_LE( s.Yn, 4 ); - CHECK_LE( s.Zn, 4 ); + MBEDTLS_ASSERT( s.Xn <= 4 ); + MBEDTLS_ASSERT( s.Yn <= 4 ); + MBEDTLS_ASSERT( s.Zn <= 4 ); memcpy( s.X, P->X.p, s.Xn * 8 ); memcpy( s.Y, P->Y.p, s.Yn * 8 ); memcpy( s.Z, P->Z.p, s.Zn * 8 ); @@ -424,11 +421,11 @@ int mbedtls_p256_add_mixed( const mbedtls_ecp_group *G, s.Zn = mbedtls_mpi_limbs( &P->Z ); s.QXn = mbedtls_mpi_limbs( &Q->X ); s.QYn = mbedtls_mpi_limbs( &Q->Y ); - CHECK_LE( s.Xn, 4 ); - CHECK_LE( s.Yn, 4 ); - CHECK_LE( s.Zn, 4 ); - CHECK_LE( s.QXn, 4 ); - CHECK_LE( s.QYn, 4 ); + MBEDTLS_ASSERT( s.Xn <= 4 ); + MBEDTLS_ASSERT( s.Yn <= 4 ); + MBEDTLS_ASSERT( s.Zn <= 4 ); + MBEDTLS_ASSERT( s.QXn <= 4 ); + MBEDTLS_ASSERT( s.QYn <= 4 ); memcpy( s.X, P->X.p, s.Xn * 8 ); memcpy( s.Y, P->Y.p, s.Yn * 8 ); memcpy( s.Z, P->Z.p, s.Zn * 8 ); diff --git a/third_party/mbedtls/ecp384.c b/third_party/mbedtls/ecp384.c index 5a1da4354..368c0dceb 100644 --- a/third_party/mbedtls/ecp384.c +++ b/third_party/mbedtls/ecp384.c @@ -16,11 +16,9 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/dce.h" #include "libc/intrin/asan.internal.h" -#include "libc/log/check.h" +#include "libc/mem/gc.h" #include "libc/nexgen32e/x86feature.h" -#include "libc/mem/gc.internal.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "third_party/mbedtls/bignum_internal.h" @@ -189,8 +187,8 @@ mbedtls_p384_mul( uint64_t X[12], } else { - if( A == X ) A = gc( memcpy( malloc( 6 * 8 ), A, 6 * 8 ) ); - if( B == X ) B = gc( memcpy( malloc( 6 * 8 ), B, 6 * 8 ) ); + if( A == X ) A = _gc( memcpy( malloc( 6 * 8 ), A, 6 * 8 ) ); + if( B == X ) B = _gc( memcpy( malloc( 6 * 8 ), B, 6 * 8 ) ); Mul( X, A, n, B, m ); mbedtls_platform_zeroize( X + n + m, (12 - n - m) * 8 ); } @@ -305,7 +303,7 @@ mbedtls_p384_add( uint64_t X[7], ADC( X[5], A[5], B[5], c, X[6] ); #endif mbedtls_p384_rum( X ); - DCHECK_EQ(0, X[6]); + MBEDTLS_ASSERT(0 == X[6]); } static void @@ -350,7 +348,7 @@ mbedtls_p384_sub( uint64_t X[7], #endif while( (int64_t)X[6] < 0 ) mbedtls_p384_gro( X ); - DCHECK_EQ(0, X[6]); + MBEDTLS_ASSERT(0 == X[6]); } static void @@ -378,7 +376,7 @@ mbedtls_p384_hub( uint64_t A[7], : "rax", "rcx", "memory", "cc"); while( (int64_t)A[6] < 0 ) mbedtls_p384_gro( A ); - DCHECK_EQ(0, A[6]); + MBEDTLS_ASSERT(0 == A[6]); #else mbedtls_p384_sub(A, A, B); #endif @@ -460,11 +458,11 @@ int mbedtls_p384_add_mixed( const mbedtls_ecp_group *G, s.Zn = mbedtls_mpi_limbs( &P->Z ); s.QXn = mbedtls_mpi_limbs( &Q->X ); s.QYn = mbedtls_mpi_limbs( &Q->Y ); - CHECK_LE( s.Xn, 6 ); - CHECK_LE( s.Yn, 6 ); - CHECK_LE( s.Zn, 6 ); - CHECK_LE( s.QXn, 6 ); - CHECK_LE( s.QYn, 6 ); + MBEDTLS_ASSERT( s.Xn <= 6 ); + MBEDTLS_ASSERT( s.Yn <= 6 ); + MBEDTLS_ASSERT( s.Zn <= 6 ); + MBEDTLS_ASSERT( s.QXn <= 6 ); + MBEDTLS_ASSERT( s.QYn <= 6 ); memcpy( s.X, P->X.p, s.Xn * 8 ); memcpy( s.Y, P->Y.p, s.Yn * 8 ); memcpy( s.Z, P->Z.p, s.Zn * 8 ); diff --git a/third_party/mbedtls/karatsuba.c b/third_party/mbedtls/karatsuba.c index 8666c998e..c450ecf75 100644 --- a/third_party/mbedtls/karatsuba.c +++ b/third_party/mbedtls/karatsuba.c @@ -16,8 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/log/check.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "third_party/mbedtls/bignum_internal.h" diff --git a/third_party/mbedtls/platform.h b/third_party/mbedtls/platform.h index 81e715895..2a584679d 100644 --- a/third_party/mbedtls/platform.h +++ b/third_party/mbedtls/platform.h @@ -51,7 +51,7 @@ COSMOPOLITAN_C_START_ #define MBEDTLS_ASSERT(EXPR) \ ((void)((EXPR) || (__assert_fail(#EXPR, __FILE__, __LINE__), 0))) #else -#define MBEDTLS_ASSERT(EXPR) (void)0 +#define MBEDTLS_ASSERT(EXPR) _unassert(EXPR) #endif typedef struct mbedtls_platform_context { diff --git a/third_party/mbedtls/test/lib.c b/third_party/mbedtls/test/lib.c index 46d4ea902..545b23d78 100644 --- a/third_party/mbedtls/test/lib.c +++ b/third_party/mbedtls/test/lib.c @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "libc/assert.h" #include "libc/calls/calls.h" #include "libc/dce.h" #include "libc/fmt/conv.h" @@ -77,14 +76,6 @@ jmp_buf jmp_tmp; int option_verbose = 1; mbedtls_test_info_t mbedtls_test_info; -static uint64_t Rando(void) { - static uint64_t x = 0x18abac12f3191aed; - uint64_t z = (x += 0x9e3779b97f4a7c15); - z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; - z = (z ^ (z >> 27)) * 0x94d049bb133111eb; - return z ^ (z >> 31); -} - int mbedtls_test_platform_setup(void) { char *p; int ret = 0; @@ -128,7 +119,7 @@ int mbedtls_hardware_poll(void *wut, unsigned char *p, size_t n, size_t *olen) { size_t i, j; unsigned char b[8]; for (i = 0; i < n; ++i) { - x = Rando(); + x = lemur64(); WRITE64LE(b, x); for (j = 0; j < 8 && i + j < n; ++j) { p[i + j] = b[j]; diff --git a/third_party/regex/regcomp.c b/third_party/regex/regcomp.c index acbacf19e..f6449d56d 100644 --- a/third_party/regex/regcomp.c +++ b/third_party/regex/regcomp.c @@ -334,7 +334,7 @@ static reg_errcode_t tre_stack_push(tre_stack_t *s, if (new_buffer == NULL) { return REG_ESPACE; } - assert(new_size > s->size); + _unassert(new_size > s->size); s->size = new_size; s->stack = new_buffer; tre_stack_push(s, value); @@ -1209,7 +1209,7 @@ static reg_errcode_t tre_add_tags(tre_mem_t mem, tre_stack_t *stack, status = REG_ESPACE; break; } - assert(tnfa->submatch_data[id].parents == NULL); + _unassert(tnfa->submatch_data[id].parents == NULL); tnfa->submatch_data[id].parents = p; for (i = 0; parents[i] >= 0; i++) p[i] = parents[i]; p[i] = -1; @@ -1254,7 +1254,7 @@ static reg_errcode_t tre_add_tags(tre_mem_t mem, tre_stack_t *stack, next_tag++; } } else { - assert(!IS_TAG(lit)); + _unassert(!IS_TAG(lit)); } break; } @@ -1498,8 +1498,7 @@ static reg_errcode_t tre_add_tags(tre_mem_t mem, tre_stack_t *stack, } default: - assert(0); - break; + unreachable; } /* end switch(symbol) */ } /* end while(tre_stack_num_objects(stack) > bottom) */ @@ -1517,7 +1516,7 @@ static reg_errcode_t tre_add_tags(tre_mem_t mem, tre_stack_t *stack, num_minimals++; } - assert(tree->num_tags == num_tags); + _unassert(tree->num_tags == num_tags); tnfa->end_tag = num_tags; tnfa->num_tags = num_tags; tnfa->num_minimals = num_minimals; @@ -1650,8 +1649,7 @@ static reg_errcode_t tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, break; } default: - assert(0); - break; + unreachable; } break; } @@ -1726,8 +1724,7 @@ static reg_errcode_t tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, break; } default: - assert(0); - break; + unreachable; } break; case EXPAND_AFTER_ITER: { @@ -1801,8 +1798,7 @@ static reg_errcode_t tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, break; } default: - assert(0); - break; + unreachable; } } @@ -1958,14 +1954,13 @@ static reg_errcode_t tre_match_empty(tre_stack_t *stack, tre_ast_node_t *node, } break; case ASSERTION: - assert(lit->code_max >= 1 || lit->code_max <= ASSERT_LAST); + _unassert(lit->code_max >= 1 || lit->code_max <= ASSERT_LAST); if (assertions != NULL) *assertions |= lit->code_max; break; case EMPTY: break; default: - assert(0); - break; + unreachable; } break; @@ -1979,14 +1974,14 @@ static reg_errcode_t tre_match_empty(tre_stack_t *stack, tre_ast_node_t *node, else if (uni->right->nullable) STACK_PUSHX(stack, voidptr, uni->right) else - assert(0); + unreachable; break; case CATENATION: /* The path must go through both children. */ cat = (tre_catenation_t *)node->obj; - assert(cat->left->nullable); - assert(cat->right->nullable); + _unassert(cat->left->nullable); + _unassert(cat->right->nullable); STACK_PUSHX(stack, voidptr, cat->left); STACK_PUSHX(stack, voidptr, cat->right); break; @@ -1999,8 +1994,7 @@ static reg_errcode_t tre_match_empty(tre_stack_t *stack, tre_ast_node_t *node, break; default: - assert(0); - break; + unreachable; } } @@ -2188,8 +2182,7 @@ static reg_errcode_t tre_compute_nfl(tre_mem_t mem, tre_stack_t *stack, } default: - assert(0); - break; + unreachable; } } @@ -2252,8 +2245,8 @@ static reg_errcode_t tre_make_trans(tre_pos_and_tags_t *p1, (p1->class ? ASSERT_CHAR_CLASS : 0) | (p1->neg_classes != NULL ? ASSERT_CHAR_CLASS_NEG : 0); if (p1->backref >= 0) { - assert((trans->assertions & ASSERT_CHAR_CLASS) == 0); - assert(p2->backref < 0); + _unassert((trans->assertions & ASSERT_CHAR_CLASS) == 0); + _unassert(p2->backref < 0); trans->u.backref = p1->backref; trans->assertions |= ASSERT_BACKREF; } else @@ -2363,10 +2356,10 @@ static reg_errcode_t tre_ast_to_tnfa(tre_ast_node_t *node, case ITERATION: iter = (tre_iteration_t *)node->obj; - assert(iter->max == -1 || iter->max == 1); + _unassert(iter->max == -1 || iter->max == 1); if (iter->max == -1) { - assert(iter->min == 0 || iter->min == 1); + _unassert(iter->min == 0 || iter->min == 1); /* Add a transition from each last position in the iterated expression to each first position. */ errcode = tre_make_trans(iter->arg->lastpos, iter->arg->firstpos, diff --git a/third_party/regex/regexec.c b/third_party/regex/regexec.c index 2134cde0d..548d70c22 100644 --- a/third_party/regex/regexec.c +++ b/third_party/regex/regexec.c @@ -56,6 +56,7 @@ │ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ │ │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/limits.h" #include "third_party/regex/tre.inc" @@ -393,7 +394,7 @@ static reg_errcode_t tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, reach_next_i++; } else { - assert(reach_pos[trans_i->state_id].pos == pos); + _unassert(reach_pos[trans_i->state_id].pos == pos); /* Another path has also reached this state. We choose the winner by examining the tag values for both paths. */ @@ -520,7 +521,7 @@ typedef struct tre_backtrack_struct { #define BT_STACK_POP() \ do { \ int i; \ - assert(stack->prev); \ + _unassert(stack->prev); \ pos = stack->item.pos; \ str_byte = stack->item.str_byte; \ state = stack->item.state; \ @@ -846,8 +847,8 @@ static void tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags, submatches. */ i = 0; while (i < tnfa->num_submatches && i < nmatch) { - if (pmatch[i].rm_eo == -1) assert(pmatch[i].rm_so == -1); - assert(pmatch[i].rm_so <= pmatch[i].rm_eo); + if (pmatch[i].rm_eo == -1) _unassert(pmatch[i].rm_so == -1); + _unassert(pmatch[i].rm_so <= pmatch[i].rm_eo); parents = submatch_data[i].parents; if (parents != NULL) diff --git a/third_party/zlib/deflate.c b/third_party/zlib/deflate.c index 4b3709ad8..6f2a9b309 100644 --- a/third_party/zlib/deflate.c +++ b/third_party/zlib/deflate.c @@ -5,7 +5,6 @@ * Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ -#include "libc/assert.h" #include "third_party/zlib/deflate.internal.h" #include "third_party/zlib/insert_string.internal.h" #include "third_party/zlib/internal.h" diff --git a/third_party/zlib/zutil.c b/third_party/zlib/zutil.c index f341f74ee..4f28338da 100644 --- a/third_party/zlib/zutil.c +++ b/third_party/zlib/zutil.c @@ -5,7 +5,6 @@ * Copyright (C) 1995-2017 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ -#include "libc/assert.h" #include "libc/intrin/weaken.h" #include "libc/log/log.h" #include "libc/mem/mem.h" @@ -319,8 +318,11 @@ voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) unsigned size; { (void)opaque; - _npassert(_weaken(malloc)); - return _weaken(malloc)(items * size); + if (_weaken(malloc)) { + return _weaken(malloc)(items * size); + } else { + return 0; + } } void ZLIB_INTERNAL zcfree (opaque, ptr) @@ -328,8 +330,9 @@ void ZLIB_INTERNAL zcfree (opaque, ptr) voidpf ptr; { (void)opaque; - _npassert(_weaken(free)); - _weaken(free)(ptr); + if (_weaken(free)) { + _weaken(free)(ptr); + } } #endif /* MY_ZCALLOC */