Improve memory safety

This commit makes numerous refinements to cosmopolitan memory handling.

The default stack size has been reduced from 2mb to 128kb. A new macro
is now provided so you can easily reconfigure the stack size to be any
value you want. Work around the breaking change by adding to your main:

    STATIC_STACK_SIZE(0x00200000);  // 2mb stack

If you're not sure how much stack you need, then you can use:

    STATIC_YOINK("stack_usage_logging");

After which you can `sort -nr o/$MODE/stack.log`. Based on the unit test
suite, nothing in the Cosmopolitan repository (except for Python) needs
a stack size greater than 30kb. There are also new macros for detecting
the size and address of the stack at runtime, e.g. GetStackAddr(). We
also now support sigaltstack() so if you want to see nice looking crash
reports whenever a stack overflow happens, you can put this in main():

    ShowCrashReports();

Under `make MODE=dbg` and `make MODE=asan` the unit testing framework
will now automatically print backtraces of memory allocations when
things like memory leaks happen. Bugs are now fixed in ASAN global
variable overrun detection. The memtrack and asan runtimes also handle
edge cases now. The new tools helped to identify a few memory leaks,
which are fixed by this change.

This change should fix an issue reported in #288 with ARG_MAX limits.
Fixing this doubled the performance of MKDEPS.COM and AR.COM yet again.
This commit is contained in:
Justine Tunney 2021-10-13 17:27:13 -07:00
parent a0b39f886c
commit 226aaf3547
317 changed files with 6474 additions and 3993 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,53 +1,61 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
#define COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
#include "libc/calls/struct/iovec.h"
#include "libc/macros.internal.h"
#define kAsanScale 3
#define kAsanMagic 0x7fff8000
#define kAsanHeapFree -1 /* F */
#define kAsanStackFree -2 /* F */
#define kAsanRelocated -3 /* R */
#define kAsanHeapUnderrun -4 /* U */
#define kAsanHeapOverrun -5 /* O */
#define kAsanGlobalOverrun -6 /* O */
#define kAsanGlobalUnregistered -7 /* G */
#define kAsanStackUnderrun -8 /* U */
#define kAsanStackOverrun -9 /* O */
#define kAsanAllocaUnderrun -10 /* U */
#define kAsanAllocaOverrun -11 /* O */
#define kAsanUnscoped -12 /* S */
#define kAsanUnmapped -13 /* M */
#define kAsanProtected -14 /* P */
#define kAsanStackGuard -15 /* _ */
#define kAsanNullPage -16
#define kAsanScale 3
#define kAsanMagic 0x7fff8000
#define kAsanNullPage -1 /* ∅ 0xff */
#define kAsanProtected -2 /* P 0xfe */
#define kAsanHeapFree -3 /* F 0xfd */
#define kAsanHeapRelocated -4 /* R 0xfc */
#define kAsanAllocaOverrun -5 /* 𝑂 0xfb */
#define kAsanHeapUnderrun -6 /* U 0xfa */
#define kAsanHeapOverrun -7 /* O 0xf9 */
#define kAsanStackUnscoped -8 /* s 0xf8 */
#define kAsanStackOverflow -9 /* ! 0xf7 */
#define kAsanGlobalOrder -10 /* I 0xf6 */
#define kAsanStackFree -11 /* r 0xf5 */
#define kAsanStackPartial -12 /* p 0xf4 */
#define kAsanStackOverrun -13 /* o 0xf3 */
#define kAsanStackMiddle -14 /* m 0xf2 */
#define kAsanStackUnderrun -15 /* u 0xf1 */
#define kAsanAllocaUnderrun -16 /* 𝑈 0xf0 */
#define kAsanUnmapped -17 /* M 0xef */
#define kAsanGlobalRedzone -18 /* G 0xee */
#define kAsanGlobalGone -19 /* 𝐺 0xed */
#define SHADOW(x) ((signed char *)(((uintptr_t)(x) >> kAsanScale) + kAsanMagic))
#define UNSHADOW(x) ((void *)(((uintptr_t)(x) + 0x7fff8000) << 3))
#define SHADOW(x) ((signed char *)(((intptr_t)(x) >> kAsanScale) + kAsanMagic))
#define UNSHADOW(x) ((void *)(MAX(0, (intptr_t)(x)-kAsanMagic) << kAsanScale))
typedef void __asan_die_f(void);
struct AsanFault {
char kind;
signed char kind;
signed char *shadow;
};
void __asan_unpoison(uintptr_t, size_t);
extern bool __asan_noreentry;
void __asan_unpoison(long, long);
void __asan_poison(long, long, signed char);
void __asan_verify(const void *, size_t);
void __asan_map_shadow(uintptr_t, size_t);
void __asan_poison(uintptr_t, size_t, int);
bool __asan_is_valid(const void *, size_t);
bool __asan_is_valid_strlist(char *const *);
bool __asan_is_valid_iov(const struct iovec *, int);
struct AsanFault __asan_check(const void *, size_t);
void __asan_report_memory_fault(void *, int, const char *) wontreturn;
void __asan_report(void *, int, const char *, char) wontreturn;
void *__asan_memalign(size_t, size_t);
bool __asan_is_valid(const void *, long) nosideeffect;
bool __asan_is_valid_strlist(char *const *) strlenesque;
bool __asan_is_valid_iov(const struct iovec *, int) nosideeffect;
wint_t __asan_symbolize_access_poison(signed char) pureconst;
const char *__asan_describe_access_poison(signed char) pureconst;
struct AsanFault __asan_check(const void *, long) nosideeffect;
void __asan_free(void *);
void *__asan_malloc(size_t);
int __asan_malloc_trim(size_t);
int __asan_print_trace(void *);
void *__asan_calloc(size_t, size_t);
void *__asan_realloc(void *, size_t);
void *__asan_memalign(size_t, size_t);
size_t __asan_get_heap_size(const void *);
void *__asan_realloc_in_place(void *, size_t);
void *__asan_valloc(size_t);
void *__asan_pvalloc(size_t);
int __asan_malloc_trim(size_t);
void __asan_die(const char *) wontreturn;
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ */

