Fix bugs and make improvements

- Get clone() working on FreeBSD
- Increase some Python build quotas
- Add more atomic builtins to chibicc
- Fix ASAN poisoning of alloca() memory
- Make MODE= mandatory link path tinier
- Improve the examples folder a little bit
- Start working on some more resource limits
- Make the linenoise auto-complete UI as good as GNU readline
- Update compile.com, avoiding AVX codegen on non-AVX systems
- Make sure empty path to syscalls like opendir raises ENOENT
- Correctly polyfill ENOENT vs. ENOTDIR on the New Technology
- Port bestline's paredit features to //third_party/linenoise
- Remove workarounds for RHEL 5.0 bugs that were fixed in 5.1
This commit is contained in:
Justine Tunney 2022-04-20 09:56:53 -07:00
parent c3fb624647
commit ae638c0850
181 changed files with 2994 additions and 1367 deletions

View file

@ -1,117 +0,0 @@
/*-*- 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 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
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/dce.h"
#include "libc/nexgen32e/nt2sysv.h"
#include "libc/nexgen32e/stackframe.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thread.h"
#include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/errfuns.h"
struct WinThread {
int (*func)(void *);
void *param;
void *stack;
};
static noasan textwindows uint32_t WinThreadMain(void *param) {
struct WinThread *wt = param;
asm volatile("mov\t%%rbp,%%r14\n\t"
"mov\t%%rsp,%%r15\n\t"
"xor\t%%ebp,%%ebp\n\t"
"mov\t%2,%%rsp\n\t"
"call\t*%0\n\t"
"mov\t%%r14,%%rbp\n\t"
"mov\t%%r15,%%rsp"
: /* no outputs */
: "m"(wt->func), "D"(wt->param), "m"(wt->stack)
: "r14", "r15", "memory");
return 0;
}
/**
* Creates thread.
*
* @param flags usually has one of
* - `CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND` for threads
* - `CLONE_VFORK|CLONE_VM|SIGCHLD` for vfork()
* - `SIGCHLD` for fork()
* as part high bytes, and the low order byte may optionally contain
* a signal e.g. SIGCHLD, to enable parent notification on terminate
*/
privileged int clone(int (*f)(void *), void *stack, int flags, void *arg, ...) {
int tidfd;
va_list va;
intptr_t ax;
uint32_t tid;
int64_t hand;
int32_t *ptid;
register void *tls asm("r8");
register int32_t *ctid asm("r10");
register int (*func)(void *) asm("r9");
if (IsLinux() || IsNetbsd()) {
va_start(va, arg);
ptid = va_arg(va, int32_t *);
tls = va_arg(va, void *);
ctid = va_arg(va, int32_t *);
va_end(va);
func = f;
stack = (void *)(((uintptr_t)stack & -16) - 8);
*(intptr_t *)stack = (intptr_t)arg;
asm volatile("syscall"
: "=a"(ax)
: "0"(__NR_clone), "D"(flags), "S"(stack), "d"(ptid),
"r"(ctid), "r"(tls), "r"(func)
: "rcx", "r11", "memory");
if (ax) return ax;
asm volatile("xor\t%%ebp,%%ebp\n\t"
"pop\t%%rdi\n\t"
"call\t%0\n\t"
"xchg\t%%eax,%%edi\n\t"
"call\t_Exit1"
: /* no outputs */
: "r"(func)
: "memory");
unreachable;
} else if (IsWindows()) {
if ((tidfd = __reservefd(-1)) == -1) return -1;
if (flags == CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND) {
if ((hand = CreateThread(&kNtIsInheritable, 0, NT2SYSV(WinThreadMain),
&(struct WinThread){f, arg, stack}, 0, &tid))) {
// XXX: this should be tracked in a separate data structure
g_fds.p[tidfd].kind = kFdProcess;
g_fds.p[tidfd].handle = hand;
g_fds.p[tidfd].flags = O_CLOEXEC;
g_fds.p[tidfd].zombie = false;
return tidfd;
} else {
return -1;
}
} else {
return einval();
}
} else {
return enosys();
}
}

View file

