Skip to content

Commit 379cd77

Browse files
committed
Improve memory manager and signal handling
On Windows, mmap() now chooses addresses transactionally. It reduces the risk of badness when interacting with the WIN32 memory manager. We don't throw darts anymore. There is also no more retry limit, since we recover from mystery maps more gracefully. The subroutine for combining adjacent maps has been rewritten for clarity. The print maps subroutine is better This change goes to great lengths to perfect the stack overflow code. On Windows you can now longjmp() out of a crash signal handler. Guard pages previously weren't being restored properly by the signal handler. That's fixed, so on Windows you can now handle a stack overflow multiple times. Great thought has been put into selecting the perfect SIGSTKSZ constants so you can save sigaltstack() memory. You can now use kprintf() with 512 bytes of stack available. The guard pages beneath the main stack are now recorded in the memory manager. This change fixes getcontext() so it works right with the %rax register.
1 parent 36e5861 commit 379cd77

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+826
-562
lines changed

libc/calls/sigaltstack.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,19 +113,24 @@ static int sigaltstack_bsd(const struct sigaltstack *neu,
113113
* struct sigaction sa;
114114
* struct sigaltstack ss;
115115
* ss.ss_flags = 0;
116-
* ss.ss_size = sysconf(_SC_MINSIGSTKSZ) + 8192;
116+
* ss.ss_size = sysconf(_SC_SIGSTKSZ);
117117
* ss.ss_sp = malloc(ss.ss_size);
118118
* sigaltstack(&ss, 0);
119119
* sigemptyset(&sa.ss_mask);
120120
* sa.sa_flags = SA_ONSTACK;
121121
* sa.sa_handler = OnStackOverflow;
122122
* sigaction(SIGSEGV, &sa, 0);
123123
*
124+
* Your stack size should be `sysconf(_SC_SIGSTKSZ)` which should be
125+
* somewhere in the ballpark of 32kb to 64kb. You should go no lower
126+
* than `sysconf(_SC_MINSIGSTKSZ) + 2048` which could be 4kb - 34kb.
127+
* Cosmo also defines `SIGSTKSZ` as 32kb, which should also be safe.
128+
*
124129
* @param neu if non-null will install new signal alt stack
125130
* @param old if non-null will receive current signal alt stack
126131
* @return 0 on success, or -1 w/ errno
127132
* @raise EFAULT if bad memory was supplied
128-
* @raise ENOMEM if `neu->ss_size` is less than `MINSIGSTKSZ`
133+
* @raise ENOMEM if `neu->ss_size` is beneath `sysconf(_SC_MINSIGSTKSZ)`
129134
*/
130135
int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) {
131136
int rc;

libc/calls/sigenter-xnu.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "libc/runtime/syslib.internal.h"
3434
#include "libc/str/str.h"
3535
#include "libc/sysv/consts/sa.h"
36+
#include "libc/sysv/consts/sig.h"
3637

3738
/**
3839
* @fileoverview XNU kernel callback normalization.
@@ -513,6 +514,7 @@ privileged void __sigenter_xnu(int sig, struct siginfo_xnu *xnuinfo,
513514
flags = __sighandflags[sig];
514515

515516
#ifdef __aarch64__
517+
516518
// xnu silicon claims to support sa_resethand but it does nothing
517519
// this can be tested, since it clears the bit from flags as well
518520
if (flags & SA_RESETHAND) {
@@ -521,6 +523,13 @@ privileged void __sigenter_xnu(int sig, struct siginfo_xnu *xnuinfo,
521523
__sighandflags[sig] = 0;
522524
__sighandrvas[sig] = 0;
523525
}
526+
527+
// unlike amd64, the instruction pointer on arm64 isn't advanced
528+
// past the debugger breakpoint instruction automatically. we need
529+
// this so execution can resume after __builtin_trap().
530+
if (xnuctx && sig == SIGTRAP)
531+
xnuctx->uc_mcontext->__ss.__pc += 4;
532+
524533
#endif
525534

526535
if (~flags & SA_SIGINFO) {

libc/calls/struct/ucontext.internal.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_INTERNAL_H_
22
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_INTERNAL_H_
33
#include "libc/calls/ucontext.h"
4-
#include "libc/nt/struct/context.h"
54
COSMOPOLITAN_C_START_
65

76
#ifdef __x86_64__
87
#define PC rip
98
#define SP rsp
109
#define BP rbp
10+
#define RES0 rax
11+
#define RES1 rdx
1112
#define ARG0 rdi
1213
#define ARG1 rsi
1314
#define ARG2 rdx
@@ -18,6 +19,8 @@ COSMOPOLITAN_C_START_
1819
#define PC pc
1920
#define SP sp
2021
#define BP regs[29]
22+
#define RES0 regs[0]
23+
#define RES1 regs[1]
2124
#define ARG0 regs[0]
2225
#define ARG1 regs[1]
2326
#define ARG2 regs[2]
@@ -28,8 +31,5 @@ COSMOPOLITAN_C_START_
2831
#error "unsupported architecture"
2932
#endif
3033

31-
void _ntcontext2linux(struct ucontext *, const struct NtContext *);
32-
void _ntlinux2context(struct NtContext *, const ucontext_t *);
33-
3434
COSMOPOLITAN_C_END_
3535
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_INTERNAL_H_ */

libc/dlopen/dlopen.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,7 @@ void *cosmo_dlopen(const char *path, int mode) {
810810
}
811811
ALLOW_CANCELATION;
812812
ALLOW_SIGNALS;
813-
STRACE("dlopen(%#s, %d) → %p% m", path, mode, res);
813+
STRACE("cosmo_dlopen(%#s, %d) → %p% m", path, mode, res);
814814
return res;
815815
}
816816