33
libc/intrin/atexit.c Normal file
View file

@ -0,0 +1,33 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/runtime/runtime.h"
/**
* Adds global destructor.
*
* Destructors are called in reverse order. They won't be called
* if the program aborts or _exit() is called. Invocations of this
* function are usually generated by the C++ compiler.
*
* @param rdi callback typed void(*)(T) (nullable)
* @return 0 on success or nonzero if out of space
*/
int atexit(void f(void)) {
return __cxa_atexit(f, 0, 0);
}

View file

@ -28,7 +28,7 @@ typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
noasan static noinline antiquity void bzero_sse(char *p, size_t n) {
xmm_t v = {0};
if (IsAsan()) __asan_check(p, n);
if (IsAsan()) __asan_verify(p, n);
if (n <= 32) {
*(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v;
@ -45,7 +45,7 @@ noasan static noinline antiquity void bzero_sse(char *p, size_t n) {
noasan microarchitecture("avx") static void bzero_avx(char *p, size_t n) {
xmm_t v = {0};
if (IsAsan()) __asan_check(p, n);
if (IsAsan()) __asan_verify(p, n);
if (n <= 32) {
*(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v;
@ -134,11 +134,6 @@ void(bzero)(void *p, size_t n) {
char *b;
uint64_t x;
b = p;
if (IsTiny()) {
if (IsAsan()) __asan_check(p, n);
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(0));
return;
}
asm("xorl\t%k0,%k0" : "=r"(x));
if (n <= 16) {
if (n >= 8) {
@ -153,6 +148,9 @@ void(bzero)(void *p, size_t n) {
b[--n] = x;
} while (n);
}
} else if (IsTiny()) {
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(0));
return;
} else if (X86_HAVE(AVX)) {
bzero_avx(b, n);
} else {

67
libc/intrin/cxaatexit.c Normal file
View file

@ -0,0 +1,67 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/runtime/cxaatexit.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
STATIC_YOINK("__cxa_finalize");
/**
* Adds global destructor.
*
* Destructors are called in reverse order. They won't be called if the
* program aborts or _exit() is called. Invocations of this function are
* usually generated by the C++ compiler. Behavior is limitless if some
* other module has linked calloc().
*
* @param fp is void(*)(T)
* @param arg is passed to callback
* @param pred can be non-null for things like dso modules
* @return 0 on success or nonzero w/ errno
* @note folks have forked libc in past just to unbloat atexit()
*/
noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
/* asan runtime depends on this function */
unsigned i;
struct CxaAtexitBlock *b, *b2;
_Static_assert(ATEXIT_MAX == CHAR_BIT * sizeof(b->mask), "");
b = __cxa_blocks.p;
if (!b) b = __cxa_blocks.p = &__cxa_blocks.root;
if (!~b->mask) {
if (weaken(calloc) &&
(b2 = weaken(calloc)(1, sizeof(struct CxaAtexitBlock)))) {
b2->next = b;
__cxa_blocks.p = b = b2;
} else {
return enomem();
}
}
i = bsr(~b->mask);
assert(i < ARRAYLEN(b->p));
b->mask |= 1u << i;
b->p[i].fp = fp;
b->p[i].arg = arg;
b->p[i].pred = pred;
return 0;
}

21
libc/intrin/cxablocks.c Normal file
View file

@ -0,0 +1,21 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/runtime/cxaatexit.internal.h"
struct CxaAtexitBlocks __cxa_blocks;

72
libc/intrin/cxafinalize.c Normal file
View file

@ -0,0 +1,72 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/runtime/cxaatexit.internal.h"
#include "libc/runtime/runtime.h"
/**
* Triggers global destructors.
*
* They're called in LIFO order. If a destructor adds more destructors,
* then those destructors will be called immediately following, before
* iteration continues.
*
* @param pred can be null to match all
*/
void __cxa_finalize(void *pred) {
unsigned i, mask;
struct CxaAtexitBlock *b, *b2;
StartOver:
if ((b = __cxa_blocks.p)) {
for (;;) {
mask = b->mask;
while (mask) {
i = bsf(mask);
mask &= ~(1u << i);
if (!pred || pred == b->p[i].pred) {
b->mask &= ~(1u << i);
if (b->p[i].fp) {
((void (*)(void *))b->p[i].fp)(b->p[i].arg);
goto StartOver;
}
}
}
if (!pred) {
b2 = b->next;
if (b2) {
assert(b != &__cxa_blocks.root);
if (weaken(free)) {
weaken(free)(b);
}
}
__cxa_blocks.p = b2;
goto StartOver;
} else {
if (b->next) {
b = b->next;
} else {
break;
}
}
}
}
}

53
libc/intrin/exit.c Normal file
View file

@ -0,0 +1,53 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/nexgen32e/vendor.internal.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/sysv/consts/nr.h"
extern void(__msabi* __imp_ExitProcess)(uint32_t);
/**
* Terminates process, ignoring destructors and atexit() handlers.
*
* When running on bare metal, this function will reboot your computer
* by hosing the interrupt descriptors and triple faulting the system.
*
* @param exitcode is masked with 255
* @asyncsignalsafe
* @vforksafe
* @noreturn
*/
privileged noinstrument noasan noubsan wontreturn void _Exit(int exitcode) {
if ((!IsWindows() && !IsMetal()) || (IsMetal() && IsGenuineCosmo())) {
asm volatile("syscall"
: /* no outputs */
: "a"(__NR_exit_group), "D"(exitcode)
: "memory");
} else if (IsWindows()) {
__imp_ExitProcess(exitcode & 0xff);
}
asm("push\t$0\n\t"
"push\t$0\n\t"
"cli\n\t"
"lidt\t(%rsp)");
for (;;) asm("ud2");
}

View file

@ -41,12 +41,27 @@ $(LIBC_INTRIN_A).pkg: \
$(LIBC_INTRIN_A_OBJS) \
$(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x)_A).pkg)
$(LIBC_INTRIN_A_OBJS): \
OVERRIDE_CFLAGS += \
-foptimize-sibling-calls
o/$(MODE)/libc/intrin/asan.o \
o/$(MODE)/libc/intrin/ubsan.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all \
-fno-stack-protector \
-O3
-fno-stack-protector
o/$(MODE)/libc/intrin/asan.o: \
OVERRIDE_CFLAGS += \
-O2 \
-finline \
-finline-functions
o/$(MODE)/libc/intrin/asan.o \
o/$(MODE)/libc/intrin/ubsan.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all \
-fno-stack-protector
o/$(MODE)/libc/intrin/memcmp.o: \
OVERRIDE_CFLAGS += \
@ -63,12 +78,18 @@ o//libc/intrin/memmove.o: \
OVERRIDE_CFLAGS += \
-O3
o/tiny/libc/intrin/memcmp.o \
o/tiny/libc/intrin/memmove.o \
o/tiny/libc/intrin/memmove-gcc.asm: \
o/$(MODE)/libc/intrin/bzero.o \
o/$(MODE)/libc/intrin/memcmp.o \
o/$(MODE)/libc/intrin/memmove.o: \
OVERRIDE_CFLAGS += \
-fpie
o/$(MODE)/libc/intrin/printf.o: \
OVERRIDE_CFLAGS += \
-Os \
-fpie \
-mgeneral-regs-only
LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)))
LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS))
LIBC_INTRIN_SRCS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_SRCS))

