mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-04-23 07:14:43 +00:00
Fix pthread stacks with larger guard size
This commit is contained in:
parent
1db76c288e
commit
e97f1a99cf
10 changed files with 68 additions and 42 deletions
|
@ -30,7 +30,6 @@ const char *(DescribeMapFlags)(char buf[64], int x) {
|
||||||
{MAP_SHARED, "SHARED"}, //
|
{MAP_SHARED, "SHARED"}, //
|
||||||
{MAP_FIXED, "FIXED"}, //
|
{MAP_FIXED, "FIXED"}, //
|
||||||
{MAP_FIXED_NOREPLACE, "FIXED_NOREPLACE"}, //
|
{MAP_FIXED_NOREPLACE, "FIXED_NOREPLACE"}, //
|
||||||
{MAP_GROWSDOWN, "GROWSDOWN"}, //
|
|
||||||
{MAP_CONCEAL, "CONCEAL"}, //
|
{MAP_CONCEAL, "CONCEAL"}, //
|
||||||
{MAP_HUGETLB, "HUGETLB"}, //
|
{MAP_HUGETLB, "HUGETLB"}, //
|
||||||
{MAP_LOCKED, "LOCKED"}, //
|
{MAP_LOCKED, "LOCKED"}, //
|
||||||
|
|
|
@ -49,7 +49,6 @@ const char *(DescribeMapping)(char p[8], int prot, int flags) {
|
||||||
DescribeProt(p, prot);
|
DescribeProt(p, prot);
|
||||||
p[3] = DescribeMapType(flags);
|
p[3] = DescribeMapType(flags);
|
||||||
p[4] = (flags & MAP_ANONYMOUS) ? 'a' : '-';
|
p[4] = (flags & MAP_ANONYMOUS) ? 'a' : '-';
|
||||||
p[5] = (flags & MAP_GROWSDOWN) ? 'G' : '-';
|
|
||||||
p[6] = (flags & MAP_FIXED) ? 'F' : '-';
|
p[6] = (flags & MAP_FIXED) ? 'F' : '-';
|
||||||
p[7] = 0;
|
p[7] = 0;
|
||||||
return p;
|
return p;
|
||||||
|
|
|
@ -85,7 +85,7 @@ typedef struct pthread_attr_s {
|
||||||
char detachstate;
|
char detachstate;
|
||||||
size_t stacksize;
|
size_t stacksize;
|
||||||
size_t guardsize;
|
size_t guardsize;
|
||||||
void *stackaddr;
|
char *stackaddr;
|
||||||
int scope;
|
int scope;
|
||||||
int schedpolicy;
|
int schedpolicy;
|
||||||
int inheritsched;
|
int inheritsched;
|
||||||
|
|
|
@ -30,8 +30,5 @@ int pthread_attr_init(pthread_attr_t *attr) {
|
||||||
.stacksize = GetStackSize(),
|
.stacksize = GetStackSize(),
|
||||||
.guardsize = PAGESIZE,
|
.guardsize = PAGESIZE,
|
||||||
};
|
};
|
||||||
if (attr->stacksize >= 1048576) {
|
|
||||||
attr->guardsize = FRAMESIZE;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -595,9 +595,7 @@ int clone(void *func, void *stk, size_t stksz, int flags, void *arg, int *ptid,
|
||||||
((flags & CLONE_VM) && (stksz < PAGESIZE || (stksz & 15)))) {
|
((flags & CLONE_VM) && (stksz < PAGESIZE || (stksz & 15)))) {
|
||||||
rc = einval();
|
rc = einval();
|
||||||
} else if (IsAsan() &&
|
} else if (IsAsan() &&
|
||||||
((stksz > PAGESIZE &&
|
(((flags & CLONE_SETTLS) && !__asan_is_valid(tls, 64)) ||
|
||||||
!__asan_is_valid((char *)stk + PAGESIZE, stksz - PAGESIZE)) ||
|
|
||||||
((flags & CLONE_SETTLS) && !__asan_is_valid(tls, 64)) ||
|
|
||||||
((flags & CLONE_SETTLS) && !__asan_is_valid(tls, sizeof(long))) ||
|
((flags & CLONE_SETTLS) && !__asan_is_valid(tls, sizeof(long))) ||
|
||||||
((flags & CLONE_PARENT_SETTID) &&
|
((flags & CLONE_PARENT_SETTID) &&
|
||||||
!__asan_is_valid(ptid, sizeof(*ptid))) ||
|
!__asan_is_valid(ptid, sizeof(*ptid))) ||
|
||||||
|
|
|
@ -13,7 +13,6 @@ extern const int MAP_EXECUTABLE;
|
||||||
extern const int MAP_FILE;
|
extern const int MAP_FILE;
|
||||||
extern const int MAP_FIXED;
|
extern const int MAP_FIXED;
|
||||||
extern const int MAP_FIXED_NOREPLACE;
|
extern const int MAP_FIXED_NOREPLACE;
|
||||||
extern const int MAP_GROWSDOWN;
|
|
||||||
extern const int MAP_HASSEMAPHORE;
|
extern const int MAP_HASSEMAPHORE;
|
||||||
extern const int MAP_HUGETLB;
|
extern const int MAP_HUGETLB;
|
||||||
extern const int MAP_HUGE_MASK;
|
extern const int MAP_HUGE_MASK;
|
||||||
|
@ -44,7 +43,6 @@ COSMOPOLITAN_C_END_
|
||||||
#define MAP_DENYWRITE SYMBOLIC(MAP_DENYWRITE)
|
#define MAP_DENYWRITE SYMBOLIC(MAP_DENYWRITE)
|
||||||
#define MAP_EXECUTABLE SYMBOLIC(MAP_EXECUTABLE)
|
#define MAP_EXECUTABLE SYMBOLIC(MAP_EXECUTABLE)
|
||||||
#define MAP_FIXED_NOREPLACE SYMBOLIC(MAP_FIXED_NOREPLACE)
|
#define MAP_FIXED_NOREPLACE SYMBOLIC(MAP_FIXED_NOREPLACE)
|
||||||
#define MAP_GROWSDOWN SYMBOLIC(MAP_GROWSDOWN)
|
|
||||||
#define MAP_HASSEMAPHORE SYMBOLIC(MAP_HASSEMAPHORE)
|
#define MAP_HASSEMAPHORE SYMBOLIC(MAP_HASSEMAPHORE)
|
||||||
#define MAP_HUGETLB SYMBOLIC(MAP_HUGETLB)
|
#define MAP_HUGETLB SYMBOLIC(MAP_HUGETLB)
|
||||||
#define MAP_HUGE_MASK SYMBOLIC(MAP_HUGE_MASK)
|
#define MAP_HUGE_MASK SYMBOLIC(MAP_HUGE_MASK)
|
||||||
|
|
|
@ -96,8 +96,8 @@ static int FixupCustomStackOnOpenbsd(pthread_attr_t *attr) {
|
||||||
n = ROUNDDOWN(n, PAGESIZE);
|
n = ROUNDDOWN(n, PAGESIZE);
|
||||||
e = errno;
|
e = errno;
|
||||||
if (__sys_mmap((void *)y, n, PROT_READ | PROT_WRITE,
|
if (__sys_mmap((void *)y, n, PROT_READ | PROT_WRITE,
|
||||||
MAP_PRIVATE | MAP_ANON_OPENBSD | MAP_STACK_OPENBSD, -1, 0,
|
MAP_PRIVATE | MAP_FIXED | MAP_ANON_OPENBSD | MAP_STACK_OPENBSD,
|
||||||
0) != MAP_FAILED) {
|
-1, 0, 0) == (void *)y) {
|
||||||
attr->stackaddr = (void *)y;
|
attr->stackaddr = (void *)y;
|
||||||
attr->stacksize = n;
|
attr->stacksize = n;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -215,8 +215,28 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||||
_pthread_free(pt);
|
_pthread_free(pt);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
pt->attr.stackaddr = mmap(0, pt->attr.stacksize, PROT_READ | PROT_WRITE,
|
if (pt->attr.guardsize == PAGESIZE) {
|
||||||
MAP_STACK | MAP_ANONYMOUS, -1, 0);
|
// user is wisely using smaller stacks with default guard size
|
||||||
|
pt->attr.stackaddr = mmap(0, pt->attr.stacksize, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_STACK | MAP_ANONYMOUS, -1, 0);
|
||||||
|
} else {
|
||||||
|
// user is tuning things, performance may suffer
|
||||||
|
pt->attr.stackaddr = mmap(0, pt->attr.stacksize, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
if (pt->attr.stackaddr != MAP_FAILED) {
|
||||||
|
if (IsOpenbsd() &&
|
||||||
|
__sys_mmap(
|
||||||
|
pt->attr.stackaddr, pt->attr.stacksize, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_PRIVATE | MAP_FIXED | MAP_ANON_OPENBSD | MAP_STACK_OPENBSD,
|
||||||
|
-1, 0, 0) != pt->attr.stackaddr) {
|
||||||
|
notpossible;
|
||||||
|
}
|
||||||
|
if (pt->attr.guardsize && !IsWindows() &&
|
||||||
|
mprotect(pt->attr.stackaddr, pt->attr.guardsize, PROT_NONE)) {
|
||||||
|
notpossible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (pt->attr.stackaddr == MAP_FAILED) {
|
if (pt->attr.stackaddr == MAP_FAILED) {
|
||||||
rc = errno;
|
rc = errno;
|
||||||
_pthread_free(pt);
|
_pthread_free(pt);
|
||||||
|
@ -227,27 +247,8 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||||
return EAGAIN;
|
return EAGAIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// mmap(MAP_STACK) creates a 4096 guard by default
|
if (IsAsan() && pt->attr.guardsize) {
|
||||||
if (pt->attr.guardsize != PAGESIZE) {
|
__asan_poison(pt->attr.stackaddr, pt->attr.guardsize, kAsanStackOverflow);
|
||||||
if (pt->attr.guardsize) {
|
|
||||||
// user requested special guard size
|
|
||||||
rc = mprotect(pt->attr.stackaddr, pt->attr.guardsize, PROT_NONE);
|
|
||||||
} else {
|
|
||||||
// user explicitly disabled guard page
|
|
||||||
rc = mprotect(pt->attr.stackaddr, PAGESIZE, PROT_READ | PROT_WRITE);
|
|
||||||
}
|
|
||||||
if (rc) {
|
|
||||||
notpossible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (IsAsan()) {
|
|
||||||
if (pt->attr.guardsize) {
|
|
||||||
__asan_poison(pt->attr.stackaddr, pt->attr.guardsize,
|
|
||||||
kAsanStackOverflow);
|
|
||||||
}
|
|
||||||
__asan_poison((char *)pt->attr.stackaddr + pt->attr.stacksize -
|
|
||||||
16 /* openbsd:stackbound */,
|
|
||||||
16, kAsanStackOverflow);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +268,7 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||||
|
|
||||||
// launch PosixThread(pt) in new thread
|
// launch PosixThread(pt) in new thread
|
||||||
if (clone(PosixThread, pt->attr.stackaddr,
|
if (clone(PosixThread, pt->attr.stackaddr,
|
||||||
pt->attr.stacksize - 16 /* openbsd:stackbound */,
|
pt->attr.stacksize - (IsOpenbsd() ? 16 : 0),
|
||||||
CLONE_VM | CLONE_THREAD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
CLONE_VM | CLONE_THREAD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
||||||
CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID |
|
CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID |
|
||||||
CLONE_CHILD_CLEARTID,
|
CLONE_CHILD_CLEARTID,
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/intrin/pthread.h"
|
#include "libc/intrin/pthread.h"
|
||||||
|
@ -25,13 +26,31 @@
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/runtime/stack.h"
|
#include "libc/runtime/stack.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
#include "libc/sysv/consts/sa.h"
|
||||||
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/testlib/ezbench.h"
|
#include "libc/testlib/ezbench.h"
|
||||||
#include "libc/testlib/subprocess.h"
|
#include "libc/testlib/subprocess.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/thread/thread.h"
|
#include "libc/thread/thread.h"
|
||||||
|
|
||||||
|
void OnTrap(int sig, struct siginfo *si, void *vctx) {
|
||||||
|
struct ucontext *ctx = vctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetUp(void) {
|
||||||
|
struct sigaction sig = {.sa_sigaction = OnTrap, .sa_flags = SA_SIGINFO};
|
||||||
|
sigaction(SIGTRAP, &sig, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TriggerSignal(void) {
|
||||||
|
sched_yield();
|
||||||
|
DebugBreak();
|
||||||
|
sched_yield();
|
||||||
|
}
|
||||||
|
|
||||||
static void *Increment(void *arg) {
|
static void *Increment(void *arg) {
|
||||||
ASSERT_EQ(gettid(), pthread_getthreadid_np());
|
ASSERT_EQ(gettid(), pthread_getthreadid_np());
|
||||||
|
TriggerSignal();
|
||||||
return (void *)((uintptr_t)arg + 1);
|
return (void *)((uintptr_t)arg + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +63,7 @@ TEST(pthread_create, testCreateReturnJoin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *IncExit(void *arg) {
|
static void *IncExit(void *arg) {
|
||||||
|
TriggerSignal();
|
||||||
pthread_exit((void *)((uintptr_t)arg + 1));
|
pthread_exit((void *)((uintptr_t)arg + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +91,7 @@ TEST(pthread_detach, testDetachUponCreation) {
|
||||||
|
|
||||||
static void *CheckStack(void *arg) {
|
static void *CheckStack(void *arg) {
|
||||||
char buf[1024 * 1024];
|
char buf[1024 * 1024];
|
||||||
|
TriggerSignal();
|
||||||
CheckLargeStackAllocation(buf, 1024 * 1024);
|
CheckLargeStackAllocation(buf, 1024 * 1024);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -85,6 +106,24 @@ TEST(pthread_detach, testBigStack) {
|
||||||
ASSERT_EQ(0, pthread_join(id, 0));
|
ASSERT_EQ(0, pthread_join(id, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *CheckStack2(void *arg) {
|
||||||
|
char buf[57244];
|
||||||
|
TriggerSignal();
|
||||||
|
CheckLargeStackAllocation(buf, sizeof(buf));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(pthread_detach, testBiggerGuardSize) {
|
||||||
|
pthread_t id;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
ASSERT_EQ(0, pthread_attr_init(&attr));
|
||||||
|
ASSERT_EQ(0, pthread_attr_setstacksize(&attr, 65536));
|
||||||
|
ASSERT_EQ(0, pthread_attr_setguardsize(&attr, 8192));
|
||||||
|
ASSERT_EQ(0, pthread_create(&id, &attr, CheckStack2, 0));
|
||||||
|
ASSERT_EQ(0, pthread_attr_destroy(&attr));
|
||||||
|
ASSERT_EQ(0, pthread_join(id, 0));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(pthread_detach, testCustomStack_withReallySmallSize) {
|
TEST(pthread_detach, testCustomStack_withReallySmallSize) {
|
||||||
char *stk;
|
char *stk;
|
||||||
size_t siz;
|
size_t siz;
|
||||||
|
|
4
third_party/libcxx/thread.cc
vendored
4
third_party/libcxx/thread.cc
vendored
|
@ -52,10 +52,6 @@
|
||||||
#include "third_party/getopt/getopt.h"
|
#include "third_party/getopt/getopt.h"
|
||||||
#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__) || defined(__wasi__)
|
#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__) || defined(__wasi__)
|
||||||
|
|
||||||
#if defined(__NetBSD__)
|
|
||||||
#pragma weak pthread_create // Do not create libpthread dependency
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_LIBCPP_WIN32API)
|
#if defined(_LIBCPP_WIN32API)
|
||||||
#include "libc/nt/accounting.h"
|
#include "libc/nt/accounting.h"
|
||||||
#include "libc/nt/automation.h"
|
#include "libc/nt/automation.h"
|
||||||
|
|
|
@ -372,7 +372,6 @@ int XlatMapFlags(int x) {
|
||||||
if (x & 2) r |= MAP_PRIVATE;
|
if (x & 2) r |= MAP_PRIVATE;
|
||||||
if (x & 16) r |= MAP_FIXED;
|
if (x & 16) r |= MAP_FIXED;
|
||||||
if (x & 32) r |= MAP_ANONYMOUS;
|
if (x & 32) r |= MAP_ANONYMOUS;
|
||||||
if (x & 256) r |= MAP_GROWSDOWN;
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue