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

View file

@ -31,13 +31,17 @@
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/stdio/append.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sig.h"
#include "libc/x/x.h"
#define kBacktraceMaxFrames 128
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1))
@ -168,13 +172,14 @@ static noasan int PrintBacktrace(int fd, const struct StackFrame *bp) {
}
noasan void ShowBacktrace(int fd, const struct StackFrame *bp) {
/* asan runtime depends on this function */
static bool noreentry;
++ftrace;
++g_ftrace;
if (!bp) bp = __builtin_frame_address(0);
if (!noreentry) {
noreentry = true;
PrintBacktrace(fd, bp);
noreentry = false;
}
--ftrace;
--g_ftrace;
}

View file

@ -31,6 +31,8 @@
#include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h"
#define LIMIT 100
/**
* Prints stack frames with symbols.
*
@ -46,14 +48,18 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
struct SymbolTable *st) {
size_t gi;
intptr_t addr;
int symbol, addend;
int i, symbol, addend;
struct Garbages *garbage;
const struct StackFrame *frame;
++ftrace;
++g_ftrace;
if (!bp) bp = __builtin_frame_address(0);
garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0;
for (frame = bp; frame; frame = frame->next) {
for (i = 0, frame = bp; frame; frame = frame->next) {
if (++i == LIMIT) {
__printf("<truncated backtrace>\n");
break;
}
addr = frame->addr;
if (addr == weakaddr("__gc")) {
do {
@ -68,15 +74,16 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
* __restore_rt where the kernel creates a stack frame that points
* to the beginning of the function.
*/
if ((symbol = GetSymbol(st, addr - 1)) != -1 ||
(symbol = GetSymbol(st, addr - 0)) != -1) {
if ((symbol = __get_symbol(st, addr - 1)) != -1 ||
(symbol = __get_symbol(st, addr - 0)) != -1) {
addend = addr - st->addr_base;
addend -= st->symbols[symbol].x;
} else {
addend = 0;
}
__printf("%p %p %s%+d\r\n", frame, addr, GetSymbolName(st, symbol), addend);
__printf("%p %p %s%+d\r\n", frame, addr, __get_symbol_name(st, symbol),
addend);
}
--ftrace;
--g_ftrace;
return 0;
}

View file

@ -1,7 +1,7 @@
/*-*- 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
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
@ -16,13 +16,45 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/runtime/cxaatexit.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sig.h"
#include "libc/stdio/stdio.h"
bool IsTerminalInarticulate(void) {
return !strcmp(nulltoempty(getenv("TERM")), "dumb");
/**
* Prints global destructors.
*
* @param pred can be null to match all
*/
void __cxa_printexits(FILE *f, void *pred) {
char name[23];
unsigned i, mask;
const char *symbol;
struct CxaAtexitBlock *b;
fprintf(f, "\n");
fprintf(f, " GLOBAL DESTRUCTORS \n");
fprintf(f, " callback arg pred \n");
fprintf(f, "---------------------- ------------------ ------------------\n");
if ((b = __cxa_blocks.p)) {
do {
mask = b->mask;
while (mask) {
i = bsf(mask);
mask &= ~(1u << i);
if (!pred || pred == b->p[i].pred) {
symbol = __get_symbol_by_addr((intptr_t)b->p[i].fp);
if (symbol) {
snprintf(name, sizeof(name), "%s", symbol);
} else {
snprintf(name, sizeof(name), "0x%016lx", b->p[i].fp);
}
fprintf(f, "%-22s 0x%016lx 0x%016lx\n", name, b->p[i].arg,
b->p[i].pred);
}
}
} while ((b = b->next));
}
fprintf(f, "\n");
}

View file

