Fix bugs and make code tinier

- Fixed bug where stdio eof wasn't being sticky
- Fixed bug where fseeko() wasn't clearing eof state
- Removed assert() usage from libc favoring _unassert() / _npassert()
This commit is contained in:
Justine Tunney 2022-10-09 22:38:28 -07:00
parent 9b7c8db846
commit d5910e2673
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
115 changed files with 510 additions and 290 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -181,7 +181,7 @@ skip_readlink:
continue;
}
k = rc;
assert(k <= p);
_npassert(k <= p);
if (k==p)
goto toolong;
if (!k) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,29 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 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;
}

View file

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

View file

@ -26,6 +26,6 @@
* This function may only be called if IsWindows() is true.
*/
privileged bool(IsAtLeastWindows10)(void) {
assert(IsWindows());
_unassert(IsWindows());
return IsAtLeastWindows10();
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 <assert.h>
#endif /* ABORT_ON_ASSERT_FAILURE */
#else /* DEBUG */
#ifndef assert

View file

@ -11,3 +11,7 @@ ORIGIN
LICENSE
BSD 3-Clause License
LOCAL CHANGES
- Use _unassert() macro for undefined behavior on failed assertions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

Some files were not shown because too many files have changed in this diff Show more