Get address sanitizer mostly working

This commit is contained in:
Justine Tunney 2020-09-03 05:44:37 -07:00
parent 1f1f3cd477
commit 7327c345f9
149 changed files with 3777 additions and 3457 deletions

370
libc/log/asan.c Normal file
View file

@ -0,0 +1,370 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/safemacros.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/conv/conv.h"
#include "libc/conv/itoa.h"
#include "libc/log/asan.h"
#include "libc/log/backtrace.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/hook/hook.h"
#include "libc/runtime/directmap.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/missioncritical.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "third_party/dlmalloc/dlmalloc.h"
/**
* @fileoverview Cosmopolitan Address Sanitizer Runtime.
*
* Someone brilliant at Google figured out a way to improve upon memory
* protection. Rather than invent another Java or Rust they changed GCC
* so it can emit fast code, that checks the validity of each memory op
* with byte granularity, by probing shadow memory.
*
* AddressSanitizer dedicates one-eighth of the virtual address space
* to its shadow memory and uses a direct mapping with a scale and
* offset to translate an application address to its corresponding
* shadow address. Given the application memory address Addr, the
* address of the shadow byte is computed as (Addr>>3)+Offset."
*
* We use the following encoding for each shadow byte: 0 means that
* all 8 bytes of the corresponding application memory region are
* addressable; k (1 k 7) means that the first k bytes are
* addressible; any negative value indicates that the entire 8-byte
* word is unaddressable. We use different negative values to
* distinguish between different kinds of unaddressable memory (heap
* redzones, stack redzones, global redzones, freed memory).
*
* Here's what the generated code looks like for 64-bit reads:
*
* movq %addr,%tmp
* shrq $3,%tmp
* cmpb $0,0x7fff8000(%tmp)
* jnz abort
* movq (%addr),%dst
*/
#define HOOK(HOOK, IMPL) \
if (weaken(HOOK)) { \
*weaken(HOOK) = IMPL; \
}
struct AsanSourceLocation {
const char *filename;
int line;
int column;
};
struct AsanAccessInfo {
const char *addr;
const char *first_bad_addr;
size_t size;
bool iswrite;
unsigned long ip;
};
struct AsanGlobal {
const char *addr;
size_t size;
size_t size_with_redzone;
const void *name;
const void *module_name;
unsigned long has_cxx_init;
struct AsanSourceLocation *location;
char *odr_indicator;
};
static bool __asan_is_mapped(void *p) {
int x, i;
x = (intptr_t)p >> 16;
i = FindMemoryInterval(&_mmi, x);
return i < _mmi.i && x >= _mmi.p[i].x && x <= _mmi.p[i].y;
}
void __asan_map_shadow(void *addr, size_t size) {
int i, n, x;
char *a, *b;
struct DirectMap sm;
a = (char *)ROUNDDOWN(SHADOW((intptr_t)addr), FRAMESIZE);
b = (char *)ROUNDDOWN(SHADOW((intptr_t)addr + size - 1), FRAMESIZE);
for (; a <= b; a += FRAMESIZE) {
if (!__asan_is_mapped(a)) {
sm = DirectMap(a, FRAMESIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (sm.addr == MAP_FAILED ||
TrackMemoryInterval(&_mmi, (intptr_t)a >> 16, (intptr_t)a >> 16,
sm.maphandle) == -1) {
abort();
}
}
}
}
size_t __asan_malloc_usable_size(const void *vp) {
char *s;
size_t n;
for (n = 0, s = (char *)SHADOW((intptr_t)vp);; ++s) {
if (!*s) {
n += 8;
} else if (*s > 0) {
n += *s & 7;
} else {
break;
}
}
return n;
}
void *__asan_allocate(size_t align, size_t size, int underrun, int overrun) {
char *p, *s;
size_t q, r, i;
if (!(p = dlmemalign(align, ROUNDUP(size, 8) + 16))) return NULL;
s = (char *)SHADOW((intptr_t)p - 16);
q = size / 8;
r = size % 8;
*s++ = underrun;
*s++ = underrun;
memset(s, 0, q);
s += q;
if (r) *s++ = r;
*s++ = overrun;
*s++ = overrun;
return p;
}
void __asan_deallocate(char *p, int kind) {
char *s;
size_t n;
s = (char *)SHADOW((intptr_t)p);
n = dlmalloc_usable_size(p);
n /= 8;
memset(s, kind, n);
dlfree(p);
}
void __asan_free(void *vp) {
__asan_deallocate(vp, kAsanHeapFree);
}
void *__asan_memalign(size_t align, size_t size) {
return __asan_allocate(align, size, kAsanHeapUnderrun, kAsanHeapOverrun);
}
void *__asan_malloc(size_t size) {
return __asan_memalign(16, size);
}
void *__asan_calloc(size_t n, size_t m) {
char *p;
size_t size;
if (__builtin_mul_overflow(n, m, &size)) size = -1;
if ((p = __asan_malloc(size))) memset(p, 0, size);
return p;
}
void *__asan_realloc(void *p, size_t n) {
char *p2;
if (p) {
if (n) {
if ((p2 = __asan_malloc(n))) {
memcpy(p2, p, min(n, dlmalloc_usable_size(p)));
__asan_deallocate(p, kAsanRelocated);
}
} else {
__asan_free(p);
p2 = NULL;
}
} else {
p2 = __asan_malloc(n);
}
return p2;
}
void *__asan_valloc(size_t n) {
return __asan_memalign(PAGESIZE, n);
}
void *__asan_pvalloc(size_t n) {
return __asan_valloc(ROUNDUP(n, PAGESIZE));
}
void __asan_poison(intptr_t addr, size_t size, size_t redsize, int kind) {
char *s;
intptr_t p;
size_t a, b, w;
w = (intptr_t)addr & 7;
p = (intptr_t)addr - w;
a = w + size;
b = w + redsize;
s = (char *)SHADOW(p + a);
if (a & 7) *s++ = a & 7;
memset(s, kind, (b - ROUNDUP(a, 8)) >> 3);
}
void __asan_register_globals(struct AsanGlobal g[], int n) {
size_t i;
for (i = 0; i < n; ++i) {
__asan_poison((intptr_t)g[i].addr, g[i].size, g[i].size_with_redzone,
kAsanGlobalOverrun);
}
}
void __asan_report_memory_fault(uint8_t *addr, int size, const char *kind) {
char *p, *s, ibuf[21], buf[256];
switch (*(char *)SHADOW((intptr_t)addr)) {
case kAsanStackFree:
s = "stack use after release";
break;
case kAsanHeapFree:
s = "heap use after free";
break;
case kAsanRelocated:
s = "heap use after relocate";
break;
case kAsanHeapUnderrun:
s = "heap underrun";
break;
case kAsanHeapOverrun:
s = "heap overrun";
break;
case kAsanStackUnderrun:
s = "stack underflow";
break;
case kAsanStackOverrun:
s = "stack overflow";
break;
case kAsanAllocaOverrun:
s = "alloca overflow";
break;
case kAsanUnscoped:
s = "unscoped";
break;
default:
s = "poisoned";
break;
}
p = buf;
p = stpcpy(p, "error: ");
p = stpcpy(p, s);
p = stpcpy(p, " ");
uint64toarray_radix10(size, ibuf);
p = stpcpy(p, ibuf);
p = stpcpy(p, "-byte ");
p = stpcpy(p, kind);
p = stpcpy(p, " at 0x");
uint64toarray_fixed16((intptr_t)addr, ibuf, 48);
p = stpcpy(p, ibuf);
p = stpcpy(p, "\n");
__print(buf, p - buf);
PrintBacktraceUsingSymbols(stderr, __builtin_frame_address(0),
getsymboltable());
DebugBreak();
_Exit(66);
}
void *__asan_stack_malloc(size_t size, int classid) {
return __asan_allocate(32, size, kAsanStackUnderrun, kAsanStackOverrun);
}
void __asan_stack_free(char *p, size_t size, int classid) {
return __asan_deallocate(p, kAsanStackFree);
}
void __asan_report_load_n(uint8_t *addr, int size) {
__asan_report_memory_fault(addr, size, "load");
}
void __asan_report_store_n(uint8_t *addr, int size) {
__asan_report_memory_fault(addr, size, "store");
}
void __asan_poison_stack_memory(uintptr_t p, size_t n) {
memset((char *)SHADOW(p), kAsanUnscoped, n >> 3);
if (n & 7) *(char *)SHADOW(p + n) = 8 - (n & 7);
}
void __asan_unpoison_stack_memory(uintptr_t p, size_t n) {
memset((char *)SHADOW(p), 0, n >> 3);
if (n & 7) *(char *)SHADOW(p + n) = n & 7;
}
void __asan_loadN(intptr_t ptr, size_t size) {
DebugBreak();
}
void __asan_storeN(intptr_t ptr, size_t size) {
DebugBreak();
}
void __asan_alloca_poison(intptr_t addr, size_t size) {
__asan_poison(addr, size, size + 32, kAsanAllocaOverrun);
}
void __asan_allocas_unpoison(uintptr_t top, uintptr_t bottom) {
memset((char *)SHADOW(top), 0, (bottom - top) >> 3);
}
void *__asan_addr_is_in_fake_stack(void *fakestack, void *addr, void **beg,
void **end) {
return NULL;
}
void *__asan_get_current_fake_stack(void) {
return NULL;
}
void __asan_install_malloc_hooks(void) {
HOOK(hook$free, __asan_free);
HOOK(hook$malloc, __asan_malloc);
HOOK(hook$calloc, __asan_calloc);
HOOK(hook$valloc, __asan_valloc);
HOOK(hook$pvalloc, __asan_pvalloc);
HOOK(hook$realloc, __asan_realloc);
HOOK(hook$memalign, __asan_memalign);
HOOK(hook$malloc_usable_size, __asan_malloc_usable_size);
}
void __asan_init(int argc, char *argv[], char **envp, intptr_t *auxv) {
int i;
static bool once;
register intptr_t rsp asm("rsp");
if (!once) {
__asan_map_shadow(_base, _end - _base);
__asan_map_shadow((void *)ROUNDDOWN(rsp, STACKSIZE), STACKSIZE);
for (i = 0; i < argc; ++i) __asan_map_shadow(argv[i], strlen(argv[i]));
for (; *envp; ++envp) __asan_map_shadow(*envp, strlen(*envp));
__asan_map_shadow(auxv, sizeof(intptr_t) * 2);
__asan_install_malloc_hooks();
once = true;
}
}
const void *const g_asan_ctor[] initarray = {getsymboltable};

21
libc/log/asan.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef COSMOPOLITAN_LIBC_LOG_ASAN_H_
#define COSMOPOLITAN_LIBC_LOG_ASAN_H_
#define kAsanScale 3
#define kAsanMagic 0x7fff8000
#define kAsanHeapFree -1
#define kAsanStackFree -2
#define kAsanRelocated -3
#define kAsanHeapUnderrun -4
#define kAsanHeapOverrun -5
#define kAsanGlobalOverrun -6
#define kAsanStackUnderrun -7
#define kAsanStackOverrun -8
#define kAsanAllocaOverrun -9
#define kAsanUnscoped -10
#define SHADOW(x) (((x) >> kAsanScale) + kAsanMagic)
void __asan_map_shadow(void *, size_t);
#endif /* COSMOPOLITAN_LIBC_LOG_ASAN_H_ */

View file

@ -23,6 +23,7 @@
#include "libc/fmt/fmt.h"
#include "libc/log/gdb.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/stackframe.h"
#include "libc/nexgen32e/vendor.h"
#include "libc/paths.h"
#include "libc/runtime/runtime.h"

View file

@ -17,8 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/dce.h"
#include "libc/log/log.h"
#include "libc/log/backtrace.h"
void backtrace(FILE *f) {
showbacktrace(f, __builtin_frame_address(0));

15
libc/log/backtrace.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef COSMOPOLITAN_LIBC_LOG_BACKTRACE_H_
#define COSMOPOLITAN_LIBC_LOG_BACKTRACE_H_
#include "libc/nexgen32e/stackframe.h"
#include "libc/runtime/symbols.h"
#include "libc/stdio/stdio.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void showbacktrace(FILE *, const struct StackFrame *);
int PrintBacktraceUsingSymbols(FILE *, const struct StackFrame *,
struct SymbolTable *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_LOG_BACKTRACE_H_ */

View file

@ -26,6 +26,7 @@
#include "libc/conv/conv.h"
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/log/backtrace.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/gc.h"
#include "libc/runtime/runtime.h"
@ -37,54 +38,7 @@
#define kBacktraceMaxFrames 128
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (16 + 1))
static char *FormatAddress(FILE *f, const struct SymbolTable *st, intptr_t addr,
char *out, unsigned size, bool symbolic) {
int64_t addend;
const char *name;
const struct Symbol *symbol;
if (st->count && ((intptr_t)addr >= (intptr_t)&_base &&
(intptr_t)addr <= (intptr_t)&_end && symbolic)) {
symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
st->count, addr - st->addr_base - 1)];
addend = addr - st->addr_base - symbol->addr_rva;
name = &st->name_base[symbol->name_rva];
snprintf(out, size, "%s%c%#x", name, addend >= 0 ? '+' : '-', abs(addend));
} else {
snprintf(out, size, "%p", addr);
}
return out;
}
static int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp,
char buf[hasatleast kBacktraceBufSize]) {
size_t gi;
intptr_t addr;
struct Garbages *garbage;
struct SymbolTable *symbols;
const struct StackFrame *frame;
if ((symbols = getsymboltable())) {
garbage = weaken(g_garbage);
gi = garbage ? garbage->i : 0;
for (frame = bp; frame; frame = frame->next) {
addr = frame->addr;
if (addr == weakaddr("CollectGarbage")) {
do {
--gi;
} while ((addr = garbage->p[gi].ret) == weakaddr("CollectGarbage"));
}
fprintf(f, "%p %p %s\n", frame, addr,
FormatAddress(f, symbols, addr, buf, kBacktraceBufSize, true));
}
return 0;
} else {
return -1;
}
}
static int PrintBacktraceUsingAddr2line(
FILE *f, const struct StackFrame *bp,
char buf[hasatleast kBacktraceBufSize],
char *argv[hasatleast kBacktraceMaxFrames]) {
static int PrintBacktraceUsingAddr2line(FILE *f, const struct StackFrame *bp) {
ssize_t got;
intptr_t addr;
size_t i, j, gi;
@ -92,6 +46,7 @@ static int PrintBacktraceUsingAddr2line(
struct Garbages *garbage;
const struct StackFrame *frame;
const char *debugbin, *p1, *p2, *p3, *addr2line;
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
if (!(debugbin = finddebugbinary()) || !(addr2line = GetAddr2linePath())) {
return -1;
}
@ -148,24 +103,20 @@ static int PrintBacktraceUsingAddr2line(
return 0;
}
static noinline int PrintBacktrace(FILE *f, const struct StackFrame *bp,
char *argv[hasatleast kBacktraceMaxFrames],
char buf[hasatleast kBacktraceBufSize]) {
static int PrintBacktrace(FILE *f, const struct StackFrame *bp) {
if (!IsTiny()) {
if (PrintBacktraceUsingAddr2line(f, bp, buf, argv) != -1) {
if (PrintBacktraceUsingAddr2line(f, bp) != -1) {
return 0;
}
}
return PrintBacktraceUsingSymbols(f, bp, buf);
return PrintBacktraceUsingSymbols(f, bp, getsymboltable());
}
void showbacktrace(FILE *f, const struct StackFrame *bp) {
static bool noreentry;
char *argv[kBacktraceMaxFrames];
char buf[kBacktraceBufSize];
if (!noreentry) {
noreentry = true;
PrintBacktrace(f, bp, argv, buf);
PrintBacktrace(f, bp);
noreentry = 0;
}
}

69
libc/log/backtrace3.c Normal file
View file

@ -0,0 +1,69 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/bisectcarleft.h"
#include "libc/bits/weaken.h"
#include "libc/fmt/fmt.h"
#include "libc/log/backtrace.h"
#include "libc/macros.h"
#include "libc/nexgen32e/gc.h"
#include "libc/nexgen32e/stackframe.h"
#include "libc/runtime/symbols.h"
#include "libc/stdio/stdio.h"
static char *FormatAddress(FILE *f, const struct SymbolTable *st, intptr_t addr,
char *out, unsigned size, bool symbolic) {
int64_t addend;
const char *name;
const struct Symbol *symbol;
if (st->count && ((intptr_t)addr >= (intptr_t)&_base &&
(intptr_t)addr <= (intptr_t)&_end && symbolic)) {
symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
st->count, addr - st->addr_base - 1)];
addend = addr - st->addr_base - symbol->addr_rva;
name = &st->name_base[symbol->name_rva];
snprintf(out, size, "%s%c%#x", name, addend >= 0 ? '+' : '-', ABS(addend));
} else {
snprintf(out, size, "%p", addr);
}
return out;
}
int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp,
struct SymbolTable *symbols) {
size_t gi;
char buf[256];
intptr_t addr;
struct Garbages *garbage;
const struct StackFrame *frame;
if (!symbols) return -1;
garbage = weaken(g_garbage);
gi = garbage ? garbage->i : 0;
for (frame = bp; frame; frame = frame->next) {
addr = frame->addr;
if (addr == weakaddr("CollectGarbage")) {
do {
--gi;
} while ((addr = garbage->p[gi].ret) == weakaddr("CollectGarbage"));
}
fprintf(f, "%p %p %s\n", frame, addr,
FormatAddress(f, symbols, addr, buf, sizeof(buf), true));
}
return 0;
}

View file

@ -28,13 +28,14 @@
*/
nodiscard char *commandvenv(const char *var, const char *cmd) {
const char *exepath;
char pathbuf[PATH_MAX];
if ((exepath = getenv(var))) {
if (!isempty(exepath) && access(exepath, X_OK) != -1) {
return exepath;
} else {
return NULL;
}
} else if ((exepath = commandv(cmd))) {
} else if ((exepath = commandv(cmd, pathbuf))) {
return exepath;
} else {
return NULL;

View file

@ -23,6 +23,7 @@
#include "libc/fmt/fmt.h"
#include "libc/log/gdb.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/stackframe.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.h"

View file

@ -29,7 +29,6 @@ COSMOPOLITAN_C_START_
struct sigset;
struct winsize;
struct StackFrame;
typedef struct FILE FILE;
extern FILE *g_logfile;
@ -51,7 +50,6 @@ void showcrashreports(void);
void callexitontermination(struct sigset *);
bool32 IsDebuggerPresent(bool);
bool isrunningundermake(void);
void showbacktrace(FILE *, const struct StackFrame *);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § liblog » logging

View file

@ -8,7 +8,6 @@ LIBC_LOG = $(LIBC_LOG_A_DEPS) $(LIBC_LOG_A)
LIBC_LOG_A = o/$(MODE)/libc/log/log.a
LIBC_LOG_A_FILES := \
$(wildcard libc/log/thunks/*) \
$(wildcard libc/log/elf/*) \
$(wildcard libc/log/*)
LIBC_LOG_A_HDRS = $(filter %.h,$(LIBC_LOG_A_FILES))
LIBC_LOG_A_SRCS_C = $(filter %.c,$(LIBC_LOG_A_FILES))
@ -38,6 +37,7 @@ LIBC_LOG_A_DIRECTDEPS = \
LIBC_TINYMATH \
LIBC_NEXGEN32E \
LIBC_NT_KERNELBASE \
LIBC_MEM \
LIBC_RAND \
LIBC_RUNTIME \
LIBC_STDIO \
@ -60,17 +60,10 @@ $(LIBC_LOG_A).pkg: \
$(LIBC_LOG_A_OBJS) \
$(foreach x,$(LIBC_LOG_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/log/die.o \
o/$(MODE)/libc/log/perror.o \
o/$(MODE)/libc/log/ftrace.o \
o/$(MODE)/libc/log/ubsan.o \
o/$(MODE)/libc/log/symbols.o \
o/$(MODE)/libc/log/backtrace.o \
o/$(MODE)/libc/log/oncrash.o \
o/$(MODE)/libc/log/shadowargs.o \
o/$(MODE)/libc/log/thunks/__check_fail_ndebug.o: \
OVERRIDE_COPTS += \
$(NO_MAGIC)
$(LIBC_LOG_A_OBJS): \
OVERRIDE_CFLAGS += \
$(NO_MAGIC) \
-fwrapv
LIBC_LOG_LIBS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)))
LIBC_LOG_SRCS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)_SRCS))

View file

@ -23,10 +23,12 @@
#include "libc/calls/ucontext.h"
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/log/backtrace.h"
#include "libc/log/gdb.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/nexgen32e/stackframe.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
@ -163,7 +165,6 @@ relegated static void ShowCrashReport(int err, FILE *f, int sig,
}
fputc('\n', f);
fflush(f);
memsummary(fileno(f));
ShowMemoryMappings(fileno(f));
}

298
libc/log/somanyasan.S Normal file
View file

@ -0,0 +1,298 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.privileged
.source __FILE__
/ @fileoverview Address Sanitizer Thunks
/
/ This has tiny code size and reduces API surface area
/ since ASAN has the same stylistic hugeness as UBSAN.
/ We also guard all the functions, against reentrancy.
__asan_load1:
push $1
jmp OnLoad
.endfn __asan_load1,globl
__asan_load2:
push $2
jmp OnLoad
.endfn __asan_load2,globl
__asan_load4:
push $4
jmp OnLoad
.endfn __asan_load4,globl
__asan_load8:
push $8
jmp OnLoad
.endfn __asan_load8,globl
__asan_load16:
push $16
jmp OnLoad
.endfn __asan_load16,globl
__asan_load32:
push $32
/ 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_load32,globl
OnLoad: pop %rsi
ezlea __asan_loadN,ax
jmp __asan_report_noreentry
.endfn OnStore
__asan_store1:
push $1
jmp OnStore
.endfn __asan_store1,globl
__asan_store2:
push $2
jmp OnStore
.endfn __asan_store2,globl
__asan_store4:
push $4
jmp OnStore
.endfn __asan_store4,globl
__asan_store8:
push $8
jmp OnStore
.endfn __asan_store8,globl
__asan_store16:
push $16
jmp OnStore
.endfn __asan_store16,globl
__asan_store32:
push $32
/ 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_store32,globl
OnStore:pop %rsi
ezlea __asan_storeN,ax
jmp __asan_report_noreentry
.endfn OnStore
__asan_report_load1:
push $1
jmp OnReportLoad
.endfn __asan_report_load1,globl
__asan_report_load2:
push $2
jmp OnReportLoad
.endfn __asan_report_load2,globl
__asan_report_load4:
push $4
jmp OnReportLoad
.endfn __asan_report_load4,globl
__asan_report_load8:
push $8
jmp OnReportLoad
.endfn __asan_report_load8,globl
__asan_report_load16:
push $16
/ 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_report_load16,globl
OnReportLoad:
pop %rsi
ezlea __asan_report_load_n,ax
jmp __asan_report_noreentry
.endfn OnReportLoad
__asan_report_store1:
push $1
jmp ReportStore
.endfn __asan_report_store1,globl
__asan_report_store2:
push $2
jmp ReportStore
.endfn __asan_report_store2,globl
__asan_report_store4:
push $4
jmp ReportStore
.endfn __asan_report_store4,globl
__asan_report_store8:
push $8
jmp ReportStore
.endfn __asan_report_store8,globl
__asan_report_store16:
push $16
jmp ReportStore
.endfn __asan_report_store16,globl
__asan_report_store32:
push $32
/ 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_report_store32,globl
ReportStore:
pop %rsi
ezlea __asan_report_store_n,ax
/ 𝑠𝑙𝑖𝑑𝑒
.endfn ReportStore
__asan_report_noreentry:
push %rbp
mov %rsp,%rbp
cmpb $0,noreentry(%rip)
jnz 2f
incb noreentry(%rip)
call *%rax
decb noreentry(%rip)
pop %rbp
ret
2: call abort
.endfn __asan_report_noreentry
__asan_stack_free_0:
push $0
jmp OnStackFree
.endfn __asan_stack_free_0,globl
__asan_stack_free_1:
push $1
jmp OnStackFree
.endfn __asan_stack_free_1,globl
__asan_stack_free_2:
push $2
jmp OnStackFree
.endfn __asan_stack_free_2,globl
__asan_stack_free_3:
push $3
jmp OnStackFree
.endfn __asan_stack_free_3,globl
__asan_stack_free_4:
push $4
jmp OnStackFree
.endfn __asan_stack_free_4,globl
__asan_stack_free_5:
push $5
jmp OnStackFree
.endfn __asan_stack_free_5,globl
__asan_stack_free_6:
push $6
jmp OnStackFree
.endfn __asan_stack_free_6,globl
__asan_stack_free_7:
push $7
jmp OnStackFree
.endfn __asan_stack_free_7,globl
__asan_stack_free_8:
push $8
jmp OnStackFree
.endfn __asan_stack_free_8,globl
__asan_stack_free_9:
push $9
jmp OnStackFree
.endfn __asan_stack_free_9,globl
__asan_stack_free_10:
push $10
/ 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_stack_free_10,globl
OnStackFree:
pop %rdx
jmp __asan_stack_free
.endfn OnStackFree
__asan_stack_malloc_0:
push $0
jmp OnStackMalloc
.endfn __asan_stack_malloc_0,globl
__asan_stack_malloc_1:
push $1
jmp OnStackMalloc
.endfn __asan_stack_malloc_1,globl
__asan_stack_malloc_2:
push $2
jmp OnStackMalloc
.endfn __asan_stack_malloc_2,globl
__asan_stack_malloc_3:
push $3
jmp OnStackMalloc
.endfn __asan_stack_malloc_3,globl
__asan_stack_malloc_4:
push $4
jmp OnStackMalloc
.endfn __asan_stack_malloc_4,globl
__asan_stack_malloc_5:
push $5
jmp OnStackMalloc
.endfn __asan_stack_malloc_5,globl
__asan_stack_malloc_6:
push $6
jmp OnStackMalloc
.endfn __asan_stack_malloc_6,globl
__asan_stack_malloc_7:
push $7
jmp OnStackMalloc
.endfn __asan_stack_malloc_7,globl
__asan_stack_malloc_8:
push $8
jmp OnStackMalloc
.endfn __asan_stack_malloc_8,globl
__asan_stack_malloc_9:
push $9
jmp OnStackMalloc
.endfn __asan_stack_malloc_9,globl
__asan_stack_malloc_10:
push $10
/ 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_stack_malloc_10,globl
OnStackMalloc:
pop %rsi
jmp __asan_stack_malloc
.endfn OnStackMalloc
__asan_handle_no_return:
ret
.endfn __asan_handle_no_return,globl
__asan_before_dynamic_init:
ret
.endfn __asan_before_dynamic_init,globl
__asan_after_dynamic_init:
ret
.endfn __asan_after_dynamic_init,globl
__asan_unregister_globals:
ret
.endfn __asan_unregister_globals,globl
__asan_version_mismatch_check_v8:
ret
.endfn __asan_version_mismatch_check_v8,globl
/ Initializes Address Sanitizer runtime earlier if linked.
.init.start 301,_init_asan
push %rdi
push %rsi
mov %r12,%rdi
mov %r13,%rsi
mov %r14,%rdx
mov %r15,%rcx
call __asan_init
pop %rsi
pop %rdi
.init.end 301,_init_asan
.rodata.cst4
__asan_option_detect_stack_use_after_return:
.long 1
.endobj __asan_option_detect_stack_use_after_return,globl
.previous
.bss
noreentry:
.byte 0
.endobj noreentry
.previous