@ -29,6 +29,7 @@
* If a debugger is present then this will trigger a breakpoint.
*/
relegated wontreturn void __die(void) {
/* asan runtime depends on this function */
static bool once;
if (cmpxchg(&once, false, true)) {
__restore_tty(1);

View file

@ -26,6 +26,6 @@
const char *GetCallerName(const struct StackFrame *bp) {
struct SymbolTable *st;
if (!bp && (bp = __builtin_frame_address(0))) bp = bp->next;
if (bp) return GetSymbolByAddr(bp->addr - 1);
if (bp) return __get_symbol_by_addr(bp->addr);
return 0;
}

View file

@ -23,7 +23,12 @@
/**
* Returns name of symbol at address.
*/
char *GetSymbolByAddr(int64_t addr) {
struct SymbolTable *st = GetSymbolTable();
return GetSymbolName(st, GetSymbol(st, addr));
noasan char *__get_symbol_by_addr(int64_t addr) {
/* asan runtime depends on this function */
int i;
struct SymbolTable *st;
st = GetSymbolTable();
i = __get_symbol(st, addr);
if (i == -1) i = __get_symbol(st, addr - 1);
return __get_symbol_name(st, i);
}

View file

@ -24,18 +24,16 @@
* Returns debug binary symbol table, as global singleton.
* @return symbol table, or NULL w/ errno on first call
*/
struct SymbolTable *GetSymbolTable(void) {
noasan struct SymbolTable *GetSymbolTable(void) {
/* asan runtime depends on this function */
static bool once;
static struct SymbolTable *singleton;
const char *debugbin;
if (!once) {
once = true;
++ftrace;
if ((debugbin = FindDebugBinary()) &&
(singleton = OpenSymbolTable(debugbin))) {
__cxa_atexit(CloseSymbolTable, &singleton, NULL);
}
--ftrace;
++g_ftrace;
singleton = OpenSymbolTable(FindDebugBinary());
--g_ftrace;
}
return singleton;
}

View file

@ -7,9 +7,11 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern int kCrashSigs[8] hidden;
extern struct termios g_oldtermios hidden;
extern struct sigaction g_oldcrashacts[8] hidden;
extern hidden int kCrashSigs[8];
extern hidden bool g_isrunningundermake;
extern hidden bool g_isterminalinarticulate;
extern hidden struct termios g_oldtermios;
extern hidden struct sigaction g_oldcrashacts[8];
void __start_fatal(const char *, int) hidden;
void __start_fatal_ndebug(void) hidden;

View file

@ -5,42 +5,94 @@
#include "libc/nexgen32e/bsr.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/nr.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern char __fatalbuf[];
void __printf(const char *, ...);
forceinline void __sysv_exit(long rc) {
asm volatile("call\t__syscall__"
: /* no outputs */
: "a"(__NR_exit_group), "D"(rc)
: "memory", "cc");
}
forceinline int __sysv_close(long fd) {
long ax;
asm volatile("call\t__syscall__"
: "=a"(ax)
: "0"(__NR_close), "D"(fd)
: "rdx", "memory", "cc");
return ax;
}
forceinline int __sysv_open(const char *path, long flags, long mode) {
long ax, dx;
asm volatile("call\t__syscall__"
: "=a"(ax), "=d"(dx)
: "0"(__NR_open), "D"(path), "S"(flags), "1"(mode)
: "memory", "cc");
return ax;
}
forceinline long __sysv_read(long fd, void *data, unsigned long size) {
long ax, dx;
asm volatile("call\t__syscall__"
: "=a"(ax), "=d"(dx)
: "0"(__NR_read), "D"(fd), "S"(data), "1"(size)
: "memory", "cc");
return ax;
}
forceinline long __sysv_write(long fd, const void *data, unsigned long size) {
long ax, dx;
asm volatile("call\t__syscall__"
: "=a"(ax), "=d"(dx)
: "0"(__NR_write), "D"(fd), "S"(data), "1"(size)
: "memory", "cc");
return ax;
}
forceinline long __sysv_mprotect(void *addr, size_t size, long prot) {
long ax, dx;
asm volatile("call\t__syscall__"
: "=a"(ax), "=d"(dx)
: "0"(__NR_mprotect), "D"(addr), "S"(size), "1"(prot)
: "memory", "cc");
return ax;
}
forceinline int __sysv_getpid(void) {
long ax;
asm volatile("call\t__syscall__"
: "=a"(ax)
: "0"(__NR_getpid)
: "rdx", "memory", "cc");
return ax;
}
forceinline int __getpid(void) {
int rc;
if (!IsWindows()) {
asm volatile("call\t__syscall__"
: "=a"(rc)
: "0"(__NR_getpid)
: "rcx", "r11", "memory");
return rc;
return __sysv_getpid();
} else {
return GetCurrentProcessId();
}
}
forceinline ssize_t __write(const void *data, size_t size) {
forceinline ssize_t __write(const void *p, size_t n) {
char cf;
ssize_t rc;
uint32_t wrote;
if (!IsWindows()) {
asm volatile("call\t__syscall__"
: "=@ccc"(cf), "=a"(rc)
: "1"(__NR_write), "D"(2), "S"(data), "d"(size)
: "rcx", "r11", "memory");
if (cf && IsBsd()) rc = -rc;
return rc;
return __sysv_write(2, p, n);
} else if (WriteFile(GetStdHandle(kNtStdErrorHandle), p, n, &wrote, 0)) {
return wrote;
} else {
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
return wrote;
} else {
return -1;
}
return -GetLastError();
}
}
@ -54,6 +106,12 @@ forceinline ssize_t __write_str(const char *s) {
return __write(s, __strlen(s));
}
forceinline int __strcmp(const char *l, const char *r) {
size_t i = 0;
while (l[i] == r[i] && r[i]) ++i;
return (l[i] & 255) - (r[i] & 255);
}
forceinline char *__stpcpy(char *d, const char *s) {
size_t i;
for (i = 0;; ++i) {
@ -63,6 +121,13 @@ forceinline char *__stpcpy(char *d, const char *s) {
}
}
forceinline void *__repstosb(void *di, char al, size_t cx) {
asm("rep stosb"
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
: "0"(di), "1"(cx), "a"(al));
return di;
}
forceinline void *__repmovsb(void *di, void *si, size_t cx) {
asm("rep movsb"
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
@ -112,7 +177,64 @@ forceinline char *__hexcpy(char p[hasatleast 17], uint64_t x) {
return __fixcpy(p, x, ROUNDUP(x ? bsrl(x) + 1 : 1, 4));
}
void __printf(const char *, ...);
forceinline const void *__memchr(const void *s, unsigned char c, size_t n) {
size_t i;
for (i = 0; i < n; ++i) {
if (((const unsigned char *)s)[i] == c) {
return (const unsigned char *)s + i;
}
}
return 0;
}
forceinline char *__strstr(const char *haystack, const char *needle) {
size_t i;
for (;;) {
for (i = 0;; ++i) {
if (!needle[i]) return (/*unconst*/ char *)haystack;
if (!haystack[i]) break;
if (needle[i] != haystack[i]) break;
}
if (!*haystack++) break;
}
return 0;
}
forceinline char *__getenv(char **p, const char *s) {
size_t i, j;
if (p) {
for (i = 0; p[i]; ++i) {
for (j = 0;; ++j) {
if (!s[j]) {
if (p[i][j] == '=') {
return p[i] + j + 1;
}
break;
}
if (s[j] != p[i][j]) {
break;
}
}
}
}
return 0;
}
forceinline unsigned long __atoul(const char *p) {
int c;
unsigned long x = 0;
while ('0' <= (c = *p++) && c <= '9') x *= 10, x += c - '0';
return x;
}
forceinline long __atol(const char *p) {
int s = *p;
unsigned long x;
if (s == '-' || s == '+') ++p;
x = __atoul(p);
if (s == '-') x = -x;
return x;
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -55,8 +55,8 @@ bool32 IsDebuggerPresent(bool);
bool IsRunningUnderMake(void);
const char *GetSiCodeName(int, int);
void AppendResourceReport(char **, struct rusage *, const char *);
char *GetSymbolByAddr(int64_t);
void PrintGarbage(FILE *);
char *__get_symbol_by_addr(int64_t);
void PrintGarbage(void);
void PrintGarbageNumeric(FILE *);
#define showcrashreports() ShowCrashReports()
@ -75,15 +75,15 @@ extern unsigned __log_level; /* log level for runtime check */
// log a message with the specified log level (not checking if LOGGABLE)
#define LOGF(LEVEL, FMT, ...) \
do { \
++ftrace; \
++g_ftrace; \
flogf(LEVEL, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \
--g_ftrace; \
} while (0)
// die with an error message without backtrace and debugger invocation
#define DIEF(FMT, ...) \
do { \
++ftrace; \
++g_ftrace; \
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
exit(1); \
unreachable; \
@ -91,7 +91,7 @@ extern unsigned __log_level; /* log level for runtime check */
#define FATALF(FMT, ...) \
do { \
++ftrace; \
++g_ftrace; \
ffatalf(kLogFatal, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
unreachable; \
} while (0)
@ -99,78 +99,78 @@ extern unsigned __log_level; /* log level for runtime check */
#define ERRORF(FMT, ...) \
do { \
if (LOGGABLE(kLogError)) { \
++ftrace; \
++g_ftrace; \
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \
--g_ftrace; \
} \
} while (0)
#define WARNF(FMT, ...) \
do { \
if (LOGGABLE(kLogWarn)) { \
++ftrace; \
++g_ftrace; \
flogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \
--g_ftrace; \
} \
} while (0)
#define INFOF(FMT, ...) \
do { \
if (LOGGABLE(kLogInfo)) { \
++ftrace; \
++g_ftrace; \
flogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \
--g_ftrace; \
} \
} while (0)
#define VERBOSEF(FMT, ...) \
do { \
if (LOGGABLE(kLogVerbose)) { \
++ftrace; \
++g_ftrace; \
fverbosef(kLogVerbose, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \
--g_ftrace; \
} \
} while (0)
#define DEBUGF(FMT, ...) \
do { \
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
++ftrace; \
++g_ftrace; \
fdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \
--g_ftrace; \
} \
} while (0)
#define NOISEF(FMT, ...) \
do { \
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
++ftrace; \
++g_ftrace; \
fnoisef(kLogNoise, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \
--g_ftrace; \
} \
} while (0)
#define FLOGF(F, FMT, ...) \
do { \
if (LOGGABLE(kLogInfo)) { \
++ftrace; \
++g_ftrace; \
flogf(kLogInfo, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
--ftrace; \
--g_ftrace; \
} \
} while (0)
#define FWARNF(F, FMT, ...) \
do { \
if (LOGGABLE(kLogWarn)) { \
++ftrace; \
++g_ftrace; \
flogf(kLogWarn, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
--ftrace; \
--g_ftrace; \
} \
} while (0)
#define FFATALF(F, FMT, ...) \
do { \
++ftrace; \
++g_ftrace; \
ffatalf(kLogFatal, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
unreachable; \
} while (0)
@ -178,18 +178,18 @@ extern unsigned __log_level; /* log level for runtime check */
#define FDEBUGF(F, FMT, ...) \
do { \
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
++ftrace; \
++g_ftrace; \
fdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
--ftrace; \
--g_ftrace; \
} \
} while (0)
#define FNOISEF(F, FMT, ...) \
do { \
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
++ftrace; \
++g_ftrace; \
fnoisef(kLogNoise, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
--ftrace; \
--g_ftrace; \
} \
} while (0)
@ -201,9 +201,9 @@ extern unsigned __log_level; /* log level for runtime check */
({ \
autotype(FORM) Ax = (FORM); \
if (UNLIKELY(Ax == (typeof(Ax))(-1)) && LOGGABLE(kLogWarn)) { \
++ftrace; \
++g_ftrace; \
__logerrno(__FILE__, __LINE__, #FORM); \
--ftrace; \
--g_ftrace; \
} \
Ax; \
})
@ -212,9 +212,9 @@ extern unsigned __log_level; /* log level for runtime check */
({ \
autotype(FORM) Ax = (FORM); \
if (Ax == NULL && LOGGABLE(kLogWarn)) { \
++ftrace; \
++g_ftrace; \
__logerrno(__FILE__, __LINE__, #FORM); \
--ftrace; \
--g_ftrace; \
} \
Ax; \
})

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
@ -44,6 +45,7 @@
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/fileno.h"
@ -94,20 +96,23 @@ relegated static const char *TinyStrSignal(int sig) {
return "???";
}
relegated static void ShowFunctionCalls(int fd, ucontext_t *ctx) {
relegated static void ShowFunctionCalls(ucontext_t *ctx) {
struct StackFrame *bp;
struct StackFrame goodframe;
write(fd, "\n", 1);
if (ctx && ctx->uc_mcontext.rip && ctx->uc_mcontext.rbp) {
if (ctx->uc_mcontext.rip && ctx->uc_mcontext.rbp) {
goodframe.next = (struct StackFrame *)ctx->uc_mcontext.rbp;
goodframe.addr = ctx->uc_mcontext.rip;
bp = &goodframe;
ShowBacktrace(fd, bp);
ShowBacktrace(2, bp);
}
}
relegated static char *AddFlag(char *p, int b, const char *s) {
if (b) p = stpcpy(p, s);
if (b) {
p = __stpcpy(p, s);
} else {
*p = 0;
}
return p;
}
@ -137,11 +142,13 @@ relegated static char *DescribeCpuFlags(char *p, int flags, int x87sw,
return p;
}
relegated static char *ShowGeneralRegisters(char *p, ucontext_t *ctx) {
relegated static void ShowGeneralRegisters(ucontext_t *ctx) {
int64_t x;
const char *s;
size_t i, j, k;
long double st;
char *p, buf[128];
p = buf;
*p++ = '\n';
for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) {
if (j > 0) *p++ = ' ';
@ -162,20 +169,25 @@ relegated static char *ShowGeneralRegisters(char *p, ucontext_t *ctx) {
if (x < 0) x = -x, *p++ = '-';
p = __uintcpy(p, x / 1000), *p++ = '.';
p = __uintcpy(p, x % 1000), *p++ = '\n';
*p = 0;
__printf("%s", buf);
p = buf;
}
}
return DescribeCpuFlags(
DescribeCpuFlags(
p, ctx->uc_mcontext.gregs[REG_EFL],
ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->swd : 0,
ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->mxcsr : 0);
__printf("%s\n", buf);
}
relegated static char *ShowSseRegisters(char *p, ucontext_t *ctx) {
relegated static void ShowSseRegisters(ucontext_t *ctx) {
size_t i;
char *p, buf[128];
if (ctx->uc_mcontext.fpregs) {
p = __stpcpy(p, "\n\n");
__printf("\n");
for (i = 0; i < 8; ++i) {
p = __stpcpy(p, "XMM");
p = buf;
if (i >= 10) {
*p++ = i / 10 + '0';
*p++ = i % 10 + '0';
@ -197,93 +209,61 @@ relegated static char *ShowSseRegisters(char *p, ucontext_t *ctx) {
*p++ = ' ';
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[1], 64);
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[0], 64);
*p++ = '\n';
*p = 0;
__printf("XMM%s\n", buf);
}
}
return p;
}
relegated static void ShowMemoryMappings(int outfd) {
ssize_t rc;
int c, infd;
char buf[64];
if (!IsTiny()) {
PrintMemoryIntervals(outfd, &_mmi);
if ((infd = open("/proc/self/maps", O_RDONLY)) != -1) {
while ((rc = read(infd, buf, sizeof(buf))) > 0) {
__write(buf, rc);
}
}
close(infd);
}
}
void ShowCrashReportHook(int, int, int, struct siginfo *, ucontext_t *);
relegated void ShowCrashReport(int err, int fd, int sig, struct siginfo *si,
relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
ucontext_t *ctx) {
int i;
char *p;
bool colorful;
char hostname[64];
char host[64];
intptr_t stackaddr;
struct utsname names;
static char buf[4096];
if (weaken(ShowCrashReportHook)) {
ShowCrashReportHook(err, fd, sig, si, ctx);
ShowCrashReportHook(2, err, sig, si, ctx);
}
colorful = cancolor();
__stpcpy(hostname, "unknown");
gethostname(hostname, sizeof(hostname));
__stpcpy(host, "unknown");
gethostname(host, sizeof(host));
p = buf;
p = __stpcpy(p, "\n");
if (colorful) p = __stpcpy(p, "\e[30;101m");
p = __stpcpy(p, "error");
if (colorful) p = __stpcpy(p, "\e[0m");
p = __stpcpy(p, ": Uncaught SIG");
p = __stpcpy(p, TinyStrSignal(sig));
if (si) {
p = __stpcpy(p, " (");
p = __stpcpy(p, GetSiCodeName(sig, si->si_code));
p = __stpcpy(p, ")");
__printf("\n%serror%s: Uncaught SIG%s",
!g_isterminalinarticulate ? "\e[30;101m" : "",
!g_isterminalinarticulate ? "\e[0m" : "", TinyStrSignal(sig));
stackaddr = GetStackAddr(0);
if (ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) &&
ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE)) {
__printf(" (Stack Overflow)");
} else if (si) {
__printf(" (%s)", GetSiCodeName(sig, si->si_code));
}
p = __stpcpy(p, " on ");
p = __stpcpy(p, hostname);
p = __stpcpy(p, " pid ");
p = __intcpy(p, __getpid());
p = __stpcpy(p, "\n ");
p = __stpcpy(p, program_invocation_name);
p = __stpcpy(p, "\n ");
p = __stpcpy(p, strerror(err));
*p++ = '\n';
__printf(" on %s pid %d\n %s\n %s\n", host, __getpid(),
program_invocation_name, strerror(err));
if (uname(&names) != -1) {
p = __stpcpy(p, " ");
p = __stpcpy(p, names.sysname), *p++ = ' ';
p = __stpcpy(p, names.nodename), *p++ = ' ';
p = __stpcpy(p, names.release), *p++ = ' ';
p = __stpcpy(p, names.version), *p++ = '\n';
__printf(" %s %s %s %s\n", names.sysname, names.nodename, names.release,
names.version);
}
__write(buf, p - buf);
ShowFunctionCalls(fd, ctx);
if (ctx) {
p = buf;
p = ShowGeneralRegisters(p, ctx);
p = ShowSseRegisters(p, ctx);
*p++ = '\n';
__write(buf, p - buf);
__printf("\n");
ShowFunctionCalls(ctx);
ShowGeneralRegisters(ctx);
ShowSseRegisters(ctx);
}
p = buf;
*p++ = '\n';
ShowMemoryMappings(fd);
__write(buf, p - buf);
__printf("\n");
PrintMemoryIntervals(2, &_mmi);
/* PrintSystemMappings(2); */
if (__argv) {
for (i = 0; i < __argc; ++i) {
if (!__argv[i]) continue;
if (IsAsan() && !__asan_is_valid(__argv[i], 1)) continue;
__write(__argv[i], strlen(__argv[i]));
__write(" ", 1);
__printf("%s ", __argv[i]);
}
}
__write("\n", 1);
__printf("\n");
}
relegated static void RestoreDefaultCrashSignalHandlers(void) {
@ -309,29 +289,48 @@ relegated static void RestoreDefaultCrashSignalHandlers(void) {
*
* This function never returns, except for traps w/ human supervision.
*/
relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
noasan relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
intptr_t rip;
int gdbpid, err;
static bool once;
err = errno;
if (once) _exit(119);
once = true;
static bool noreentry, notpossible;
++g_ftrace;
rip = ctx ? ctx->uc_mcontext.rip : 0;
if ((gdbpid = IsDebuggerPresent(true))) {
DebugBreak();
} else if (IsTerminalInarticulate() || IsRunningUnderMake()) {
gdbpid = -1;
} else if (FindDebugBinary()) {
RestoreDefaultCrashSignalHandlers();
gdbpid =
attachdebugger(((sig == SIGTRAP || sig == SIGQUIT) &&
(rip >= (intptr_t)&_base && rip < (intptr_t)&_etext))
? rip
: 0);
if (cmpxchg(&noreentry, false, true)) {
err = errno;
if ((gdbpid = IsDebuggerPresent(true))) {
DebugBreak();
} else if (g_isterminalinarticulate || g_isrunningundermake) {
gdbpid = -1;
} else if (FindDebugBinary()) {
RestoreDefaultCrashSignalHandlers();
gdbpid =
attachdebugger(((sig == SIGTRAP || sig == SIGQUIT) &&
(rip >= (intptr_t)&_base && rip < (intptr_t)&_etext))
? rip
: 0);
}
if (!(gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT))) {
__restore_tty(1);
ShowCrashReport(err, sig, si, ctx);
_Exit(128 + sig);
}
} else if (cmpxchg(&notpossible, false, true)) {
__printf("\n"
"\n"
"CRASHED WHILE CRASHING WITH SIG%s\n"
"%s\n"
"RIP %x\n"
"RSP %x\n"
"RBP %x\n"
"\n",
TinyStrSignal(sig), __argv[0], rip, ctx ? ctx->uc_mcontext.rsp : 0,
ctx ? ctx->uc_mcontext.rbp : 0);
_Exit(119);
} else {
for (;;) {
asm("ud2");
}
}
if (gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT)) return;
__restore_tty(1);
ShowCrashReport(err, STDERR_FILENO, sig, si, ctx);
exit(128 + sig);
unreachable;
noreentry = false;
--g_ftrace;
}

View file

@ -16,6 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/stdio/stdio.h"
@ -24,19 +26,31 @@
/**
* Prints list of deferred operations on shadow stack.
*/
void PrintGarbage(FILE *f) {
void PrintGarbage(void) {
size_t i;
f = stderr;
fprintf(f, "\n");
fprintf(f, " SHADOW STACK @ 0x%016lx\n", __builtin_frame_address(0));
fprintf(f, " garbage entry parent frame original ret callback arg \n");
fprintf(f, "-------------- -------------- ------------------ ------------------ ------------------\n");
for (i = __garbage.i; i--;) {
fprintf(f, "0x%012lx 0x%012lx %-18s %-18s 0x%016lx\n",
__garbage.p + i,
__garbage.p[i].frame,
GetSymbolByAddr(__garbage.p[i].ret-1),
GetSymbolByAddr(__garbage.p[i].fn),
__garbage.p[i].arg);
char name[19];
const char *symbol;
__printf("\n");
__printf(" SHADOW STACK @ 0x%p\n", __builtin_frame_address(0));
__printf("garbage entry parent frame original ret callback arg \n");
__printf("-------------- -------------- ------------------ ------------------ ------------------\n");
if (__garbage.i) {
for (i = __garbage.i; i--;) {
symbol = __get_symbol_by_addr(__garbage.p[i].ret);
if (symbol) {
snprintf(name, sizeof(name), "%s", symbol);
} else {
snprintf(name, sizeof(name), "0x%012lx", __garbage.p[i].ret);
}
__printf("0x%p 0x%p %18s %18s 0x%016lx\n",
__garbage.p + i,
__garbage.p[i].frame,
name,
__get_symbol_by_addr(__garbage.p[i].fn),
__garbage.p[i].arg);
}
} else {
__printf("%14s %14s %18s %18s %18s\n","empty","-","-","-","-");
}
__printf("\n");
}

View file

@ -16,22 +16,15 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/termios.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/dce.h"
#include "libc/log/check.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigaltstack.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/nt/signals.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/ss.h"
STATIC_YOINK("__die");
@ -57,6 +50,7 @@ extern const unsigned char __oncrash_thunks[8][11];
void ShowCrashReports(void) {
size_t i;
struct sigaction sa;
struct sigaltstack ss;
/* <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
kCrashSigs[0] = SIGQUIT; /* ctrl+\ aka ctrl+break */
kCrashSigs[1] = SIGFPE; /* 1 / 0 */
@ -68,11 +62,16 @@ void ShowCrashReports(void) {
kCrashSigs[7] = SIGPIPE; /* write to closed thing */
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
bzero(&sa, sizeof(sa));
sa.sa_flags = SA_RESETHAND | SA_SIGINFO;
ss.ss_flags = 0;
ss.ss_size = SIGSTKSZ;
ss.ss_sp = malloc(SIGSTKSZ);
__cxa_atexit(free, ss.ss_sp, 0);
sa.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
sigfillset(&sa.sa_mask);
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
sigdelset(&sa.sa_mask, kCrashSigs[i]);
}
sigaltstack(&ss, 0);
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
if (kCrashSigs[i]) {
sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i];