@ -42,6 +42,7 @@
#include "libc/nt/signals.h"
#include "libc/nt/struct/ntexceptionpointers.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/ntstdin.internal.h"
@ -51,7 +52,6 @@
STATIC_YOINK("_check_sigchld");
extern int __pid;
extern int64_t __wincrashearly;
extern unsigned long long __kbirth;
extern unsigned char __data_start[]; /* αpε */
@ -60,7 +60,7 @@ extern unsigned char __bss_start[]; /* αpε */
extern unsigned char __bss_end[]; /* αpε */
bool32 __onntconsoleevent_nt(uint32_t);
static textwindows wontreturn void KillForkChild(const char *func) {
static textwindows wontreturn void AbortFork(const char *func) {
STRACE("fork() %s() failed %d", func, GetLastError());
ExitProcess(177);
}
@ -100,7 +100,25 @@ static dontinline textwindows bool WriteAll(int64_t h, void *buf, size_t n) {
static textwindows dontinline void ReadOrDie(int64_t h, void *buf, size_t n) {
if (!ForkIo2(h, buf, n, ReadFile, "ReadFile")) {
KillForkChild("ReadFile");
AbortFork("ReadFile");
}
}
static textwindows int64_t MapOrDie(uint32_t prot, uint64_t size) {
int64_t h;
if ((h = CreateFileMapping(-1, 0, prot, size >> 32, size, 0))) {
return h;
} else {
AbortFork("MapOrDie");
}
}
static textwindows void ViewOrDie(int64_t h, uint32_t access, size_t pos,
size_t size, void *base) {
void *got;
got = MapViewOfFileEx(h, access, pos >> 32, pos, size, base);
if (!got || (base && got != base)) {
AbortFork("ViewOrDie");
}
}
@ -135,16 +153,13 @@ textwindows void WinMainForked(void) {
ReadOrDie(reader, &mapcount, sizeof(_mmi.i));
ReadOrDie(reader, &mapcapacity, sizeof(_mmi.n));
specialz = ROUNDUP(mapcapacity * sizeof(_mmi.p[0]), kMemtrackGran);
MapViewOfFileEx(
CreateFileMapping(-1, 0, kNtPageReadwrite, specialz >> 32, specialz, 0),
kNtFileMapWrite, 0, 0, specialz, maps);
ViewOrDie(MapOrDie(kNtPageReadwrite, specialz), kNtFileMapWrite, 0, specialz,
maps);
ReadOrDie(reader, maps, mapcount * sizeof(_mmi.p[0]));
if (IsAsan()) {
shad = (char *)(((intptr_t)maps >> 3) + 0x7fff8000);
size = ROUNDUP(specialz >> 3, FRAMESIZE);
MapViewOfFileEx(
CreateFileMapping(-1, 0, kNtPageReadwrite, size >> 32, size, 0),
kNtFileMapWrite, 0, 0, size, maps);
ViewOrDie(MapOrDie(kNtPageReadwrite, size), kNtFileMapWrite, 0, size, maps);
ReadOrDie(reader, shad, (mapcount * sizeof(_mmi.p[0])) >> 3);
}
@ -156,18 +171,15 @@ textwindows void WinMainForked(void) {
upsize = ROUNDUP(size, FRAMESIZE);
// we don't need to close the map handle because sys_mmap_nt
// doesn't mark it inheritable across fork() for MAP_PRIVATE
maps[i].h = CreateFileMapping(-1, 0, kNtPageExecuteReadwrite,
upsize >> 32, upsize, 0);
MapViewOfFileEx(maps[i].h, kNtFileMapWrite | kNtFileMapExecute, 0, 0,
upsize, addr);
ViewOrDie((maps[i].h = MapOrDie(kNtPageExecuteReadwrite, upsize)),
kNtFileMapWrite | kNtFileMapExecute, 0, upsize, addr);
ReadOrDie(reader, addr, size);
} else {
// we can however safely inherit MAP_SHARED with zero copy
MapViewOfFileEx(maps[i].h,
maps[i].readonlyfile
? kNtFileMapRead | kNtFileMapExecute
: kNtFileMapWrite | kNtFileMapExecute,
maps[i].offset >> 32, maps[i].offset, size, addr);
ViewOrDie(maps[i].h,
maps[i].readonlyfile ? kNtFileMapRead | kNtFileMapExecute
: kNtFileMapWrite | kNtFileMapExecute,
maps[i].offset, size, addr);
}
}
@ -187,13 +199,13 @@ textwindows void WinMainForked(void) {
for (i = 0; i < mapcount; ++i) {
if (!VirtualProtect((void *)((uint64_t)maps[i].x << 16), maps[i].size,
__prot2nt(maps[i].prot, maps[i].iscow), &oldprot)) {
KillForkChild("VirtualProtect");
AbortFork("VirtualProtect");
}
}
// mitosis complete
if (!CloseHandle(reader)) {
KillForkChild("CloseHandle");
AbortFork("CloseHandle");
}
// rewrap the stdin named pipe hack
@ -223,9 +235,9 @@ textwindows int sys_fork_nt(void) {
char **args, **args2;
char16_t pipename[64];
int64_t reader, writer;
struct NtStartupInfo startinfo;
int i, n, pid, untrackpid, rc = -1;
char *p, forkvar[6 + 21 + 1 + 21 + 1];
struct NtStartupInfo startinfo;
struct NtProcessInformation procinfo;
if (!setjmp(jb)) {
pid = untrackpid = __reservefd(-1);

View file

@ -23,8 +23,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/nt/process.h"
extern int __pid;
#include "libc/runtime/internal.h"
/**
* Creates new process.

View file

@ -21,6 +21,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigset.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h"
@ -58,8 +59,10 @@ privileged noinstrument noasan int __hook(void *ifunc,
intptr_t kProgramCodeStart = (intptr_t)&_ereal;
intptr_t kPrivilegedStart = (intptr_t)&__privileged_start;
bool kIsBinaryAligned = !(kPrivilegedStart & (PAGESIZE - 1));
sigfillset(&mask);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
if (!IsWindows()) {
sigfillset(&mask);
sys_sigprocmask(SIG_BLOCK, &mask, &oldmask);
}
if ((rc = mprotect(
(void *)symbols->addr_base, kPrivilegedStart - symbols->addr_base,
kIsBinaryAligned ? PROT_READ | PROT_WRITE
@ -127,6 +130,8 @@ privileged noinstrument noasan int __hook(void *ifunc,
mprotect((void *)symbols->addr_base, kPrivilegedStart - symbols->addr_base,
PROT_READ | PROT_EXEC);
}
sigprocmask(SIG_SETMASK, &oldmask, NULL);
if (!IsWindows()) {
sys_sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
return rc;
}

View file

@ -12,6 +12,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern int __pid;
extern uint32_t __ntconsolemode[3];
extern const char v_ntsubsystem[] __attribute__((__weak__));
extern const uintptr_t __fini_array_end[] __attribute__((__weak__));

View file

@ -76,16 +76,10 @@ static noasan bool ExtendMemoryIntervals(struct MemoryIntervals *mm) {
if (IsAsan()) {
shad = (char *)(((intptr_t)base >> 3) + 0x7fff8000);
dm = sys_mmap(shad, gran >> 3, prot, flags, -1, 0);
if (!dm.addr) {
STRACE("ExtendMemoryIntervals() fail #1");
return false;
}
if (!dm.addr) return false;
}
dm = sys_mmap(base, gran, prot, flags, -1, 0);
if (!dm.addr) {
STRACE("ExtendMemoryIntervals() fail #2");
return false;
}
if (!dm.addr) return false;
MoveMemoryIntervals(dm.addr, mm->p, mm->i);
mm->p = dm.addr;
mm->n = gran / sizeof(*mm->p);
@ -95,16 +89,10 @@ static noasan bool ExtendMemoryIntervals(struct MemoryIntervals *mm) {
if (IsAsan()) {
shad = (char *)(((intptr_t)base >> 3) + 0x7fff8000);
dm = sys_mmap(shad, gran >> 3, prot, flags, -1, 0);
if (!dm.addr) {
STRACE("ExtendMemoryIntervals() fail #3");
return false;
}
if (!dm.addr) return false;
}
dm = sys_mmap(base, gran, prot, flags, -1, 0);
if (!dm.addr) {
STRACE("ExtendMemoryIntervals() fail #4");
return false;
}
if (!dm.addr) return false;
mm->n = (size + gran) / sizeof(*mm->p);
}
assert(AreMemoryIntervalsOk(mm));

View file

@ -27,6 +27,7 @@
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/limits.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
@ -281,7 +282,7 @@ noasan void *mmap(void *addr, size_t size, int prot, int flags, int fd,
} else if (__isfdkind(fd, kFdZip)) {
STRACE("fd is zipos handle");
res = VIP(einval());
} else if (__virtualmax &&
} else if (__virtualmax < LONG_MAX &&
(__builtin_add_overflow((virtualused = GetMemtrackSize(&_mmi)),
size, &virtualneed) ||
virtualneed > __virtualmax)) {

View file

@ -28,6 +28,7 @@
#include "libc/elf/struct/shdr.h"
#include "libc/elf/struct/sym.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/limits.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
@ -51,7 +52,7 @@
((Elf64_Shdr *)((intptr_t)(e) + (e)->e_shoff + \
(size_t)(e)->e_shentsize * (i)))
noasan static char *GetStrtab(Elf64_Ehdr *e, size_t *n) {
static char *GetStrtab(Elf64_Ehdr *e, size_t *n) {
char *name;
Elf64_Half i;
Elf64_Shdr *shdr;
@ -68,7 +69,7 @@ noasan static char *GetStrtab(Elf64_Ehdr *e, size_t *n) {
return 0;
}
noasan static Elf64_Sym *GetSymtab(Elf64_Ehdr *e, Elf64_Xword *n) {
static Elf64_Sym *GetSymtab(Elf64_Ehdr *e, Elf64_Xword *n) {
Elf64_Half i;
Elf64_Shdr *shdr;
for (i = e->e_shnum; i > 0; --i) {
@ -82,7 +83,7 @@ noasan static Elf64_Sym *GetSymtab(Elf64_Ehdr *e, Elf64_Xword *n) {
return 0;
}
noasan static void GetImageRange(Elf64_Ehdr *elf, intptr_t *x, intptr_t *y) {
static void GetImageRange(Elf64_Ehdr *elf, intptr_t *x, intptr_t *y) {
unsigned i;
Elf64_Phdr *phdr;
intptr_t start, end, pstart, pend;
@ -105,11 +106,11 @@ noasan static void GetImageRange(Elf64_Ehdr *elf, intptr_t *x, intptr_t *y) {
*
* @return object freeable with CloseSymbolTable(), or NULL w/ errno
*/
noasan struct SymbolTable *OpenSymbolTable(const char *filename) {
struct SymbolTable *OpenSymbolTable(const char *filename) {
int fd;
void *map;
long *stp;
struct stat st;
ssize_t filesize;
unsigned i, j, x;
const Elf64_Ehdr *elf;
const char *name_base;
@ -119,10 +120,10 @@ noasan struct SymbolTable *OpenSymbolTable(const char *filename) {
ptrdiff_t names_offset, name_base_offset, stp_offset;
map = MAP_FAILED;
if ((fd = open(filename, O_RDONLY)) == -1) return 0;
if (fstat(fd, &st) == -1) goto SystemError;
if (st.st_size > INT_MAX) goto RaiseE2big;
if (st.st_size < 64) goto RaiseEnoexec;
elf = map = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if ((filesize = getfiledescriptorsize(fd)) == -1) goto SystemError;
if (filesize > INT_MAX) goto RaiseE2big;
if (filesize < 64) goto RaiseEnoexec;
elf = map = mmap(0, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED) goto SystemError;
if (READ32LE(map) != READ32LE("\177ELF")) goto RaiseEnoexec;
if (!(name_base = GetStrtab(map, &m))) goto RaiseEnobufs;
@ -181,7 +182,7 @@ noasan struct SymbolTable *OpenSymbolTable(const char *filename) {
}
t->count = j;
munmap(stp, ROUNDUP(sizeof(const Elf64_Sym *) * n, FRAMESIZE));
munmap(map, st.st_size);
munmap(map, filesize);
close(fd);
return t;
RaiseE2big:
@ -195,7 +196,7 @@ RaiseEnoexec:
SystemError:
STRACE("OpenSymbolTable()% m");
if (map != MAP_FAILED) {
munmap(map, st.st_size);
munmap(map, filesize);
}
close(fd);
return 0;

View file

@ -240,9 +240,9 @@ textstartup void __printargs(const char *prologue) {
PRINT("FILE DESCRIPTORS");
for (i = 0; i < ARRAYLEN(pfds); ++i) {
pfds[i].fd = i;
pfds[i].events = POLLIN | POLLOUT;
pfds[i].events = POLLIN;
}
if ((n = poll(pfds, ARRAYLEN(pfds), 20)) != -1) {
if ((n = poll(pfds, ARRAYLEN(pfds), 0)) != -1) {
for (i = 0; i < ARRAYLEN(pfds); ++i) {
if (i && (pfds[i].revents & POLLNVAL)) continue;
PRINT(" ☼ %d (revents=%#hx F_GETFL=%#x)", i, pfds[i].revents,

View file

@ -58,11 +58,8 @@ $(LIBC_RUNTIME_A).pkg: \
$(foreach x,$(LIBC_RUNTIME_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/runtime/fork-nt.o \
o/$(MODE)/libc/runtime/printf.o \
o/$(MODE)/libc/runtime/abort-nt.o \
o/$(MODE)/libc/runtime/printmemoryintervals.o \
o/$(MODE)/libc/runtime/arememoryintervalsok.o \
o/$(MODE)/libc/runtime/assertfail.o \
o/$(MODE)/libc/runtime/directmap.o \
o/$(MODE)/libc/runtime/directmapnt.o \
o/$(MODE)/libc/runtime/findmemoryinterval.o \
@ -75,12 +72,14 @@ o/$(MODE)/libc/runtime/hook.greg.o \
o/$(MODE)/libc/runtime/isheap.o \
o/$(MODE)/libc/runtime/memtrack.o \
o/$(MODE)/libc/runtime/memtracknt.o \
o/$(MODE)/libc/runtime/metalprintf.greg.o \
o/$(MODE)/libc/runtime/printargs.greg.o \
o/$(MODE)/libc/runtime/mman.greg.o \
o/$(MODE)/libc/runtime/print.greg.o \
o/$(MODE)/libc/runtime/stackchkfail.o \
o/$(MODE)/libc/runtime/stackchkfaillocal.o \
o/$(MODE)/libc/runtime/winmain.greg.o \
o/$(MODE)/libc/runtime/opensymboltable.o \
o/$(MODE)/libc/runtime/getsymboltable.greg.o: \
OVERRIDE_CFLAGS += \
-ffreestanding \
@ -96,6 +95,14 @@ o/$(MODE)/libc/runtime/qsort.o: \
OVERRIDE_CFLAGS += \
-Og
# make always linked runtimes less huge when it's profitable
o//libc/runtime/mmap.o \
o//libc/runtime/munmap.o \
o//libc/runtime/memtrack.greg.o \
o//libc/runtime/opensymboltable.greg.o: \
OVERRIDE_CFLAGS += \
-Os
o/$(MODE)/libc/runtime/ftrace.greg.o: \
OVERRIDE_CFLAGS += \
-mgeneral-regs-only

View file

@ -62,7 +62,7 @@ extern char ape_stack_align[] __attribute__((__weak__));
* Returns address of bottom of stack.
*/
#define GetStackAddr(ADDEND) \
(((intptr_t)__builtin_frame_address(0) & -GetStackSize()) + (ADDEND))
((((intptr_t)__builtin_frame_address(0) - 1) & -GetStackSize()) + (ADDEND))
/**
* Returns preferred bottom address of stack.

View file

@ -25,6 +25,7 @@
#include "libc/elf/pf2prot.internal.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/nomultics.internal.h"
#include "libc/log/libfatal.internal.h"
@ -86,7 +87,6 @@ struct WinArgs {
char envblock[ARG_MAX];
};
extern int __pid;
extern uint32_t __winmainpid;
extern int64_t __wincrashearly;
extern const char kConsoleHandles[3];
@ -164,10 +164,15 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
for (i = 0; i < 3; ++i) {
hand = GetStdHandle(kConsoleHandles[i]);
rc = GetConsoleMode(hand, __ntconsolemode + i);
NTTRACE("GetConsoleMode(%p, [%#x]) → %hhhd", hand, __ntconsolemode[i],
NTTRACE("GetConsoleMode(%p, [%s]) → %hhhd", hand,
i ? DescribeNtConsoleModeOutputFlags(__ntconsolemode[i])
: DescribeNtConsoleModeInputFlags(__ntconsolemode[i]),
rc);
rc = SetConsoleMode(hand, kConsoleModes[i]);
NTTRACE("SetConsoleMode(%p, %#x) → %hhhd", hand, kConsoleModes[i], rc);
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", hand,
i ? DescribeNtConsoleModeOutputFlags(kConsoleModes[i])
: DescribeNtConsoleModeInputFlags(kConsoleModes[i]),
rc);
}
}
_mmi.p = _mmi.s;