Make more threading improvements

- ASAN memory morgue is now lockless
- Make C11 atomics header more portable
- Rewrote pthread keys support to be lockless
- Simplify Python's unicode table unpacking code
- Make crash report write(2) closer to being atomic
- Make it possible to strace/ftrace a single thread
- ASAN now checks nul-terminated strings fast and properly
- Windows fork() now restores TLS memory of calling thread
This commit is contained in:
Justine Tunney 2022-11-01 22:36:03 -07:00
parent d7b88734cd
commit e522aa3a07
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
189 changed files with 1363 additions and 1217 deletions

View file

@ -47,7 +47,10 @@ textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
} else {
x = y;
}
x &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP) | GetSigBit(SIGABRT));
x &= ~(0
#define M(x) | GetSigBit(x)
#include "libc/intrin/sigisprecious.inc"
);
*mask = x;
}
return 0;

View file

@ -36,7 +36,7 @@
int chdir(const char *path) {
int rc;
GetProgramExecutableName(); // XXX: ugly workaround
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
rc = efault();
} else if (!IsWindows()) {
rc = sys_chdir(path);

View file

@ -49,7 +49,7 @@
*/
int chroot(const char *path) {
int rc;
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
rc = efault();
} else {
rc = sys_chroot(path);

View file

@ -54,7 +54,7 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
int rc;
size_t i;
if (!prog || !argv || !envp ||
(IsAsan() && (!__asan_is_valid(prog, 1) || //
(IsAsan() && (!__asan_is_valid_str(prog) || //
!__asan_is_valid_strlist(argv) || //
!__asan_is_valid_strlist(envp)))) {
rc = efault();

View file

@ -37,7 +37,7 @@
int execvpe(const char *prog, char *const argv[], char *const *envp) {
char *exe;
char pathbuf[PATH_MAX];
if (IsAsan() && !__asan_is_valid(prog, 1)) return efault();
if (IsAsan() && !__asan_is_valid_str(prog)) return efault();
if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) return -1;
return execve(exe, argv, envp);
}

View file

@ -51,7 +51,7 @@
int faccessat(int dirfd, const char *path, int amode, int flags) {
int e, rc;
struct ZiposUri zipname;
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
rc = efault();
} else if (__isfdkind(dirfd, kFdZip)) {
rc = enotsup();

View file

@ -44,7 +44,7 @@
*/
int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) {
int rc;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
rc = efault();
} else if (_weaken(__zipos_notat) &&
(rc = __zipos_notat(dirfd, path)) == -1) {

View file

@ -43,7 +43,7 @@
int fchownat(int dirfd, const char *path, uint32_t uid, uint32_t gid,
int flags) {
int rc;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
rc = efault();
} else if (_weaken(__zipos_notat) &&
(rc = __zipos_notat(dirfd, path)) == -1) {

View file

@ -21,8 +21,7 @@
#include "libc/dce.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
@ -48,21 +47,8 @@ int fexecve(int fd, char *const argv[], char *const envp[]) {
(!__asan_is_valid_strlist(argv) || !__asan_is_valid_strlist(envp)))) {
rc = efault();
} else {
#ifdef SYSDEBUG
if (UNLIKELY(__strace > 0)) {
kprintf(STRACE_PROLOGUE "fexecve(%d, {", fd);
for (i = 0; argv[i]; ++i) {
if (i) kprintf(", ");
kprintf("%#s", argv[i]);
}
kprintf("}, {");
for (i = 0; envp[i]; ++i) {
if (i) kprintf(", ");
kprintf("%#s", envp[i]);
}
kprintf("})\n");
}
#endif
STRACE("fexecve(%d, %s, %s) → ...", fd, DescribeStringList(argv),
DescribeStringList(envp));
if (IsLinux()) {
char path[14 + 12];
FormatInt32(stpcpy(path, "/proc/self/fd/"), fd);

View file

@ -51,7 +51,7 @@ bool fileexists(const char *path) {
struct ZiposUri zipname;
uint16_t path16[PATH_MAX];
e = errno;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
efault();
res = false;
} else if (_weaken(__zipos_open) &&

View file

@ -31,7 +31,7 @@ int32_t sys_fstatat(int32_t dirfd, const char *path, struct stat *st,
int rc;
void *p;
union metastat ms;
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (IsAsan() && !__asan_is_valid_str(path)) return efault();
if (IsLinux()) {
_Static_assert(sizeof(*st) == sizeof(ms.linux), "assumption broken");
if (IsAsan() && (st && !__asan_is_valid(st, sizeof(*st)))) return efault();

View file

@ -51,7 +51,7 @@ bool isdirectory(const char *path) {
union metastat st;
struct ZiposUri zipname;
e = errno;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
efault();
res = false;
} else if (_weaken(__zipos_open) &&

View file

@ -48,7 +48,7 @@ bool isregularfile(const char *path) {
union metastat st;
struct ZiposUri zipname;
e = errno;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
efault();
res = false;
} else if (_weaken(__zipos_open) &&

View file

@ -51,7 +51,7 @@ bool issymlink(const char *path) {
union metastat st;
struct ZiposUri zipname;
e = errno;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
efault();
res = false;
} else if (_weaken(__zipos_open) &&

View file

@ -41,7 +41,7 @@ int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath,
int flags) {
int rc;
if (IsAsan() &&
(!__asan_is_valid(oldpath, 1) || !__asan_is_valid(newpath, 1))) {
(!__asan_is_valid_str(oldpath) || !__asan_is_valid_str(newpath))) {
rc = efault();
} else if (_weaken(__zipos_notat) &&
((rc = __zipos_notat(olddirfd, oldpath)) == -1 ||

View file

@ -53,7 +53,7 @@
*/
int mkdirat(int dirfd, const char *path, unsigned mode) {
int rc;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
rc = efault();
} else if (_weaken(__zipos_notat) &&
(rc = __zipos_notat(dirfd, path)) == -1) {

View file

@ -17,10 +17,10 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/ipc.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h"
@ -36,7 +36,7 @@
int mkfifo(const char *pathname, unsigned mode) {
// TODO(jart): Windows?
int rc;
if (IsAsan() && !__asan_is_valid(pathname, 1)) {
if (IsAsan() && !__asan_is_valid_str(pathname)) {
rc = efault();
} else if (IsLinux()) {
rc = sys_mknod(pathname, mode | S_IFIFO, 0);

View file

@ -17,10 +17,10 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h"
@ -40,7 +40,7 @@
*/
int mknod(const char *path, uint32_t mode, uint64_t dev) {
int rc;
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (IsAsan() && !__asan_is_valid_str(path)) return efault();
if (mode & S_IFREG) return creat(path, mode & ~S_IFREG);
if (mode & S_IFDIR) return mkdir(path, mode & ~S_IFDIR);
if (mode & S_IFIFO) return mkfifo(path, mode & ~S_IFIFO);

View file

@ -21,9 +21,7 @@
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/systeminfo.h"
#include "libc/str/oldutf16.internal.h"
#include "libc/str/str.h"
#include "libc/str/tpdecode.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
@ -61,9 +59,13 @@ textwindows int __mkntpath(const char *path,
/**
* Copies path for Windows NT.
*
* This entails (1) UTF-8 to UTF-16 conversion; (2) replacing
* forward-slashes with backslashes; and (3) remapping several
* well-known paths (e.g. /dev/null NUL) for convenience.
* This function does the following chores:
*
* 1. Converting UTF-8 to UTF-16
* 2. Replacing forward-slashes with backslashes
* 3. Fixing drive letter paths, e.g. `/c/` `c:\`
* 4. Add `\\?\` prefix for paths exceeding 260 chars
* 5. Remapping well-known paths, e.g. `/dev/null` `NUL`
*
* @param flags is used by open()
* @param path16 is shortened so caller can prefix, e.g. \\.\pipe\, and

View file

@ -16,7 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/runtime/directmap.internal.h"
#include "libc/intrin/directmap.internal.h"
#include "libc/runtime/pc.internal.h"
noasan int sys_munmap_metal(void *addr, size_t size) {

View file

@ -16,11 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/intrin/directmap.internal.h"
#include "libc/intrin/strace.internal.h"
/**
* Unmaps memory directly with system.

View file

@ -18,9 +18,7 @@
*/
#include "libc/calls/ntspawn.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/pushpop.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h"
@ -80,6 +78,8 @@ textwindows int ntspawn(
rc = -1;
block = NULL;
if (__mkntpath(prog, prog16) == -1) return -1;
// we can't call malloc() because we're higher in the topological order
// we can't call kmalloc() because fork() calls this when kmalloc is locked
if ((handle = CreateFileMapping(-1, 0, pushpop(kNtPageReadwrite), 0,
sizeof(*block), 0)) &&
(block = MapViewOfFileEx(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0,

View file

@ -154,7 +154,7 @@ int openat(int dirfd, const char *file, int flags, ...) {
va_start(va, flags);
mode = va_arg(va, unsigned);
va_end(va);
if (file && (!IsAsan() || __asan_is_valid(file, 1))) {
if (file && (!IsAsan() || __asan_is_valid_str(file))) {
if (!__isfdkind(dirfd, kFdZip)) {
if (_weaken(__zipos_open) &&
_weaken(__zipos_parseuri)(file, &zipname) != -1) {

View file

@ -16,17 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/sock/struct/pollfd.internal.h"
#include "libc/sysv/errfuns.h"
@ -68,8 +60,8 @@
* @norestart
*/
int poll(struct pollfd *fds, size_t nfds, int timeout_ms) {
int rc;
size_t n;
int i, rc;
uint64_t millis;
if (IsAsan() && (__builtin_mul_overflow(nfds, sizeof(struct pollfd), &n) ||
@ -86,24 +78,7 @@ int poll(struct pollfd *fds, size_t nfds, int timeout_ms) {
rc = sys_poll_nt(fds, nfds, &millis, 0);
}
#if defined(SYSDEBUG) && _POLLTRACE
if (UNLIKELY(__strace > 0)) {
kprintf(STRACE_PROLOGUE "poll(");
if ((!IsAsan() && kisdangerous(fds)) ||
(IsAsan() && !__asan_is_valid(fds, nfds * sizeof(struct pollfd)))) {
kprintf("%p", fds);
} else {
kprintf("[{");
for (i = 0; i < MIN(5, nfds); ++i) {
kprintf("%s{%d, %s, %s}", i ? ", " : "", fds[i].fd,
DescribePollFlags(fds[i].events),
DescribePollFlags(fds[i].revents));
}
kprintf("%s}]", i == 5 ? "..." : "");
}
kprintf(", %'zu, %'d) → %d% lm\n", nfds, timeout_ms, rc);
}
#endif
STRACE("poll(%s, %'zu, %'d) → %d% lm\n", DescribePollFds(rc, fds, nfds), nfds,
timeout_ms, rc);
return rc;
}

View file

@ -16,15 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/sock/struct/pollfd.internal.h"
#include "libc/sysv/consts/sig.h"
@ -58,7 +57,7 @@
int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
const sigset_t *sigmask) {
size_t n;
int e, i, rc;
int e, rc;
uint64_t millis;
sigset_t oldmask;
struct timespec ts, *tsp;
@ -96,25 +95,7 @@ int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
rc = sys_poll_nt(fds, nfds, &millis, sigmask);
}
#if defined(SYSDEBUG) && _POLLTRACE
if (UNLIKELY(__strace > 0)) {
kprintf(STRACE_PROLOGUE "ppoll(");
if ((!IsAsan() && kisdangerous(fds)) ||
(IsAsan() && !__asan_is_valid(fds, nfds * sizeof(struct pollfd)))) {
kprintf("%p", fds);
} else {
kprintf("[{");
for (i = 0; i < MIN(5, nfds); ++i) {
kprintf("%s{%d, %s, %s}", i ? ", " : "", fds[i].fd,
DescribePollFlags(fds[i].events),
DescribePollFlags(fds[i].revents));
}
kprintf("%s}]", i == 5 ? "..." : "");
}
kprintf(", %'zu, %s, %s) → %d% lm\n", nfds, DescribeTimeval(0, timeout),
DescribeSigset(0, sigmask), rc);
}
#endif
STRACE("ppoll(%s, %'zu, %s, %s) → %d% lm\n", DescribePollFds(rc, fds, nfds),
nfds, DescribeTimespec(0, timeout), DescribeSigset(0, sigmask), rc);
return rc;
}

View file

@ -47,7 +47,7 @@ int renameat(int olddirfd, const char *oldpath, int newdirfd,
const char *newpath) {
int rc;
if (IsAsan() &&
(!__asan_is_valid(oldpath, 1) || !__asan_is_valid(newpath, 1))) {
(!__asan_is_valid_str(oldpath) || !__asan_is_valid_str(newpath))) {
rc = efault();
} else if (_weaken(__zipos_notat) &&
((rc = __zipos_notat(olddirfd, oldpath)) == -1 ||

View file

@ -16,26 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/dce.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/extend.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
// TODO(jart): make more of this code lockless

View file

@ -17,12 +17,12 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
@ -42,7 +42,7 @@
int symlinkat(const char *target, int newdirfd, const char *linkpath) {
int rc;
if (IsAsan() &&
(!__asan_is_valid(target, 1) || !__asan_is_valid(linkpath, 1))) {
(!__asan_is_valid_str(target) || !__asan_is_valid_str(linkpath))) {
rc = efault();
}
if (!IsWindows()) {

View file

@ -17,11 +17,11 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#define IsPeek(request) (IsLinux() && (request)-1u < 3)
@ -46,7 +46,7 @@ int sys_ptrace(int op, ...) {
va_end(va);
rc = __sys_ptrace(op, pid, addr, data);
#ifdef SYSDEBUG
if (UNLIKELY(__strace > 0)) {
if (UNLIKELY(__strace > 0) && strace_enabled(0) > 0) {
if (rc != -1 && IsPeek(op) && data) {
STRACE("sys_ptrace(%s, %d, %p, [%p]) → %p% m", DescribePtrace(op), pid,
addr, *data, rc);

View file

@ -66,7 +66,7 @@ int truncate(const char *path, int64_t length) {
struct ZiposUri zipname;
if (IsMetal()) {
rc = enosys();
} else if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
} else if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
rc = efault();
} else if (_weaken(__zipos_parseuri) &&
_weaken(__zipos_parseuri)(path, &zipname) != -1) {

View file

@ -40,7 +40,7 @@
*/
int unlinkat(int dirfd, const char *path, int flags) {
int rc;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
rc = efault();
} else if (_weaken(__zipos_notat) &&
(rc = __zipos_notat(dirfd, path)) == -1) {

View file

@ -38,7 +38,7 @@ int __utimens(int fd, const char *path, const struct timespec ts[2],
struct ZiposUri zipname;
if (IsMetal()) {
rc = enosys();
} else if (IsAsan() && ((fd == AT_FDCWD && !__asan_is_valid(path, 1)) ||
} else if (IsAsan() && ((fd == AT_FDCWD && !__asan_is_valid_str(path)) ||
(ts && (!__asan_is_valid_timespec(ts + 0) ||
!__asan_is_valid_timespec(ts + 1))))) {
rc = efault(); // bad memory