View file

@ -0,0 +1,58 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/vendor.internal.h"
#include "libc/nt/struct/teb.h"
#include "libc/sysv/consts/o.h"
#define kBufSize 1024
#define kPid "TracerPid:\t"
/**
* Determines if gdb, strace, windbg, etc. is controlling process.
* @return non-zero if attached, otherwise 0
*/
noasan noubsan int IsDebuggerPresent(bool force) {
/* asan runtime depends on this function */
int fd, res;
ssize_t got;
char *p, buf[1024];
if (!force) {
if (IsGenuineCosmo()) return 0;
if (__getenv(__envp, "HEISENDEBUG")) return 0;
}
if (IsWindows()) {
return NtGetPeb()->BeingDebugged; /* needs noasan */
} else {
res = 0;
if ((fd = __sysv_open("/proc/self/status", O_RDONLY, 0)) >= 0) {
if ((got = __sysv_read(fd, buf, sizeof(buf) - 1)) > 0) {
buf[got] = '\0';
if ((p = __strstr(buf, kPid))) {
p += sizeof(kPid) - 1;
res = __atoul(p);
}
}
__sysv_close(fd);
}
return res;
}
}

View file

@ -0,0 +1,40 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
bool g_isrunningundermake;
/**
* Returns true if current process was spawned by GNU Make.
*/
bool IsRunningUnderMake(void) {
return g_isrunningundermake;
}
textstartup void g_isrunningundermake_init(int argc, char **argv, char **envp,
intptr_t *auxv) {
g_isrunningundermake = !!__getenv(envp, "MAKEFLAGS");
}
const void *const g_isrunningundermake_ctor[] initarray = {
g_isrunningundermake_init,
};

View file

@ -0,0 +1,46 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/safemacros.internal.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/nt/enum/version.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
bool g_isterminalinarticulate;
bool IsTerminalInarticulate(void) {
return g_isterminalinarticulate;
}
textstartup noasan void g_isterminalinarticulate_init(int argc, char **argv,
char **envp,
intptr_t *auxv) {
char *s;
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
g_isterminalinarticulate = true;
} else if ((s = __getenv(envp, "TERM"))) {
g_isterminalinarticulate = !__strcmp(s, "dumb");
}
}
const void *const g_isterminalinarticulate_ctor[] initarray = {
g_isterminalinarticulate_init,
};

View file