@@ -855,7 +855,7 @@ void *cosmo_dlsym(void *handle, const char *name) {
855855
} else {
856856
func = 0;
857857
}
858-
STRACE("dlsym(%p, %#s) → %p", handle, name, func);
858+
STRACE("cosmo_dlsym(%p, %#s) → %p", handle, name, func);
859859
return func;
860860
}
861861

@@ -890,7 +890,7 @@ int cosmo_dlclose(void *handle) {
890890
} else {
891891
res = -1;
892892
}
893-
STRACE("dlclose(%p) → %d", handle, res);
893+
STRACE("cosmo_dlclose(%p) → %d", handle, res);
894894
return res;
895895
}
896896

@@ -909,6 +909,6 @@ char *cosmo_dlerror(void) {
909909
} else {
910910
res = dlerror_buf;
911911
}
912-
STRACE("dlerror() → %#s", res);
912+
STRACE("cosmo_dlerror() → %#s", res);
913913
return res;
914914
}

libc/dlopen/stubs.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/dlopen/dlfcn.h"
20+
#include "libc/intrin/strace.h"
21+
22+
#define DLOPEN_ERROR \
23+
"dlopen() isn't supported; consider using cosmo_dlopen() and read its docs"
2024

2125
/**
2226
* Opens dynamic shared object using host platform libc.
@@ -27,12 +31,13 @@
2731
*
2832
* @return null always
2933
*/
30-
void *dlopen(const char *, int) {
34+
void *dlopen(const char *path, int mode) {
35+
STRACE("dlopen(%#s, %d) → 0 [%s]", path, mode, DLOPEN_ERROR);
3136
return 0;
3237
}
3338

3439
char *dlerror(void) {
35-
return "dlopen() isn't supported by cosmo; try using cosmo_dlopen()";
40+
return DLOPEN_ERROR;
3641
}
3742

3843
void *dlsym(void *, const char *) {

libc/intrin/directmap.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/intrin/directmap.h"
1920
#include "libc/calls/calls.h"
2021
#include "libc/calls/syscall-sysv.internal.h"
2122
#include "libc/dce.h"
2223
#include "libc/errno.h"
24+
#include "libc/intrin/describebacktrace.h"
2325
#include "libc/intrin/describeflags.h"
24-
#include "libc/intrin/directmap.h"
2526
#include "libc/intrin/strace.h"
2627
#include "libc/nt/runtime.h"
2728
#include "libc/runtime/memtrack.internal.h"

libc/intrin/getminsigstksz.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,47 @@
1616
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/calls/struct/siginfo.h"
20+
#include "libc/calls/ucontext.h"
21+
#include "libc/dce.h"
1922
#include "libc/intrin/getauxval.h"
20-
#include "libc/macros.h"
2123
#include "libc/runtime/runtime.h"
2224
#include "libc/sysv/consts/auxv.h"
2325
#include "libc/sysv/consts/ss.h"
2426

2527
long __get_minsigstksz(void) {
26-
struct AuxiliaryValue x;
27-
x = __getauxval(AT_MINSIGSTKSZ);
28-
if (x.isfound) {
29-
return MAX(_MINSIGSTKSZ - 1024, x.value) + 1024;
28+
struct AuxiliaryValue av;
29+
av = __getauxval(AT_MINSIGSTKSZ);
30+
if (av.isfound) {
31+
long res = av.value;
32+
if (!IsLinux())
33+
res += sizeof(struct ucontext) + sizeof(struct siginfo) + 128;
34+
if (res < _MINSIGSTKSZ)
35+
res = _MINSIGSTKSZ;
36+
return res;
3037
} else {
38+
// _MINSIGSTKSZ takes these things into consideration:
39+
//
40+
// 1. The platform definition of MINSIGSTKSZ. This will probably be
41+
// enforced by the kernel when calling sys_sigaltstack(). On ARM
42+
// platforms this might be several kilobytes larger than x86. On
43+
// Linux they really want you to use AT_MINSIGSTKSZ instead. The
44+
// kernel should ideally set this to be the number of bytes that
45+
// get subtracted from the stack pointer when delivering signals
46+
// meaning that if you use this for a stack size your handler is
47+
// called successfully but if it uses the stack then it'll crash
48+
//
49+
// 2. Cosmo sigenter overhead. On non-Linux OSes the kernel calls a
50+
// trampoline in the libc runtime, which translates the platform
51+
// specific signal frame to the Linux memory layout. It means we
52+
// need to push ~1024 extra bytes on the stack to call a handler
53+
//
54+
// 3. Sanity testing. Assume we use sysconf(_SC_MINSIGSTKSZ) + 2048
55+
// as our stack size (see stackoverflow1_test.c). Then we should
56+
// have enough room to use kprintf() from our signal handler. If
57+
// that isn't the case, then this should be increased a bit more
58+
// noting that if 1024 is used then kprintf should print refusal
59+
//
3160
return _MINSIGSTKSZ;
3261
}
3362
}

libc/intrin/getsafesize.greg.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "ape/sections.internal.h"
20-
#include "libc/intrin/kprintf.h"
2120
#include "libc/runtime/memtrack.internal.h"
21+
#include "libc/runtime/runtime.h"
2222
#include "libc/runtime/stack.h"
2323
#include "libc/thread/posixthread.internal.h"
2424
#include "libc/thread/tls.h"
@@ -37,12 +37,13 @@ privileged optimizesize long __get_safe_size(long want, long extraspace) {
3737
struct PosixThread *pt;
3838
struct CosmoTib *tib = __get_tls_privileged();
3939
long bottom, sp = GetStackPointer();
40-
if ((char *)sp >= tib->tib_sigstack_addr &&
41-
(char *)sp <= tib->tib_sigstack_addr + tib->tib_sigstack_size) {
40+
if (sp >= (long)tib->tib_sigstack_addr &&
41+
sp < (long)tib->tib_sigstack_addr + tib->tib_sigstack_size) {
4242
bottom = (long)tib->tib_sigstack_addr;
4343
} else if ((pt = (struct PosixThread *)tib->tib_pthread) &&
44-
pt->pt_attr.__stacksize) {
45-
bottom = (long)pt->pt_attr.__stackaddr + pt->pt_attr.__guardsize;
44+
sp >= (long)pt->pt_attr.__stackaddr &&
45+
sp < (long)pt->pt_attr.__stackaddr + pt->pt_attr.__stacksize) {
46+
bottom = (long)pt->pt_attr.__stackaddr;
4647
} else {
4748
return want;
4849
}

libc/intrin/kisdangerous.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/intrin/kprintf.h"
2020
#include "libc/intrin/maps.h"
21+
#include "libc/runtime/runtime.h"
2122

2223
privileged optimizesize bool32 kisdangerous(const void *addr) {
2324
bool32 res = true;
@@ -26,7 +27,8 @@ privileged optimizesize bool32 kisdangerous(const void *addr) {
2627
struct Map *map;
2728
if ((map = __maps_floor(addr)))
2829
if ((const char *)addr >= map->addr &&
29-
(const char *)addr < map->addr + map->size)
30+
(const char *)addr <
31+
map->addr + ((map->size + __pagesize - 1) & -__pagesize))
3032
res = false;
3133
} else {
3234
res = false;

libc/intrin/kprintf.greg.c

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -352,9 +352,8 @@ ABI void klog(const char *b, size_t n) {
352352
long h;
353353
uint32_t wrote;
354354
long rax, rdi, rsi, rdx;
355-
if ((h = kloghandle()) == -1) {
355+
if ((h = kloghandle()) == -1)
356356
return;
357-
}
358357
if (IsWindows()) {
359358
bool32 ok;
360359
intptr_t ev;
@@ -408,10 +407,11 @@ ABI void klog(const char *b, size_t n) {
408407
ABI static size_t kformat(char *b, size_t n, const char *fmt, va_list va) {
409408
int si;
410409
wint_t t, u;
410+
char *cxxbuf;
411411
const char *abet;
412412
signed char type;
413413
const char *s, *f;
414-
char cxxbuf[3000];
414+
int cxxbufsize = 0;
415415
struct CosmoTib *tib;
416416
unsigned long long x;
417417
unsigned i, j, m, rem, sign, hash, cols, prec;
@@ -755,13 +755,25 @@ ABI static size_t kformat(char *b, size_t n, const char *fmt, va_list va) {
755755
x = va_arg(va, intptr_t);
756756
if (_weaken(__symtab) && *_weaken(__symtab) &&
757757
(idx = _weaken(__get_symbol)(0, x)) != -1) {
758-
/* if (p + 1 <= e) */
759-
/* *p++ = '&'; */
760758
s = (*_weaken(__symtab))->name_base +
761759
(*_weaken(__symtab))->names[idx];
762-
if (_weaken(__is_mangled) && _weaken(__is_mangled)(s) &&
763-
_weaken(__demangle)(cxxbuf, s, sizeof(cxxbuf)) != -1)
764-
s = cxxbuf;
760+
#pragma GCC push_options
761+
#pragma GCC diagnostic ignored "-Walloca-larger-than="
762+
// decipher c++ symbols if there's enough stack memory
763+
// stack size requirement assumes max_depth's still 20
764+
if (_weaken(__demangle) && //
765+
_weaken(__is_mangled) && //
766+
_weaken(__is_mangled)(s)) {
767+
if (!cxxbufsize)
768+
if ((cxxbufsize = __get_safe_size(8192, 8192)) >= 512) {
769+
cxxbuf = alloca(cxxbufsize);
770+
CheckLargeStackAllocation(cxxbuf, sizeof(cxxbufsize));
771+
}
772+
if (cxxbufsize >= 512)
773+
if (_weaken(__demangle)(cxxbuf, s, cxxbufsize) != -1)
774+
s = cxxbuf;
775+
}
776+
#pragma GCC pop_options
765777
goto FormatString;
766778
}
767779
base = 4;
@@ -1050,7 +1062,7 @@ ABI size_t kvsnprintf(char *b, size_t n, const char *fmt, va_list v) {
10501062
ABI void kvprintf(const char *fmt, va_list v) {
10511063
#pragma GCC push_options
10521064
#pragma GCC diagnostic ignored "-Walloca-larger-than="
1053-
long size = __get_safe_size(8000, 8000);
1065+
long size = __get_safe_size(8192, 2048);
10541066
if (size < 80) {
10551067
klog(STACK_ERROR, sizeof(STACK_ERROR) - 1);
10561068
return;

0 commit comments

Comments
 (0)