From 3265324e00634e8e9d659ba705da5b0ce88e78ef Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Fri, 9 Sep 2022 16:54:28 -0700 Subject: [PATCH] Don't relocate file descriptor memory This change fixes #496 where ASAN spotted a race condition that could happen in multithreaded programs, with more than OPEN_MAX descriptors when using ZipOS or Windows NT, which require tracking open file info and this change fixes that table so it never relocates, thus allowing us to continue to enjoy the benefits of avoiding locks while reading. --- Makefile | 1 + examples/walk.c | 4 - libc/calls/calls.mk | 14 ---- libc/calls/extend.internal.h | 10 +++ libc/calls/reservefd.c | 31 ++----- libc/calls/sig2.c | 1 + libc/calls/struct/fd.internal.h | 7 +- libc/integral/normalize.inc | 4 +- libc/{calls => intrin}/arememoryintervalsok.c | 0 libc/{calls => intrin}/directmap-metal.c | 0 libc/{calls => intrin}/directmap-nt.c | 0 libc/{calls => intrin}/directmap.c | 0 libc/intrin/extend.c | 84 +++++++++++++++++++ libc/intrin/g_fds.c | 32 +++---- libc/intrin/intrin.mk | 14 ++++ libc/{calls => intrin}/memtrack.greg.c | 0 libc/{calls => intrin}/mman.greg.c | 0 libc/log/libfatal.internal.h | 4 +- libc/log/showcrashreports.c | 3 +- libc/runtime/enable_tls.c | 1 - libc/runtime/fork-nt.c | 6 +- libc/runtime/hook.greg.c | 7 -- libc/runtime/memtrack64.txt | 2 +- libc/stdio/ecvt.c | 17 +++- libc/zipos/free.c | 5 -- libc/zipos/open.c | 49 +++-------- libc/zipos/zipos.h | 0 libc/zipos/zipos.internal.h | 1 - test/libc/calls/reservefd_test.c | 1 - .../{fmt/fcvt_test.c => stdio/ecvt_test.c} | 0 test/libc/test.mk | 1 + test/libc/thread/pthread_create_test.c | 11 ++- test/libc/zipos/open_test.c | 56 +++++++++++++ test/libc/zipos/test.mk | 63 ++++++++++++++ tool/scripts/check-includes.py | 20 ----- 35 files changed, 297 insertions(+), 152 deletions(-) create mode 100644 libc/calls/extend.internal.h rename libc/{calls => intrin}/arememoryintervalsok.c (100%) rename libc/{calls => intrin}/directmap-metal.c (100%) rename libc/{calls => intrin}/directmap-nt.c (100%) rename libc/{calls => intrin}/directmap.c (100%) create mode 100644 libc/intrin/extend.c rename libc/{calls => intrin}/memtrack.greg.c (100%) rename libc/{calls => intrin}/mman.greg.c (100%) create mode 100755 libc/zipos/zipos.h rename test/libc/{fmt/fcvt_test.c => stdio/ecvt_test.c} (100%) create mode 100644 test/libc/zipos/open_test.c create mode 100644 test/libc/zipos/test.mk delete mode 100755 tool/scripts/check-includes.py diff --git a/Makefile b/Makefile index de71e9b39..73fed5bd3 100644 --- a/Makefile +++ b/Makefile @@ -211,6 +211,7 @@ include test/libc/fmt/test.mk include test/libc/dns/test.mk include test/libc/time/test.mk include test/libc/stdio/test.mk +include test/libc/zipos/test.mk include test/libc/release/test.mk include test/libc/test.mk include test/net/http/test.mk diff --git a/examples/walk.c b/examples/walk.c index b9eca8eba..6b6253a70 100644 --- a/examples/walk.c +++ b/examples/walk.c @@ -7,16 +7,12 @@ │ • http://creativecommons.org/publicdomain/zero/1.0/ │ ╚─────────────────────────────────────────────────────────────────*/ #endif -#include "libc/calls/calls.h" -#include "libc/calls/struct/stat.h" #include "libc/errno.h" -#include "libc/runtime/gc.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/exit.h" #include "libc/sysv/consts/s.h" -#include "libc/x/x.h" #include "third_party/musl/ftw.h" /** diff --git a/libc/calls/calls.mk b/libc/calls/calls.mk index bab0d35be..10177d083 100644 --- a/libc/calls/calls.mk +++ b/libc/calls/calls.mk @@ -79,14 +79,6 @@ o/$(MODE)/libc/calls/vdsofunc.greg.o: private \ -ffreestanding \ -fno-sanitize=address -# we can't use asan because: -# asan guard pages haven't been allocated yet -o/$(MODE)/libc/calls/directmap.o \ -o/$(MODE)/libc/calls/directmap-nt.o: private \ - OVERRIDE_COPTS += \ - -ffreestanding \ - -fno-sanitize=address - # we can't use asan because: # ntspawn allocates 128kb of heap memory via win32 o/$(MODE)/libc/calls/ntspawn.o \ @@ -144,12 +136,6 @@ o/$(MODE)/libc/calls/ioctl-siocgifconf-nt.o: private \ -ffunction-sections \ -fdata-sections -# we want small code size because: -# to keep .text.head under 4096 bytes -o/$(MODE)/libc/calls/mman.greg.o: private \ - OVERRIDE_COPTS += \ - -Os - # we always want -Os because: # va_arg codegen is very bloated in default mode o//libc/calls/open.o \ diff --git a/libc/calls/extend.internal.h b/libc/calls/extend.internal.h new file mode 100644 index 000000000..6de407ddc --- /dev/null +++ b/libc/calls/extend.internal.h @@ -0,0 +1,10 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_EXTEND_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_CALLS_EXTEND_INTERNAL_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +void *_extend(void *, size_t, void *, intptr_t); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_EXTEND_INTERNAL_H_ */ diff --git a/libc/calls/reservefd.c b/libc/calls/reservefd.c index ee27f7b6f..d0a4f3e34 100644 --- a/libc/calls/reservefd.c +++ b/libc/calls/reservefd.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" +#include "libc/calls/extend.internal.h" #include "libc/calls/internal.h" #include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" @@ -46,33 +47,11 @@ static volatile size_t mapsize; * @asyncsignalsafe */ int __ensurefds_unlocked(int fd) { - uint64_t addr; - int prot, flags; - size_t size, chunk; - struct DirectMap dm; + bool relocate; if (fd < g_fds.n) return fd; - STRACE("__ensurefds(%d) extending", fd); - size = mapsize; - chunk = FRAMESIZE; - if (IsAsan()) chunk *= 8; - addr = kMemtrackFdsStart + size; - prot = PROT_READ | PROT_WRITE; - flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED; - dm = sys_mmap((char *)addr, chunk, prot, flags, -1, 0); - TrackMemoryInterval(&_mmi, addr >> 16, (addr + chunk - 1) >> 16, dm.maphandle, - prot, flags, false, false, 0, chunk); - if (IsAsan()) { - addr = (addr >> 3) + 0x7fff8000; - dm = sys_mmap((char *)addr, FRAMESIZE, prot, flags, -1, 0); - TrackMemoryInterval(&_mmi, addr >> 16, addr >> 16, dm.maphandle, prot, - flags, false, false, 0, FRAMESIZE); - } - if (!size) { - g_fds.p = memcpy((char *)kMemtrackFdsStart, g_fds.__init_p, - sizeof(g_fds.__init_p)); - } - g_fds.n = (size + chunk) / sizeof(*g_fds.p); - mapsize = size + chunk; + g_fds.n = fd + 1; + g_fds.e = + _extend(g_fds.p, g_fds.n * sizeof(*g_fds.p), g_fds.e, 0x6ff000000000); return fd; } diff --git a/libc/calls/sig2.c b/libc/calls/sig2.c index 606514086..9d4c0bd19 100644 --- a/libc/calls/sig2.c +++ b/libc/calls/sig2.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" #include "libc/calls/sig.internal.h" #include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" diff --git a/libc/calls/struct/fd.internal.h b/libc/calls/struct/fd.internal.h index 17d586236..fe117b253 100644 --- a/libc/calls/struct/fd.internal.h +++ b/libc/calls/struct/fd.internal.h @@ -25,10 +25,9 @@ struct Fd { }; struct Fds { - int f; /* lowest free slot */ - size_t n; /* monotonic capacity */ - struct Fd *p; - struct Fd __init_p[OPEN_MAX]; + int f; /* lowest free slot */ + size_t n; + struct Fd *p, *e; }; COSMOPOLITAN_C_END_ diff --git a/libc/integral/normalize.inc b/libc/integral/normalize.inc index 513778444..30be7c9b9 100644 --- a/libc/integral/normalize.inc +++ b/libc/integral/normalize.inc @@ -67,8 +67,8 @@ #endif /* TODO(jart): Remove this in favor of GetStackSize() */ -#if defined(COSMO) && defined(MODE_DBG) -#define STACKSIZE 131072 /* 128kb stack */ +#if defined(COSMO) && (defined(MODE_DBG) || defined(__SANITIZE_ADDRESS__)) +#define STACKSIZE 262144 /* 256kb stack */ #elif defined(COSMO) #define STACKSIZE 65536 /* 64kb stack */ #else diff --git a/libc/calls/arememoryintervalsok.c b/libc/intrin/arememoryintervalsok.c similarity index 100% rename from libc/calls/arememoryintervalsok.c rename to libc/intrin/arememoryintervalsok.c diff --git a/libc/calls/directmap-metal.c b/libc/intrin/directmap-metal.c similarity index 100% rename from libc/calls/directmap-metal.c rename to libc/intrin/directmap-metal.c diff --git a/libc/calls/directmap-nt.c b/libc/intrin/directmap-nt.c similarity index 100% rename from libc/calls/directmap-nt.c rename to libc/intrin/directmap-nt.c diff --git a/libc/calls/directmap.c b/libc/intrin/directmap.c similarity index 100% rename from libc/calls/directmap.c rename to libc/intrin/directmap.c diff --git a/libc/intrin/extend.c b/libc/intrin/extend.c new file mode 100644 index 000000000..11da2f91f --- /dev/null +++ b/libc/intrin/extend.c @@ -0,0 +1,84 @@ +/*-*- 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 2022 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/assert.h" +#include "libc/calls/calls.h" +#include "libc/dce.h" +#include "libc/intrin/asan.internal.h" +#include "libc/intrin/asancodes.h" +#include "libc/macros.internal.h" +#include "libc/runtime/directmap.internal.h" +#include "libc/runtime/memtrack.internal.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/prot.h" + +#define G FRAMESIZE + +static void _mapframe(void *p) { + int prot, flags; + struct DirectMap dm; + prot = PROT_READ | PROT_WRITE; + flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED; + if ((dm = sys_mmap(p, G, prot, flags, -1, 0)).addr != p) { + notpossible; + } + if (TrackMemoryInterval(&_mmi, (uintptr_t)p >> 16, + ((uintptr_t)p + G - 1) >> 16, dm.maphandle, prot, + flags, false, false, 0, G)) { + notpossible; + } +} + +/** + * Extends static allocation. + * + * This simple fixed allocator has unusual invariants + * + * !(p & 0xffff) && !(((p >> 3) + 0x7fff8000) & 0xffff) + * + * which must be the case when selecting a starting address. + * + * @param p points to start of memory region + * @param n specifies how many bytes are needed + * @param e points to end of memory that's allocated + * @param h is highest address to which `e` may grow + * @return new value for `e` + */ +noasan void *_extend(void *p, size_t n, void *e, intptr_t h) { + char *q; +#ifndef NDEBUG + if ((uintptr_t)SHADOW(p) & (G - 1)) notpossible; + if ((uintptr_t)p + (G << kAsanScale) > h) notpossible; +#endif + for (q = e; q < ((char *)p + n); q += 8) { + if (!((uintptr_t)q & (G - 1))) { + if (q + G > (char *)h) notpossible; + _mapframe(q); + if (IsAsan()) { + if (!((uintptr_t)SHADOW(q) & (G - 1))) { + _mapframe(SHADOW(q)); + __asan_poison(q, G << kAsanScale, kAsanProtected); + } + } + } + if (IsAsan()) { + *SHADOW(q) = 0; + } + } + return q; +} diff --git a/libc/intrin/g_fds.c b/libc/intrin/g_fds.c index 192476725..171fb3801 100644 --- a/libc/intrin/g_fds.c +++ b/libc/intrin/g_fds.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/extend.internal.h" #include "libc/calls/internal.h" #include "libc/calls/state.internal.h" #include "libc/intrin/pthread.h" @@ -33,8 +34,8 @@ static textwindows dontinline void SetupWinStd(struct Fds *fds, int i, int x) { int64_t h; h = GetStdHandle(x); if (!h || h == -1) return; - fds->__init_p[i].kind = pushpop(kFdFile); - fds->__init_p[i].handle = h; + fds->p[i].kind = pushpop(kFdFile); + fds->p[i].handle = h; fds->f = i + 1; } @@ -42,29 +43,30 @@ textstartup void InitializeFileDescriptors(void) { struct Fds *fds; __fds_lock_obj.type = PTHREAD_MUTEX_RECURSIVE; fds = VEIL("r", &g_fds); - pushmov(&fds->n, ARRAYLEN(fds->__init_p)); + fds->p = fds->e = (void *)0x6fe000040000; + fds->n = 4; fds->f = 3; - fds->p = fds->__init_p; + fds->e = _extend(fds->p, fds->n * sizeof(*fds->p), fds->e, 0x6ff000000000); if (IsMetal()) { extern const char vga_console[]; pushmov(&fds->f, 3ull); if (weaken(vga_console)) { - fds->__init_p[0].kind = pushpop(kFdConsole); - fds->__init_p[1].kind = pushpop(kFdConsole); - fds->__init_p[2].kind = pushpop(kFdConsole); + fds->p[0].kind = pushpop(kFdConsole); + fds->p[1].kind = pushpop(kFdConsole); + fds->p[2].kind = pushpop(kFdConsole); } else { - fds->__init_p[0].kind = pushpop(kFdSerial); - fds->__init_p[1].kind = pushpop(kFdSerial); - fds->__init_p[2].kind = pushpop(kFdSerial); + fds->p[0].kind = pushpop(kFdSerial); + fds->p[1].kind = pushpop(kFdSerial); + fds->p[2].kind = pushpop(kFdSerial); } - fds->__init_p[0].handle = VEIL("r", 0x3F8ull); - fds->__init_p[1].handle = VEIL("r", 0x3F8ull); - fds->__init_p[2].handle = VEIL("r", 0x3F8ull); + fds->p[0].handle = VEIL("r", 0x3F8ull); + fds->p[1].handle = VEIL("r", 0x3F8ull); + fds->p[2].handle = VEIL("r", 0x3F8ull); } else if (IsWindows()) { SetupWinStd(fds, 0, kNtStdInputHandle); SetupWinStd(fds, 1, kNtStdOutputHandle); SetupWinStd(fds, 2, kNtStdErrorHandle); } - fds->__init_p[1].flags = O_WRONLY | O_APPEND; - fds->__init_p[2].flags = O_WRONLY | O_APPEND; + fds->p[1].flags = O_WRONLY | O_APPEND; + fds->p[2].flags = O_WRONLY | O_APPEND; } diff --git a/libc/intrin/intrin.mk b/libc/intrin/intrin.mk index 891ae56c0..7d32d0143 100644 --- a/libc/intrin/intrin.mk +++ b/libc/intrin/intrin.mk @@ -43,6 +43,20 @@ $(LIBC_INTRIN_A).pkg: \ $(LIBC_INTRIN_A_OBJS) \ $(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x)_A).pkg) +# we can't use asan because: +# asan guard pages haven't been allocated yet +o/$(MODE)/libc/intrin/directmap.o \ +o/$(MODE)/libc/intrin/directmap-nt.o: private \ + OVERRIDE_COPTS += \ + -ffreestanding \ + -fno-sanitize=address + +# we want small code size because: +# to keep .text.head under 4096 bytes +o/$(MODE)/libc/intrin/mman.greg.o: private \ + OVERRIDE_COPTS += \ + -Os + # we can't use asan and ubsan because: # this is asan and ubsan o/$(MODE)/libc/intrin/asan.o \ diff --git a/libc/calls/memtrack.greg.c b/libc/intrin/memtrack.greg.c similarity index 100% rename from libc/calls/memtrack.greg.c rename to libc/intrin/memtrack.greg.c diff --git a/libc/calls/mman.greg.c b/libc/intrin/mman.greg.c similarity index 100% rename from libc/calls/mman.greg.c rename to libc/intrin/mman.greg.c diff --git a/libc/log/libfatal.internal.h b/libc/log/libfatal.internal.h index ddf054af6..77a55f4b1 100644 --- a/libc/log/libfatal.internal.h +++ b/libc/log/libfatal.internal.h @@ -1,9 +1,7 @@ #ifndef COSMOPOLITAN_LIBC_LOG_LIBFATAL_INTERNAL_H_ #define COSMOPOLITAN_LIBC_LOG_LIBFATAL_INTERNAL_H_ -#include "libc/calls/calls.h" #include "libc/dce.h" #include "libc/macros.internal.h" -#include "libc/nexgen32e/bsr.h" #include "libc/nt/runtime.h" #include "libc/sysv/consts/nr.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) @@ -206,7 +204,7 @@ forceinline char *__fixcpy(char p[hasatleast 17], uint64_t x, uint8_t k) { } forceinline char *__hexcpy(char p[hasatleast 17], uint64_t x) { - return __fixcpy(p, x, ROUNDUP(x ? bsrl(x) + 1 : 1, 4)); + return __fixcpy(p, x, ROUNDUP(x ? (__builtin_clzll(x) ^ 63) + 1 : 1, 4)); } forceinline const void *__memchr(const void *s, unsigned char c, size_t n) { diff --git a/libc/log/showcrashreports.c b/libc/log/showcrashreports.c index fafdddf1c..c460ea04b 100644 --- a/libc/log/showcrashreports.c +++ b/libc/log/showcrashreports.c @@ -121,8 +121,7 @@ void ShowCrashReports(void) { ss.ss_size = GetStackSize(); // FreeBSD sigaltstack() will EFAULT if we use MAP_STACK here // OpenBSD sigaltstack() auto-applies MAP_STACK to the memory - if ((sp = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) { + if ((sp = _mapanon(GetStackSize()))) { ss.ss_sp = sp; if (!sigaltstack(&ss, &g_oldsigaltstack)) { __cxa_atexit(FreeSigAltStack, ss.ss_sp, 0); diff --git a/libc/runtime/enable_tls.c b/libc/runtime/enable_tls.c index b6916d131..a6c4f9bb3 100644 --- a/libc/runtime/enable_tls.c +++ b/libc/runtime/enable_tls.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" -#include "libc/calls/strace.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" diff --git a/libc/runtime/fork-nt.c b/libc/runtime/fork-nt.c index a80a6a75b..93401e7a1 100644 --- a/libc/runtime/fork-nt.c +++ b/libc/runtime/fork-nt.c @@ -226,9 +226,9 @@ textwindows void WinMainForked(void) { // rewrap the stdin named pipe hack // since the handles closed on fork struct Fds *fds = VEIL("r", &g_fds); - fds->p[0].handle = fds->__init_p[0].handle = GetStdHandle(kNtStdInputHandle); - fds->p[1].handle = fds->__init_p[1].handle = GetStdHandle(kNtStdOutputHandle); - fds->p[2].handle = fds->__init_p[2].handle = GetStdHandle(kNtStdErrorHandle); + fds->p[0].handle = GetStdHandle(kNtStdInputHandle); + fds->p[1].handle = GetStdHandle(kNtStdOutputHandle); + fds->p[2].handle = GetStdHandle(kNtStdErrorHandle); // untrack children of parent since we specify with both // CreateProcess() and CreateThread() as non-inheritable diff --git a/libc/runtime/hook.greg.c b/libc/runtime/hook.greg.c index c68cbb904..24d7de0a3 100644 --- a/libc/runtime/hook.greg.c +++ b/libc/runtime/hook.greg.c @@ -16,16 +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/calls/struct/sigset.h" -#include "libc/dce.h" -#include "libc/errno.h" -#include "libc/intrin/bits.h" -#include "libc/log/libfatal.internal.h" #include "libc/runtime/runtime.h" #include "libc/runtime/symbols.internal.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/prot.h" /** * Rewrites code in memory to hook function calls. diff --git a/libc/runtime/memtrack64.txt b/libc/runtime/memtrack64.txt index 2f5356616..9b090ce99 100644 --- a/libc/runtime/memtrack64.txt +++ b/libc/runtime/memtrack64.txt @@ -1810,7 +1810,7 @@ 6fb00000-6fbfffff 64gb free 6fc00000-6fcfffff 64gb free 6fd00000-6fdfffff 64gb zipos -6fe00000-6fefffff 64gb g_fds +6fe00004-6feffffc 64gb g_fds 6ff00000-6ffffffd 64gb free 6ffffffe-6fffffff 128kb winargs diff --git a/libc/stdio/ecvt.c b/libc/stdio/ecvt.c index 61f4455d9..2eba91728 100644 --- a/libc/stdio/ecvt.c +++ b/libc/stdio/ecvt.c @@ -24,6 +24,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/fmt/fmt.h" #include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "third_party/gdtoa/gdtoa.h" @@ -33,10 +34,24 @@ Copyright (c) 2002, 2006, 2010 Todd C. Miller \""); asm(".include \"libc/disclaimer.inc\""); // clang-format off +static char *s; + +static void +__cvt_atexit(void) +{ + free(s); + s = 0; +} + +static void __attribute__((__constructor__)) +__cvt_init(void) +{ + atexit(__cvt_atexit); +} + static char * __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad) { - static char *s; char *p, *rve, c; size_t siz; diff --git a/libc/zipos/free.c b/libc/zipos/free.c index 5962dcc3a..512a71eba 100644 --- a/libc/zipos/free.c +++ b/libc/zipos/free.c @@ -23,11 +23,6 @@ #include "libc/str/str.h" #include "libc/zipos/zipos.internal.h" -/** - * Frees ZipOS handle. - * @asyncsignalsafe - * @threadsafe - */ void __zipos_free(struct Zipos *z, struct ZiposHandle *h) { if (IsAsan()) { __asan_poison((char *)h + sizeof(struct ZiposHandle), diff --git a/libc/zipos/open.c b/libc/zipos/open.c index ad6ad9918..44979f08e 100644 --- a/libc/zipos/open.c +++ b/libc/zipos/open.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" +#include "libc/calls/extend.internal.h" #include "libc/calls/internal.h" #include "libc/calls/state.internal.h" #include "libc/calls/struct/sigset.h" @@ -42,47 +43,19 @@ #include "libc/zip.h" #include "libc/zipos/zipos.internal.h" -static volatile size_t maptotal; - -static pureconst size_t __zipos_granularity(void) { - return FRAMESIZE * (IsAsan() ? 8 : 1); -} +static char *mapend; +static size_t maptotal; static void *__zipos_mmap(size_t mapsize) { + char *start; size_t offset; - struct DirectMap dm; - int rc, prot, flags; - uint64_t addr, addr2, addr3; assert(mapsize); - do offset = maptotal; - while (!_cmpxchg(&maptotal, offset, maptotal + mapsize)); - if (offset + mapsize <= kMemtrackZiposSize) { - prot = PROT_READ | PROT_WRITE; - flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED; - addr = kMemtrackZiposStart + offset; - if ((dm = sys_mmap((void *)addr, mapsize, prot, flags, -1, 0)).addr != - MAP_FAILED) { - rc = TrackMemoryInterval(&_mmi, addr >> 16, (addr + mapsize - 1) >> 16, - dm.maphandle, prot, flags, false, false, 0, - mapsize); - assert(!rc); - if (IsAsan()) { - addr2 = (addr >> 3) + 0x7fff8000; - addr3 = ((addr + mapsize) >> 3) + 0x7fff8000; - assert(!(addr2 & (FRAMESIZE - 1))); - assert(!(addr3 & (FRAMESIZE - 1))); - dm = sys_mmap((void *)addr2, mapsize >> 3, prot, flags, -1, 0); - assert(dm.addr != MAP_FAILED); - rc = TrackMemoryInterval(&_mmi, addr2 >> 16, (addr3 >> 16) - 1, - dm.maphandle, prot, flags, false, false, 0, - mapsize >> 3); - assert(!rc); - } - return (void *)addr; - } - } - enomem(); - return 0; + offset = maptotal; + maptotal += mapsize; + start = (char *)0x6fd000040000; + if (!mapend) mapend = start; + mapend = _extend(start, maptotal, mapend, 0x6fdfffff0000); + return start + offset; } static struct ZiposHandle *__zipos_alloc(struct Zipos *zipos, size_t size) { @@ -90,7 +63,7 @@ static struct ZiposHandle *__zipos_alloc(struct Zipos *zipos, size_t size) { struct ZiposHandle *h, **ph; __zipos_lock(); mapsize = sizeof(struct ZiposHandle) + size; - mapsize = ROUNDUP(mapsize, __zipos_granularity()); + mapsize = ROUNDUP(mapsize, 4096); StartOver: ph = &zipos->freelist; while ((h = *ph)) { diff --git a/libc/zipos/zipos.h b/libc/zipos/zipos.h new file mode 100755 index 000000000..e69de29bb diff --git a/libc/zipos/zipos.internal.h b/libc/zipos/zipos.internal.h index 6fb612e6a..dcccad9cb 100644 --- a/libc/zipos/zipos.internal.h +++ b/libc/zipos/zipos.internal.h @@ -1,6 +1,5 @@ #ifndef COSMOPOLITAN_LIBC_ZIPOS_ZIPOS_H_ #define COSMOPOLITAN_LIBC_ZIPOS_ZIPOS_H_ -#include "libc/calls/calls.h" #include "libc/intrin/nopl.h" #include "libc/nexgen32e/threaded.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) diff --git a/test/libc/calls/reservefd_test.c b/test/libc/calls/reservefd_test.c index a513cb243..b06e47680 100644 --- a/test/libc/calls/reservefd_test.c +++ b/test/libc/calls/reservefd_test.c @@ -61,7 +61,6 @@ void PullSomeZipFilesIntoLinkage(void) { TEST(reservefd, testGrowthOfFdsDataStructure) { int i, n; struct rlimit rlim; - ASSERT_EQ(g_fds.n, OPEN_MAX); n = 1700; // pe '2**16/40' → 1638 (likely value of g_fds.n) if (!getrlimit(RLIMIT_NOFILE, &rlim)) n = MIN(n, rlim.rlim_cur - 3); for (i = 0; i < n; ++i) { diff --git a/test/libc/fmt/fcvt_test.c b/test/libc/stdio/ecvt_test.c similarity index 100% rename from test/libc/fmt/fcvt_test.c rename to test/libc/stdio/ecvt_test.c diff --git a/test/libc/test.mk b/test/libc/test.mk index ef908621a..4abd1a1e0 100644 --- a/test/libc/test.mk +++ b/test/libc/test.mk @@ -19,4 +19,5 @@ o/$(MODE)/test/libc: \ o/$(MODE)/test/libc/time \ o/$(MODE)/test/libc/tinymath \ o/$(MODE)/test/libc/x \ + o/$(MODE)/test/libc/zipos \ o/$(MODE)/test/libc/xed diff --git a/test/libc/thread/pthread_create_test.c b/test/libc/thread/pthread_create_test.c index 421761208..b59d3c51b 100644 --- a/test/libc/thread/pthread_create_test.c +++ b/test/libc/thread/pthread_create_test.c @@ -26,6 +26,7 @@ #include "libc/intrin/pthread2.h" #include "libc/macros.internal.h" #include "libc/mem/mem.h" +#include "libc/nexgen32e/nexgen32e.h" #include "libc/runtime/runtime.h" #include "libc/runtime/stack.h" #include "libc/sysv/consts/prot.h" @@ -37,18 +38,19 @@ #include "libc/testlib/testlib.h" #include "libc/thread/thread.h" -void OnTrap(int sig, struct siginfo *si, void *vctx) { +void OnUsr1(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); + struct sigaction sig = {.sa_sigaction = OnUsr1, .sa_flags = SA_SIGINFO}; + sigaction(SIGUSR1, &sig, 0); } void TriggerSignal(void) { sched_yield(); - DebugBreak(); + /* kprintf("raising at %p\n", __builtin_frame_address(0)); */ + raise(SIGUSR1); sched_yield(); } @@ -67,6 +69,7 @@ TEST(pthread_create, testCreateReturnJoin) { } static void *IncExit(void *arg) { + CheckStackIsAligned(); TriggerSignal(); pthread_exit((void *)((uintptr_t)arg + 1)); } diff --git a/test/libc/zipos/open_test.c b/test/libc/zipos/open_test.c new file mode 100644 index 000000000..a94e8bba3 --- /dev/null +++ b/test/libc/zipos/open_test.c @@ -0,0 +1,56 @@ +/*-*- 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 2022 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/calls.h" +#include "libc/mem/mem.h" +#include "libc/runtime/gc.h" +#include "libc/runtime/runtime.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/o.h" +#include "libc/testlib/hyperion.h" +#include "libc/testlib/testlib.h" +#include "libc/thread/spawn.h" +#include "libc/zipos/zipos.h" + +STATIC_YOINK("zip_uri_support"); +STATIC_YOINK("libc/testlib/hyperion.txt"); +/* STATIC_YOINK("inflate"); */ +/* STATIC_YOINK("inflateInit2"); */ +/* STATIC_YOINK("inflateEnd"); */ + +int Worker(void *arg, int tid) { + int i, fd; + char *data; + for (i = 0; i < 20; ++i) { + ASSERT_NE(-1, (fd = open("/zip/libc/testlib/hyperion.txt", O_RDONLY))); + data = malloc(kHyperionSize); + ASSERT_EQ(kHyperionSize, read(fd, data, kHyperionSize)); + ASSERT_EQ(0, memcmp(data, kHyperion, kHyperionSize)); + ASSERT_SYS(0, 0, close(fd)); + free(data); + } + return 0; +} + +TEST(zipos, test) { + int i, n = 16; + struct spawn *t = _gc(malloc(sizeof(struct spawn) * n)); + for (i = 0; i < n; ++i) ASSERT_SYS(0, 0, _spawn(Worker, 0, t + i)); + for (i = 0; i < n; ++i) EXPECT_SYS(0, 0, _join(t + i)); + /* __print_maps(); */ +} diff --git a/test/libc/zipos/test.mk b/test/libc/zipos/test.mk new file mode 100644 index 000000000..086867e33 --- /dev/null +++ b/test/libc/zipos/test.mk @@ -0,0 +1,63 @@ +#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ +#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘ + +PKGS += TEST_LIBC_ZIPOS + +TEST_LIBC_ZIPOS_SRCS := $(wildcard test/libc/zipos/*.c) +TEST_LIBC_ZIPOS_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_ZIPOS_SRCS)) + +TEST_LIBC_ZIPOS_OBJS = \ + $(TEST_LIBC_ZIPOS_SRCS:%.c=o/$(MODE)/%.o) + +TEST_LIBC_ZIPOS_COMS = \ + $(TEST_LIBC_ZIPOS_SRCS:%.c=o/$(MODE)/%.com) + +TEST_LIBC_ZIPOS_BINS = \ + $(TEST_LIBC_ZIPOS_COMS) \ + $(TEST_LIBC_ZIPOS_COMS:%=%.dbg) + +TEST_LIBC_ZIPOS_TESTS = \ + $(TEST_LIBC_ZIPOS_SRCS_TEST:%.c=o/$(MODE)/%.com.ok) + +TEST_LIBC_ZIPOS_CHECKS = \ + $(TEST_LIBC_ZIPOS_SRCS_TEST:%.c=o/$(MODE)/%.com.runs) + +TEST_LIBC_ZIPOS_DIRECTDEPS = \ + LIBC_CALLS \ + LIBC_FMT \ + LIBC_INTRIN \ + LIBC_MEM \ + LIBC_NEXGEN32E \ + LIBC_RUNTIME \ + LIBC_STR \ + LIBC_STUBS \ + LIBC_THREAD \ + LIBC_SYSV \ + LIBC_ZIPOS \ + LIBC_TIME \ + LIBC_TESTLIB \ + THIRD_PARTY_ZLIB + +TEST_LIBC_ZIPOS_DEPS := \ + $(call uniq,$(foreach x,$(TEST_LIBC_ZIPOS_DIRECTDEPS),$($(x)))) + +o/$(MODE)/test/libc/zipos/zipos.pkg: \ + $(TEST_LIBC_ZIPOS_OBJS) \ + $(foreach x,$(TEST_LIBC_ZIPOS_DIRECTDEPS),$($(x)_A).pkg) + +#o/$(MODE)/libc/testlib/hyperion.txt.zip.o: private ZIPOBJ_FLAGS += -0 + +o/$(MODE)/test/libc/zipos/%.com.dbg: \ + $(TEST_LIBC_ZIPOS_DEPS) \ + o/$(MODE)/test/libc/zipos/%.o \ + o/$(MODE)/test/libc/zipos/zipos.pkg \ + o/$(MODE)/libc/testlib/hyperion.txt.zip.o \ + $(LIBC_TESTMAIN) \ + $(CRT) \ + $(APE_NO_MODIFY_SELF) + @$(APELINK) + +.PHONY: o/$(MODE)/test/libc/zipos +o/$(MODE)/test/libc/zipos: \ + $(TEST_LIBC_ZIPOS_BINS) \ + $(TEST_LIBC_ZIPOS_CHECKS) diff --git a/tool/scripts/check-includes.py b/tool/scripts/check-includes.py deleted file mode 100755 index eed104417..000000000 --- a/tool/scripts/check-includes.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python.com - -import os -import sys - -def CheckFile(path): - if path.endswith(('.png', '.ico')): - return - sys.stderr.write('%s\n' % (path)) - with open(path) as f: - data = f.read() - assert '#include' not in data[65530:], "late include in %s" % (path) - -for arg in sys.argv[1:]: - if os.path.isdir(arg): - for dirpath, dirs, files in os.walk(arg): - for filepath in files: - CheckFile(os.path.join(dirpath, filepath)) - else: - CheckFile(arg)