@ -21,6 +21,8 @@
#include "libc/nexgen32e/x86feature.h"
#include "libc/str/str.h"
#define PMOVMSKB(x) __builtin_ia32_pmovmskb128(x)
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
static noinline antiquity int memcmp_sse(const unsigned char *p,
@ -29,9 +31,7 @@ static noinline antiquity int memcmp_sse(const unsigned char *p,
unsigned u, u0, u1, u2, u3;
if (n > 32) {
while (n > 16 + 16) {
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p ==
*(const xmm_t *)q) -
0xffff)) {
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
n -= 16;
p += 16;
q += 16;
@ -41,10 +41,8 @@ static noinline antiquity int memcmp_sse(const unsigned char *p,
}
}
}
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p == *(const xmm_t *)q) -
0xffff)) {
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)(p + n - 16) ==
*(const xmm_t *)(q + n - 16)) -
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
if (!(u = PMOVMSKB(*(xmm_t *)(p + n - 16) == *(xmm_t *)(q + n - 16)) ^
0xffff)) {
return 0;
} else {
@ -61,19 +59,13 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
const unsigned char *q,
size_t n) {
uint64_t w;
unsigned u, u0, u1, u2, u3;
unsigned u;
if (n > 32) {
while (n >= 16 + 64) {
u0 = __builtin_ia32_pmovmskb128(
(((const xmm_t *)p)[0] == ((const xmm_t *)q)[0]));
u1 = __builtin_ia32_pmovmskb128(
(((const xmm_t *)p)[1] == ((const xmm_t *)q)[1]));
u2 = __builtin_ia32_pmovmskb128(
(((const xmm_t *)p)[2] == ((const xmm_t *)q)[2]));
u3 = __builtin_ia32_pmovmskb128(
(((const xmm_t *)p)[3] == ((const xmm_t *)q)[3]));
w = (uint64_t)u0 | (uint64_t)u1 << 16 | (uint64_t)u2 << 32 |
(uint64_t)u3 << 48;
w = (uint64_t)PMOVMSKB(((xmm_t *)p)[0] == ((xmm_t *)q)[0]) << 000 |
(uint64_t)PMOVMSKB(((xmm_t *)p)[1] == ((xmm_t *)q)[1]) << 020 |
(uint64_t)PMOVMSKB(((xmm_t *)p)[2] == ((xmm_t *)q)[2]) << 040 |
(uint64_t)PMOVMSKB(((xmm_t *)p)[3] == ((xmm_t *)q)[3]) << 060;
if (w == -1) {
n -= 64;
p += 64;
@ -84,9 +76,7 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
}
}
while (n > 16 + 16) {
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p ==
*(const xmm_t *)q) -
0xffff)) {
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
n -= 16;
p += 16;
q += 16;
@ -96,10 +86,8 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
}
}
}
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p == *(const xmm_t *)q) -
0xffff)) {
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)(p + n - 16) ==
*(const xmm_t *)(q + n - 16)) -
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
if (!(u = PMOVMSKB(*(xmm_t *)(p + n - 16) == *(xmm_t *)(q + n - 16)) ^
0xffff)) {
return 0;
} else {

View file

@ -26,9 +26,6 @@
typedef long long xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
asm("memcpy = memmove\n\t"
".globl\tmemcpy");
/**
* Copies memory.
*
@ -120,8 +117,6 @@ void *memmove(void *dst, const void *src, size_t n) {
*d = *s;
}
} else {
if (IsAsan()) __asan_check(d, n);
if (IsAsan()) __asan_check(s, n);
if (d <= s) {
asm("rep movsb"
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])dst)
@ -224,8 +219,8 @@ void *memmove(void *dst, const void *src, size_t n) {
*(xmm_t *)(d + n + 16) = w;
} while (n >= 32);
} else {
if (IsAsan()) __asan_check(d, n);
if (IsAsan()) __asan_check(s, n);
if (IsAsan()) __asan_verify(d, n);
if (IsAsan()) __asan_verify(s, n);
asm("std\n\t"
"rep movsb\n\t"
"cld"
@ -246,8 +241,8 @@ void *memmove(void *dst, const void *src, size_t n) {
s += i;
n -= i;
} else {
if (IsAsan()) __asan_check(d, n);
if (IsAsan()) __asan_check(s, n);
if (IsAsan()) __asan_verify(d, n);
if (IsAsan()) __asan_verify(s, n);
asm("rep movsb"
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])d)
: "m"(*(char(*)[n])s));
@ -313,3 +308,6 @@ void *memmove(void *dst, const void *src, size_t n) {
return dst;
}
}
asm("memcpy = memmove\n\t"
".globl\tmemcpy");

View file

@ -28,7 +28,7 @@ typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
noasan static noinline antiquity void *memset_sse(char *p, char c, size_t n) {
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
if (IsAsan()) __asan_check(p, n);
if (IsAsan()) __asan_verify(p, n);
if (n <= 32) {
*(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v;
@ -48,7 +48,7 @@ noasan microarchitecture("avx") static void *memset_avx(char *p, char c,
size_t n) {
char *t;
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
if (IsAsan()) __asan_check(p, n);
if (IsAsan()) __asan_verify(p, n);
if (n <= 32) {
*(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v;
@ -140,11 +140,6 @@ void *memset(void *p, int c, size_t n) {
uint32_t u;
uint64_t x;
b = p;
if (IsTiny()) {
if (IsAsan()) __asan_check(p, n);
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(c));
return p;
}
if (n <= 16) {
if (n >= 8) {
x = 0x0101010101010101ul * (c & 255);
@ -161,6 +156,9 @@ void *memset(void *p, int c, size_t n) {
} while (n);
}
return b;
} else if (IsTiny()) {
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(c));
return p;
} else if (X86_HAVE(AVX)) {
return memset_avx(b, c, n);
} else {

View file

@ -18,7 +18,6 @@
*/
#include "libc/limits.h"
#include "libc/log/libfatal.internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
@ -26,23 +25,25 @@
#include "libc/sysv/consts/nr.h"
/**
* Low-level printf.
* Privileged printf.
*
* This will work without any cosmopolitan runtime support once the
* executable has been loaded into memory.
*/
privileged noasan noinstrument void __printf(const char *fmt, ...) {
long d, ax;
privileged noasan noubsan noinstrument void __printf(const char *fmt, ...) {
/* system call support runtime depends on this function */
/* function tracing runtime depends on this function */
/* asan runtime depends on this function */
short w[2];
va_list va;
uint16_t dx;
const char *s;
const void *s;
uint32_t wrote;
unsigned long x;
unsigned char al;
const char16_t *S;
int i, n, t, w, plus;
char c, f, *p, *e, b[2048];
w = 0;
int i, j, t, cstr;
long d, rax, rdi, rsi, rdx, dot;
char c, *p, *e, pad, bits, base, sign, thou, z[28], b[2048];
p = b;
e = p + sizeof(b);
va_start(va, fmt);
@ -56,98 +57,132 @@ privileged noasan noinstrument void __printf(const char *fmt, ...) {
case '\0':
break;
case '%':
w = 0;
f = ' ';
plus = 0;
n = INT_MAX;
dot = 0;
pad = ' ';
sign = 0;
bits = 0;
thou = 0;
w[0] = 0;
w[1] = SHRT_MAX;
NeedMoar:
switch ((c = *fmt++)) {
case '\0':
break;
case '0':
f = c;
case 'l':
case 'z':
goto NeedMoar;
case ' ':
case '+':
plus = c;
sign = c;
goto NeedMoar;
case 'e':
dot = 1;
goto NeedMoar;
case ',':
thou = c;
goto NeedMoar;
case 'h':
bits = 16;
goto NeedMoar;
case '0':
pad = c;
/* fallthrough */
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
w[dot] *= 10;
w[dot] += c - '0';
goto NeedMoar;
case '*':
w = va_arg(va, int);
w[dot] = va_arg(va, int);
goto NeedMoar;
case 'd':
d = va_arg(va, long);
ApiAbuse:
if (p + 22 <= e) {
if (d || !plus) {
if (d > 0 && plus) {
*p++ = plus;
}
p = __intcpy(p, d);
x = d;
if (d < 0) {
x = -x;
sign = '-';
}
for (i = j = 0;;) {
z[i++] = x % 10 + '0';
if (!(x /= 10)) break;
if (thou && !(++j % 3)) {
z[i++] = thou;
}
}
if (sign) {
z[i++] = sign;
}
EmitNumber:
while (w[0]-- > i) {
if (p < e) *p++ = pad;
}
do {
if (p < e) *p++ = z[--i];
} while (i);
break;
case 'b':
base = 1;
BinaryNumber:
i = 0;
x = va_arg(va, unsigned long);
do z[i++] = "0123456789abcdef"[x & ((1 << base) - 1)];
while ((x >>= base) && i < w[1]);
goto EmitNumber;
case 'p':
w = 12;
f = '0';
pad = '0';
w[0] = 12;
w[1] = 12;
/* fallthrough */
case 'x':
x = va_arg(va, unsigned long);
if (x) {
n = __builtin_clzl(x) ^ (sizeof(long) * 8 - 1);
n >>= 2;
n += 1;
} else {
n = 1;
}
while (w-- > n) {
if (p < e) {
*p++ = f;
}
}
while (n--) {
if (p < e) {
*p++ = "0123456789abcdef"[(x >> (n << 2)) & 15];
}
}
break;
case 'S':
n = va_arg(va, int);
/* fallthrough */
base = 4;
goto BinaryNumber;
case 'o':
base = 3;
goto BinaryNumber;
case 'c':
cstr = va_arg(va, int);
s = &cstr;
goto EmitString;
case 's':
s = va_arg(va, const char *);
s = va_arg(va, const void *);
EmitString:
if (!s) {
EmitNullString:
s = "NULL";
}
if ((uintptr_t)s < PAGESIZE) {
bits = 0;
} else if ((uintptr_t)s < PAGESIZE) {
d = (intptr_t)s;
goto ApiAbuse;
}
for (i = 0; i < n; ++i) {
if (!s[i]) {
n = i;
break;
}
}
while (w-- > n) {
if (p < e) {
*p++ = f;
}
}
for (i = 0; i < n && p < e; ++i) {
*p++ = s[i];
}
break;
case 'u':
S = va_arg(va, const char16_t *);
if (!S) goto EmitNullString;
while ((t = *S++)) {
if (p + 3 <= e && (t & 0xfc00) != 0xdc00) {
if (t <= 0x7ff) {
p[0] = 0300 | t >> 6;
p[1] = 0200 | x << 8 | t & 077;
p += 2;
for (i = 0; i < w[1]; ++i) {
if (!bits) {
t = ((const char *)s)[i];
EmitByte:
if (t) {
if (p < e) {
*p++ = t;
}
} else {
if (t > 0xffff) t = 0xfffd;
break;
}
} else {
t = ((const char16_t *)s)[i];
if (t <= 0x7f) {
goto EmitByte;
} else if (t <= 0x7ff) {
if (p + 1 < e) {
p[0] = 0300 | t >> 6;
p[1] = 0200 | x << 8 | t & 077;
p += 2;
}
} else if (p + 2 < e) {
p[0] = 0340 | t >> 12;
p[1] = 0200 | x << 8 | (t >> 6) & 077;
p[2] = 0200 | x << 8 | t & 077;
@ -155,6 +190,9 @@ privileged noasan noinstrument void __printf(const char *fmt, ...) {
}
}
}
while (w[0]-- > i) {
if (p < e) *p++ = pad;
}
break;
default:
break;
@ -186,8 +224,8 @@ privileged noasan noinstrument void __printf(const char *fmt, ...) {
}
} else {
asm volatile("syscall"
: "=a"(ax)
: "0"(__NR_write), "D"(2), "S"(b), "d"(p - b)
: "rcx", "r11", "memory");
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
: "0"(__NR_write), "1"(2L), "2"(b), "3"(p - b)
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
}
}

View file

@ -0,0 +1,37 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/sysv/consts/o.h"
privileged void PrintSystemMappings(int outfd) {
int infd;
ssize_t rc;
char buf[64];
if (!IsWindows()) {
if ((infd = __sysv_open("/proc/self/maps", O_RDONLY, 0)) >= 0) {
__sysv_write(outfd, "\n", 1);
while ((rc = __sysv_read(infd, buf, sizeof(buf))) > 0) {
__sysv_write(outfd, buf, rc);
}
}
__sysv_close(infd);
}
}

View file

@ -19,384 +19,165 @@
#include "libc/macros.internal.h"
.source __FILE__
.macro .acall fn:req
xor %eax,%eax
mov $1,%r10b
cmpxchg %r10b,__asan_noreentry(%rip)
jnz 2f
call \fn
decb __asan_noreentry(%rip)
2: nop
.endm
.rodata.cst4
__asan_option_detect_stack_use_after_return:
.long 0
.endobj __asan_option_detect_stack_use_after_return,globl
.previous
.bss
__asan_noreentry:
.byte 0
.endobj __asan_noreentry
.previous
__asan_report_load1:
push %rbp
mov %rsp,%rbp
.profilable
mov $1,%esi
.acall __asan_report_load
pop %rbp
ret
push $1
jmp 1f
.endfn __asan_report_load1,globl
__asan_report_load2:
push %rbp
mov %rsp,%rbp
.profilable
mov $2,%esi
.acall __asan_report_load
pop %rbp
ret
push $2
jmp 1f
.endfn __asan_report_load2,globl
__asan_report_load4:
push %rbp
mov %rsp,%rbp
.profilable
mov $4,%esi
.acall __asan_report_load
pop %rbp
ret
push $4
jmp 1f
.endfn __asan_report_load4,globl
__asan_report_load8:
push %rbp
mov %rsp,%rbp
.profilable
mov $8,%esi
.acall __asan_report_load
pop %rbp
ret
push $8
jmp 1f
.endfn __asan_report_load8,globl
__asan_report_load16:
push %rbp
mov %rsp,%rbp
.profilable
mov $16,%esi
.acall __asan_report_load
pop %rbp
ret
push $16
jmp 1f
.endfn __asan_report_load16,globl
__asan_report_load32:
push %rbp
mov %rsp,%rbp
.profilable
mov $32,%esi
.acall __asan_report_load
pop %rbp
ret
push $32
1: pop %rsi
0: jmp __asan_report_load
.endfn __asan_report_load32,globl
__asan_report_load_n:
push %rbp
mov %rsp,%rbp
.profilable
.acall __asan_report_load
pop %rbp
ret
jmp 0b
.endfn __asan_report_load_n,globl
__asan_report_store1:
push %rbp
mov %rsp,%rbp
.profilable
mov $1,%esi
.acall __asan_report_store
pop %rbp
ret
push $1
jmp 1f
.endfn __asan_report_store1,globl
__asan_report_store2:
push %rbp
mov %rsp,%rbp
.profilable
mov $2,%esi
.acall __asan_report_store
pop %rbp
ret
push $2
jmp 1f
.endfn __asan_report_store2,globl
__asan_report_store4:
push %rbp
mov %rsp,%rbp
.profilable
mov $4,%esi
.acall __asan_report_store
pop %rbp
ret
push $4
jmp 1f
.endfn __asan_report_store4,globl
__asan_report_store8:
push %rbp
mov %rsp,%rbp
.profilable
mov $8,%esi
.acall __asan_report_store
pop %rbp
ret
push $8
jmp 1f
.endfn __asan_report_store8,globl
__asan_report_store16:
push %rbp
mov %rsp,%rbp
.profilable
mov $16,%esi
.acall __asan_report_store
pop %rbp
ret
push $16
jmp 1f
.endfn __asan_report_store16,globl
__asan_report_store32:
push %rbp
mov %rsp,%rbp
.profilable
mov $32,%esi
.acall __asan_report_store
pop %rbp
ret
push $32
1: pop %rsi
0: jmp __asan_report_store
.endfn __asan_report_store32,globl
__asan_report_store_n:
push %rbp
mov %rsp,%rbp
.profilable
.acall __asan_report_store
pop %rbp
ret
jmp 0b
.endfn __asan_report_store_n,globl
__asan_stack_free_0:
push %rbp
mov %rsp,%rbp
.profilable
mov $0,%edx
call __asan_stack_free
pop %rbp
ret
push $0
jmp 1f
.endfn __asan_stack_free_0,globl
__asan_stack_free_1:
push %rbp
mov %rsp,%rbp
.profilable
mov $1,%edx
call __asan_stack_free
pop %rbp
ret
push $1
jmp 1f
.endfn __asan_stack_free_1,globl
__asan_stack_free_2:
push %rbp
mov %rsp,%rbp
.profilable
mov $2,%edx
call __asan_stack_free
pop %rbp
ret
push $2
jmp 1f
.endfn __asan_stack_free_2,globl
__asan_stack_free_3:
push %rbp
mov %rsp,%rbp
.profilable
mov $3,%edx
call __asan_stack_free
pop %rbp
ret
push $3
jmp 1f
.endfn __asan_stack_free_3,globl
__asan_stack_free_4:
push %rbp
mov %rsp,%rbp
.profilable
mov $4,%edx
call __asan_stack_free
pop %rbp
ret
push $4
jmp 1f
.endfn __asan_stack_free_4,globl
__asan_stack_free_5:
push %rbp
mov %rsp,%rbp
.profilable
mov $5,%edx
call __asan_stack_free
pop %rbp
ret
push $5
.endfn __asan_stack_free_5,globl
__asan_stack_free_hop:
1: pop %rdx
jmp __asan_stack_free
.endfn __asan_report_store_n,globl
__asan_stack_free_6:
push %rbp
mov %rsp,%rbp
.profilable
mov $6,%edx
call __asan_stack_free
pop %rbp
ret
push $6
jmp 1b
.endfn __asan_stack_free_6,globl
__asan_stack_free_7:
push %rbp
mov %rsp,%rbp
.profilable
mov $7,%edx
call __asan_stack_free
pop %rbp
ret
push $7
jmp 1b
.endfn __asan_stack_free_7,globl
__asan_stack_free_8:
push %rbp
mov %rsp,%rbp
.profilable
mov $8,%edx
call __asan_stack_free
pop %rbp
ret
push $8
jmp 1b
.endfn __asan_stack_free_8,globl
__asan_stack_free_9:
push %rbp
mov %rsp,%rbp
.profilable
mov $9,%edx
call __asan_stack_free
pop %rbp
ret
push $9
jmp 1b
.endfn __asan_stack_free_9,globl
__asan_stack_free_10:
push %rbp
mov %rsp,%rbp
.profilable
mov $10,%edx
call __asan_stack_free
pop %rbp
ret
push $10
jmp 1b
.endfn __asan_stack_free_10,globl
__asan_stack_malloc_0:
push %rbp
mov %rsp,%rbp
.profilable
mov $0,%esi
call __asan_stack_malloc
pop %rbp
ret
push $0
jmp 1f
.endfn __asan_stack_malloc_0,globl
__asan_stack_malloc_1:
push %rbp
mov %rsp,%rbp
.profilable
mov $1,%esi
call __asan_stack_malloc
pop %rbp
ret
push $1
jmp 1f
.endfn __asan_stack_malloc_1,globl
__asan_stack_malloc_2:
push %rbp
mov %rsp,%rbp
.profilable
mov $2,%esi
call __asan_stack_malloc
pop %rbp
ret
push $2
jmp 1f
.endfn __asan_stack_malloc_2,globl
__asan_stack_malloc_3:
push %rbp
mov %rsp,%rbp
.profilable
mov $3,%esi
call __asan_stack_malloc
pop %rbp
ret
push $3
jmp 1f
.endfn __asan_stack_malloc_3,globl
__asan_stack_malloc_4:
push %rbp
mov %rsp,%rbp
.profilable
mov $4,%esi
call __asan_stack_malloc
pop %rbp
ret
push $4
jmp 1f
.endfn __asan_stack_malloc_4,globl
__asan_stack_malloc_5:
push %rbp
mov %rsp,%rbp
.profilable
mov $5,%esi
call __asan_stack_malloc
pop %rbp
ret
push $5
jmp 1f
.endfn __asan_stack_malloc_5,globl
__asan_stack_malloc_hop:
1: pop %rsi
jmp __asan_stack_malloc
.endfn __asan_report_store_n,globl
__asan_stack_malloc_6:
push %rbp
mov %rsp,%rbp
.profilable
mov $6,%esi
call __asan_stack_malloc
pop %rbp
ret
push $6
jmp 1b
.endfn __asan_stack_malloc_6,globl
__asan_stack_malloc_7:
push %rbp
mov %rsp,%rbp
.profilable
mov $7,%esi
call __asan_stack_malloc
pop %rbp
ret
push $7
jmp 1b
.endfn __asan_stack_malloc_7,globl
__asan_stack_malloc_8:
push %rbp
mov %rsp,%rbp
.profilable
mov $8,%esi
call __asan_stack_malloc
pop %rbp
ret
push $8
jmp 1b
.endfn __asan_stack_malloc_8,globl
__asan_stack_malloc_9:
push %rbp
mov %rsp,%rbp
.profilable
mov $9,%esi
call __asan_stack_malloc
pop %rbp
ret
push $9
jmp 1b
.endfn __asan_stack_malloc_9,globl
__asan_stack_malloc_10:
push %rbp
mov %rsp,%rbp
.profilable
mov $10,%esi
call __asan_stack_malloc
pop %rbp
ret
push $10
jmp 1b
.endfn __asan_stack_malloc_10,globl
__asan_version_mismatch_check_v8:

View file

@ -17,8 +17,49 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
// Invokes SYSCALL for libfatal forceinline asm() routines.
//
// @param rax is ordinal
// @param rdi is arg1
// @param rsi is arg2
// @param rdx is arg3
// @param rcx is arg4
// @param r8 is arg5
// @param r9 is arg6
// @param rsp may contain more args
// @return rdx:rax where rax holds -errno on error
// @clob rax,rdx,memory,cc
__syscall__:
mov %rcx,.Lrcx(%rip)
mov %rdi,.Lrdi(%rip)
mov %rsi,.Lrsi(%rip)
mov %r8,.Lr8(%rip)
mov %r9,.Lr9(%rip)
mov %r10,.Lr10(%rip)
mov %r11,.Lr11(%rip)
mov %rcx,%r10
clc
syscall
jnc 1f
neg %rax
1: mov .Lrcx(%rip),%rcx
mov .Lrdi(%rip),%rdi
mov .Lrsi(%rip),%rsi
mov .Lr8(%rip),%r8
mov .Lr9(%rip),%r9
mov .Lr10(%rip),%r10
mov .Lr11(%rip),%r11
ret
.endfn __syscall__,globl,hidden
.bss
.align 8
.Lrcx: .quad 0 # clobbered by syscall
.Lrdi: .quad 0 # just in case
.Lrsi: .quad 0 # just in case
.Lr8: .quad 0 # freebsd bug?
.Lr9: .quad 0 # just in case
.Lr10: .quad 0 # just in case
.Lr11: .quad 0 # clobbered by syscall

View file

@ -22,6 +22,7 @@
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/internal.h"
@ -151,55 +152,19 @@ static bool __ubsan_negative(struct UbsanTypeDescriptor *t, uintptr_t x) {
return __ubsan_signed(t) && (intptr_t)x < 0;
}
static size_t __ubsan_strlen(const char *s) {
size_t n = 0;
while (*s++) ++n;
return n;
}
static char *__ubsan_stpcpy(char *d, const char *s) {
size_t i;
for (i = 0;; ++i) {
if (!(d[i] = s[i])) {
return d + i;
}
}
}
static char *__ubsan_poscpy(char *p, uintptr_t i) {
int j = 0;
do {
p[j++] = i % 10 + '0';
i /= 10;
} while (i > 0);
reverse(p, j);
return p + j;
}
static char *__ubsan_intcpy(char *p, intptr_t i) {
if (i >= 0) return __ubsan_poscpy(p, i);
*p++ = '-';
return __ubsan_poscpy(p, -i);
}
static char *__ubsan_hexcpy(char *p, uintptr_t x, int k) {
while (k) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
return p;
}
static char *__ubsan_itpcpy(char *p, struct UbsanTypeDescriptor *t,
uintptr_t x) {
if (__ubsan_signed(t)) {
return __ubsan_intcpy(p, x);
return __intcpy(p, x);
} else {
return __ubsan_poscpy(p, x);
return __uintcpy(p, x);
}
}
static const char *__ubsan_dubnul(const char *s, unsigned i) {
size_t n;
while (i--) {
if ((n = __ubsan_strlen(s))) {
if ((n = __strlen(s))) {
s += n + 1;
} else {
return NULL;
@ -222,53 +187,11 @@ static uintptr_t __ubsan_extend(struct UbsanTypeDescriptor *t, uintptr_t x) {
return x;
}
static privileged noinline wontreturn void __ubsan_exit(int rc) {
if (!IsWindows()) {
asm volatile("syscall"
: /* no outputs */
: "a"(__NR_exit_group), "D"(rc)
: "memory");
unreachable;
} else {
ExitProcess(rc);
}
}
static privileged noinline ssize_t __ubsan_write(const void *data,
size_t size) {
ssize_t rc;
uint32_t wrote;
if (!IsWindows()) {
asm volatile("syscall"
: "=a"(rc)
: "0"(__NR_write), "D"(2), "S"(data), "d"(size)
: "rcx", "r11", "memory");
return rc;
} else {
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
return wrote;
} else {
return -1;
}
}
}
static ssize_t __ubsan_write_string(const char *s) {
return __ubsan_write(s, __ubsan_strlen(s));
}
void __ubsan_abort(const struct UbsanSourceLocation *loc,
const char *description) {
char buf[1024], *p = buf;
p = __ubsan_stpcpy(p, "error: ");
p = __ubsan_stpcpy(p, loc->file), *p++ = ':';
p = __ubsan_intcpy(p, loc->line);
p = __ubsan_stpcpy(p, ": ");
p = __ubsan_stpcpy(p, description);
p = __ubsan_stpcpy(p, "\r\n");
__ubsan_write_string(buf);
__printf("\r\n%s:%d: ubsan error: %s\r\n", loc->file, loc->line, description);
if (weaken(__die)) weaken(__die)();
__ubsan_exit(134);
_Exit(134);
}
static const char *__ubsan_describe_shift(
@ -291,11 +214,11 @@ void __ubsan_handle_shift_out_of_bounds(struct UbsanShiftOutOfBoundsInfo *info,
char buf[512], *p = buf;
lhs = __ubsan_extend(info->lhs_type, lhs);
rhs = __ubsan_extend(info->rhs_type, rhs);
p = __ubsan_stpcpy(p, __ubsan_describe_shift(info, lhs, rhs)), *p++ = ' ';
p = __stpcpy(p, __ubsan_describe_shift(info, lhs, rhs)), *p++ = ' ';
p = __ubsan_itpcpy(p, info->lhs_type, lhs), *p++ = ' ';
p = __ubsan_stpcpy(p, info->lhs_type->name), *p++ = ' ';
p = __stpcpy(p, info->lhs_type->name), *p++ = ' ';
p = __ubsan_itpcpy(p, info->rhs_type, rhs), *p++ = ' ';
p = __ubsan_stpcpy(p, info->rhs_type->name);
p = __stpcpy(p, info->rhs_type->name);
__ubsan_abort(&info->location, buf);
}
@ -307,12 +230,12 @@ void __ubsan_handle_shift_out_of_bounds_abort(
void __ubsan_handle_out_of_bounds(struct UbsanOutOfBoundsInfo *info,
uintptr_t index) {
char buf[512], *p = buf;
p = __ubsan_stpcpy(p, info->index_type->name);
p = __ubsan_stpcpy(p, " index ");
p = __stpcpy(p, info->index_type->name);
p = __stpcpy(p, " index ");
p = __ubsan_itpcpy(p, info->index_type, index);
p = __ubsan_stpcpy(p, " into ");
p = __ubsan_stpcpy(p, info->array_type->name);
p = __ubsan_stpcpy(p, " out of bounds");
p = __stpcpy(p, " into ");
p = __stpcpy(p, info->array_type->name);
p = __stpcpy(p, " out of bounds");
__ubsan_abort(&info->location, buf);
}
@ -328,19 +251,19 @@ void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *info,
if (!pointer) __ubsan_abort(&info->location, "null pointer access");
kind = __ubsan_dubnul(kUbsanTypeCheckKinds, info->type_check_kind);
if (info->alignment && (pointer & (info->alignment - 1))) {
p = __ubsan_stpcpy(p, "unaligned ");
p = __ubsan_stpcpy(p, kind), *p++ = ' ';
p = __ubsan_stpcpy(p, info->type->name), *p++ = ' ', *p++ = '@';
p = __stpcpy(p, "unaligned ");
p = __stpcpy(p, kind), *p++ = ' ';
p = __stpcpy(p, info->type->name), *p++ = ' ', *p++ = '@';
p = __ubsan_itpcpy(p, info->type, pointer);
p = __ubsan_stpcpy(p, " align ");
p = __ubsan_intcpy(p, info->alignment);
p = __stpcpy(p, " align ");
p = __intcpy(p, info->alignment);
} else {
p = __ubsan_stpcpy(p, "insufficient size\r\n\t");
p = __ubsan_stpcpy(p, kind);
p = __ubsan_stpcpy(p, " address 0x");
p = __ubsan_hexcpy(p, pointer, sizeof(pointer) * CHAR_BIT);
p = __ubsan_stpcpy(p, " with insufficient space for object of type ");
p = __ubsan_stpcpy(p, info->type->name);
p = __stpcpy(p, "insufficient size\r\n\t");
p = __stpcpy(p, kind);
p = __stpcpy(p, " address 0x");
p = __fixcpy(p, pointer, sizeof(pointer) * CHAR_BIT);
p = __stpcpy(p, " with insufficient space for object of type ");
p = __stpcpy(p, info->type->name);
}
__ubsan_abort(&info->location, buf);
}