mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-06 08:56:22 +00:00
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.
This commit is contained in:
parent
c3208eb9d5
commit
3265324e00
35 changed files with 297 additions and 152 deletions
1
Makefile
1
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
|
||||
|
|
|
@ -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"
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 \
|
||||
|
|
10
libc/calls/extend.internal.h
Normal file
10
libc/calls/extend.internal.h
Normal file
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
|
|
84
libc/intrin/extend.c
Normal file
84
libc/intrin/extend.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 <millert@openbsd.org>\"");
|
|||
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;
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)) {
|
||||
|
|
0
libc/zipos/zipos.h
Executable file
0
libc/zipos/zipos.h
Executable file
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
56
test/libc/zipos/open_test.c
Normal file
56
test/libc/zipos/open_test.c
Normal file
|
@ -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(); */
|
||||
}
|
63
test/libc/zipos/test.mk
Normal file
63
test/libc/zipos/test.mk
Normal file
|
@ -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)
|
|
@ -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)
|
Loading…
Add table
Reference in a new issue