From cbfd4ccd1e26c0c93c7d2422d7645855affeba51 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Tue, 2 Feb 2021 03:45:31 -0800 Subject: [PATCH 1/5] Make more functions friendly to Address Sanitizer --- Makefile | 8 +- ape/ape.mk | 1 + build/compile | 20 +++- build/mkdeps | 8 +- dsp/core/core.mk | 5 +- dsp/scale/scale.mk | 1 + libc/alg/alg.mk | 2 + libc/calls/calls.mk | 2 + libc/calls/dup3-sysv.c | 3 +- libc/calls/madvise-nt.c | 4 +- libc/calls/now.c | 19 +-- libc/fmt/fmt.mk | 2 + libc/integral/c.inc | 2 +- libc/intrin/asan.c | 43 +++---- libc/intrin/intrin.mk | 3 +- libc/intrin/psrldq.c | 4 +- libc/libc.mk | 1 + libc/nexgen32e/khalfcache3.S | 2 +- libc/nexgen32e/nexgen32e.h | 2 + libc/nexgen32e/nexgen32e.mk | 2 + libc/nexgen32e/strsak.S | 80 +------------ libc/nt/nt.mk | 6 +- libc/sock/sock.mk | 3 + libc/stdio/g_stderr.c | 2 +- libc/stdio/g_stdin.c | 2 +- libc/stdio/g_stdout.c | 2 +- libc/str/{tinymemccpy.c => index.c} | 20 ++-- libc/str/memccpy.c | 57 +++++++-- libc/str/memchr.c | 47 ++++++++ libc/str/memmove-pure.c | 160 +++++++++++++++++++++++++ libc/str/memset-pure.c | 100 ++++++++++++++++ libc/str/rawmemchr.c | 53 ++++++++ libc/str/str.h | 42 +++++-- libc/str/str.mk | 2 + libc/str/strchr.c | 69 +++++++++++ libc/str/strchrnul.c | 69 +++++++++++ libc/str/strcmp.c | 28 ++++- libc/str/strcspn-pure.c | 62 ++++++++++ libc/str/strlen-pure.c | 34 +++--- libc/str/strnlen.c | 57 +++++++++ libc/sysv/sysv.mk | 2 + libc/testlib/ezbenchreport.c | 4 +- libc/time/time.h | 3 +- test/dsp/scale/scale_test.c | 7 +- test/libc/crypto/test.mk | 1 + test/libc/mem/test.mk | 1 + test/libc/nexgen32e/memmove_test.c | 152 ++++++++++++++--------- test/libc/sock/test.mk | 1 + test/libc/str/memccpy_test.c | 12 +- test/libc/str/memcpy_test.c | 115 ++++++++++++++++-- test/libc/str/strchr_test.c | 99 +++++++++++++++ test/libc/str/strlen_test.c | 12 +- test/libc/tinymath/test.mk | 1 + third_party/compiler_rt/compiler_rt.mk | 2 + third_party/duktape/duktape.mk | 2 + third_party/gdtoa/gdtoa.mk | 2 + third_party/lemon/lemon.mk | 6 + third_party/lz4cli/bench.c | 12 +- third_party/lz4cli/datagen.c | 4 +- third_party/lz4cli/lz4.c | 2 +- third_party/lz4cli/lz4cli.c | 12 +- third_party/lz4cli/lz4cli.mk | 4 + third_party/lz4cli/lz4hc.c | 4 +- third_party/lz4cli/lz4hc.h | 2 +- third_party/lz4cli/xxhash.c | 2 +- third_party/lz4cli/xxhash.h | 2 +- third_party/regex/regex.mk | 1 + tool/build/blinkenlights.c | 40 +++++-- tool/build/lib/syscall.c | 20 +++- tool/emacs/cosmo-c-builtins.el | 2 + 70 files changed, 1267 insertions(+), 291 deletions(-) rename libc/str/{tinymemccpy.c => index.c} (81%) create mode 100644 libc/str/memchr.c create mode 100644 libc/str/memmove-pure.c create mode 100644 libc/str/memset-pure.c create mode 100644 libc/str/rawmemchr.c create mode 100644 libc/str/strchr.c create mode 100644 libc/str/strchrnul.c create mode 100644 libc/str/strcspn-pure.c create mode 100644 libc/str/strnlen.c diff --git a/Makefile b/Makefile index 37ac7ec62..03ed5172d 100644 --- a/Makefile +++ b/Makefile @@ -199,6 +199,7 @@ include test/test.mk OBJS = $(foreach x,$(PKGS),$($(x)_OBJS)) SRCS = $(foreach x,$(PKGS),$($(x)_SRCS)) HDRS = $(foreach x,$(PKGS),$($(x)_HDRS)) +INCS = $(foreach x,$(PKGS),$($(x)_INCS)) BINS = $(foreach x,$(PKGS),$($(x)_BINS)) TESTS = $(foreach x,$(PKGS),$($(x)_TESTS)) CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS)) @@ -215,10 +216,10 @@ o/$(MODE)/.x: o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x)))) $(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x))) -o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS),$(dir $(x)))) - $(file >$@) $(foreach x,$(HDRS),$(file >>$@,$(x))) +o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x)))) + $(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x))) -o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(SRCS) $(HDRS) +o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(SRCS) $(HDRS) $(INCS) @build/mkdeps -o $@ -r o/$(MODE)/ o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt TAGS: o/$(MODE)/srcs.txt $(SRCS) @@ -351,6 +352,7 @@ o/cosmopolitan.html: \ ~/.cosmo.mk: $(SRCS): $(HDRS): +$(INCS): .DEFAULT: @echo >&2 @echo NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2 diff --git a/ape/ape.mk b/ape/ape.mk index 529c0d1e9..a9589aafb 100644 --- a/ape/ape.mk +++ b/ape/ape.mk @@ -33,6 +33,7 @@ APELINK = \ APE_FILES := $(wildcard ape/*.*) APE_HDRS = $(filter %.h,$(APE_FILES)) +APE_INCS = $(filter %.inc,$(APE_FILES)) APE_SRCS = $(filter %.S,$(APE_FILES)) APE_OBJS = $(APE_SRCS:%.S=o/$(MODE)/%.o) APE_DEPS = $(APE_LIB) diff --git a/build/compile b/build/compile index bfef27189..96b311e32 100755 --- a/build/compile +++ b/build/compile @@ -37,6 +37,8 @@ export LC_ALL=C MKDIR=${MKDIR:-$(command -v mkdir) -p} || exit GZME= +ASAN= +UBSAN= PLAT="${1%% *}" FDIAGNOSTIC_COLOR= CCNAME=${CCNAME:-gcc} @@ -87,11 +89,21 @@ for x; do set -- "$@" "$x" -Wa,-msse2avx -D__MNO_VZEROUPPER__ ;; -fsanitize=address) - set -- "$@" "$x" -D__FSANITIZE_ADDRESS__ + ASAN="$x -D__FSANITIZE_ADDRESS__" ;; -fsanitize=undefined) - set -- "$@" "$x" -D__FSANITIZE_UNDEFINED__ - COUNTERMAND="$COUNTERMAND -fno-data-sections" # sqlite.o + # UBSAN w/ -fdata-sections exceeds ELF's 65,280 section limit + UBSAN="$x -fno-data-sections" + ;; + -fno-sanitize=address) + ASAN= + ;; + -fno-sanitize=ubsan) + UBSAN= + ;; + -fno-sanitize=all) + ASAN= + UBSAN= ;; -mnop-mcount) if [ "$CCNAME" = "gcc" ] && [ "$CCVERSION" -ge 6 ]; then @@ -256,7 +268,7 @@ else done fi -set -- "$@" -no-canonical-prefixes $FDIAGNOSTIC_COLOR $COUNTERMAND +set -- "$@" -no-canonical-prefixes $FDIAGNOSTIC_COLOR $ASAN $UBSAN $COUNTERMAND if [ "$SILENT" = "0" ]; then printf "%s\n" "$*" >&2 diff --git a/build/mkdeps b/build/mkdeps index e1d83bf15..b6919ca4b 100755 --- a/build/mkdeps +++ b/build/mkdeps @@ -2,16 +2,16 @@ #-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐ #───vi: set net ft=sh ts=2 sts=2 fenc=utf-8 :vi─────────────┘ -#if [ -x "o/$MODE/tool/build/mkdeps.com" ]; then -# set -- "o/$MODE/tool/build/mkdeps.com" "$@" -#else +if [ -x "o/$MODE/tool/build/mkdeps.com" ]; then + set -- "o/$MODE/tool/build/mkdeps.com" "$@" +else if [ ! -x o/build/bootstrap/mkdeps.com ]; then mkdir -p o/build/bootstrap && cp -a build/bootstrap/mkdeps.com \ o/build/bootstrap/mkdeps.com || exit fi set -- o/build/bootstrap/mkdeps.com "$@" -#fi +fi if [ "$SILENT" = "0" ]; then printf "%s\n" "$*" >&2 diff --git a/dsp/core/core.mk b/dsp/core/core.mk index d4e130f36..66bba02f2 100644 --- a/dsp/core/core.mk +++ b/dsp/core/core.mk @@ -24,9 +24,10 @@ DSP_CORE_A_CHECKS = \ $(DSP_CORE_A_HDRS:%=o/$(MODE)/%.ok) DSP_CORE_A_DIRECTDEPS = \ - LIBC_NEXGEN32E \ - LIBC_MEM \ LIBC_INTRIN \ + LIBC_MEM \ + LIBC_NEXGEN32E \ + LIBC_STR \ LIBC_TINYMATH \ LIBC_STUBS diff --git a/dsp/scale/scale.mk b/dsp/scale/scale.mk index 09403c741..ead96d43a 100644 --- a/dsp/scale/scale.mk +++ b/dsp/scale/scale.mk @@ -30,6 +30,7 @@ DSP_SCALE_A_DIRECTDEPS = \ LIBC_MEM \ LIBC_NEXGEN32E \ LIBC_RUNTIME \ + LIBC_STR \ LIBC_STUBS \ LIBC_STUBS \ LIBC_TIME \ diff --git a/libc/alg/alg.mk b/libc/alg/alg.mk index a0ad35482..df07ceb29 100644 --- a/libc/alg/alg.mk +++ b/libc/alg/alg.mk @@ -8,6 +8,7 @@ LIBC_ALG = $(LIBC_ALG_A_DEPS) $(LIBC_ALG_A) LIBC_ALG_A = o/$(MODE)/libc/alg/alg.a LIBC_ALG_A_FILES := $(wildcard libc/alg/*) LIBC_ALG_A_HDRS = $(filter %.h,$(LIBC_ALG_A_FILES)) +LIBC_ALG_A_INCS = $(filter %.inc,$(LIBC_ALG_A_FILES)) LIBC_ALG_A_SRCS_S = $(filter %.S,$(LIBC_ALG_A_FILES)) LIBC_ALG_A_SRCS_C = $(filter %.c,$(LIBC_ALG_A_FILES)) @@ -51,6 +52,7 @@ o/$(MODE)/libc/alg/critbit0.o: \ LIBC_ALG_LIBS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x))) LIBC_ALG_SRCS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_SRCS)) LIBC_ALG_HDRS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_HDRS)) +LIBC_ALG_INCS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_INCS)) LIBC_ALG_CHECKS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_CHECKS)) LIBC_ALG_OBJS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_OBJS)) $(LIBC_ALG_OBJS): $(BUILD_FILES) libc/alg/alg.mk diff --git a/libc/calls/calls.mk b/libc/calls/calls.mk index 7511494d3..c7f103d63 100644 --- a/libc/calls/calls.mk +++ b/libc/calls/calls.mk @@ -21,6 +21,7 @@ LIBC_CALLS_A_FILES := \ $(wildcard libc/calls/struct/*) \ $(wildcard libc/calls/*) LIBC_CALLS_A_HDRS = $(filter %.h,$(LIBC_CALLS_A_FILES)) +LIBC_CALLS_A_INCS = $(filter %.inc,$(LIBC_CALLS_A_FILES)) LIBC_CALLS_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_A_FILES)) LIBC_CALLS_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_A_FILES)) @@ -86,6 +87,7 @@ o/$(MODE)/libc/calls/mkntenvblock.o: \ LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x))) LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS)) LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS)) +LIBC_CALLS_INCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_INCS)) LIBC_CALLS_BINS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_BINS)) LIBC_CALLS_CHECKS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_CHECKS)) LIBC_CALLS_OBJS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_OBJS)) diff --git a/libc/calls/dup3-sysv.c b/libc/calls/dup3-sysv.c index 142484110..f231daf3b 100644 --- a/libc/calls/dup3-sysv.c +++ b/libc/calls/dup3-sysv.c @@ -25,13 +25,14 @@ int32_t dup3$sysv(int32_t oldfd, int32_t newfd, int flags) { static bool once, demodernize; int olderr, fd; if (!once) { - once = true; olderr = errno; fd = __dup3$sysv(oldfd, newfd, flags); if ((fd == -1 && errno == ENOSYS) || fd == __NR_dup3_linux) { demodernize = true; + once = true; errno = olderr; } else { + once = true; return fd; } } else if (!demodernize) { diff --git a/libc/calls/madvise-nt.c b/libc/calls/madvise-nt.c index 9d8005d1e..780e57b8c 100644 --- a/libc/calls/madvise-nt.c +++ b/libc/calls/madvise-nt.c @@ -29,9 +29,9 @@ forceinline typeof(PrefetchVirtualMemory) *GetPrefetchVirtualMemory(void) { static bool once; static typeof(PrefetchVirtualMemory) *PrefetchVirtualMemory_; if (!once) { - once = true; PrefetchVirtualMemory_ = /* win8.1+ */ GetProcAddressModule("Kernel32.dll", "PrefetchVirtualMemory"); + once = true; } return PrefetchVirtualMemory_; } @@ -40,9 +40,9 @@ forceinline typeof(OfferVirtualMemory) *GetOfferVirtualMemory(void) { static bool once; static typeof(OfferVirtualMemory) *OfferVirtualMemory_; if (!once) { - once = true; OfferVirtualMemory_ = /* win8.1+ */ GetProcAddressModule("Kernel32.dll", "OfferVirtualMemory"); + once = true; } return OfferVirtualMemory_; } diff --git a/libc/calls/now.c b/libc/calls/now.c index 4cdef2ebe..2e4cf360d 100644 --- a/libc/calls/now.c +++ b/libc/calls/now.c @@ -23,6 +23,7 @@ #include "libc/dce.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/x86feature.h" +#include "libc/str/str.h" #include "libc/sysv/consts/clock.h" #include "libc/time/time.h" @@ -55,19 +56,21 @@ static long double MeasureNanosPerCycle(void) { } static void InitTime(void) { - g_now.cpn = MeasureNanosPerCycle(); - g_now.r0 = dtime(CLOCK_REALTIME); - g_now.k0 = rdtsc(); - g_now.once = true; + struct Now now; + now.cpn = MeasureNanosPerCycle(); + now.r0 = dtime(CLOCK_REALTIME); + now.k0 = rdtsc(); + now.once = true; + memcpy(&g_now, &now, sizeof(now)); } -long double converttickstonanos(uint64_t ticks) { +long double ConvertTicksToNanos(uint64_t ticks) { if (!g_now.once) InitTime(); return ticks * g_now.cpn; /* pico scale */ } -long double converttickstoseconds(uint64_t ticks) { - return 1 / 1e9 * converttickstonanos(ticks); +static long double ConvertTicksToSeconds(uint64_t ticks) { + return 1 / 1e9 * ConvertTicksToNanos(ticks); } long double nowl$sys(void) { @@ -78,5 +81,5 @@ long double nowl$art(void) { uint64_t ticks; if (!g_now.once) InitTime(); ticks = unsignedsubtract(rdtsc(), g_now.k0); - return g_now.r0 + converttickstoseconds(ticks); + return g_now.r0 + ConvertTicksToSeconds(ticks); } diff --git a/libc/fmt/fmt.mk b/libc/fmt/fmt.mk index ccffc3d4e..e906da317 100644 --- a/libc/fmt/fmt.mk +++ b/libc/fmt/fmt.mk @@ -17,6 +17,7 @@ LIBC_FMT = $(LIBC_FMT_A_DEPS) $(LIBC_FMT_A) LIBC_FMT_A = o/$(MODE)/libc/fmt/fmt.a LIBC_FMT_A_FILES := $(wildcard libc/fmt/*) LIBC_FMT_A_HDRS = $(filter %.h,$(LIBC_FMT_A_FILES)) +LIBC_FMT_A_INCS = $(filter %.inc,$(LIBC_FMT_A_FILES)) LIBC_FMT_A_SRCS_S = $(filter %.S,$(LIBC_FMT_A_FILES)) LIBC_FMT_A_SRCS_C = $(filter %.c,$(LIBC_FMT_A_FILES)) @@ -75,6 +76,7 @@ o/$(MODE)/libc/fmt/itoa128radix10.greg.o: \ LIBC_FMT_LIBS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x))) LIBC_FMT_SRCS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_SRCS)) LIBC_FMT_HDRS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_HDRS)) +LIBC_FMT_INCS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_INCS)) LIBC_FMT_CHECKS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_CHECKS)) LIBC_FMT_OBJS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_OBJS)) $(LIBC_FMT_OBJS): $(BUILD_FILES) libc/fmt/fmt.mk diff --git a/libc/integral/c.inc b/libc/integral/c.inc index 56aa255f2..56cc7d496 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -331,7 +331,7 @@ typedef uint64_t uintmax_t; #ifndef nullterminated #if !defined(__STRICT_ANSI__) && \ - (__has_attribute(__sentinel__) || __GNUC__ >= 4) + (__has_attribute(__sentinel__) || __GNUC__ + 0 >= 4) #define nullterminated(x) __attribute__((__sentinel__ x)) #else #define nullterminated(x) diff --git a/libc/intrin/asan.c b/libc/intrin/asan.c index 950d39c08..3d934be3b 100644 --- a/libc/intrin/asan.c +++ b/libc/intrin/asan.c @@ -154,6 +154,13 @@ static void *__asan_repstosb(void *di, int al, size_t cx) { return di; } +static void *__asan_repmovsb(void *di, void *si, size_t cx) { + asm("rep movsb" + : "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di) + : "0"(di), "1"(si), "2"(cx), "m"(*(char(*)[cx])si)); + return di; +} + static void *__asan_memset(void *p, int c, size_t n) { char *b; size_t i; @@ -264,14 +271,18 @@ static void *__asan_mempcpy(void *dst, const void *src, size_t n) { __builtin_memcpy(d + n - 8, &b, 8); return d + n; default: - i = 0; - do { - __builtin_memcpy(&a, s + i, 8); - asm volatile("" ::: "memory"); - __builtin_memcpy(d + i, &a, 8); - } while ((i += 8) + 8 <= n); - for (; i < n; ++i) d[i] = s[i]; - return d + i; + if (n <= 64) { + i = 0; + do { + __builtin_memcpy(&a, s + i, 8); + asm volatile("" ::: "memory"); + __builtin_memcpy(d + i, &a, 8); + } while ((i += 8) + 8 <= n); + for (; i < n; ++i) d[i] = s[i]; + return d + i; + } else { + return __asan_repmovsb(d, s, n); + } } } @@ -280,16 +291,6 @@ static void *__asan_memcpy(void *dst, const void *src, size_t n) { return dst; } -static void *__asan_memrchr(void *p, int c, size_t n) { - uint8_t *b; - for (c &= 0xff, b = p; n--;) { - if (b[n] == c) { - return b + n; - } - } - return NULL; -} - static size_t __asan_int2hex(uint64_t x, char b[17], uint8_t k) { int i; char *p; @@ -455,8 +456,6 @@ static wontreturn void __asan_report_heap_fault(void *addr, long c) { char *p, ibuf[21], buf[256]; p = __asan_report_start(buf); p = __asan_stpcpy(p, __asan_dscribe_heap_poison(c)); - p = __asan_stpcpy(p, " "); - p = __asan_mempcpy(p, ibuf, __asan_int2str(c, ibuf)); p = __asan_stpcpy(p, " at 0x"); p = __asan_mempcpy(p, ibuf, __asan_int2hex((intptr_t)addr, ibuf, 48)); p = __asan_stpcpy(p, " shadow 0x"); @@ -709,7 +708,9 @@ void __asan_map_shadow(uintptr_t p, size_t n) { int i, x, a, b; struct DirectMap sm; struct MemoryIntervals *m; - if (0x7fff8000 <= p && p < 0x100080000000) { + if ((0x7fff8000 <= p && p < 0x100080000000) || + (0x7fff8000 <= p + n && p + n < 0x100080000000) || + (p < 0x7fff8000 && 0x100080000000 <= p + n)) { __asan_die("asan error: mmap can't shadow a shadow\r\n"); } m = weaken(_mmi); diff --git a/libc/intrin/intrin.mk b/libc/intrin/intrin.mk index cd9a91927..4506a7ab8 100644 --- a/libc/intrin/intrin.mk +++ b/libc/intrin/intrin.mk @@ -46,7 +46,8 @@ $(LIBC_INTRIN_A_OBJS): \ o/$(MODE)/libc/intrin/asan.o: \ OVERRIDE_CFLAGS += \ - -mgeneral-regs-only + -mgeneral-regs-only \ + -O2 LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x))) LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS)) diff --git a/libc/intrin/psrldq.c b/libc/intrin/psrldq.c index 2c88aea42..505d870e1 100644 --- a/libc/intrin/psrldq.c +++ b/libc/intrin/psrldq.c @@ -29,6 +29,6 @@ void(psrldq)(uint8_t b[16], const uint8_t a[16], unsigned long n) { unsigned i; if (n > 16) n = 16; - memcpy(b, a + n, 16 - n); - memset(b + (16 - n), 0, n); + __builtin_memcpy(b, a + n, 16 - n); + __builtin_memset(b + (16 - n), 0, n); } diff --git a/libc/libc.mk b/libc/libc.mk index 7bbaec715..91a0d9be0 100644 --- a/libc/libc.mk +++ b/libc/libc.mk @@ -4,6 +4,7 @@ PKGS += LIBC LIBC_HDRS = $(filter %.h,$(LIBC_FILES)) +LIBC_INCS = $(filter %.inc,$(LIBC_FILES)) LIBC_FILES := $(wildcard libc/*) LIBC_CHECKS = $(LIBC_HDRS:%=o/$(MODE)/%.ok) diff --git a/libc/nexgen32e/khalfcache3.S b/libc/nexgen32e/khalfcache3.S index 11fc2b572..d807f0251 100644 --- a/libc/nexgen32e/khalfcache3.S +++ b/libc/nexgen32e/khalfcache3.S @@ -18,8 +18,8 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -/ Half size of level 3 cache in bytes. .initbss 202,_init_kHalfCache3 +/ Half size of level 3 cache in bytes. kHalfCache3: .quad 0 .endobj kHalfCache3,globl diff --git a/libc/nexgen32e/nexgen32e.h b/libc/nexgen32e/nexgen32e.h index 7ac2ea8eb..90aa608a6 100644 --- a/libc/nexgen32e/nexgen32e.h +++ b/libc/nexgen32e/nexgen32e.h @@ -3,6 +3,8 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ +extern long kHalfCache3; + void imapxlatab(void *); void insertionsort(int32_t *, size_t); diff --git a/libc/nexgen32e/nexgen32e.mk b/libc/nexgen32e/nexgen32e.mk index 620d53e11..5a9571f73 100644 --- a/libc/nexgen32e/nexgen32e.mk +++ b/libc/nexgen32e/nexgen32e.mk @@ -8,6 +8,7 @@ LIBC_NEXGEN32E = $(LIBC_NEXGEN32E_A_DEPS) $(LIBC_NEXGEN32E_A) LIBC_NEXGEN32E_A = o/$(MODE)/libc/nexgen32e/nexgen32e.a LIBC_NEXGEN32E_A_FILES := $(wildcard libc/nexgen32e/*) LIBC_NEXGEN32E_A_HDRS = $(filter %.h,$(LIBC_NEXGEN32E_A_FILES)) +LIBC_NEXGEN32E_A_INCS = $(filter %.inc,$(LIBC_NEXGEN32E_A_FILES)) LIBC_NEXGEN32E_A_SRCS_A = $(filter %.s,$(LIBC_NEXGEN32E_A_FILES)) LIBC_NEXGEN32E_A_SRCS_S = $(filter %.S,$(LIBC_NEXGEN32E_A_FILES)) LIBC_NEXGEN32E_A_SRCS_C = $(filter %.c,$(LIBC_NEXGEN32E_A_FILES)) @@ -49,6 +50,7 @@ o/$(MODE)/libc/nexgen32e/tinystrncmp.ncabi.o: \ LIBC_NEXGEN32E_LIBS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x))) LIBC_NEXGEN32E_SRCS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_SRCS)) LIBC_NEXGEN32E_HDRS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_HDRS)) +LIBC_NEXGEN32E_INCS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_INCS)) LIBC_NEXGEN32E_CHECKS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_CHECKS)) LIBC_NEXGEN32E_OBJS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_OBJS)) $(LIBC_NEXGEN32E_OBJS): $(BUILD_FILES) libc/nexgen32e/nexgen32e.mk diff --git a/libc/nexgen32e/strsak.S b/libc/nexgen32e/strsak.S index acdf5c9a1..05d030470 100644 --- a/libc/nexgen32e/strsak.S +++ b/libc/nexgen32e/strsak.S @@ -21,71 +21,6 @@ #include "libc/macros.h" .source __FILE__ -/ Returns pointer to first instance of character. -/ -/ @param rdi is a non-null NUL-terminated string pointer -/ @param esi is the search byte -/ @return rax points to character, or to NUL byte if not found -/ @note this won't return NULL if search character is NUL -strchrnul: - .leafprologue - .profilable - or $-1,%r9 - jmp 0f - .endfn strchrnul,globl - -/ Returns pointer to first instance of character, the BSD way. -/ -/ @param rdi is a non-null NUL-terminated string pointer -/ @param esi is the search byte -/ @return rax points to first result, or NULL if not found -/ @note this won't return NULL if search character is NUL -index: nop -/ 𝑠𝑙𝑖𝑑𝑒 - .endfn index,globl - -/ Returns pointer to first instance of character. -/ -/ @param rdi is a non-null NUL-terminated string pointer -/ @param esi is the search byte -/ @return rax points to first result, or NULL if not found -/ @note this won't return NULL if search character is NUL -/ @asyncsignalsafe -strchr: .leafprologue - .profilable - xor %r9d,%r9d -0: movzbl %sil,%edx - or $-1,%rsi - xor %r8,%r8 - jmp strsak - .endfn strchr,globl - -/ Returns pointer to first instance of character in range. -/ -/ @param rdi is a non-null pointer to memory -/ @param esi is the search byte -/ @return rax points to byte if found, or else undefined behavior -rawmemchr: - or $-1,%rdx -/ 𝑠𝑙𝑖𝑑𝑒 - .endfn rawmemchr,globl - -/ Returns pointer to first instance of character in range. -/ -/ @param rdi is a non-null pointer to memory -/ @param esi is the search byte -/ @param rdx is length of memory in bytes -/ @return rax points to byte if found or NULL -/ @asyncsignalsafe -memchr: .leafprologue - .profilable - xchg %rsi,%rdx - mov %dl,%dh - xor %r8,%r8 - xor %r10,%r10 - jmp strsak - .endfn memchr,globl - / Returns length of NUL-terminated string w/ security blankets. / / This is like strnlen() except it'll return 0 if (1) RDI is NULL @@ -102,24 +37,13 @@ strnlen_s: test %rdi,%rdi jnz 0f .leafepilogue - .endfn strnlen_s,globl - -/ Returns length of NUL-terminated memory, with limit. -/ -/ @param rdi is non-null memory -/ @param rsi is the maximum number of bytes to consider -/ @return rax is the number of bytes, excluding the NUL -/ @asyncsignalsafe -strnlen:.leafprologue - .profilable - or $-1,%r10 0: xor %edx,%edx mov %rdi,%r8 / 𝑠𝑙𝑖𝑑𝑒 - .endfn strnlen,globl + .endfn strnlen_s,globl / Swiss army knife of string character scanning. -/ Fourteen fast functions in one. +/ Used to be fourteen fast functions in one. / / @param rdi is non-null string memory / @param rsi is max number of bytes to consider diff --git a/libc/nt/nt.mk b/libc/nt/nt.mk index 8c157b5f8..26918848e 100644 --- a/libc/nt/nt.mk +++ b/libc/nt/nt.mk @@ -5,6 +5,7 @@ PKGS += LIBC_NT LIBC_NT_LIBS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x))) LIBC_NT_HDRS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_HDRS)) +LIBC_NT_INCS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_INCS)) LIBC_NT_SRCS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_SRCS)) LIBC_NT_OBJS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_OBJS)) LIBC_NT_CHECKS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_CHECKS)) @@ -22,9 +23,8 @@ LIBC_NT_A_FILES := \ $(wildcard libc/nt/nt/*.*) \ $(wildcard libc/nt/*) -LIBC_NT_A_HDRS = \ - $(filter %.h,$(LIBC_NT_A_FILES)) - +LIBC_NT_A_HDRS = $(filter %.h,$(LIBC_NT_A_FILES)) +LIBC_NT_A_INCS = $(filter %.inc,$(LIBC_NT_A_FILES)) LIBC_NT_A_CHECKS = $(patsubst %,o/$(MODE)/%.ok,$(filter %.h,$(LIBC_NT_A_HDRS))) #─────────────────────────────────────────────────────────────────────────────── diff --git a/libc/sock/sock.mk b/libc/sock/sock.mk index 98e5b1466..217c2c88a 100644 --- a/libc/sock/sock.mk +++ b/libc/sock/sock.mk @@ -8,6 +8,7 @@ LIBC_SOCK = $(LIBC_SOCK_A_DEPS) $(LIBC_SOCK_A) LIBC_SOCK_A = o/$(MODE)/libc/sock/sock.a LIBC_SOCK_A_FILES := $(wildcard libc/sock/*) LIBC_SOCK_A_HDRS = $(filter %.h,$(LIBC_SOCK_A_FILES)) +LIBC_SOCK_A_INCS = $(filter %.inc,$(LIBC_SOCK_A_FILES)) LIBC_SOCK_A_SRCS = $(filter %.c,$(LIBC_SOCK_A_FILES)) LIBC_SOCK_A_OBJS = \ @@ -31,6 +32,7 @@ LIBC_SOCK_A_DIRECTDEPS = \ LIBC_NT_WS2_32 \ LIBC_RUNTIME \ LIBC_STDIO \ + LIBC_STR \ LIBC_STUBS \ LIBC_SYSV_CALLS \ LIBC_SYSV @@ -49,6 +51,7 @@ $(LIBC_SOCK_A).pkg: \ LIBC_SOCK_LIBS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x))) LIBC_SOCK_SRCS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x)_SRCS)) LIBC_SOCK_HDRS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x)_HDRS)) +LIBC_SOCK_INCS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x)_INCS)) LIBC_SOCK_CHECKS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x)_CHECKS)) LIBC_SOCK_OBJS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x)_OBJS)) $(LIBC_SOCK_OBJS): $(BUILD_FILES) libc/sock/sock.mk diff --git a/libc/stdio/g_stderr.c b/libc/stdio/g_stderr.c index 6db70e02e..6b1de57ad 100644 --- a/libc/stdio/g_stderr.c +++ b/libc/stdio/g_stderr.c @@ -27,7 +27,7 @@ STATIC_YOINK("_init_g_stderr"); FILE *stderr; hidden FILE g_stderr; -hidden unsigned char g_stderr_buf[BUFSIZ] forcealign(PAGESIZE); +hidden unsigned char g_stderr_buf[BUFSIZ]; static textstartup void _init_g_stderr2() { _fflushregister(stderr); diff --git a/libc/stdio/g_stdin.c b/libc/stdio/g_stdin.c index 82a38cb5a..ae5329940 100644 --- a/libc/stdio/g_stdin.c +++ b/libc/stdio/g_stdin.c @@ -27,7 +27,7 @@ STATIC_YOINK("_init_g_stdin"); FILE *stdin; hidden FILE g_stdin; -hidden unsigned char g_stdin_buf[BUFSIZ] forcealign(PAGESIZE); +hidden unsigned char g_stdin_buf[BUFSIZ]; static textstartup void g_stdin_init() { _fflushregister(stdin); diff --git a/libc/stdio/g_stdout.c b/libc/stdio/g_stdout.c index a2d6fc61b..761fd2f42 100644 --- a/libc/stdio/g_stdout.c +++ b/libc/stdio/g_stdout.c @@ -30,7 +30,7 @@ STATIC_YOINK("_init_g_stdout"); FILE *stdout; hidden FILE g_stdout; -hidden unsigned char g_stdout_buf[BUFSIZ] forcealign(PAGESIZE); +hidden unsigned char g_stdout_buf[BUFSIZ]; static textstartup void _init_g_stdout2() { struct FILE *sf; diff --git a/libc/str/tinymemccpy.c b/libc/str/index.c similarity index 81% rename from libc/str/tinymemccpy.c rename to libc/str/index.c index 328cf6a3a..6e1decccf 100644 --- a/libc/str/tinymemccpy.c +++ b/libc/str/index.c @@ -1,7 +1,7 @@ /*-*- 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 2020 Justine Alexandra Roberts Tunney │ +│ 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 │ @@ -18,12 +18,14 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" -void *tinymemccpy(void *dst, const void *src, int termchar, size_t limit) { - size_t i; - unsigned char *d; - const unsigned char *s; - for (termchar &= 0xff, d = dst, s = src, i = 0; i < limit; ++i) { - if ((d[i] = s[i]) == termchar) return d + i + 1; - } - return NULL; +/** + * Returns pointer to first instance of character, the BSD way. + * + * @param s is a NUL-terminated string + * @param is masked with 255 as byte to search for + * @return is pointer to first instance of c or NULL if not found, + * noting that c being NUL will return a pointer to terminator + */ +char *index(const char *s, int c) { + return strchr(s, c); } diff --git a/libc/str/memccpy.c b/libc/str/memccpy.c index 1276d6348..c982372a4 100644 --- a/libc/str/memccpy.c +++ b/libc/str/memccpy.c @@ -18,8 +18,14 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +static noasan uint64_t UncheckedAlignedRead64(unsigned char *p) { + return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; +} + /** - * Copies at most 𝑛 bytes from 𝑠 to 𝑑 until 𝑐 is encountered. + * Copies at most N bytes from SRC to DST until 𝑐 is encountered. * * This is little-known C Standard Library approach, dating back to the * Fourth Edition of System Five, for copying a C strings to fixed-width @@ -39,17 +45,46 @@ * char cstrbuf[16]; * snprintf(cstrbuf, sizeof(cstrbuf), "%s", CSTR); * - * @return 𝑑 + idx(𝑐) + 1, or NULL if 𝑐 ∉ 𝑠₀․․ₙ₋₁ - * @note 𝑑 and 𝑠 can't overlap + * @param c is search character and is masked with 255 + * @return DST + idx(c) + 1, or NULL if 𝑐 ∉ 𝑠₀․․ₙ₋₁ + * @note DST and SRC can't overlap * @asyncsignalsafe */ -void *memccpy(void *d, const void *s, int c, size_t n) { - const char *p, *pe; - p = s; - if ((pe = memchr(p, c, n))) { - return mempcpy(d, s, pe - p + 1); - } else { - memcpy(d, s, n); - return NULL; +void *memccpy(void *dst, const void *src, int c, size_t n) { + size_t i; + uint64_t v, w; + unsigned char *d; + unsigned char *pd; + const unsigned char *s; + i = 0; + d = dst; + s = src; + c &= 255; + v = 0x0101010101010101 * c; + for (; (uintptr_t)(s + i) & 7; ++i) { + if (i == n) return NULL; + if ((d[i] = s[i]) == c) return d + i + 1; } + for (; i + 8 <= n; i += 8) { + w = UncheckedAlignedRead64(s + i); + if (~(w ^ v) & ((w ^ v) - 0x0101010101010101) & 0x8080808080808080) { + break; + } else { + pd = d + i; + pd[0] = (w >> 000) & 255; + pd[1] = (w >> 010) & 255; + pd[2] = (w >> 020) & 255; + pd[3] = (w >> 030) & 255; + pd[4] = (w >> 040) & 255; + pd[5] = (w >> 050) & 255; + pd[6] = (w >> 060) & 255; + pd[7] = (w >> 070) & 255; + } + } + for (; i < n; ++i) { + if ((d[i] = s[i]) == c) { + return d + i + 1; + } + } + return NULL; } diff --git a/libc/str/memchr.c b/libc/str/memchr.c new file mode 100644 index 000000000..1c917fb70 --- /dev/null +++ b/libc/str/memchr.c @@ -0,0 +1,47 @@ +/*-*- 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/str/str.h" + +/** + * Returns pointer to first instance of character. + * + * @param m is memory to search + * @param c is search byte which is masked with 255 + * @param n is byte length of p + * @return is pointer to first instance of c or NULL if not found + * @asyncsignalsafe + */ +void *memchr(const void *m, int c, size_t n) { + uint64_t v, w; + const unsigned char *p, *pe; + c &= 255; + v = 0x0101010101010101 * c; + for (p = (const unsigned char *)m, pe = p + n; p + 8 <= pe; p += 8) { + w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + if ((w = ~(w ^ v) & ((w ^ v) - 0x0101010101010101) & 0x8080808080808080)) { + return p + ((unsigned)__builtin_ctzll(w) >> 3); + } + } + for (; p < pe; ++p) { + if (*p == c) return p; + } + return NULL; +} diff --git a/libc/str/memmove-pure.c b/libc/str/memmove-pure.c new file mode 100644 index 000000000..2f0bbddfc --- /dev/null +++ b/libc/str/memmove-pure.c @@ -0,0 +1,160 @@ +/*-*- 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/str/str.h" + +typedef long long xmm_t __attribute__((__vector_size__(16), __aligned__(1))); + +/** + * Copies memory. + * + * DST and SRC may overlap. + * + * @param dst is destination + * @param src is memory to copy + * @param n is number of bytes to copy + * @return dst + * @asyncsignalsafe + */ +void *memmove$pure(void *dst, const void *src, size_t n) { + size_t i; + xmm_t v, w; + char *d, *r; + const char *s; + uint64_t a, b; + d = dst; + s = src; + switch (n) { + case 9 ... 15: + __builtin_memcpy(&a, s, 8); + __builtin_memcpy(&b, s + n - 8, 8); + __builtin_memcpy(d, &a, 8); + __builtin_memcpy(d + n - 8, &b, 8); + return d; + case 5 ... 7: + __builtin_memcpy(&a, s, 4); + __builtin_memcpy(&b, s + n - 4, 4); + __builtin_memcpy(d, &a, 4); + __builtin_memcpy(d + n - 4, &b, 4); + return d; + case 17 ... 32: + __builtin_memcpy(&v, s, 16); + __builtin_memcpy(&w, s + n - 16, 16); + __builtin_memcpy(d, &v, 16); + __builtin_memcpy(d + n - 16, &w, 16); + return d; + case 16: + __builtin_memcpy(&v, s, 16); + __builtin_memcpy(d, &v, 16); + return d; + case 0: + return d; + case 1: + *d = *s; + return d; + case 8: + __builtin_memcpy(&a, s, 8); + __builtin_memcpy(d, &a, 8); + return d; + case 4: + __builtin_memcpy(&a, s, 4); + __builtin_memcpy(d, &a, 4); + return d; + case 2: + __builtin_memcpy(&a, s, 2); + __builtin_memcpy(d, &a, 2); + return d; + case 3: + __builtin_memcpy(&a, s, 2); + __builtin_memcpy(&b, s + 1, 2); + __builtin_memcpy(d, &a, 2); + __builtin_memcpy(d + 1, &b, 2); + return d; + default: + r = d; + if (d > s) { + do { + n -= 32; + __builtin_memcpy(&v, s + n, 16); + __builtin_memcpy(&w, s + n + 16, 16); + __builtin_memcpy(d + n, &v, 16); + __builtin_memcpy(d + n + 16, &w, 16); + } while (n >= 32); + } else { + i = 0; + do { + __builtin_memcpy(&v, s + i, 16); + __builtin_memcpy(&w, s + i + 16, 16); + __builtin_memcpy(d + i, &v, 16); + __builtin_memcpy(d + i + 16, &w, 16); + } while ((i += 32) + 32 <= n); + d += i; + s += i; + n -= i; + } + switch (n) { + case 0: + return r; + case 17 ... 31: + __builtin_memcpy(&v, s, 16); + __builtin_memcpy(&w, s + n - 16, 16); + __builtin_memcpy(d, &v, 16); + __builtin_memcpy(d + n - 16, &w, 16); + return r; + case 9 ... 15: + __builtin_memcpy(&a, s, 8); + __builtin_memcpy(&b, s + n - 8, 8); + __builtin_memcpy(d, &a, 8); + __builtin_memcpy(d + n - 8, &b, 8); + return r; + case 5 ... 7: + __builtin_memcpy(&a, s, 4); + __builtin_memcpy(&b, s + n - 4, 4); + __builtin_memcpy(d, &a, 4); + __builtin_memcpy(d + n - 4, &b, 4); + return r; + case 16: + __builtin_memcpy(&v, s, 16); + __builtin_memcpy(d, &v, 16); + return r; + case 8: + __builtin_memcpy(&a, s, 8); + __builtin_memcpy(d, &a, 8); + return r; + case 4: + __builtin_memcpy(&a, s, 4); + __builtin_memcpy(d, &a, 4); + return r; + case 1: + *d = *s; + return r; + case 2: + __builtin_memcpy(&a, s, 2); + __builtin_memcpy(d, &a, 2); + return r; + case 3: + __builtin_memcpy(&a, s, 2); + __builtin_memcpy(&b, s + 1, 2); + __builtin_memcpy(d, &a, 2); + __builtin_memcpy(d + 1, &b, 2); + return r; + default: + unreachable; + } + } +} diff --git a/libc/str/memset-pure.c b/libc/str/memset-pure.c new file mode 100644 index 000000000..60a132eb2 --- /dev/null +++ b/libc/str/memset-pure.c @@ -0,0 +1,100 @@ +/*-*- 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/str/str.h" + +/** + * Sets memory. + * + * @param p is memory address + * @param c is masked with 255 and used as repeated byte + * @param n is byte length + * @return p + * @asyncsignalsafe + */ +void *memset$pure(void *p, int c, size_t n) { + char *b; + uint64_t x; + b = p; + x = 0x0101010101010101 * (c & 0xff); + switch (n) { + case 0: + return p; + case 1: + __builtin_memcpy(b, &x, 1); + return p; + case 2: + __builtin_memcpy(b, &x, 2); + return p; + case 3: + __builtin_memcpy(b, &x, 2); + __builtin_memcpy(b + 1, &x, 2); + return p; + case 4: + __builtin_memcpy(b, &x, 4); + return p; + case 5 ... 7: + __builtin_memcpy(b, &x, 4); + __builtin_memcpy(b + n - 4, &x, 4); + return p; + case 8: + __builtin_memcpy(b, &x, 8); + return p; + case 9 ... 16: + __builtin_memcpy(b, &x, 8); + __builtin_memcpy(b + n - 8, &x, 8); + return p; + default: + do { + n -= 16; + __builtin_memcpy(b + n, &x, 8); + asm volatile("" ::: "memory"); + __builtin_memcpy(b + n + 8, &x, 8); + } while (n >= 16); + switch (n) { + case 0: + return p; + case 1: + __builtin_memcpy(b, &x, 1); + return p; + case 2: + __builtin_memcpy(b, &x, 2); + return p; + case 3: + __builtin_memcpy(b, &x, 2); + __builtin_memcpy(b + 1, &x, 2); + return p; + case 4: + __builtin_memcpy(b, &x, 4); + return p; + case 5 ... 7: + __builtin_memcpy(b, &x, 4); + __builtin_memcpy(b + n - 4, &x, 4); + return p; + case 8: + __builtin_memcpy(b, &x, 8); + return p; + case 9 ... 15: + __builtin_memcpy(b, &x, 8); + __builtin_memcpy(b + n - 8, &x, 8); + return p; + default: + unreachable; + } + } +} diff --git a/libc/str/rawmemchr.c b/libc/str/rawmemchr.c new file mode 100644 index 000000000..dab660dc2 --- /dev/null +++ b/libc/str/rawmemchr.c @@ -0,0 +1,53 @@ +/*-*- 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/assert.h" +#include "libc/str/str.h" + +static noasan uint64_t UncheckedAlignedRead64(unsigned char *p) { + return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; +} + +/** + * Returns pointer to first instance of character. + * + * @param m is memory to search + * @param c is search byte which is masked with 255 + * @return is pointer to first instance of c + */ +void *rawmemchr(const void *m, int c) { + uint64_t v, w; + const unsigned char *s; + s = m; + c &= 255; + v = 0x0101010101010101 * c; + for (; (uintptr_t)s & 7; ++s) { + if (*s == c) return s; + } + for (;; s += 8) { + w = UncheckedAlignedRead64(s); + if ((w = ~(w ^ v) & ((w ^ v) - 0x0101010101010101) & 0x8080808080808080)) { + s += (unsigned)__builtin_ctzll(w) >> 3; + break; + } + } + assert(*s == c); + return s; +} diff --git a/libc/str/str.h b/libc/str/str.h index b26931069..740227ec2 100644 --- a/libc/str/str.h +++ b/libc/str/str.h @@ -90,7 +90,6 @@ void *memeqmask(void *, const void *, const void *, size_t) memcpyesque; size_t strlen(const char *) strlenesque; size_t strnlen(const char *, size_t) strlenesque; size_t strnlen_s(const char *, size_t); -size_t strlen$pure(const char *) strlenesque; char *strchr(const char *, int) strlenesque; char *index(const char *, int) strlenesque; void *memchr(const void *, int, size_t) strlenesque; @@ -246,8 +245,8 @@ char *strsignal(int) returnsnonnull libcesque; │ cosmopolitan § strings » optimizations ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -#define __memcpy_isgoodsize(SIZE) \ - (__builtin_constant_p(SIZE) && ((SIZE) <= __BIGGEST_ALIGNMENT__ * 2 && \ +#define __memcpy_isgoodsize(SIZE) \ + (__builtin_constant_p(SIZE) && ((SIZE) <= __BIGGEST_ALIGNMENT__ && \ __builtin_popcountl((unsigned)(SIZE)) == 1)) #define __memset_isgoodsize(SIZE) \ @@ -361,15 +360,44 @@ char *strsignal(int) returnsnonnull libcesque; }) #endif /* hosted/sse2/unbloat */ -#ifdef __FSANITIZE_ADDRESS__ /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § strings » address sanitizer ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ +void *memset$pure(void *, int, size_t) memcpyesque; +void *memmove$pure(void *, const void *, size_t) memcpyesque; +size_t strlen$pure(const char *) strlenesque; +size_t strcspn$pure(const char *, const char *) strlenesque; +#if defined(__FSANITIZE_ADDRESS__) + +#define strcspn(STR, REJECT) strcspn$pure(STR, REJECT) -#ifdef strlen #undef strlen -#endif -#define strlen(s) strlen$pure(s) +#define strlen(STR) \ + (__builtin_constant_p(STR) ? __builtin_strlen(STR) : strlen$pure(STR)) + +#undef memset +#define memset(DST, CHAR, SIZE) \ + (__memcpy_isgoodsize(SIZE) ? __builtin_memset(DST, CHAR, SIZE) \ + : memset$pure(DST, CHAR, SIZE)) + +#undef memmove +#define memmove(DST, SRC, SIZE) \ + (__memcpy_isgoodsize(SIZE) ? __builtin_memmove(DST, SRC, SIZE) \ + : memmove$pure(DST, SRC, SIZE)) + +#undef memcpy +#define memcpy(DST, SRC, SIZE) \ + (__memcpy_isgoodsize(SIZE) ? __builtin_memcpy(DST, SRC, SIZE) \ + : memmove$pure(DST, SRC, SIZE)) + +#undef mempcpy +#define mempcpy(DST, SRC, SIZE) \ + (__memcpy_isgoodsize(SIZE) ? __builtin_mempcpy(DST, SRC, SIZE) : ({ \ + void *DsT = (DST); \ + size_t SiZe = (SIZE); \ + memmove$pure(DsT, SRC, SiZe); \ + (void *)((char *)DsT + SiZe); \ + })) #endif /* __FSANITIZE_ADDRESS__ */ #endif /* __GNUC__ && !__STRICT_ANSI__ */ diff --git a/libc/str/str.mk b/libc/str/str.mk index 6f9927c6a..d634a3a80 100644 --- a/libc/str/str.mk +++ b/libc/str/str.mk @@ -8,6 +8,7 @@ LIBC_STR = $(LIBC_STR_A_DEPS) $(LIBC_STR_A) LIBC_STR_A = o/$(MODE)/libc/str/str.a LIBC_STR_A_FILES := $(wildcard libc/str/*) LIBC_STR_A_HDRS = $(filter %.h,$(LIBC_STR_A_FILES)) +LIBC_STR_A_INCS = $(filter %.inc,$(LIBC_STR_A_FILES)) LIBC_STR_A_SRCS_A = $(filter %.s,$(LIBC_STR_A_FILES)) LIBC_STR_A_SRCS_S = $(filter %.S,$(LIBC_STR_A_FILES)) LIBC_STR_A_SRCS_C = $(filter %.c,$(LIBC_STR_A_FILES)) @@ -49,6 +50,7 @@ o/$(MODE)/libc/str/memmem.o: \ LIBC_STR_LIBS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x))) LIBC_STR_SRCS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_SRCS)) LIBC_STR_HDRS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_HDRS)) +LIBC_STR_INCS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_INCS)) LIBC_STR_BINS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_BINS)) LIBC_STR_CHECKS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_CHECKS)) LIBC_STR_OBJS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_OBJS)) diff --git a/libc/str/strchr.c b/libc/str/strchr.c new file mode 100644 index 000000000..6d7ea516c --- /dev/null +++ b/libc/str/strchr.c @@ -0,0 +1,69 @@ +/*-*- 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/assert.h" +#include "libc/str/str.h" + +noasan static const unsigned char *strchr$x64(const unsigned char *p, + uint64_t c) { + unsigned a, b; + uint64_t w, x, y; + for (c *= 0x0101010101010101;; p += 8) { + w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + if ((x = ~(w ^ c) & ((w ^ c) - 0x0101010101010101) & 0x8080808080808080) | + (y = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) { + if (x) { + a = __builtin_ctzll(x); + if (y) { + b = __builtin_ctzll(y); + if (a <= b) { + return p + (a >> 3); + } else { + return NULL; + } + } else { + return p + (a >> 3); + } + } else { + return NULL; + } + } + } +} + +/** + * Returns pointer to first instance of character. + * + * @param s is a NUL-terminated string + * @param c is masked with 255 as byte to search for + * @return pointer to first instance of c or NULL if not found + * noting that if c is NUL we return pointer to terminator + * @asyncsignalsafe + */ +char *strchr(const char *s, int c) { + char *r; + for (c &= 0xff; (uintptr_t)s & 7; ++s) { + if ((*s & 0xff) == c) return s; + if (!*s) return NULL; + } + r = (char *)strchr$x64((const unsigned char *)s, c); + assert(!r || *r || !c); + return r; +} diff --git a/libc/str/strchrnul.c b/libc/str/strchrnul.c new file mode 100644 index 000000000..8efc95274 --- /dev/null +++ b/libc/str/strchrnul.c @@ -0,0 +1,69 @@ +/*-*- 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/assert.h" +#include "libc/str/str.h" + +noasan static const unsigned char *strchrnul$x64(const unsigned char *p, + uint64_t c) { + unsigned a, b; + uint64_t w, x, y; + for (c *= 0x0101010101010101;; p += 8) { + w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + if ((x = ~(w ^ c) & ((w ^ c) - 0x0101010101010101) & 0x8080808080808080) | + (y = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) { + if (x) { + a = __builtin_ctzll(x); + if (y) { + b = __builtin_ctzll(y); + if (a <= b) { + return p + (a >> 3); + } else { + return p + (b >> 3); + } + } else { + return p + (a >> 3); + } + } else { + b = __builtin_ctzll(y); + return p + (b >> 3); + } + } + } +} + +/** + * Returns pointer to first instance of character. + * + * @param s is a NUL-terminated string + * @param c is masked with 255 as byte to search for + * @return pointer to first instance of c, or pointer to + * NUL terminator if c is not found + */ +char *strchrnul(const char *s, int c) { + char *r; + for (c &= 0xff; (uintptr_t)s & 7; ++s) { + if ((*s & 0xff) == c) return s; + if (!*s) return s; + } + r = (char *)strchrnul$x64((const unsigned char *)s, c); + assert((*r & 0xff) == c || !*r); + return r; +} diff --git a/libc/str/strcmp.c b/libc/str/strcmp.c index cf6760aef..53cc44cf5 100644 --- a/libc/str/strcmp.c +++ b/libc/str/strcmp.c @@ -18,6 +18,12 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +static inline noasan uint64_t UncheckedAlignedRead64(unsigned char *p) { + return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; +} + /** * Compares NUL-terminated strings. * @@ -28,7 +34,25 @@ */ int strcmp(const char *a, const char *b) { size_t i = 0; + uint64_t v, w, d; if (a == b) return 0; - while (a[i] == b[i] && b[i]) ++i; - return (a[i] & 0xff) - (b[i] & 0xff); + if (((uintptr_t)a & 7) == ((uintptr_t)b & 7)) { + for (; (uintptr_t)a & 7; ++i) { + if (a[i] != b[i] || !b[i]) { + return (a[i] & 0xff) - (b[i] & 0xff); + } + } + for (;; i += 8) { + v = UncheckedAlignedRead64(a + i); + w = UncheckedAlignedRead64(b + i); + w = (v ^ w) | (~v & (v - 0x0101010101010101) & 0x8080808080808080); + if (w) { + i += (unsigned)__builtin_ctzll(w) >> 3; + return (a[i] & 0xff) - (b[i] & 0xff); + } + } + } else { + while (a[i] == b[i] && b[i]) ++i; + return (a[i] & 0xff) - (b[i] & 0xff); + } } diff --git a/libc/str/strcspn-pure.c b/libc/str/strcspn-pure.c new file mode 100644 index 000000000..0acecb89a --- /dev/null +++ b/libc/str/strcspn-pure.c @@ -0,0 +1,62 @@ +/*-*- 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 2020 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/intrin/pcmpeqb.h" +#include "libc/intrin/pmovmskb.h" +#include "libc/intrin/pshufd.h" +#include "libc/intrin/punpcklbw.h" +#include "libc/intrin/punpcklwd.h" +#include "libc/nexgen32e/hascharacter.internal.h" +#include "libc/str/str.h" + +#define V(p) (void *)(p) + +/** + * Returns prefix length, consisting of chars not in reject. + * a.k.a. Return index of first byte that's in charset. + * + * @param reject is nul-terminated character set + * @see strspn(), strtok_r() + * @asyncsignalsafe + */ +size_t strcspn$pure(const char *s, const char *reject) { + size_t i, n; + unsigned m; + char cv[16], sv[16]; + if ((n = strlen(reject)) < 16) { + memset(sv, 0, 16); + memcpy(sv, reject, n); + for (i = 0;; ++i) { + cv[0] = s[i]; + punpcklbw(V(cv), V(cv), V(cv)); + punpcklwd(V(cv), V(cv), V(cv)); + pshufd(V(cv), V(cv), 0); + pcmpeqb(V(cv), V(cv), V(sv)); + if ((m = pmovmskb(V(cv)))) { + break; + } + } + return i; + } + for (i = 0; s[i]; ++i) { + if (HasCharacter(s[i], reject)) { + break; + } + } + return i; +} diff --git a/libc/str/strlen-pure.c b/libc/str/strlen-pure.c index cf6d698c2..8c3ba391c 100644 --- a/libc/str/strlen-pure.c +++ b/libc/str/strlen-pure.c @@ -16,35 +16,35 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/str/str.h" -noasan static const char *strlen$pure$x64(const char *p) { +static noasan size_t strlen$pure$x64(const char *s, size_t i) { uint64_t w; + const unsigned char *p; for (;;) { - w = *(uint64_t *)p; - if (~w & (w - 0x0101010101010101) & 0x8080808080808080) { - break; + p = (const unsigned char *)s + i; + w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + if ((w = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) { + return i + ((unsigned)__builtin_ctzll(w) >> 3); } else { - p += 8; + i += 8; } } - return p; } /** * Returns length of NUL-terminated string. */ size_t strlen$pure(const char *s) { - const char *p; - p = s; - while ((uintptr_t)p & 7) { - if (*p) { - ++p; - } else { - return p - s; - } + size_t i; + for (i = 0; (uintptr_t)(s + i) & 7; ++i) { + if (!s[i]) return i; } - p = strlen$pure$x64(p); - while (*p) ++p; - return p - s; + i = strlen$pure$x64(s, i); + assert(!i || s[0]); + assert(!s[i]); + return i; } diff --git a/libc/str/strnlen.c b/libc/str/strnlen.c new file mode 100644 index 000000000..8fa348e62 --- /dev/null +++ b/libc/str/strnlen.c @@ -0,0 +1,57 @@ +/*-*- 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/assert.h" +#include "libc/str/str.h" + +static noasan size_t strnlen$x64(const char *s, size_t n, size_t i) { + uint64_t w; + const unsigned char *p; + for (; i + 8 < n; i += 8) { + p = (const unsigned char *)s + i; + w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + if ((w = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) { + i += (unsigned)__builtin_ctzll(w) >> 3; + break; + } + } + return i; +} + +/** + * Returns length of NUL-terminated string w/ limit. + * + * @param s is string + * @param n is max length + * @return byte length + * @asyncsignalsafe + */ +size_t strnlen(const char *s, size_t n) { + size_t i; + for (i = 0; (uintptr_t)(s + i) & 7; ++i) { + if (i == n || !s[i]) return i; + } + i = strnlen$x64(s, n, i); + for (;; ++i) { + if (i == n || !s[i]) break; + } + assert(i == n || (i < n && !s[i])); + return i; +} diff --git a/libc/sysv/sysv.mk b/libc/sysv/sysv.mk index 72ac457fe..189fd55d1 100644 --- a/libc/sysv/sysv.mk +++ b/libc/sysv/sysv.mk @@ -5,6 +5,7 @@ PKGS += LIBC_SYSV LIBC_SYSV_LIBS = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_A)) LIBC_SYSV_ARCHIVES = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_A)) LIBC_SYSV_HDRS = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_HDRS)) +LIBC_SYSV_INCS = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_INCS)) LIBC_SYSV_BINS = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_BINS)) LIBC_SYSV_CHECKS = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_CHECKS)) LIBC_SYSV_OBJS = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_OBJS)) @@ -20,6 +21,7 @@ LIBC_SYSV = \ LIBC_SYSV_ARTIFACTS += LIBC_SYSV_A LIBC_SYSV_A = o/$(MODE)/libc/sysv/sysv.a LIBC_SYSV_A_HDRS = $(filter %.h,$(LIBC_SYSV_A_FILES)) +LIBC_SYSV_A_INCS = $(filter %.inc,$(LIBC_SYSV_A_FILES)) LIBC_SYSV_A_SRCS_A = $(filter %.s,$(LIBC_SYSV_A_FILES)) LIBC_SYSV_A_SRCS_S = $(filter %.S,$(LIBC_SYSV_A_FILES)) LIBC_SYSV_A_CHECKS = $(LIBC_SYSV_A).pkg diff --git a/libc/testlib/ezbenchreport.c b/libc/testlib/ezbenchreport.c index 704933ffa..1f27b9acd 100644 --- a/libc/testlib/ezbenchreport.c +++ b/libc/testlib/ezbenchreport.c @@ -27,8 +27,8 @@ STATIC_YOINK("strnwidth"); void __testlib_ezbenchreport(const char *form, uint64_t c1, uint64_t c2) { uint64_t ns1, ns2; - ns1 = rintl(converttickstonanos(c1)); - ns2 = rintl(converttickstonanos(c2)); + ns1 = rintl(ConvertTicksToNanos(c1)); + ns2 = rintl(ConvertTicksToNanos(c2)); (fprintf)(stderr, VEIL("r", "%-30s l: %,10lu𝑐 %,10lu𝑛𝑠 m: %,10lu𝑐 %,10lu𝑛𝑠\n"), form, c1, ns1, c2, ns2); diff --git a/libc/time/time.h b/libc/time/time.h index a33985d3e..f56b98cb4 100644 --- a/libc/time/time.h +++ b/libc/time/time.h @@ -60,8 +60,7 @@ int futimesat(int, const char *, const struct timeval[2]); long double dtime(int); long double dsleep(long double); extern long double (*nowl)(void); -long double converttickstonanos(uint64_t); -long double converttickstoseconds(uint64_t); +long double ConvertTicksToNanos(uint64_t); double difftime(int64_t, int64_t) nothrow pureconst; diff --git a/test/dsp/scale/scale_test.c b/test/dsp/scale/scale_test.c index f6f89315a..0ba91e37d 100644 --- a/test/dsp/scale/scale_test.c +++ b/test/dsp/scale/scale_test.c @@ -80,11 +80,12 @@ prpppppppppppppoooooooonnnnnnnnnnnnnnnooooooooppppppppppppptp\ pppppppppppppppppppoooooooooooooooooooooooppppppppppppppppppp"; TEST(gyarados, testIdentityDifference) { - static unsigned char A[1][32][62]; - static unsigned char B[1][32][62]; + static unsigned char A[1][32][61]; + static unsigned char B[1][32][61]; + ASSERT_EQ(sizeof(A), strlen(kDieWelle)); memcpy(A, kDieWelle, sizeof(A)); EzGyarados(1, 32, 61, B, 1, 32, 61, A, 0, 1, 32, 61, 32, 61, 1, 1, 0, 0); - AbsoluteDifference(32, 62, B[0], 32, 62, B[0], 32, 62, A[0]); + AbsoluteDifference(32, 61, B[0], 32, 61, B[0], 32, 61, A[0]); EXPECT_STREQ(u"\n\                                                              \n\                                                              \n\ diff --git a/test/libc/crypto/test.mk b/test/libc/crypto/test.mk index 3b2ec1427..5b7d429bc 100644 --- a/test/libc/crypto/test.mk +++ b/test/libc/crypto/test.mk @@ -26,6 +26,7 @@ TEST_LIBC_CRYPTO_DIRECTDEPS = \ LIBC_INTRIN \ LIBC_NEXGEN32E \ LIBC_RUNTIME \ + LIBC_STR \ LIBC_STUBS \ LIBC_TESTLIB diff --git a/test/libc/mem/test.mk b/test/libc/mem/test.mk index 0ddfb6ac3..dd1120293 100644 --- a/test/libc/mem/test.mk +++ b/test/libc/mem/test.mk @@ -30,6 +30,7 @@ TEST_LIBC_MEM_DIRECTDEPS = \ LIBC_RAND \ LIBC_RUNTIME \ LIBC_STDIO \ + LIBC_STR \ LIBC_STUBS \ LIBC_SYSV \ LIBC_TESTLIB diff --git a/test/libc/nexgen32e/memmove_test.c b/test/libc/nexgen32e/memmove_test.c index 460b9e6f9..d69ceb422 100644 --- a/test/libc/nexgen32e/memmove_test.c +++ b/test/libc/nexgen32e/memmove_test.c @@ -17,77 +17,117 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" -#include "libc/bits/safemacros.h" +#include "libc/macros.h" #include "libc/mem/mem.h" +#include "libc/rand/rand.h" #include "libc/str/str.h" #include "libc/testlib/testlib.h" -#define N 256 -#define S 7 +#define N 65 +#define S 1 long i, j, n; -char *b1, *b2; +char *b0, *b1, *b2; + +noinline char *PosixMemmove(char *dst, const char *src, size_t n) { + char *tmp; + tmp = malloc(n); + memcpy(tmp, src, n); + memcpy(dst, tmp, n); + free(tmp); + return dst; +} TEST(memmove, overlapping) { for (i = 0; i < N; i += S) { - for (j = 10; j < N; j += S) { - b1 = malloc(N); - b2 = malloc(N); - n = min(N - i, N - j); - memcpy(b2, b1 + i, n); - ASSERT_EQ(b1 + j, memmove(b1 + j, b1 + i, n)); - ASSERT_EQ(0, memcmp(b1 + j, b2, n)); - free(b2); - free(b1); + for (j = 0; j < N; j += S) { + for (n = MIN(N - i, N - j) + 1; n--;) { + b0 = rngset(malloc(N), N, rand64, -1); + b1 = memcpy(malloc(N), b0, N); + b2 = memcpy(malloc(N), b0, N); + ASSERT_EQ(b1 + j, memmove(b1 + j, b1 + i, n)); + ASSERT_EQ(b2 + j, PosixMemmove(b2 + j, b2 + i, n)); + ASSERT_EQ(0, memcmp(b1, b2, N), + "j=%ld i=%ld n=%ld\n" + "\t%#.*s data\n" + "\t%#.*s memmove\n" + "\t%#.*s posix", + j, i, n, n, b0, n, b1, n, b2); + free(b2); + free(b1); + free(b0); + } + } + } +} + +TEST(memmove$pure, overlapping) { + for (i = 0; i < N; i += S) { + for (j = 0; j < N; j += S) { + for (n = MIN(N - i, N - j) + 1; n--;) { + b0 = rngset(malloc(N), N, rand64, -1); + b1 = memcpy(malloc(N), b0, N); + b2 = memcpy(malloc(N), b0, N); + ASSERT_EQ(b1 + j, memmove$pure(b1 + j, b1 + i, n)); + ASSERT_EQ(b2 + j, PosixMemmove(b2 + j, b2 + i, n)); + ASSERT_EQ(0, memcmp(b1, b2, N), + "j=%ld i=%ld n=%ld\n" + "\t%#.*s data\n" + "\t%#.*s memmove\n" + "\t%#.*s posix", + j, i, n, n, b0, n, b1, n, b2); + free(b2); + free(b1); + free(b0); + } + } + } +} + +TEST(memcpy, overlapping) { + for (i = 0; i < N; i += S) { + for (j = 0; j < N; j += S) { + for (n = MIN(N - i, N - j) + 1; n--;) { + if (j <= i) { + b0 = rngset(malloc(N), N, rand64, -1); + b1 = memcpy(malloc(N), b0, N); + b2 = memcpy(malloc(N), b0, N); + ASSERT_EQ(b1 + j, memcpy(b1 + j, b1 + i, n)); + ASSERT_EQ(b2 + j, PosixMemmove(b2 + j, b2 + i, n)); + ASSERT_EQ(0, memcmp(b1, b2, N), + "j=%ld i=%ld n=%ld\n" + "\t%#.*s data\n" + "\t%#.*s memmove\n" + "\t%#.*s posix", + j, i, n, n, b0, n, b1, n, b2); + free(b2); + free(b1); + free(b0); + } + } } } } TEST(memmove, overlappingDirect) { for (i = 0; i < N; i += S) { - for (j = 10; j < N; j += S) { - b1 = malloc(N); - b2 = malloc(N); - n = min(N - i, N - j); - memcpy(b2, b1 + i, n); - ASSERT_EQ(b1 + j, (memmove)(b1 + j, b1 + i, n)); - ASSERT_EQ(0, memcmp(b1 + j, b2, n)); - free(b2); - free(b1); + for (j = 0; j < N; j += S) { + for (n = MIN(N - i, N - j) + 1; n--;) { + b0 = rngset(malloc(N), N, rand64, -1); + b1 = memcpy(malloc(N), b0, N); + b2 = memcpy(malloc(N), b0, N); + ASSERT_EQ(b1 + j, (memmove)(b1 + j, b1 + i, n)); + ASSERT_EQ(b2 + j, PosixMemmove(b2 + j, b2 + i, n)); + ASSERT_EQ(0, memcmp(b1, b2, N), + "j=%ld i=%ld n=%ld\n" + "\t%#.*s data\n" + "\t%#.*s memmove\n" + "\t%#.*s posix", + j, i, n, n, b0, n, b1, n, b2); + free(b2); + free(b1); + free(b0); + } } } } - -char *MoveMemory(char *dst, const char *src, size_t n) { - size_t i; - for (i = 0; i < n; ++i) { - dst[i] = src[i]; - } - return dst; -} - -TEST(memmove, overlappingBackwards_isGenerallySafe) { - char buf[32]; - strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); - ASSERT_STREQ("cdefghijklmnopqrstuvwxyzyz", MoveMemory(buf, buf + 2, 24)); - strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); - ASSERT_STREQ("cdefghijklmnopqrstuvwxyzyz", memmove(buf, buf + 2, 24)); - strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); - ASSERT_STREQ("cdefghijklmnopqrstuvwxyzyz", memcpy(buf, buf + 2, 24)); -} - -TEST(memmove, overlappingForwards_avoidsRunLengthDecodeBehavior) { - volatile char buf[32]; - strcpy(buf, "abc"); - MoveMemory(buf + 1, buf, 2); - ASSERT_STREQ("aaa", buf); - strcpy(buf, "abc"); - (memmove)(buf + 1, buf, 2); - ASSERT_STREQ("aab", buf); - strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); - MoveMemory(buf + 2, buf, 24); - ASSERT_STREQ("ababababababababababababab", buf); - strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); - memmove(buf + 2, buf, 24); - ASSERT_STREQ("ababcdefghijklmnopqrstuvwx", buf); -} diff --git a/test/libc/sock/test.mk b/test/libc/sock/test.mk index aa47dc97a..961a53c4a 100644 --- a/test/libc/sock/test.mk +++ b/test/libc/sock/test.mk @@ -31,6 +31,7 @@ TEST_LIBC_SOCK_DIRECTDEPS = \ LIBC_RUNTIME \ LIBC_SOCK \ LIBC_STDIO \ + LIBC_STR \ LIBC_STUBS \ LIBC_SYSV \ LIBC_TESTLIB \ diff --git a/test/libc/str/memccpy_test.c b/test/libc/str/memccpy_test.c index 3051bffea..fc6cc6357 100644 --- a/test/libc/str/memccpy_test.c +++ b/test/libc/str/memccpy_test.c @@ -23,7 +23,15 @@ #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" -void *memccpy2(void *, const void *, int, size_t); +void *memccpy$pure(void *d, const void *s, int c, size_t n) { + size_t i; + unsigned char *x; + const unsigned char *y; + for (c &= 0xff, x = d, y = s, i = 0; i < n; ++i) { + if ((x[i] = y[i]) == c) return x + i + 1; + } + return NULL; +} TEST(memccpy, testStringCopy) { char buf[16]; @@ -49,7 +57,7 @@ TEST(memccpy, memcpy) { b2 = calloc(1, n); b3 = calloc(1, n); rngset(b1, n, rand64, -1); - e1 = tinymemccpy(b2, b1, 31337, n); + e1 = memccpy$pure(b2, b1, 31337, n); e2 = memccpy(b3, b1, 31337, n); n1 = e1 ? e1 - b2 : n; n2 = e2 ? e2 - b3 : n; diff --git a/test/libc/str/memcpy_test.c b/test/libc/str/memcpy_test.c index 2181c428a..ec1be0696 100644 --- a/test/libc/str/memcpy_test.c +++ b/test/libc/str/memcpy_test.c @@ -18,38 +18,54 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" #include "libc/mem/mem.h" +#include "libc/nexgen32e/nexgen32e.h" +#include "libc/rand/rand.h" +#include "libc/stdio/stdio.h" #include "libc/str/str.h" +#include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" -TEST(memcpy, memcpy) { +TEST(memcpy, test) { char *b1, *b2; for (unsigned n = 0; n < 1026; ++n) { b1 = malloc(n); b2 = malloc(n); - ASSERT_EQ(b1, memcpy(b1, b2, n)); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); + ASSERT_EQ(b1, memcpy(b1, b2, n), "%ld\n\t%#.*s\n\t%#.*s", n, n, b1, n, b2); + ASSERT_EQ(0, memcmp(b1, b2, n)); + free(b2); + free(b1); + } + for (unsigned n = kHalfCache3 - 1; n < kHalfCache3 + 2; ++n) { + b1 = malloc(n); + b2 = malloc(n); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); + ASSERT_EQ(b1, memcpy(b1, b2, n), "%ld\n\t%#.*s\n\t%#.*s", n, n, b1, n, b2); ASSERT_EQ(0, memcmp(b1, b2, n)); free(b2); free(b1); } } -TEST(memcpy, memcpyDirect) { +TEST(mempcpy, test) { char *b1, *b2; for (unsigned n = 0; n < 1026; ++n) { b1 = malloc(n); b2 = malloc(n); - ASSERT_EQ(b1, (memcpy)(b1, b2, n)); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); + ASSERT_EQ(b1 + n, mempcpy(b1, b2, n)); ASSERT_EQ(0, memcmp(b1, b2, n)); free(b2); free(b1); } -} - -TEST(memcpy, mempcpy) { - char *b1, *b2; - for (unsigned n = 0; n < 1026; ++n) { + for (unsigned n = kHalfCache3 - 1; n < kHalfCache3 + 2; ++n) { b1 = malloc(n); b2 = malloc(n); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); ASSERT_EQ(b1 + n, mempcpy(b1, b2, n)); ASSERT_EQ(0, memcmp(b1, b2, n)); free(b2); @@ -57,11 +73,49 @@ TEST(memcpy, mempcpy) { } } -TEST(memcpy, mempcpyDirect) { +TEST(memcpy, direct) { char *b1, *b2; for (unsigned n = 0; n < 1026; ++n) { b1 = malloc(n); b2 = malloc(n); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); + ASSERT_EQ(b1, (memcpy)(b1, b2, n), "%ld\n\t%#.*s\n\t%#.*s", n, n, b1, n, + b2); + ASSERT_EQ(0, memcmp(b1, b2, n)); + free(b2); + free(b1); + } + for (unsigned n = kHalfCache3 - 1; n < kHalfCache3 + 2; ++n) { + b1 = malloc(n); + b2 = malloc(n); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); + ASSERT_EQ(b1, (memcpy)(b1, b2, n), "%ld\n\t%#.*s\n\t%#.*s", n, n, b1, n, + b2); + ASSERT_EQ(0, memcmp(b1, b2, n)); + free(b2); + free(b1); + } +} + +TEST(mempcpy, direct) { + char *b1, *b2; + for (unsigned n = 0; n < 1026; ++n) { + b1 = malloc(n); + b2 = malloc(n); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); + ASSERT_EQ(b1 + n, (mempcpy)(b1, b2, n)); + ASSERT_EQ(0, memcmp(b1, b2, n)); + free(b2); + free(b1); + } + for (unsigned n = kHalfCache3 - 1; n < kHalfCache3 + 2; ++n) { + b1 = malloc(n); + b2 = malloc(n); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); ASSERT_EQ(b1 + n, (mempcpy)(b1, b2, n)); ASSERT_EQ(0, memcmp(b1, b2, n)); free(b2); @@ -105,3 +159,44 @@ TEST(memcpy, testBackwardsOverlap3) { EXPECT_EQ('C', c[1]); free(c); } + +void *MemCpy(void *, const void *, size_t); + +#define B(F, N) \ + do { \ + char *d = rngset(malloc(N), N, rand64, -1); \ + char *s = rngset(malloc(N), N, rand64, -1); \ + EZBENCH2(#F " " #N, donothing, \ + EXPROPRIATE(F(VEIL("r", d), VEIL("r", s), N))); \ + free(d); \ + free(s); \ + } while (0) + +#define BB(N) \ + do { \ + B(memmove$pure, N); \ + B(memcpy, N); \ + B(MemCpy, N); \ + fprintf(stderr, "\n"); \ + } while (0) + +BENCH(memcpy, bench) { + BB(0); + BB(1); + BB(2); + BB(3); + BB(7); + BB(8); + BB(15); + BB(16); + BB(31); + BB(32); + BB(63); + BB(64); + BB(255); + BB(256); + BB(1023); + BB(1024); + BB(PAGESIZE); + BB(FRAMESIZE); +} diff --git a/test/libc/str/strchr_test.c b/test/libc/str/strchr_test.c index 7b34a8100..bdb1c6215 100644 --- a/test/libc/str/strchr_test.c +++ b/test/libc/str/strchr_test.c @@ -17,7 +17,10 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +#include "libc/mem/mem.h" +#include "libc/rand/rand.h" #include "libc/str/str.h" +#include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" TEST(strchr, blank) { @@ -66,3 +69,99 @@ TEST(strchrnul, notFound_returnsPointerToNulByte) { EXPECT_STREQ("", strchrnul(buf, 'z')); EXPECT_EQ(&buf[2], strchrnul(buf, 'z')); } + +char *strchr$pure(const char *s, int c) { + char *r; + for (c &= 0xff;; ++s) { + if ((*s & 0xff) == c) return (char *)s; + if (!*s) return NULL; + } +} + +TEST(strchr, fuzz) { + char *p; + int i, j; + p = calloc(1, 64); + for (i = -2; i < 257; ++i) { + for (j = 0; j < 17; ++j) { + rngset(p, 63, rand64, -1); + ASSERT_EQ(strchr(p + j, i), strchr$pure(p + j, i)); + } + } + free(p); +} + +BENCH(strchr, bench) { + EZBENCH2("strchr 0", donothing, EXPROPRIATE(strchr(VEIL("r", ""), 0))); + EZBENCH2("strchr 5", donothing, EXPROPRIATE(strchr(VEIL("r", "hello"), 'o'))); + EZBENCH2("strchr 8", donothing, + EXPROPRIATE(strchr(VEIL("r", "hellzzzo"), 'o'))); + EZBENCH2("strchr 17", donothing, + EXPROPRIATE(strchr(VEIL("r", "hellzzzhellzzzeeo"), 'o'))); + EZBENCH2("strchr 34", donothing, + EXPROPRIATE( + strchr(VEIL("r", "hellzzzhellzzzeeAhellzzzhellzzzeeo"), 'o'))); +} + +char *memchr$pure(const char *m, int c, size_t n) { + const unsigned char *p, *pe; + for (c &= 0xff, p = (const unsigned char *)m, pe = p + n; p < pe; ++p) { + if (*p == c) return p; + } + return NULL; +} + +TEST(memchr, fuzz) { + char *p; + int i, j; + p = malloc(64); + for (i = -2; i < 257; ++i) { + for (j = 0; j < 17; ++j) { + rngset(p, 64, rand64, -1); + ASSERT_EQ(memchr(p + j, i, 64 - j), memchr$pure(p + j, i, 64 - j)); + } + } + free(p); +} + +char *strchrnul$pure(const char *s, int c) { + char *r; + for (c &= 0xff;; ++s) { + if ((*s & 0xff) == c) return (char *)s; + if (!*s) return s; + } +} + +TEST(strchrnul, fuzz) { + char *p; + int i, j; + p = calloc(1, 64); + for (i = -2; i < 257; ++i) { + for (j = 0; j < 17; ++j) { + rngset(p, 63, rand64, -1); + ASSERT_EQ(strchrnul(p + j, i), strchrnul$pure(p + j, i)); + } + } + free(p); +} + +void *rawmemchr$pure(const void *m, int c) { + const unsigned char *s; + for (c &= 255, s = m;; ++s) { + if (*s == c) return s; + } +} + +TEST(rawmemchr, fuzz) { + char *p; + int i, j; + p = malloc(64); + for (i = -2; i < 257; ++i) { + for (j = 0; j < 17; ++j) { + rngset(p, 63, rand64, -1); + p[63] = i; + ASSERT_EQ(rawmemchr(p + j, i), rawmemchr$pure(p + j, i)); + } + } + free(p); +} diff --git a/test/libc/str/strlen_test.c b/test/libc/str/strlen_test.c index b874bd6ed..8c1cb1078 100644 --- a/test/libc/str/strlen_test.c +++ b/test/libc/str/strlen_test.c @@ -19,8 +19,10 @@ #include "libc/bits/bits.h" #include "libc/macros.h" #include "libc/mem/mem.h" +#include "libc/nexgen32e/bsr.h" #include "libc/nexgen32e/tinystrlen.internal.h" #include "libc/rand/rand.h" +#include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" @@ -30,6 +32,8 @@ char16_t u16[] = u"utf16 ☻"; wchar_t u32[] = L"utf32 ☻"; TEST(strlen, usageExample_c11) { + _Alignas(16) char ugh[] = "eeeeeeeeeeeeeee\017"; + EXPECT_EQ(1, strlen$pure(ugh + 15)); EXPECT_EQ(6 + 3, strlen(u8)); EXPECT_EQ(7, strlen16(u16)); EXPECT_EQ(7, wcslen(u32)); @@ -143,7 +147,7 @@ TEST(strlen, fuzz) { b = rngset(calloc(1, n), n - 1, rand64, -1); n1 = strlen(b); n2 = strlen$pure(b); - ASSERT_EQ(n1, n2); + ASSERT_EQ(n1, n2, "%#.*s", n, b); n1 = strlen(b + 1); n2 = strlen$pure(b + 1); ASSERT_EQ(n1, n2); @@ -166,8 +170,14 @@ BENCH(strlen, bench) { EZBENCH2("strlen$pure 8", donothing, strlen$pure_("1234567")); EZBENCH2("strlen 9", donothing, strlen_("12345678")); EZBENCH2("strlen$pure 9", donothing, strlen$pure_("12345678")); + EZBENCH2("strlen 11", donothing, strlen_("12345678aa")); + EZBENCH2("strlen$pure 11", donothing, strlen$pure_("12345678aa")); + EZBENCH2("strlen 13", donothing, strlen_("12345678aabb")); + EZBENCH2("strlen$pure 13", donothing, strlen$pure_("12345678aabb")); EZBENCH2("strlen 16", donothing, strlen_("123456781234567")); EZBENCH2("strlen$pure 16", donothing, strlen$pure_("123456781234567")); + EZBENCH2("strlen 17", donothing, strlen_("123456781234567e")); + EZBENCH2("strlen$pure 17", donothing, strlen$pure_("123456781234567e")); EZBENCH2("strlen 1023", donothing, strlen_(b)); EZBENCH2("strlen$pure 1023", donothing, strlen$pure_(b)); } diff --git a/test/libc/tinymath/test.mk b/test/libc/tinymath/test.mk index fbe434b1a..e02150f8d 100644 --- a/test/libc/tinymath/test.mk +++ b/test/libc/tinymath/test.mk @@ -28,6 +28,7 @@ TEST_LIBC_TINYMATH_DIRECTDEPS = \ LIBC_MEM \ LIBC_NEXGEN32E \ LIBC_RUNTIME \ + LIBC_STR \ LIBC_STUBS \ LIBC_TESTLIB \ LIBC_TINYMATH \ diff --git a/third_party/compiler_rt/compiler_rt.mk b/third_party/compiler_rt/compiler_rt.mk index e888d5742..575d5e9d7 100644 --- a/third_party/compiler_rt/compiler_rt.mk +++ b/third_party/compiler_rt/compiler_rt.mk @@ -10,6 +10,7 @@ THIRD_PARTY_COMPILER_RT_A_FILES := \ $(wildcard third_party/compiler_rt/*) \ $(wildcard third_party/compiler_rt/nexgen32e/*) THIRD_PARTY_COMPILER_RT_A_HDRS = $(filter %.h,$(THIRD_PARTY_COMPILER_RT_A_FILES)) +THIRD_PARTY_COMPILER_RT_A_INCS = $(filter %.inc,$(THIRD_PARTY_COMPILER_RT_A_FILES)) THIRD_PARTY_COMPILER_RT_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_COMPILER_RT_A_FILES)) THIRD_PARTY_COMPILER_RT_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_COMPILER_RT_A_FILES)) @@ -51,6 +52,7 @@ $(THIRD_PARTY_COMPILER_RT_A_OBJS): \ THIRD_PARTY_COMPILER_RT_LIBS = $(foreach x,$(THIRD_PARTY_COMPILER_RT_ARTIFACTS),$($(x))) THIRD_PARTY_COMPILER_RT_SRCS = $(foreach x,$(THIRD_PARTY_COMPILER_RT_ARTIFACTS),$($(x)_SRCS)) THIRD_PARTY_COMPILER_RT_HDRS = $(foreach x,$(THIRD_PARTY_COMPILER_RT_ARTIFACTS),$($(x)_HDRS)) +THIRD_PARTY_COMPILER_RT_INCS = $(foreach x,$(THIRD_PARTY_COMPILER_RT_ARTIFACTS),$($(x)_INCS)) THIRD_PARTY_COMPILER_RT_CHECKS = $(foreach x,$(THIRD_PARTY_COMPILER_RT_ARTIFACTS),$($(x)_CHECKS)) THIRD_PARTY_COMPILER_RT_OBJS = $(foreach x,$(THIRD_PARTY_COMPILER_RT_ARTIFACTS),$($(x)_OBJS)) diff --git a/third_party/duktape/duktape.mk b/third_party/duktape/duktape.mk index 49f800c19..81ae7f206 100644 --- a/third_party/duktape/duktape.mk +++ b/third_party/duktape/duktape.mk @@ -8,6 +8,7 @@ THIRD_PARTY_DUKTAPE = $(THIRD_PARTY_DUKTAPE_A_DEPS) $(THIRD_PARTY_DUKTAPE_A) THIRD_PARTY_DUKTAPE_A = o/$(MODE)/third_party/duktape/duktape.a THIRD_PARTY_DUKTAPE_A_FILES := $(wildcard third_party/duktape/*) THIRD_PARTY_DUKTAPE_A_HDRS = $(filter %.h,$(THIRD_PARTY_DUKTAPE_A_FILES)) +THIRD_PARTY_DUKTAPE_A_INCS = $(filter %.inc,$(THIRD_PARTY_DUKTAPE_A_FILES)) THIRD_PARTY_DUKTAPE_A_SRCS_A = $(filter %.s,$(THIRD_PARTY_DUKTAPE_A_FILES)) THIRD_PARTY_DUKTAPE_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_DUKTAPE_A_FILES)) THIRD_PARTY_DUKTAPE_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_DUKTAPE_A_FILES)) @@ -60,6 +61,7 @@ o/dbg/third_party/duktape/duk_js_executor.o: \ THIRD_PARTY_DUKTAPE_LIBS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x))) THIRD_PARTY_DUKTAPE_SRCS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x)_SRCS)) THIRD_PARTY_DUKTAPE_HDRS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x)_HDRS)) +THIRD_PARTY_DUKTAPE_INCS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x)_INCS)) THIRD_PARTY_DUKTAPE_BINS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x)_BINS)) THIRD_PARTY_DUKTAPE_CHECKS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x)_CHECKS)) THIRD_PARTY_DUKTAPE_OBJS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x)_OBJS)) diff --git a/third_party/gdtoa/gdtoa.mk b/third_party/gdtoa/gdtoa.mk index deff0ad14..ef587ed15 100644 --- a/third_party/gdtoa/gdtoa.mk +++ b/third_party/gdtoa/gdtoa.mk @@ -8,6 +8,7 @@ THIRD_PARTY_GDTOA = $(THIRD_PARTY_GDTOA_A_DEPS) $(THIRD_PARTY_GDTOA_A) THIRD_PARTY_GDTOA_A = o/$(MODE)/third_party/gdtoa/gdtoa.a THIRD_PARTY_GDTOA_A_FILES := $(wildcard third_party/gdtoa/*) THIRD_PARTY_GDTOA_A_HDRS = $(filter %.h,$(THIRD_PARTY_GDTOA_A_FILES)) +THIRD_PARTY_GDTOA_A_INCS = $(filter %.inc,$(THIRD_PARTY_GDTOA_A_FILES)) THIRD_PARTY_GDTOA_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_GDTOA_A_FILES)) THIRD_PARTY_GDTOA_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_GDTOA_A_FILES)) @@ -54,6 +55,7 @@ $(THIRD_PARTY_GDTOA_A_OBJS): \ THIRD_PARTY_GDTOA_LIBS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x))) THIRD_PARTY_GDTOA_SRCS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_SRCS)) THIRD_PARTY_GDTOA_HDRS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_HDRS)) +THIRD_PARTY_GDTOA_INCS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_INCS)) THIRD_PARTY_GDTOA_CHECKS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_CHECKS)) THIRD_PARTY_GDTOA_OBJS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_OBJS)) $(THIRD_PARTY_GDTOA_OBJS): $(BUILD_FILES) third_party/gdtoa/gdtoa.mk diff --git a/third_party/lemon/lemon.mk b/third_party/lemon/lemon.mk index c055b2ada..3de296d05 100644 --- a/third_party/lemon/lemon.mk +++ b/third_party/lemon/lemon.mk @@ -1,6 +1,12 @@ #-*-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 += THIRD_PARTY_LEMON +THIRD_PARTY_LEMON_FILES := $(wildcard third_party/lemon/*) +THIRD_PARTY_LEMON_HDRS = $(filter %.h,$(THIRD_PARTY_LEMON_FILES)) +THIRD_PARTY_LEMON_INCS = $(filter %.inc,$(THIRD_PARTY_LEMON_FILES)) +THIRD_PARTY_LEMON_SRCS = $(filter %.c,$(THIRD_PARTY_LEMON_FILES)) + LEMON = $(MKDIR) $(@D) && ACTION="LEMON $@" build/do $(THIRD_PARTY_LEMON) THIRD_PARTY_LEMON = o/$(MODE)/third_party/lemon/lemon.com.dbg diff --git a/third_party/lz4cli/bench.c b/third_party/lz4cli/bench.c index 9906cbb3e..a924bf9bb 100644 --- a/third_party/lz4cli/bench.c +++ b/third_party/lz4cli/bench.c @@ -36,8 +36,8 @@ /* ************************************* * Includes ***************************************/ -#include "platform.h" /* Compiler options */ -#include "util.h" /* UTIL_GetFileSize, UTIL_sleep */ +#include "third_party/lz4cli/platform.h" /* Compiler options */ +#include "third_party/lz4cli/util.h" /* UTIL_GetFileSize, UTIL_sleep */ #include "libc/mem/mem.h" /* malloc, free */ #include "libc/str/str.h" /* memset */ #include "libc/stdio/stdio.h" /* fprintf, fopen, ftello */ @@ -46,17 +46,17 @@ #include "libc/bits/initializer.internal.h" #include "libc/runtime/runtime.h" /* assert */ -#include "datagen.h" /* RDG_genBuffer */ -#include "xxhash.h" +#include "third_party/lz4cli/datagen.h" /* RDG_genBuffer */ +#include "third_party/lz4cli/xxhash.h" -#include "lz4.h" +#include "third_party/lz4cli/lz4.h" #define COMPRESSOR0 LZ4_compress_local static int LZ4_compress_local(const char* src, char* dst, int srcSize, int dstSize, int clevel) { int const acceleration = (clevel < 0) ? -clevel + 1 : 1; return LZ4_compress_fast(src, dst, srcSize, dstSize, acceleration); } -#include "lz4hc.h" +#include "third_party/lz4cli/lz4hc.h" #define COMPRESSOR1 LZ4_compress_HC #define DEFAULTCOMPRESSOR COMPRESSOR0 #define LZ4_isError(errcode) (errcode==0) diff --git a/third_party/lz4cli/datagen.c b/third_party/lz4cli/datagen.c index 3ba944cc5..37326dcd2 100644 --- a/third_party/lz4cli/datagen.c +++ b/third_party/lz4cli/datagen.c @@ -27,8 +27,8 @@ /************************************** * Includes **************************************/ -#include "platform.h" /* Compiler options, SET_BINARY_MODE */ -#include "util.h" /* U32 */ +#include "third_party/lz4cli/platform.h" /* Compiler options, SET_BINARY_MODE */ +#include "third_party/lz4cli/util.h" /* U32 */ #include "libc/mem/mem.h" /* malloc */ #include "libc/stdio/stdio.h" /* FILE, fwrite */ #include "libc/str/str.h" /* memcpy */ diff --git a/third_party/lz4cli/lz4.c b/third_party/lz4cli/lz4.c index 6853188a3..cfaed5688 100644 --- a/third_party/lz4cli/lz4.c +++ b/third_party/lz4cli/lz4.c @@ -94,7 +94,7 @@ **************************************/ #define LZ4_STATIC_LINKING_ONLY #define LZ4_DISABLE_DEPRECATE_WARNINGS /* due to LZ4_decompress_safe_withPrefix64k */ -#include "lz4.h" +#include "third_party/lz4cli/lz4.h" /* see also "memory routines" below */ diff --git a/third_party/lz4cli/lz4cli.c b/third_party/lz4cli/lz4cli.c index f4e181fe3..1ce02243e 100644 --- a/third_party/lz4cli/lz4cli.c +++ b/third_party/lz4cli/lz4cli.c @@ -36,17 +36,17 @@ asm(".include \"third_party/lz4cli/COPYING\""); /**************************** * Includes *****************************/ -#include "platform.h" /* Compiler options, IS_CONSOLE */ -#include "util.h" /* UTIL_HAS_CREATEFILELIST, UTIL_createFileList */ +#include "third_party/lz4cli/platform.h" /* Compiler options, IS_CONSOLE */ +#include "third_party/lz4cli/util.h" /* UTIL_HAS_CREATEFILELIST, UTIL_createFileList */ #include "libc/stdio/stdio.h" /* fprintf, getchar */ #include "libc/mem/mem.h" /* exit, calloc, free */ #include "libc/str/str.h" /* strcmp, strlen */ -#include "bench.h" /* BMK_benchFile, BMK_SetNbIterations, BMK_SetBlocksize, BMK_SetPause */ -#include "lz4io.h" /* LZ4IO_compressFilename, LZ4IO_decompressFilename, LZ4IO_compressMultipleFilenames */ -#include "lz4hc.h" /* LZ4HC_CLEVEL_MAX */ +#include "third_party/lz4cli/bench.h" /* BMK_benchFile, BMK_SetNbIterations, BMK_SetBlocksize, BMK_SetPause */ +#include "third_party/lz4cli/lz4io.h" /* LZ4IO_compressFilename, LZ4IO_decompressFilename, LZ4IO_compressMultipleFilenames */ +#include "third_party/lz4cli/lz4hc.h" /* LZ4HC_CLEVEL_MAX */ #include "libc/runtime/runtime.h" #include "libc/log/log.h" -#include "lz4.h" /* LZ4_VERSION_STRING */ +#include "third_party/lz4cli/lz4.h" /* LZ4_VERSION_STRING */ /***************************** diff --git a/third_party/lz4cli/lz4cli.mk b/third_party/lz4cli/lz4cli.mk index c46dae862..48116f25e 100644 --- a/third_party/lz4cli/lz4cli.mk +++ b/third_party/lz4cli/lz4cli.mk @@ -13,6 +13,10 @@ PKGS += THIRD_PARTY_LZ4CLI +THIRD_PARTY_LZ4CLI_FILES := $(wildcard third_party/lz4cli/*) +THIRD_PARTY_LZ4CLI_SRCS = $(filter %.c,$(THIRD_PARTY_LZ4CLI_FILES)) +THIRD_PARTY_LZ4CLI_HDRS = $(filter %.h,$(THIRD_PARTY_LZ4CLI_FILES)) + THIRD_PARTY_LZ4CLI = \ o/$(MODE)/third_party/lz4cli/lz4cli.com diff --git a/third_party/lz4cli/lz4hc.c b/third_party/lz4cli/lz4hc.c index 68ea9d32d..fa8cc4025 100644 --- a/third_party/lz4cli/lz4hc.c +++ b/third_party/lz4cli/lz4hc.c @@ -51,7 +51,7 @@ /*=== Dependency ===*/ #define LZ4_HC_STATIC_LINKING_ONLY -#include "lz4hc.h" +#include "third_party/lz4cli/lz4hc.h" /*=== Common LZ4 definitions ===*/ @@ -63,7 +63,7 @@ #endif #define LZ4_COMMONDEFS_ONLY -#include "lz4.c" /* LZ4_count, constants, mem */ +#include "third_party/lz4cli/lz4.c" /* LZ4_count, constants, mem */ /*=== Constants ===*/ diff --git a/third_party/lz4cli/lz4hc.h b/third_party/lz4cli/lz4hc.h index e18bd1cd5..f412c5da0 100644 --- a/third_party/lz4cli/lz4hc.h +++ b/third_party/lz4cli/lz4hc.h @@ -41,7 +41,7 @@ extern "C" { /* --- Dependency --- */ /* note : lz4hc requires lz4.h/lz4.c for compilation */ -#include "lz4.h" /* stddef, LZ4LIB_API, LZ4_DEPRECATED */ +#include "third_party/lz4cli/lz4.h" /* stddef, LZ4LIB_API, LZ4_DEPRECATED */ /* --- Useful constants --- */ diff --git a/third_party/lz4cli/xxhash.c b/third_party/lz4cli/xxhash.c index cdac03e12..2e157f83a 100644 --- a/third_party/lz4cli/xxhash.c +++ b/third_party/lz4cli/xxhash.c @@ -106,7 +106,7 @@ static void XXH_free (void* p) { free(p); } static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); } #define XXH_STATIC_LINKING_ONLY -#include "xxhash.h" +#include "third_party/lz4cli/xxhash.h" /* ************************************* diff --git a/third_party/lz4cli/xxhash.h b/third_party/lz4cli/xxhash.h index 0be20cc8f..0048760f5 100644 --- a/third_party/lz4cli/xxhash.h +++ b/third_party/lz4cli/xxhash.h @@ -280,7 +280,7 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src #endif # ifdef XXH_PRIVATE_API -# include "xxhash.c" /* include xxhash function bodies as `static`, for inlining */ +# include "third_party/lz4cli/xxhash.c" /* include xxhash function bodies as `static`, for inlining */ # endif #endif /* XXH_STATIC_LINKING_ONLY */ diff --git a/third_party/regex/regex.mk b/third_party/regex/regex.mk index ecb602015..a052c695e 100644 --- a/third_party/regex/regex.mk +++ b/third_party/regex/regex.mk @@ -8,6 +8,7 @@ THIRD_PARTY_REGEX = $(THIRD_PARTY_REGEX_A_DEPS) $(THIRD_PARTY_REGEX_A) THIRD_PARTY_REGEX_A = o/$(MODE)/third_party/regex/regex.a THIRD_PARTY_REGEX_A_FILES := $(wildcard third_party/regex/*) THIRD_PARTY_REGEX_A_HDRS = $(filter %.h,$(THIRD_PARTY_REGEX_A_FILES)) +THIRD_PARTY_REGEX_A_INCS = $(filter %.inc,$(THIRD_PARTY_REGEX_A_FILES)) THIRD_PARTY_REGEX_A_SRCS = $(filter %.c,$(THIRD_PARTY_REGEX_A_FILES)) THIRD_PARTY_REGEX_A_OBJS = \ diff --git a/tool/build/blinkenlights.c b/tool/build/blinkenlights.c index 0d47a85c0..0e14cd992 100644 --- a/tool/build/blinkenlights.c +++ b/tool/build/blinkenlights.c @@ -245,6 +245,10 @@ static long rombase; static long codesize; static int64_t opstart; static int64_t mapsstart; +static uint64_t readaddr; +static uint64_t readsize; +static uint64_t writeaddr; +static uint64_t writesize; static int64_t framesstart; static int64_t breakpointsstart; static uint64_t last_opcount; @@ -424,6 +428,10 @@ static void OnSigBusted(void) { longjmp(onbusted, 1); } +static bool IsShadow(int64_t v) { + return 0x7fff8000 <= v && v < 0x100080000000; +} + static int VirtualBing(int64_t v) { int rc; uint8_t *p; @@ -446,7 +454,7 @@ static int VirtualShadow(int64_t v) { int rc; char *p; jmp_buf busted; - if (0x7fff8000 <= v && v < 0x100080000000) return -2; + if (IsShadow(v)) return -2; onbusted = busted; if ((p = FindReal(m, (v >> 3) + 0x7fff8000))) { if (!setjmp(busted)) { @@ -1171,11 +1179,12 @@ static void DrawSse(struct Panel *p) { } static void ScrollMemoryView(struct Panel *p, struct MemoryView *v, int64_t a) { - long i, n; + long i, n, w; + w = DUMPWIDTH * (1ull << v->zoom); n = p->bottom - p->top; - i = a / (DUMPWIDTH * (1ull << v->zoom)); + i = a / w; if (!(v->start <= i && i < v->start + n)) { - v->start = i; + v->start = i - n / 4; } } @@ -1194,8 +1203,8 @@ static void ZoomMemoryView(struct MemoryView *v, long y, long x, int dy) { static void ScrollMemoryViews(void) { ScrollMemoryView(&pan.code, &codeview, GetIp()); - ScrollMemoryView(&pan.readdata, &readview, m->readaddr); - ScrollMemoryView(&pan.writedata, &writeview, m->writeaddr); + ScrollMemoryView(&pan.readdata, &readview, readaddr); + ScrollMemoryView(&pan.writedata, &writeview, writeaddr); ScrollMemoryView(&pan.stack, &stackview, GetSp()); } @@ -1299,9 +1308,9 @@ static void DrawMemoryUnzoomed(struct Panel *p, struct MemoryView *view, if (sc > 7) { x = 129; /* PURPLE: shadow corruption */ } else if (sc == kAsanHeapFree) { - x = 17; /* NAVYBLUE: heap freed */ + x = 20; /* BLUE: heap freed */ } else if (sc == kAsanRelocated) { - x = 18; /* DARKBLUE: heap relocated */ + x = 16; /* BLACK: heap relocated */ } else if (sc == kAsanHeapUnderrun || sc == kAsanAllocaUnderrun) { x = 53; /* RED+PURPLETINGE: heap underrun */ } else if (sc == kAsanHeapOverrun || sc == kAsanAllocaOverrun) { @@ -1309,7 +1318,7 @@ static void DrawMemoryUnzoomed(struct Panel *p, struct MemoryView *view, } else if (sc < 0) { x = 52; /* RED: uncategorized invalid */ } else if (sc > 0 && (k & 7) >= sc) { - x = 54; /* REDPURP: invalid address (skew) */ + x = 88; /* BRIGHTRED: invalid address (skew) */ } else if (!sc || (sc > 0 && (k & 7) < sc)) { x = 22; /* GREEN: valid address */ } else { @@ -1529,6 +1538,14 @@ static void PreventBufferbloat(void) { static void Redraw(void) { int i, j; + if (!IsShadow(m->readaddr) && !IsShadow(m->readaddr + m->readsize)) { + readaddr = m->readaddr; + readsize = m->readsize; + } + if (!IsShadow(m->writeaddr) && !IsShadow(m->writeaddr + m->writesize)) { + writeaddr = m->writeaddr; + writesize = m->writesize; + } ScrollOp(&pan.disassembly, GetDisIndex()); if (last_opcount) { ips = unsignedsubtract(opcount, last_opcount) / (nowl() - last_seconds); @@ -1555,9 +1572,8 @@ static void Redraw(void) { DrawFrames(&pan.frames); DrawBreakpoints(&pan.breakpoints); DrawMemory(&pan.code, &codeview, GetIp(), GetIp() + m->xedd->length); - DrawMemory(&pan.readdata, &readview, m->readaddr, m->readaddr + m->readsize); - DrawMemory(&pan.writedata, &writeview, m->writeaddr, - m->writeaddr + m->writesize); + DrawMemory(&pan.readdata, &readview, readaddr, readaddr + readsize); + DrawMemory(&pan.writedata, &writeview, writeaddr, writeaddr + writesize); DrawMemory(&pan.stack, &stackview, GetSp(), GetSp() + GetPointerWidth()); DrawStatus(&pan.status); PreventBufferbloat(); diff --git a/tool/build/lib/syscall.c b/tool/build/lib/syscall.c index d78880fa0..b2ac15305 100644 --- a/tool/build/lib/syscall.c +++ b/tool/build/lib/syscall.c @@ -1011,6 +1011,10 @@ static int OpMkdir(struct Machine *m, int64_t path, int mode) { return mkdir(LoadStr(m, path), mode); } +static int OpMkdirat(struct Machine *m, int dirfd, int64_t path, int mode) { + return mkdirat(XlatAfd(m, dirfd), LoadStr(m, path), mode); +} + static int OpMknod(struct Machine *m, int64_t path, uint32_t mode, uint64_t dev) { return mknod(LoadStr(m, path), mode, dev); @@ -1024,10 +1028,20 @@ static int OpUnlink(struct Machine *m, int64_t path) { return unlink(LoadStr(m, path)); } +static int OpUnlinkat(struct Machine *m, int dirfd, int64_t path, int flags) { + return unlinkat(XlatAfd(m, dirfd), LoadStr(m, path), XlatAtf(flags)); +} + static int OpRename(struct Machine *m, int64_t src, int64_t dst) { return rename(LoadStr(m, src), LoadStr(m, dst)); } +static int OpRenameat(struct Machine *m, int srcdirfd, int64_t src, + int dstdirfd, int64_t dst) { + return renameat(XlatAfd(m, srcdirfd), LoadStr(m, src), XlatAfd(m, dstdirfd), + LoadStr(m, dst)); +} + static int OpTruncate(struct Machine *m, int64_t path, uint64_t length) { return truncate(LoadStr(m, path), length); } @@ -1384,12 +1398,12 @@ void OpSyscall(struct Machine *m, uint32_t rde) { SYSCALL(0x0DD, OpFadvise(m, di, si, dx, r0)); SYSCALL(0x0E4, OpClockGettime(m, di, si)); SYSCALL(0x101, OpOpenat(m, di, si, dx, r0)); - SYSCALL(0x102, mkdirat(XlatAfd(m, di), P(si), dx)); + SYSCALL(0x102, OpMkdirat(m, di, si, dx)); SYSCALL(0x104, fchownat(XlatAfd(m, di), P(si), dx, r0, XlatAtf(r8))); SYSCALL(0x105, futimesat(XlatAfd(m, di), P(si), P(dx))); SYSCALL(0x106, OpFstatat(m, di, si, dx, r0)); - SYSCALL(0x107, unlinkat(XlatAfd(m, di), P(si), XlatAtf(dx))); - SYSCALL(0x108, renameat(XlatAfd(m, di), P(si), XlatAfd(m, dx), P(r0))); + SYSCALL(0x107, OpUnlinkat(m, di, si, dx)); + SYSCALL(0x108, OpRenameat(m, di, si, dx, r0)); SYSCALL(0x10D, OpFaccessat(m, di, si, dx, r0)); SYSCALL(0x113, splice(di, P(si), dx, P(r0), r8, XlatAtf(r9))); SYSCALL(0x115, sync_file_range(di, si, dx, XlatAtf(r0))); diff --git a/tool/emacs/cosmo-c-builtins.el b/tool/emacs/cosmo-c-builtins.el index cb068a29c..355de558c 100644 --- a/tool/emacs/cosmo-c-builtins.el +++ b/tool/emacs/cosmo-c-builtins.el @@ -259,6 +259,8 @@ "__builtin_lrintf" "__builtin_lrintl" "__builtin_memcpy" + "__builtin_mempcpy" + "__builtin_memmove" "__builtin_memcmp" "__builtin_memset" "__builtin_strlen")) From c8432433227e6183affcde12510db94802a14d45 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Tue, 2 Feb 2021 20:21:06 -0800 Subject: [PATCH 2/5] Implement more security stuff - Support deterministic stacks on OpenBSD - Support OpenBSD system call origin verification - Fix overrun by one in chibicc string token allocator - Get all chibicc tests passing under Address Sanitizer --- ape/ape.lds | 7 ++ build/config.mk | 3 +- examples/tiny-raw-linux-tutorial.S | 1 + libc/calls/chmod.c | 1 - libc/calls/clock_gettime.c | 1 - libc/calls/fadvise.c | 1 - libc/calls/fallocate.c | 1 - libc/calls/fchmod.c | 1 - libc/calls/fchown.c | 1 - libc/calls/fcntl.c | 1 - libc/calls/fdatasync.c | 1 - libc/calls/hefty/vfork.S | 1 + libc/calls/mprotect.greg.c | 2 +- libc/elf/elf.lds | 8 ++ libc/integral/c.inc | 1 + libc/intrin/asan.c | 20 ++++- libc/log/startfatal.c | 18 +++- libc/macros.internal.inc | 3 + libc/nexgen32e/strcaseconv.S | 100 ---------------------- libc/runtime/abort.S | 2 +- libc/runtime/arch_prctl.c | 4 +- libc/runtime/exit3.S | 2 +- libc/runtime/print.greg.c | 6 +- libc/runtime/stackchkfail.c | 2 +- libc/str/memccpy.c | 2 +- libc/str/pututf16.ncabi.c | 2 + libc/str/rawmemchr.c | 2 +- libc/str/str.h | 1 - libc/str/strntoupper.c | 20 +++-- libc/str/{ctz.c => strtolower.c} | 19 ++++- libc/str/strtoupper.c | 35 ++++++++ libc/str/tinymemmem.c | 16 ++-- libc/str/tinymemmem.internal.h | 26 ------ libc/str/tinystrstr.c | 15 +++- libc/str/tinystrstr.internal.h | 26 ------ libc/str/tinystrstr16.c | 13 ++- libc/str/tpdecode.ncabi.c | 2 + libc/str/tpenc.h | 21 ++--- libc/stubs/asan.S | 130 +++++++++++++++++++++++++++-- libc/sysv/calls/msyscall.s | 2 + libc/sysv/consts.sh | 6 +- libc/sysv/consts/MAP_CONCEAL.s | 2 + libc/sysv/consts/MAP_GROWSDOWN.s | 2 +- libc/sysv/consts/MAP_NOCORE.s | 2 + libc/sysv/consts/__NR_msyscall.s | 2 + libc/sysv/consts/map.h | 7 +- libc/sysv/consts/nr.h | 2 + libc/sysv/restorert.S | 1 + libc/sysv/syscalls.sh | 1 + libc/sysv/systemfive.S | 35 ++++++-- test/libc/str/tpenc_test.c | 3 +- third_party/chibicc/tokenize.c | 2 +- third_party/third_party.mk | 7 +- tool/build/lib/syscall.c | 26 ++++++ tool/emacs/cosmo-c-keywords.el | 1 + tool/emacs/cosmo-stuff.el | 2 +- 56 files changed, 376 insertions(+), 245 deletions(-) delete mode 100644 libc/nexgen32e/strcaseconv.S rename libc/str/{ctz.c => strtolower.c} (87%) create mode 100644 libc/str/strtoupper.c delete mode 100644 libc/str/tinymemmem.internal.h delete mode 100644 libc/str/tinystrstr.internal.h create mode 100644 libc/sysv/calls/msyscall.s create mode 100644 libc/sysv/consts/MAP_CONCEAL.s create mode 100644 libc/sysv/consts/MAP_NOCORE.s create mode 100644 libc/sysv/consts/__NR_msyscall.s diff --git a/ape/ape.lds b/ape/ape.lds index 077ae3f91..7ca29a2c8 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -282,6 +282,9 @@ SECTIONS { KEEP(*(.textwindowsepilogue)) *(SORT_BY_ALIGNMENT(.text.modernity)) *(SORT_BY_ALIGNMENT(.text.modernity.*)) + HIDDEN(__text_syscall_start = .); + *(.text.syscall .text.syscall.*) + HIDDEN(__text_syscall_end = .); *(SORT_BY_ALIGNMENT(.text.hot)) *(SORT_BY_ALIGNMENT(.text.hot.*)) KEEP(*(.keep.text)) @@ -483,6 +486,10 @@ SHSTUB2(.Lape.macho.dd.skip, RVA(ape.macho) / 8); SHSTUB2(.Lape.macho.dd.count, (.Lape.macho.end - ape.macho) / 8); PFSTUB4(.Lape.pe.offset, ape.pe - ape.mz); +HIDDEN(__text_syscall_addr = ROUNDDOWN(__text_syscall_start, PAGESIZE)); +HIDDEN(__text_syscall_size = (ROUNDUP(__text_syscall_end, PAGESIZE) - + ROUNDDOWN(__text_syscall_start, PAGESIZE))); + HIDDEN(.Lape.pe.optsz = .Lape.pe.sections - (ape.pe + 24)); HIDDEN(.Lape.pe.shnum = (.Lape.pe.sections_end - .Lape.pe.sections) / 40); HIDDEN(.Lidata.idtsize = idata.idtend - idata.idt); diff --git a/build/config.mk b/build/config.mk index ea6e01e2f..90677eacb 100644 --- a/build/config.mk +++ b/build/config.mk @@ -94,8 +94,7 @@ CONFIG_CPPFLAGS += \ CONFIG_CCFLAGS += \ $(BACKTRACES) \ $(FTRACE) \ - -O1 \ - -fno-inline + -O2 CONFIG_COPTS += \ $(SECURITY_BLANKETS) \ diff --git a/examples/tiny-raw-linux-tutorial.S b/examples/tiny-raw-linux-tutorial.S index b851f9e60..2ae9f035e 100644 --- a/examples/tiny-raw-linux-tutorial.S +++ b/examples/tiny-raw-linux-tutorial.S @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" +.text.syscall / Tiny Raw Linux Binary Tutorial / diff --git a/libc/calls/chmod.c b/libc/calls/chmod.c index 334bbb665..7df6f93ad 100644 --- a/libc/calls/chmod.c +++ b/libc/calls/chmod.c @@ -42,7 +42,6 @@ * @errors ENOENT, ENOTDIR, ENOSYS * @asyncsignalsafe * @see fchmod() - * @syscall */ int chmod(const char *pathname, uint32_t mode) { if (!pathname) return efault(); diff --git a/libc/calls/clock_gettime.c b/libc/calls/clock_gettime.c index 25ac8e058..042c6ea39 100644 --- a/libc/calls/clock_gettime.c +++ b/libc/calls/clock_gettime.c @@ -50,7 +50,6 @@ * errno isn't restored to its original value, to detect prec. loss * @see strftime(), gettimeofday() * @asyncsignalsafe - * @syscall */ int clock_gettime(int clockid, struct timespec *out_ts) { /* TODO(jart): Just ignore O/S for MONOTONIC and measure RDTSC on start */ diff --git a/libc/calls/fadvise.c b/libc/calls/fadvise.c index 614348875..959884b6a 100644 --- a/libc/calls/fadvise.c +++ b/libc/calls/fadvise.c @@ -29,7 +29,6 @@ * @param len 0 means ‘til end of file * @param advice can be MADV_SEQUENTIAL, MADV_RANDOM, etc. * @return -1 on error - * @syscall */ int fadvise(int fd, uint64_t offset, uint64_t len, int advice) { if (!IsWindows()) { diff --git a/libc/calls/fallocate.c b/libc/calls/fallocate.c index 622641b16..e3c983c1b 100644 --- a/libc/calls/fallocate.c +++ b/libc/calls/fallocate.c @@ -38,7 +38,6 @@ * @return 0 on success, or -1 w/ errno * @note limited availability on rhel5 and openbsd * @see ftruncate() - * @syscall */ int fallocate(int fd, int32_t mode, int64_t offset, int64_t length) { int rc; diff --git a/libc/calls/fchmod.c b/libc/calls/fchmod.c index 86df1b92e..7c32f492f 100644 --- a/libc/calls/fchmod.c +++ b/libc/calls/fchmod.c @@ -40,7 +40,6 @@ * @errors ENOSYS * @asyncsignalsafe * @see chmod() - * @syscall */ int fchmod(int fd, uint32_t mode) { /* TODO(jart): Windows */ diff --git a/libc/calls/fchown.c b/libc/calls/fchown.c index f86e8ef12..92e821868 100644 --- a/libc/calls/fchown.c +++ b/libc/calls/fchown.c @@ -28,7 +28,6 @@ * @return 0 on success, or -1 w/ errno * @see /etc/passwd for user ids * @see /etc/group for group ids - * @syscall */ int fchown(int fd, uint32_t uid, uint32_t gid) { /* TODO(jart): Windows? */ diff --git a/libc/calls/fcntl.c b/libc/calls/fcntl.c index 157bca070..954daff77 100644 --- a/libc/calls/fcntl.c +++ b/libc/calls/fcntl.c @@ -29,7 +29,6 @@ * @param arg can be FD_CLOEXEC, etc. depending * @return 0 on success, or -1 w/ errno * @asyncsignalsafe - * @syscall */ int fcntl(int fd, int cmd, ...) { va_list va; diff --git a/libc/calls/fdatasync.c b/libc/calls/fdatasync.c index 59bed3393..9eacbbff3 100644 --- a/libc/calls/fdatasync.c +++ b/libc/calls/fdatasync.c @@ -26,7 +26,6 @@ * @return 0 on success, or -1 w/ errno * @see fsync(), sync_file_range() * @asyncsignalsafe - * @syscall */ int fdatasync(int fd) { if (!IsWindows()) { diff --git a/libc/calls/hefty/vfork.S b/libc/calls/hefty/vfork.S index 4821a69fb..021160cd2 100644 --- a/libc/calls/hefty/vfork.S +++ b/libc/calls/hefty/vfork.S @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/dce.h" #include "libc/macros.h" +.text.syscall / Forks process without copying page tables. / diff --git a/libc/calls/mprotect.greg.c b/libc/calls/mprotect.greg.c index 36a61d7a0..8c6558afc 100644 --- a/libc/calls/mprotect.greg.c +++ b/libc/calls/mprotect.greg.c @@ -34,7 +34,7 @@ extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect; * @return 0 on success, or -1 w/ errno * @see mmap() */ -int mprotect(void *addr, uint64_t len, int prot) { +textsyscall int mprotect(void *addr, uint64_t len, int prot) { bool cf; int64_t rc; uint32_t oldprot; diff --git a/libc/elf/elf.lds b/libc/elf/elf.lds index 845d938b2..87e553221 100644 --- a/libc/elf/elf.lds +++ b/libc/elf/elf.lds @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "ape/relocations.h" +#include "libc/macros.h" /** * @fileoverview Cosmopolitan ELF-Normative Linker Script. @@ -66,6 +67,9 @@ SECTIONS { .text : { *(SORT_BY_ALIGNMENT(.text.hot)) KEEP(*(.keep.text)) + HIDDEN(__text_syscall_start = .); + *(.text.syscall .text.syscall.*) + HIDDEN(__text_syscall_end = .); *(.text .text.*) KEEP(*(SORT_BY_NAME(.sort.text.*))) } @@ -207,3 +211,7 @@ SECTIONS { *(.*) } } + +HIDDEN(__text_syscall_addr = ROUNDDOWN(__text_syscall_start, PAGESIZE)); +HIDDEN(__text_syscall_size = (ROUNDUP(__text_syscall_end, PAGESIZE) - + ROUNDDOWN(__text_syscall_start, PAGESIZE))); diff --git a/libc/integral/c.inc b/libc/integral/c.inc index 56cc7d496..1a7e9dd85 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -618,6 +618,7 @@ typedef uint64_t uintmax_t; #define textexit _Section(".text.exit") noinstrument #define textreal _Section(".text.real") #define textwindows _Section(".text.windows") +#define textsyscall _Section(".text.syscall") #define antiquity _Section(".text.antiquity") #else #define testonly diff --git a/libc/intrin/asan.c b/libc/intrin/asan.c index 3d934be3b..3983a2a7a 100644 --- a/libc/intrin/asan.c +++ b/libc/intrin/asan.c @@ -374,7 +374,9 @@ static const char *__asan_dscribe_heap_poison(long c) { } } -static const char *__asan_describe_access_poison(int c) { +static const char *__asan_describe_access_poison(char *p) { + int c = p[0]; + if (1 <= c && c <= 7) c = p[1]; switch (c) { case kAsanHeapFree: return "heap use after free"; @@ -407,7 +409,7 @@ static const char *__asan_describe_access_poison(int c) { } } -static ssize_t __asan_write(const void *data, size_t size) { +static textsyscall ssize_t __asan_write(const void *data, size_t size) { ssize_t rc; if (weaken(write)) { if ((rc = weaken(write)(2, data, size)) != -1) { @@ -421,7 +423,7 @@ static ssize_t __asan_write_string(const char *s) { return __asan_write(s, __asan_strlen(s)); } -static wontreturn void __asan_exit(int rc) { +static textsyscall wontreturn void __asan_exit(int rc) { if (weaken(_Exit)) { weaken(_Exit)(rc); } else { @@ -431,6 +433,7 @@ static wontreturn void __asan_exit(int rc) { } static wontreturn void __asan_abort(void) { + if (weaken(__die)) weaken(__die)(); if (weaken(abort)) weaken(abort)(); __asan_exit(134); } @@ -468,7 +471,7 @@ static wontreturn void __asan_report_memory_fault(uint8_t *addr, int size, const char *kind) { char *p, ibuf[21], buf[256]; p = __asan_report_start(buf); - p = __asan_stpcpy(p, __asan_describe_access_poison(*SHADOW(addr))); + p = __asan_stpcpy(p, __asan_describe_access_poison(SHADOW(addr))); p = __asan_stpcpy(p, " "); p = __asan_mempcpy(p, ibuf, __asan_int2str(size, ibuf)); p = __asan_stpcpy(p, "-byte "); @@ -524,6 +527,7 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun) { __asan_unpoison((uintptr_t)p, n); __asan_poison((uintptr_t)p - 16, 16, underrun); /* see dlmalloc design */ __asan_poison((uintptr_t)p + n, c - n, overrun); + __asan_memset(p, 0xF9, n); WRITE64BE(p + c - sizeof(n), n); } return p; @@ -664,6 +668,14 @@ void __asan_report_store_impl(uint8_t *addr, int size) { __asan_report_memory_fault(addr, size, "store"); } +void __asan_poison_stack_memory(uintptr_t addr, size_t size) { + __asan_poison(addr, size, kAsanStackFree); +} + +void __asan_unpoison_stack_memory(uintptr_t addr, size_t size) { + __asan_unpoison(addr, size); +} + void __asan_alloca_poison(uintptr_t addr, size_t size) { /* TODO(jart): Make sense of this function. */ /* __asan_poison(addr - 32, 32, kAsanAllocaUnderrun); */ diff --git a/libc/log/startfatal.c b/libc/log/startfatal.c index bc0cb46c4..abecaa951 100644 --- a/libc/log/startfatal.c +++ b/libc/log/startfatal.c @@ -17,9 +17,11 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/fmt/itoa.h" #include "libc/log/color.internal.h" #include "libc/log/internal.h" #include "libc/runtime/runtime.h" +#include "libc/str/str.h" #include "libc/sysv/consts/fileno.h" /** @@ -29,6 +31,18 @@ * @see __start_fatal_ndebug() */ relegated void __start_fatal(const char *file, int line) { - dprintf(STDERR_FILENO, "%s%s%s%s:%s:%d:%s%s: ", CLS, RED, "error", BLUE1, - file, line, program_invocation_short_name, RESET); + char s[16 + 16 + 16 + 16 + PATH_MAX + 16 + NAME_MAX + 16], *p; + p = stpcpy(s, CLS); + p = stpcpy(p, RED); + p = stpcpy(p, "error"); + p = stpcpy(p, BLUE1); + p = stpcpy(p, ":"); + p = stpcpy(p, file); + p = stpcpy(p, ":"); + p += int64toarray_radix10(line, p); + p = stpcpy(p, ":"); + p = stpcpy(p, program_invocation_short_name); + p = stpcpy(p, RESET); + p = stpcpy(p, ": "); + write(2, s, p - s); } diff --git a/libc/macros.internal.inc b/libc/macros.internal.inc index 26a333f32..90c5aac7d 100644 --- a/libc/macros.internal.inc +++ b/libc/macros.internal.inc @@ -33,6 +33,9 @@ .macro .text.exit .section .text.exit,"ax",@progbits .endm +.macro .text.syscall + .section .text.syscall,"ax",@progbits +.endm .macro .firstclass .section .text.hot,"ax",@progbits .endm diff --git a/libc/nexgen32e/strcaseconv.S b/libc/nexgen32e/strcaseconv.S deleted file mode 100644 index ad0ff2d6f..000000000 --- a/libc/nexgen32e/strcaseconv.S +++ /dev/null @@ -1,100 +0,0 @@ -/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ -│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 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/nexgen32e/macros.h" -#include "libc/nexgen32e/x86feature.h" -#include "libc/macros.h" - -/ Mutates string to uppercase roman characters. -/ -/ @param RDI points to non-const NUL-terminated string -/ @return RAX will be original RDI -/ @note 10x faster than C -strtoupper: - mov $'A-'a,%edx # adding this uppers - mov $'a|'z<<8,%ecx # uint8_t range a..z - jmp strcaseconv - .endfn strtoupper,globl - -/ Mutates string to lowercase roman characters. -/ -/ @param RDI points to non-const NUL-terminated string -/ @return RAX will be original RDI -/ @note 10x faster than C -strtolower: - mov $'a-'A,%edx # adding this lowers - mov $'A|'Z<<8,%ecx # uint8_t range A..Z -/ 𝑠𝑙𝑖𝑑𝑒 - .endfn strtolower,globl - -/ Support code for strtolower() and strtoupper(). -/ -/ @param RDI points to non-const NUL-terminated string -/ @param CL defines start of character range to mutate -/ @param CH defines end of character range to mutate -/ @param DL is added to each DIL ∈ [CL,CH] -/ @return RAX will be original RDI -strcaseconv: - .leafprologue - .profilable - mov %rdi,%rsi -0: testb $15,%sil # is it aligned? -#if X86_NEED(SSE4_2) - jz .Lsse4 -#else - jnz 1f - testb X86_HAVE(SSE4_2)+kCpuids(%rip) - jnz .Lsse4 # is it nehalem? -#endif -1: lodsb # AL = *RSI++ - test %al,%al # is it NUL? - jz 3f - cmp %cl,%al # is it in range? - jb 0b - cmp %ch,%al - ja 0b - add %dl,-1(%rsi) - jmp 0b -.Lsse4: movd %ecx,%xmm1 # XMM1 = ['A,'Z,0,0,...] - movd %edx,%xmm2 # XMM2 = ['a-'A,'a-'A,...] - pbroadcastb %xmm2 - xor %ecx,%ecx -2: movdqa (%rsi,%rcx),%xmm3 -/ ┌─0:index of the LEAST significant, set, bit is used -/ │ regardless of corresponding input element validity -/ │ intres2 is returned in least significant bits of xmm0 -/ ├─1:index of the MOST significant, set, bit is used -/ │ regardless of corresponding input element validity -/ │ each bit of intres2 is expanded to byte/word -/ │┌─0:negation of intres1 is for all 16 (8) bits -/ │├─1:negation of intres1 is masked by reg/mem validity -/ ││┌─intres1 is negated (1’s complement) -/ │││┌─mode{equalany,ranges,equaleach,equalordered} -/ ││││ ┌─issigned -/ ││││ │┌─is16bit -/ u│││├┐││ - pcmpistrm $0b01000100,%xmm3,%xmm1 # →XMM0 8-bit byte mask - pand %xmm2,%xmm0 # won't mask after NUL - paddb %xmm0,%xmm3 - movdqa %xmm3,(%rsi,%rcx) - lea 16(%rcx),%rcx - jnz 2b # PCMPISTRM found NUL -3: mov %rdi,%rax - .leafepilogue - .endfn strcaseconv - .source __FILE__ diff --git a/libc/runtime/abort.S b/libc/runtime/abort.S index 36164db63..a2a24c9c5 100644 --- a/libc/runtime/abort.S +++ b/libc/runtime/abort.S @@ -21,7 +21,7 @@ #include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/nr.h" #include "libc/macros.h" -.real +.text.syscall .source __FILE__ / Terminates program abnormally. diff --git a/libc/runtime/arch_prctl.c b/libc/runtime/arch_prctl.c index 4a148fa41..4f784b66a 100644 --- a/libc/runtime/arch_prctl.c +++ b/libc/runtime/arch_prctl.c @@ -95,7 +95,7 @@ static int arch_prctl$freebsd(int code, int64_t addr) { } } -static int arch_prctl$xnu(int code, int64_t addr) { +static textsyscall int arch_prctl$xnu(int code, int64_t addr) { int ax; switch (code) { case ARCH_SET_GS: @@ -113,7 +113,7 @@ static int arch_prctl$xnu(int code, int64_t addr) { } } -static int arch_prctl$openbsd(int code, int64_t addr) { +static textsyscall int arch_prctl$openbsd(int code, int64_t addr) { int64_t rax; switch (code) { case ARCH_GET_FS: diff --git a/libc/runtime/exit3.S b/libc/runtime/exit3.S index 5b12aa34e..421977f67 100644 --- a/libc/runtime/exit3.S +++ b/libc/runtime/exit3.S @@ -19,7 +19,7 @@ #include "libc/dce.h" #include "libc/runtime/internal.h" #include "libc/macros.h" -.privileged +.text.syscall .source __FILE__ / Terminates process, ignoring destructors and atexit() handlers. diff --git a/libc/runtime/print.greg.c b/libc/runtime/print.greg.c index 6d06456ba..8e18dda60 100644 --- a/libc/runtime/print.greg.c +++ b/libc/runtime/print.greg.c @@ -28,7 +28,7 @@ #define WasImported(SLOT) \ ((void *)*SLOT && *SLOT != (void *)&missingno /* see libc/crt/crt.S */) -static privileged void __print$nt(const void *data, size_t len) { +static void __print$nt(const void *data, size_t len) { int64_t hand; char xmm[256]; uint32_t wrote; @@ -49,7 +49,7 @@ static privileged void __print$nt(const void *data, size_t len) { * @param len can be computed w/ tinystrlen() * @clob nothing except flags */ -privileged void __print(const void *data, size_t len) { +textsyscall void __print(const void *data, size_t len) { int64_t ax, ordinal; if (WasImported(__imp_WriteFile)) { __print$nt(data, len); @@ -68,7 +68,7 @@ privileged void __print(const void *data, size_t len) { } } -privileged void __print_string(const char *s) { +void __print_string(const char *s) { size_t n = 0; while (s[n]) ++n; __print(s, n); diff --git a/libc/runtime/stackchkfail.c b/libc/runtime/stackchkfail.c index a9a604104..ff2c1da82 100644 --- a/libc/runtime/stackchkfail.c +++ b/libc/runtime/stackchkfail.c @@ -29,7 +29,7 @@ /** * Aborts program under enemy fire to avoid being taken alive. */ -void __stack_chk_fail(void) { +textsyscall void __stack_chk_fail(void) { size_t len; const char *msg; int64_t ax, cx, si; diff --git a/libc/str/memccpy.c b/libc/str/memccpy.c index c982372a4..adcd21eec 100644 --- a/libc/str/memccpy.c +++ b/libc/str/memccpy.c @@ -18,7 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" -static noasan uint64_t UncheckedAlignedRead64(unsigned char *p) { +static inline noasan uint64_t UncheckedAlignedRead64(unsigned char *p) { return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; diff --git a/libc/str/pututf16.ncabi.c b/libc/str/pututf16.ncabi.c index 9f53e49a6..5023c7550 100644 --- a/libc/str/pututf16.ncabi.c +++ b/libc/str/pututf16.ncabi.c @@ -19,6 +19,8 @@ #include "libc/str/oldutf16.internal.h" #include "libc/str/str.h" +/* TODO(jart): DELETE */ + /** * Encodes character to string as UTF-16. * diff --git a/libc/str/rawmemchr.c b/libc/str/rawmemchr.c index dab660dc2..4ffd31621 100644 --- a/libc/str/rawmemchr.c +++ b/libc/str/rawmemchr.c @@ -19,7 +19,7 @@ #include "libc/assert.h" #include "libc/str/str.h" -static noasan uint64_t UncheckedAlignedRead64(unsigned char *p) { +static inline noasan uint64_t UncheckedAlignedRead64(unsigned char *p) { return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; diff --git a/libc/str/str.h b/libc/str/str.h index 740227ec2..5def2bd4e 100644 --- a/libc/str/str.h +++ b/libc/str/str.h @@ -187,7 +187,6 @@ char16_t *tinystrstr16(const char16_t *, const char16_t *) strlenesque; void *tinymemmem(const void *, size_t, const void *, size_t) strlenesque; void *tinymemccpy(void *, const void *, int, size_t) memcpyesque; -void *memtolower(void *, size_t); char *strntolower(char *, size_t); char *strtolower(char *) paramsnonnull(); char *strntoupper(char *, size_t); diff --git a/libc/str/strntoupper.c b/libc/str/strntoupper.c index 48155a403..dea8994ae 100644 --- a/libc/str/strntoupper.c +++ b/libc/str/strntoupper.c @@ -18,16 +18,18 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Mutates string to ASCII uppercase w/ limit. + * + * @praam s is string + * @praam n is max bytes to consider + * @return string + */ char *strntoupper(char *s, size_t n) { - unsigned char *p = (unsigned char *)s; - for (;;) { - if (n-- && *p) { - if ('a' <= *p && *p <= 'z') { - *p -= 'a' - 'A'; - } - ++p; - } else { - break; + size_t i; + for (i = 0; s[i] && i < n; ++i) { + if ('a' <= s[i] && s[i] <= 'z') { + s[i] -= 'a' - 'A'; } } return s; diff --git a/libc/str/ctz.c b/libc/str/strtolower.c similarity index 87% rename from libc/str/ctz.c rename to libc/str/strtolower.c index 40f21d3fa..54a63a2ee 100644 --- a/libc/str/ctz.c +++ b/libc/str/strtolower.c @@ -16,9 +16,20 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/math.h" -#include "libc/nexgen32e/nexgen32e.h" +#include "libc/str/str.h" -bool ctz(double x, double y) { - return __builtin_islessgreater(x, y); +/** + * Mutates string to ASCII lowercase. + * + * @praam s is string + * @return string + */ +char *strtolower(char *s) { + size_t i; + for (i = 0; s[i]; ++i) { + if ('A' <= s[i] && s[i] <= 'Z') { + s[i] += 'a' - 'A'; + } + } + return s; } diff --git a/libc/str/strtoupper.c b/libc/str/strtoupper.c new file mode 100644 index 000000000..2ff4505d8 --- /dev/null +++ b/libc/str/strtoupper.c @@ -0,0 +1,35 @@ +/*-*- 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 2020 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/str/str.h" + +/** + * Mutates string to ASCII uppercase. + * + * @praam s is string + * @return string + */ +char *strtoupper(char *s) { + size_t i; + for (i = 0; s[i]; ++i) { + if ('a' <= s[i] && s[i] <= 'z') { + s[i] -= 'a' - 'A'; + } + } + return s; +} diff --git a/libc/str/tinymemmem.c b/libc/str/tinymemmem.c index b6e67ca77..dcc9476b8 100644 --- a/libc/str/tinymemmem.c +++ b/libc/str/tinymemmem.c @@ -17,15 +17,21 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" -#include "libc/str/tinymemmem.internal.h" /** * Naïve substring search implementation. * @see libc/alg/memmem.c */ -void *tinymemmem(const void *haystk, size_t haystksize, const void *needle, +void *tinymemmem(const void *haystack, size_t haystacksize, const void *needle, size_t needlesize) { - return (/*unconst*/ void *)tinymemmemi( - (const unsigned char *)haystk, haystksize, (const unsigned char *)needle, - needlesize); + size_t i; + const char *p, *pe; + for (p = haystack, pe = p + haystacksize; p < pe;) { + for (++p, i = 0;;) { + if (++i > needlesize) return p - 1; + if (p == pe) break; + if (((const char *)needle)[i - 1] != (p - 1)[i - 1]) break; + } + } + return !haystacksize && !needlesize ? haystack : NULL; } diff --git a/libc/str/tinymemmem.internal.h b/libc/str/tinymemmem.internal.h deleted file mode 100644 index c96fccd32..000000000 --- a/libc/str/tinymemmem.internal.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_STR_TINYSTRSTR_H_ -#define COSMOPOLITAN_LIBC_STR_TINYSTRSTR_H_ -#ifndef __STRICT_ANSI__ -#include "libc/str/str.h" -#if !(__ASSEMBLER__ + __LINKER__ + 0) - -forceinline void *tinymemmemi(const void *haystk, size_t haystksize, - const void *needle, size_t needlesize) { - const char *p = (const char *)haystk; - const char *pe = (const char *)haystk + haystksize; - while (p < pe) { - size_t i = 0; - ++p; - for (;;) { - ++i; - if (i > needlesize) return (/*unconst*/ char *)(p - 1); - if (p == pe) break; - if (((const char *)needle)[i - 1] != (p - 1)[i - 1]) break; - } - } - return (/*unconst*/ char *)(!haystksize && !needlesize ? haystk : NULL); -} - -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* !ANSI */ -#endif /* COSMOPOLITAN_LIBC_STR_TINYMEMMEM_H_ */ diff --git a/libc/str/tinystrstr.c b/libc/str/tinystrstr.c index 4437049a5..86a53d3eb 100644 --- a/libc/str/tinystrstr.c +++ b/libc/str/tinystrstr.c @@ -17,13 +17,22 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/internal.h" -#include "libc/str/tinystrstr.internal.h" /** * Naïve substring search implementation. * @see libc/str/strstr.c * @asyncsignalsafe */ -char *(tinystrstr)(const char *haystack, const char *needle) { - return (/*unconst*/ char *)tinystrstr(haystack, needle); +char *tinystrstr(const char *haystack, const char *needle) { + size_t i; + for (;;) { + for (i = 0;;) { + if (!needle[i]) return (/*unconst*/ char *)haystack; + if (!haystack[i]) break; + if (needle[i] != haystack[i]) break; + ++i; + } + if (!*haystack++) break; + } + return NULL; } diff --git a/libc/str/tinystrstr.internal.h b/libc/str/tinystrstr.internal.h deleted file mode 100644 index 3c050339e..000000000 --- a/libc/str/tinystrstr.internal.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_STR_TINYSTRSTR_H_ -#define COSMOPOLITAN_LIBC_STR_TINYSTRSTR_H_ -#include "libc/str/str.h" -#if !(__ASSEMBLER__ + __LINKER__ + 0) - -#define tinystrstr(HAYSTACK, NEEDLE) \ - ({ \ - autotype(HAYSTACK) Haystack = (HAYSTACK); \ - typeof(Haystack) Needle = (NEEDLE); \ - for (;;) { \ - size_t i = 0; \ - for (;;) { \ - if (!Needle[i]) goto Found; \ - if (!Haystack[i]) break; \ - if (Needle[i] != Haystack[i]) break; \ - ++i; \ - } \ - if (!*Haystack++) break; \ - } \ - Haystack = NULL; \ - Found: \ - Haystack; \ - }) - -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_STR_TINYSTRSTR_H_ */ diff --git a/libc/str/tinystrstr16.c b/libc/str/tinystrstr16.c index 49614ef18..a17195684 100644 --- a/libc/str/tinystrstr16.c +++ b/libc/str/tinystrstr16.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/internal.h" -#include "libc/str/tinystrstr.internal.h" /** * Naïve substring search implementation. @@ -25,5 +24,15 @@ * @asyncsignalsafe */ char16_t *tinystrstr16(const char16_t *haystack, const char16_t *needle) { - return (/*unconst*/ char16_t *)tinystrstr(haystack, needle); + size_t i; + for (;;) { + for (i = 0;;) { + if (!needle[i]) return (/*unconst*/ char16_t *)haystack; + if (!haystack[i]) break; + if (needle[i] != haystack[i]) break; + ++i; + } + if (!*haystack++) break; + } + return NULL; } diff --git a/libc/str/tpdecode.ncabi.c b/libc/str/tpdecode.ncabi.c index 5b1511549..24d0c13e0 100644 --- a/libc/str/tpdecode.ncabi.c +++ b/libc/str/tpdecode.ncabi.c @@ -21,6 +21,8 @@ #include "libc/str/tpdecode.internal.h" #include "libc/str/tpdecodecb.internal.h" +/* TODO(jart): DELETE */ + forceinline int getbyte(void *arg, uint32_t i) { return ((const unsigned char *)arg)[i]; } diff --git a/libc/str/tpenc.h b/libc/str/tpenc.h index 0400a1bdc..f72d6d66c 100644 --- a/libc/str/tpenc.h +++ b/libc/str/tpenc.h @@ -6,19 +6,14 @@ COSMOPOLITAN_C_START_ uint64_t tpenc(int32_t) pureconst; #ifndef __STRICT_ANSI__ -#define tpenc(CODE) \ - ({ \ - long Buf; \ - int32_t Code = (CODE); \ - if (0 <= Code && Code <= 127) { \ - Buf = Code; \ - } else { \ - asm("call\ttpenc" \ - : "=a"(Buf), "+D"(Code) \ - : /* inputs */ \ - : "rcx", "rdx", "cc"); \ - } \ - Buf; \ +#define tpenc(CODE) \ + ({ \ + long Edi, Buf; \ + asm("call\ttpenc" \ + : "=a"(Buf), "=D"(Edi) \ + : "1"(CODE) \ + : "rcx", "rdx", "cc"); \ + Buf; \ }) #endif diff --git a/libc/stubs/asan.S b/libc/stubs/asan.S index e3a750ce5..3cd9388d4 100644 --- a/libc/stubs/asan.S +++ b/libc/stubs/asan.S @@ -22,253 +22,367 @@ / @fileoverview Address Sanitizer Linker Poison __asan_addr_is_in_fake_stack: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_addr_is_in_fake_stack,weak __asan_after_dynamic_init: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_after_dynamic_init,weak __asan_alloca_poison: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_alloca_poison,weak __asan_allocas_unpoison: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_allocas_unpoison,weak __asan_before_dynamic_init: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_before_dynamic_init,weak __asan_get_current_fake_stack: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_get_current_fake_stack,weak __asan_handle_no_return: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_handle_no_return,weak __asan_init: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_init,weak __asan_load1: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_load1,weak __asan_load2: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_load2,weak __asan_load4: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_load4,weak __asan_load8: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_load8,weak __asan_load16: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_load16,weak __asan_load32: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_load32,weak __asan_option_detect_stack_use_after_return: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_option_detect_stack_use_after_return,weak -__asan_poison_stack_memory: - ud2 - .endfn __asan_poison_stack_memory,weak - __asan_register_globals: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_register_globals,weak __asan_report_load1: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_report_load1,weak __asan_report_load2: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_report_load2,weak __asan_report_load4: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_report_load4,weak __asan_report_load8: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_report_load8,weak __asan_report_load16: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_report_load16,weak __asan_report_load_n: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_report_load_n,weak __asan_report_store1: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_report_store1,weak __asan_report_store2: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_report_store2,weak __asan_report_store4: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_report_store4,weak __asan_report_store8: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_report_store8,weak __asan_report_store16: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_report_store16,weak __asan_report_store32: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_report_store32,weak __asan_report_store_n: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_report_store_n,weak __asan_stack_free: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_free,weak __asan_stack_free_0: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_free_0,weak __asan_stack_free_1: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_free_1,weak __asan_stack_free_10: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_free_10,weak __asan_stack_free_2: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_free_2,weak __asan_stack_free_3: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_free_3,weak __asan_stack_free_4: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_free_4,weak __asan_stack_free_5: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_free_5,weak __asan_stack_free_6: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_free_6,weak __asan_stack_free_7: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_free_7,weak __asan_stack_free_8: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_free_8,weak __asan_stack_free_9: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_free_9,weak __asan_stack_malloc: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_malloc,weak __asan_stack_malloc_0: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_malloc_0,weak __asan_stack_malloc_1: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_malloc_1,weak __asan_stack_malloc_2: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_malloc_2,weak __asan_stack_malloc_3: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_malloc_3,weak __asan_stack_malloc_4: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_malloc_4,weak __asan_stack_malloc_5: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_malloc_5,weak __asan_stack_malloc_6: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_malloc_6,weak __asan_stack_malloc_7: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_malloc_7,weak __asan_stack_malloc_8: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_malloc_8,weak __asan_stack_malloc_9: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_malloc_9,weak __asan_stack_malloc_10: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_stack_malloc_10,weak __asan_store1: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_store1,weak __asan_store2: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_store2,weak __asan_store4: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_store4,weak __asan_store8: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_store8,weak __asan_store16: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_store16,weak __asan_store32: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_store32,weak -__asan_unpoison_stack_memory: - ud2 - .endfn __asan_unpoison_stack_memory,weak - __asan_unregister_globals: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_unregister_globals,weak __asan_version_mismatch_check_v8: + push %rbp + mov %rsp,%rbp ud2 .endfn __asan_version_mismatch_check_v8,weak diff --git a/libc/sysv/calls/msyscall.s b/libc/sysv/calls/msyscall.s new file mode 100644 index 000000000..1eb00f37d --- /dev/null +++ b/libc/sysv/calls/msyscall.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall msyscall 0x0025ffffffffffff globl diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index d7544d1fe..3c3d458c4 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -237,8 +237,9 @@ syscon mmap MAP_SHARED 1 1 1 1 1 # forced consensus & faked nt syscon mmap MAP_PRIVATE 2 2 2 2 2 # forced consensus & faked nt syscon mmap MAP_FIXED 0x10 0x10 0x10 0x10 0x10 # unix consensus; openbsd appears to forbid; faked nt syscon mmap MAP_ANONYMOUS 0x20 0x1000 0x1000 0x1000 0x20 # bsd consensus; faked nt +syscon mmap MAP_GROWSDOWN 0x0100 0 0x0400 0x4000 0x100000 # mandatory for OpenBSD stacks; MAP_STACK on Free/OpenBSD; MEM_TOP_DOWN on NT +syscon mmap MAP_CONCEAL 0 0 0x20000 0x8000 0 # omit from core dumps; MAP_NOCORE on FreeBSD syscon mmap MAP_NORESERVE 0x4000 0x40 0 0 0 # Linux calls it "reserve"; NT calls it "commit"? which is default? -syscon mmap MAP_GROWSDOWN 0x0100 0 0x0400 0x0400 0x100000 # MAP_STACK on BSD; MEM_TOP_DOWN on NT syscon mmap MAP_HUGETLB 0x040000 0 0 0 0x80000000 # kNtSecLargePages syscon mmap MAP_HUGE_MASK 63 0 0 0 0 syscon mmap MAP_HUGE_SHIFT 26 0 0 0 0 @@ -246,6 +247,8 @@ syscon mmap MAP_LOCKED 0x2000 0 0 0 0 syscon mmap MAP_NONBLOCK 0x10000 0 0 0 0 syscon mmap MAP_POPULATE 0x8000 0 0 0 0 # can avoid madvise(MADV_WILLNEED) on private file mapping syscon mmap MAP_TYPE 15 0 0 0 0 # what is it +syscon compat MAP_STACK 0x0100 0 0x0400 0x4000 0x100000 # use MAP_GROWSDOWN +syscon compat MAP_NOCORE 0 0 0x20000 0x8000 0 # use MAP_CONCEAL syscon compat MAP_ANON 0x20 0x1000 0x1000 0x1000 0x20 # bsd consensus; faked nt syscon compat MAP_STACK 0x020000 0 0x0400 0x4000 0x100000 syscon compat MAP_EXECUTABLE 0x1000 0 0 0 0 # ignored @@ -3112,6 +3115,7 @@ syscon nr __NR_io_uring_setup 0x01a9 -1 -1 -1 -1 syscon nr __NR_io_uring_enter 0x01aa -1 -1 -1 -1 syscon nr __NR_io_uring_register 0x01ab -1 -1 -1 -1 syscon nr __NR_pledge -1 -1 -1 0x006c -1 +syscon nr __NR_msyscall -1 -1 -1 0x0025 -1 syscon nr __NR_ktrace -1 -1 0x002d 0x002d -1 syscon nr __NR_kqueue -1 0x200016a 0x016a 0x010d -1 syscon nr __NR_kevent -1 0x2000171 0x0230 0x0048 -1 diff --git a/libc/sysv/consts/MAP_CONCEAL.s b/libc/sysv/consts/MAP_CONCEAL.s new file mode 100644 index 000000000..9b1d09cfd --- /dev/null +++ b/libc/sysv/consts/MAP_CONCEAL.s @@ -0,0 +1,2 @@ +.include "libc/sysv/consts/syscon.inc" +.syscon mmap MAP_CONCEAL 0 0 0x20000 0x8000 0 diff --git a/libc/sysv/consts/MAP_GROWSDOWN.s b/libc/sysv/consts/MAP_GROWSDOWN.s index 984d336a9..af235cba3 100644 --- a/libc/sysv/consts/MAP_GROWSDOWN.s +++ b/libc/sysv/consts/MAP_GROWSDOWN.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon mmap MAP_GROWSDOWN 0x0100 0 0x0400 0x0400 0x100000 +.syscon mmap MAP_GROWSDOWN 0x0100 0 0x0400 0x4000 0x100000 diff --git a/libc/sysv/consts/MAP_NOCORE.s b/libc/sysv/consts/MAP_NOCORE.s new file mode 100644 index 000000000..57c215aa6 --- /dev/null +++ b/libc/sysv/consts/MAP_NOCORE.s @@ -0,0 +1,2 @@ +.include "libc/sysv/consts/syscon.inc" +.syscon compat MAP_NOCORE 0 0 0x20000 0x8000 0 diff --git a/libc/sysv/consts/__NR_msyscall.s b/libc/sysv/consts/__NR_msyscall.s new file mode 100644 index 000000000..6fafd5ff5 --- /dev/null +++ b/libc/sysv/consts/__NR_msyscall.s @@ -0,0 +1,2 @@ +.include "libc/sysv/consts/syscon.inc" +.syscon nr __NR_msyscall -1 -1 -1 0x0025 -1 diff --git a/libc/sysv/consts/map.h b/libc/sysv/consts/map.h index 5c3681e9d..2778fd452 100644 --- a/libc/sysv/consts/map.h +++ b/libc/sysv/consts/map.h @@ -21,7 +21,6 @@ hidden extern const long MAP_NORESERVE; hidden extern const long MAP_POPULATE; hidden extern const long MAP_PRIVATE; hidden extern const long MAP_SHARED; -hidden extern const long MAP_STACK; hidden extern const long MAP_TYPE; COSMOPOLITAN_C_END_ @@ -34,6 +33,7 @@ COSMOPOLITAN_C_END_ #define MAP_32BIT SYMBOLIC(MAP_32BIT) #define MAP_ANONYMOUS SYMBOLIC(MAP_ANONYMOUS) +#define MAP_CONCEAL SYMBOLIC(MAP_CONCEAL) #define MAP_DENYWRITE SYMBOLIC(MAP_DENYWRITE) #define MAP_EXECUTABLE SYMBOLIC(MAP_EXECUTABLE) #define MAP_GROWSDOWN SYMBOLIC(MAP_GROWSDOWN) @@ -46,7 +46,8 @@ COSMOPOLITAN_C_END_ #define MAP_POPULATE SYMBOLIC(MAP_POPULATE) #define MAP_TYPE SYMBOLIC(MAP_TYPE) -#define MAP_ANON MAP_ANONYMOUS -#define MAP_STACK MAP_GROWSDOWN +#define MAP_ANON MAP_ANONYMOUS +#define MAP_NOCORE MAP_CONCEAL +#define MAP_STACK MAP_GROWSDOWN #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_MAP_H_ */ diff --git a/libc/sysv/consts/nr.h b/libc/sysv/consts/nr.h index c2c486e41..7a57e2035 100644 --- a/libc/sysv/consts/nr.h +++ b/libc/sysv/consts/nr.h @@ -332,6 +332,7 @@ #define __NR_io_uring_enter SYMBOLIC(__NR_io_uring_enter) #define __NR_io_uring_register SYMBOLIC(__NR_io_uring_register) #define __NR_pledge SYMBOLIC(__NR_pledge) +#define __NR_msyscall SYMBOLIC(__NR_msyscall) #define __NR_ktrace SYMBOLIC(__NR_ktrace) #define __NR_kqueue SYMBOLIC(__NR_kqueue) #define __NR_kevent SYMBOLIC(__NR_kevent) @@ -1105,6 +1106,7 @@ hidden extern const long __NR_io_uring_setup; hidden extern const long __NR_io_uring_enter; hidden extern const long __NR_io_uring_register; hidden extern const long __NR_pledge; +hidden extern const long __NR_msyscall; hidden extern const long __NR_ktrace; hidden extern const long __NR_kqueue; hidden extern const long __NR_kevent; diff --git a/libc/sysv/restorert.S b/libc/sysv/restorert.S index ffbc9af9d..299bbb6b2 100644 --- a/libc/sysv/restorert.S +++ b/libc/sysv/restorert.S @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" +.text.syscall .source __FILE__ / Linux Signal Trampoline (HOLY CODE) diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index 431267a93..15b540241 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -365,6 +365,7 @@ scall io_uring_enter 0xffffffffffff01aa globl scall io_uring_register 0xffffffffffff01ab globl #────────────────────────RHEL CLOUD────────────────────────── # ←┬─ red hat terminates community release of enterprise linux circa 2020 scall pledge 0x006cffffffffffff globl # └─ online linux services ban the president of united states of america +scall msyscall 0x0025ffffffffffff globl # The Fifth Bell System Interface, Community Edition # » besiyata dishmaya diff --git a/libc/sysv/systemfive.S b/libc/sysv/systemfive.S index 16ee0077f..4d7aa8dde 100644 --- a/libc/sysv/systemfive.S +++ b/libc/sysv/systemfive.S @@ -102,6 +102,8 @@ __systemfive: .quad 0 .endobj __systemfive,globl,hidden .previous + + .text.syscall .Lanchorpoint: systemfive.linux: movswl %ax,%eax # gnu/systemd ordinal is first word @@ -256,11 +258,9 @@ systemfive.init.magnums: pop %rbx / 𝑠𝑙𝑖𝑑𝑒 #ifndef TINY -systemfive.init.stack: +systemfive.init.stack: # determinism ftw! testb IsWindows() # already did this jnz systemfive.init.done - testb IsOpenbsd() # todo fix openbsd - jnz systemfive.init.done push %rdi push %rsi mov __NR_mmap,%eax @@ -269,13 +269,20 @@ systemfive.init.stack: mov $PROT_READ|PROT_WRITE,%edx mov $MAP_PRIVATE|MAP_FIXED,%r10d or MAP_ANONYMOUS,%r10d - or MAP_GROWSDOWN,%r10d - or $-1,%r8 + or $-1,%r8d xor %r9d,%r9d push %r9 # openbsd:pad -/ clc + push %r9 # openbsd:align + testb IsOpenbsd() + jz 0f + syscall # openbsd:dubstack + jc 1f + mov __NR_mmap,%eax +0: or MAP_GROWSDOWN,%r10d # openbsd:mapstack + clc syscall pop %r9 + pop %r9 jnc 2f 1: mov %eax,%edi mov __NR_exit_group,%eax @@ -295,12 +302,26 @@ systemfive.init.stack: pop %rdi leave pop %rcx - lea STACKSIZE(%rax),%rsp + lea STACKSIZE-16(%rax),%rsp # openbsd:stackbound push %rcx xor %ebp,%ebp push %rbp mov %rsp,%rbp / 𝑠𝑙𝑖𝑑𝑒 +systemfive.init.syscall: + mov __NR_msyscall,%eax # syscall origin protect + test %eax,%eax # openbsd is pretty cool + js systemfive.init.done + push %rdi + push %rsi + .weak __text_syscall_addr + .weak __text_syscall_size + mov $__text_syscall_addr,%edi + mov $__text_syscall_size,%esi + syscall + pop %rsi + pop %rdi +/ 𝑠𝑙𝑖𝑑𝑒 #endif /* TINY */ systemfive.init.done: nop diff --git a/test/libc/str/tpenc_test.c b/test/libc/str/tpenc_test.c index 47733e9fb..7d262e518 100644 --- a/test/libc/str/tpenc_test.c +++ b/test/libc/str/tpenc_test.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/limits.h" +#include "libc/rand/rand.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/str/tpenc.h" @@ -45,7 +46,7 @@ TEST(tpenc, testBeyondTheStandard) { } uint64_t Tpenc(int x) { - return (v = tpenc(VEIL("r", x))); + return (v = EXPROPRIATE(tpenc(VEIL("r", x)))); } BENCH(tpenc, bench) { diff --git a/third_party/chibicc/tokenize.c b/third_party/chibicc/tokenize.c index 73056fcb1..568fafbc8 100644 --- a/third_party/chibicc/tokenize.c +++ b/third_party/chibicc/tokenize.c @@ -275,7 +275,7 @@ static Token *read_string_literal(char *start, char *quote) { // is called a "surrogate pair". static Token *read_utf16_string_literal(char *start, char *quote) { char *end = string_literal_end(quote + 1); - uint16_t *buf = calloc(2, end - start - 1); + uint16_t *buf = calloc(2, end - start); int len = 0; for (char *p = quote + 1; p < end;) { if (*p == '\\') { diff --git a/third_party/third_party.mk b/third_party/third_party.mk index db1822be9..63217935b 100644 --- a/third_party/third_party.mk +++ b/third_party/third_party.mk @@ -1,15 +1,10 @@ #-*-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───────────────────────┘ -# TODO(jart): make chibicc compiled chibicc work with asan runtime -ifneq ($(MODE),dbg) -THIRD_PARTY_CHIBICC_XXX = o/$(MODE)/third_party/chibicc -endif - .PHONY: o/$(MODE)/third_party o/$(MODE)/third_party: \ o/$(MODE)/third_party/blas \ - $(THIRD_PARTY_CHIBICC_XXX) \ + o/$(MODE)/third_party/chibicc \ o/$(MODE)/third_party/compiler_rt \ o/$(MODE)/third_party/dlmalloc \ o/$(MODE)/third_party/gdtoa \ diff --git a/tool/build/lib/syscall.c b/tool/build/lib/syscall.c index b2ac15305..a51ca8514 100644 --- a/tool/build/lib/syscall.c +++ b/tool/build/lib/syscall.c @@ -19,6 +19,7 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/ioctl.h" +#include "libc/calls/struct/dirent.h" #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/rusage.h" #include "libc/calls/struct/sigaction-linux.internal.h" @@ -770,6 +771,30 @@ static ssize_t OpRead(struct Machine *m, int fd, int64_t addr, size_t size) { return rc; } +static int OpGetdents(struct Machine *m, int dirfd, int64_t addr, + uint32_t size) { + int rc; + DIR *dir; + struct dirent *ent; + if (size < sizeof(struct dirent)) return einval(); + if (0 <= dirfd && dirfd < m->fds.i) { + if ((dir = fdopendir(m->fds.p[dirfd].fd))) { + rc = 0; + while (rc + sizeof(struct dirent) <= size) { + if (!(ent = readdir(dir))) break; + VirtualRecvWrite(m, addr + rc, ent, ent->d_reclen); + rc += ent->d_reclen; + } + free(dir); + } else { + rc = -1; + } + } else { + rc = ebadf(); + } + return rc; +} + static ssize_t OpPread(struct Machine *m, int fd, int64_t addr, size_t size, int64_t offset) { ssize_t rc; @@ -1395,6 +1420,7 @@ void OpSyscall(struct Machine *m, uint32_t rde) { SYSCALL(0x09E, OpArchPrctl(m, di, si)); SYSCALL(0x0BA, OpGetTid(m)); SYSCALL(0x0CB, sched_setaffinity(di, si, P(dx))); + SYSCALL(0x0D9, OpGetdents(m, di, si, dx)); SYSCALL(0x0DD, OpFadvise(m, di, si, dx, r0)); SYSCALL(0x0E4, OpClockGettime(m, di, si)); SYSCALL(0x101, OpOpenat(m, di, si, dx, r0)); diff --git a/tool/emacs/cosmo-c-keywords.el b/tool/emacs/cosmo-c-keywords.el index 1af8f1ca3..ad8a5243e 100644 --- a/tool/emacs/cosmo-c-keywords.el +++ b/tool/emacs/cosmo-c-keywords.el @@ -176,6 +176,7 @@ "interruptfn" "nocallback" "textstartup" + "textsyscall" "warnifused" "attributeallocsize" "attributeallocalign" diff --git a/tool/emacs/cosmo-stuff.el b/tool/emacs/cosmo-stuff.el index 2c8fbbf43..eeb77c7cc 100644 --- a/tool/emacs/cosmo-stuff.el +++ b/tool/emacs/cosmo-stuff.el @@ -441,7 +441,7 @@ (cond ((not (eq 0 (logand 8 arg))) (cosmo--assembly (setq arg (logand (lognot 8))) "SILENT=0 OVERRIDE_COPTS='-fverbose-asm -fsanitize=address'")) - (t (cosmo--assembly arg "SILENT=0 OVERRIDE_COPTS='-fverbose-asm -fsanitize=address' CPPFLAGS='-DSTACK_FRAME_UNLIMITED'")))) + (t (cosmo--assembly arg "SILENT=0 OVERRIDE_COPTS='' CPPFLAGS='-DSTACK_FRAME_UNLIMITED'")))) (defun cosmo-assembly-native (arg) (interactive "P") From 23a14b537c4114bca5e6172608f849a231bdda74 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Tue, 2 Feb 2021 22:17:53 -0800 Subject: [PATCH 3/5] Delete LIBC_CALLS_HEFTY - fork() no longer requires malloc() - readdir() moved to LIBC_STDIO - Custom APIs moved to LIBC_X --- Makefile | 2 - examples/cp.c | 2 +- examples/examples.mk | 1 - examples/nesemu1.cc | 6 +- libc/calls/calls.mk | 4 +- libc/calls/{hefty => }/copyfile.c | 2 +- libc/calls/{hefty => }/copyfile.h | 6 +- libc/calls/execve-nt.c | 2 +- libc/calls/getenv.c | 3 - libc/calls/hefty/hefty.mk | 72 ------------------- libc/calls/ioctl.c | 1 + libc/calls/mkntenvblock.c | 11 ++- libc/calls/ntspawn.c | 5 +- libc/calls/ntspawn.h | 10 +-- libc/calls/openat.c | 9 ++- libc/calls/sigaction.c | 1 + libc/calls/{hefty => }/ttyname.c | 0 libc/calls/{hefty => }/ttyname_r.c | 0 libc/log/backtrace2.c | 10 --- libc/log/commandvenv.c | 27 ++++--- libc/log/log.h | 2 +- libc/log/log.mk | 1 - libc/{calls/hefty => runtime}/fork-nt.c | 51 ++++++------- libc/{calls/hefty => runtime}/fork.c | 0 libc/{calls/hefty => runtime}/vfork.S | 0 libc/{calls/hefty => stdio}/dirstream.c | 0 .../hefty => stdio}/get_current_dir_name.c | 0 libc/stdio/stdio.mk | 1 - libc/{calls/hefty => x}/filecmp.c | 0 libc/{calls/hefty => x}/replaceuser.c | 0 libc/x/x.mk | 1 - test/libc/calls/{hefty => }/fork_test.c | 0 test/libc/calls/mkntenvblock_test.c | 17 ++++- test/libc/calls/test.mk | 5 +- test/libc/calls/{hefty => }/vfork_test.c | 0 .../{calls/hefty => stdio}/dirstream_test.c | 0 test/libc/stdio/test.mk | 1 + third_party/chibicc/chibicc.mk | 1 - third_party/musl/musl.mk | 1 - tool/build/build.mk | 1 - tool/build/lib/buildlib.mk | 1 - tool/net/net.mk | 1 - tool/viz/printvideo.c | 4 +- tool/viz/viz.mk | 1 - 44 files changed, 95 insertions(+), 168 deletions(-) rename libc/calls/{hefty => }/copyfile.c (99%) rename libc/calls/{hefty => }/copyfile.h (66%) delete mode 100644 libc/calls/hefty/hefty.mk rename libc/calls/{hefty => }/ttyname.c (100%) rename libc/calls/{hefty => }/ttyname_r.c (100%) rename libc/{calls/hefty => runtime}/fork-nt.c (86%) rename libc/{calls/hefty => runtime}/fork.c (100%) rename libc/{calls/hefty => runtime}/vfork.S (100%) rename libc/{calls/hefty => stdio}/dirstream.c (100%) rename libc/{calls/hefty => stdio}/get_current_dir_name.c (100%) rename libc/{calls/hefty => x}/filecmp.c (100%) rename libc/{calls/hefty => x}/replaceuser.c (100%) rename test/libc/calls/{hefty => }/fork_test.c (100%) rename test/libc/calls/{hefty => }/vfork_test.c (100%) rename test/libc/{calls/hefty => stdio}/dirstream_test.c (100%) diff --git a/Makefile b/Makefile index 03ed5172d..37cf9490d 100644 --- a/Makefile +++ b/Makefile @@ -116,7 +116,6 @@ include libc/zipos/zipos.mk # │ include third_party/gdtoa/gdtoa.mk # │ include libc/time/time.mk # │ include libc/alg/alg.mk # │ -include libc/calls/hefty/hefty.mk # │ include libc/stdio/stdio.mk # │ include third_party/f2c/f2c.mk # │ include third_party/blas/blas.mk # │ @@ -252,7 +251,6 @@ COSMOPOLITAN_OBJECTS = \ APE_LIB \ THIRD_PARTY_MUSL \ LIBC_STDIO \ - LIBC_CALLS_HEFTY \ THIRD_PARTY_REGEX \ LIBC_ALG \ LIBC_MEM \ diff --git a/examples/cp.c b/examples/cp.c index 0a6d558f1..0df70114a 100644 --- a/examples/cp.c +++ b/examples/cp.c @@ -8,7 +8,7 @@ ╚─────────────────────────────────────────────────────────────────*/ #endif #include "libc/calls/calls.h" -#include "libc/calls/hefty/copyfile.h" +#include "libc/calls/copyfile.h" #include "libc/errno.h" #include "libc/fmt/conv.h" #include "libc/fmt/fmt.h" diff --git a/examples/examples.mk b/examples/examples.mk index 3b96bb137..5c8fda62a 100644 --- a/examples/examples.mk +++ b/examples/examples.mk @@ -44,7 +44,6 @@ EXAMPLES_DIRECTDEPS = \ LIBC_ALG \ LIBC_BITS \ LIBC_CALLS \ - LIBC_CALLS_HEFTY \ LIBC_FMT \ LIBC_INTRIN \ LIBC_LOG \ diff --git a/examples/nesemu1.cc b/examples/nesemu1.cc index 6cc6a69fb..b5e5664b5 100644 --- a/examples/nesemu1.cc +++ b/examples/nesemu1.cc @@ -154,7 +154,6 @@ static bool resized_; static size_t vtsize_; static bool artifacts_; static long tyn_, txn_; -static const char* ffplay_; static struct Frame vf_[2]; static struct Audio audio_; static const char* inputfn_; @@ -1685,6 +1684,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) { FILE* fp; int devnull; int pipefds[2]; + const char* ffplay; inputfn_ = opt_tasfile; if (!(fp = fopen(romfile, "rb"))) { @@ -1701,7 +1701,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) { // open speaker // todo: this needs plenty of work - if ((ffplay_ = commandvenv("FFPLAY", "ffplay"))) { + if ((ffplay = commandvenv("FFPLAY", "ffplay"))) { devnull = open("/dev/null", O_WRONLY | O_CLOEXEC); pipe2(pipefds, O_CLOEXEC); if (!(playpid_ = vfork())) { @@ -1713,7 +1713,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) { dup2(pipefds[0], 0); dup2(devnull, 1); dup2(devnull, 2); - execv(ffplay_, (char* const*)args); + execv(ffplay, (char* const*)args); abort(); } close(pipefds[0]); diff --git a/libc/calls/calls.mk b/libc/calls/calls.mk index c7f103d63..ec5993a26 100644 --- a/libc/calls/calls.mk +++ b/libc/calls/calls.mk @@ -94,6 +94,4 @@ LIBC_CALLS_OBJS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_OBJS)) LIBC_CALLS_TESTS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_TESTS)) .PHONY: o/$(MODE)/libc/calls -o/$(MODE)/libc/calls: \ - o/$(MODE)/libc/calls/hefty \ - $(LIBC_CALLS_CHECKS) +o/$(MODE)/libc/calls: $(LIBC_CALLS_CHECKS) diff --git a/libc/calls/hefty/copyfile.c b/libc/calls/copyfile.c similarity index 99% rename from libc/calls/hefty/copyfile.c rename to libc/calls/copyfile.c index 47fc77dd4..d32e1801a 100644 --- a/libc/calls/hefty/copyfile.c +++ b/libc/calls/copyfile.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/hefty/copyfile.h" +#include "libc/calls/copyfile.h" #include "libc/calls/internal.h" #include "libc/calls/struct/stat.h" #include "libc/dce.h" diff --git a/libc/calls/hefty/copyfile.h b/libc/calls/copyfile.h similarity index 66% rename from libc/calls/hefty/copyfile.h rename to libc/calls/copyfile.h index 0f0c78ed6..f9ba2f877 100644 --- a/libc/calls/hefty/copyfile.h +++ b/libc/calls/copyfile.h @@ -1,5 +1,5 @@ -#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_ -#define COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_ +#ifndef COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_ +#define COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_ #define COPYFILE_NOCLOBBER 1 #define COPYFILE_PRESERVE_OWNER 2 @@ -12,4 +12,4 @@ int copyfile(const char *, const char *, int) paramsnonnull(); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_ */ +#endif /* COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_ */ diff --git a/libc/calls/execve-nt.c b/libc/calls/execve-nt.c index 49ff0296f..c6c5a476e 100644 --- a/libc/calls/execve-nt.c +++ b/libc/calls/execve-nt.c @@ -47,7 +47,7 @@ textwindows int execve$nt(const char *program, char *const argv[], close(i); } } - rc = ntspawn(program, argv, envp, NULL, NULL, true, 0, NULL, &startinfo, + rc = ntspawn(program, argv, envp, NULL, NULL, NULL, true, 0, NULL, &startinfo, &procinfo); if (rc == -1) return -1; CloseHandle(procinfo.hThread); diff --git a/libc/calls/getenv.c b/libc/calls/getenv.c index a6ea91c28..cff58f1e9 100644 --- a/libc/calls/getenv.c +++ b/libc/calls/getenv.c @@ -16,10 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/bits.h" -#include "libc/bits/safemacros.h" #include "libc/runtime/runtime.h" -#include "libc/str/str.h" /** * Returns value of environment variable, or NULL if not found. diff --git a/libc/calls/hefty/hefty.mk b/libc/calls/hefty/hefty.mk deleted file mode 100644 index 36914e522..000000000 --- a/libc/calls/hefty/hefty.mk +++ /dev/null @@ -1,72 +0,0 @@ -#-*-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───────────────────────┘ -# -# SYNOPSIS -# -# Cosmopolitan System Call Compatibility Layer -# -# DESCRIPTION -# -# This subpackage exports functions traditionally understood as system -# calls that Cosmopolitan needs to wrap in a nontrivial way, requiring -# things like dynamic memory allocation. - -PKGS += LIBC_CALLS_HEFTY - -LIBC_CALLS_HEFTY_ARTIFACTS += LIBC_CALLS_HEFTY_A -LIBC_CALLS_HEFTY = $(LIBC_CALLS_HEFTY_A_DEPS) $(LIBC_CALLS_HEFTY_A) -LIBC_CALLS_HEFTY_A = o/$(MODE)/libc/calls/hefty/hefty.a -LIBC_CALLS_HEFTY_A_FILES := $(wildcard libc/calls/hefty/*) -LIBC_CALLS_HEFTY_A_HDRS = $(filter %.h,$(LIBC_CALLS_HEFTY_A_FILES)) -LIBC_CALLS_HEFTY_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_HEFTY_A_FILES)) -LIBC_CALLS_HEFTY_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_HEFTY_A_FILES)) - -LIBC_CALLS_HEFTY_A_SRCS = \ - $(LIBC_CALLS_HEFTY_A_SRCS_S) \ - $(LIBC_CALLS_HEFTY_A_SRCS_C) - -LIBC_CALLS_HEFTY_A_OBJS = \ - $(LIBC_CALLS_HEFTY_A_SRCS_S:%.S=o/$(MODE)/%.o) \ - $(LIBC_CALLS_HEFTY_A_SRCS_C:%.c=o/$(MODE)/%.o) - -LIBC_CALLS_HEFTY_A_CHECKS = \ - $(LIBC_CALLS_HEFTY_A).pkg \ - $(LIBC_CALLS_HEFTY_A_HDRS:%=o/$(MODE)/%.ok) - -LIBC_CALLS_HEFTY_A_DIRECTDEPS = \ - LIBC_ALG \ - LIBC_CALLS \ - LIBC_FMT \ - LIBC_INTRIN \ - LIBC_MEM \ - LIBC_NEXGEN32E \ - LIBC_NT_KERNEL32 \ - LIBC_RUNTIME \ - LIBC_STR \ - LIBC_STUBS \ - LIBC_SYSV \ - LIBC_SYSV_CALLS - -LIBC_CALLS_HEFTY_A_DEPS := \ - $(call uniq,$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x)))) - -$(LIBC_CALLS_HEFTY_A): \ - libc/calls/hefty/ \ - $(LIBC_CALLS_HEFTY_A).pkg \ - $(LIBC_CALLS_HEFTY_A_OBJS) - -$(LIBC_CALLS_HEFTY_A).pkg: \ - $(LIBC_CALLS_HEFTY_A_OBJS) \ - $(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x)_A).pkg) - -LIBC_CALLS_HEFTY_LIBS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x))) -LIBC_CALLS_HEFTY_SRCS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_SRCS)) -LIBC_CALLS_HEFTY_HDRS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_HDRS)) -LIBC_CALLS_HEFTY_BINS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_BINS)) -LIBC_CALLS_HEFTY_CHECKS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_CHECKS)) -LIBC_CALLS_HEFTY_OBJS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_OBJS)) -LIBC_CALLS_HEFTY_TESTS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_TESTS)) -$(LIBC_CALLS_HEFTY_OBJS): $(BUILD_FILES) libc/calls/hefty/hefty.mk - -.PHONY: o/$(MODE)/libc/calls/hefty -o/$(MODE)/libc/calls/hefty: $(LIBC_CALLS_HEFTY_CHECKS) diff --git a/libc/calls/ioctl.c b/libc/calls/ioctl.c index 1aac73136..4b3e5f864 100644 --- a/libc/calls/ioctl.c +++ b/libc/calls/ioctl.c @@ -25,6 +25,7 @@ /** * Controls settings on device. + * @vforksafe */ int(ioctl)(int fd, uint64_t request, void *memory) { __IOCTL_DISPATCH(EQUAL, fd, request, memory); diff --git a/libc/calls/mkntenvblock.c b/libc/calls/mkntenvblock.c index 0ec52f5e1..beae3b238 100644 --- a/libc/calls/mkntenvblock.c +++ b/libc/calls/mkntenvblock.c @@ -51,18 +51,23 @@ static void SortStrings(char **a, size_t n) { * * This is designed to meet the requirements of CreateProcess(). * + * @param envvars receives sorted double-NUL terminated string list * @param envp is an a NULL-terminated array of UTF-8 strings - * @return freshly allocated lpEnvironment or NULL w/ errno + * @param extravar is a VAR=val string we consider part of envp or NULL + * @return 0 on success, or -1 w/ errno + * @error E2BIG if total number of shorts exceeded ARG_MAX (0x8000) */ -textwindows int mkntenvblock(char16_t envvars[ARG_MAX], char *const envp[]) { +textwindows int mkntenvblock(char16_t envvars[ARG_MAX], char *const envp[], + const char *extravar) { axdx_t rc; uint64_t w; char **vars; wint_t x, y; size_t i, j, k, n, m; for (n = 0; envp[n];) n++; - vars = alloca(n * sizeof(char *)); + vars = alloca((n + 1) * sizeof(char *)); memcpy(vars, envp, n * sizeof(char *)); + if (extravar) vars[n++] = extravar; SortStrings(vars, n); for (k = i = 0; i < n; ++i) { j = 0; diff --git a/libc/calls/ntspawn.c b/libc/calls/ntspawn.c index a3606b50d..1ee9b41dd 100644 --- a/libc/calls/ntspawn.c +++ b/libc/calls/ntspawn.c @@ -48,6 +48,7 @@ struct SpawnBlock { * don't need to be passed in sorted order; however, this function * goes faster the closer they are to sorted * @param envp[m-1] is NULL + * @param extravar is added to envp to avoid setenv() in caller * @param bInheritHandles means handles already marked inheritable will * be inherited; which, assuming the System V wrapper functions are * being used, should mean (1) all files and sockets that weren't @@ -59,7 +60,7 @@ struct SpawnBlock { */ textwindows int ntspawn( const char *prog, char *const argv[], char *const envp[], - struct NtSecurityAttributes *opt_lpProcessAttributes, + const char *extravar, struct NtSecurityAttributes *opt_lpProcessAttributes, struct NtSecurityAttributes *opt_lpThreadAttributes, bool32 bInheritHandles, uint32_t dwCreationFlags, const char16_t *opt_lpCurrentDirectory, const struct NtStartupInfo *lpStartupInfo, @@ -81,7 +82,7 @@ textwindows int ntspawn( MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0, blocksize, NULL, kNtNumaNoPreferredNode))) { if (mkntcmdline(block->cmdline, prog, argv) != -1 && - mkntenvblock(block->envvars, envp) != -1) { + mkntenvblock(block->envvars, envp, extravar) != -1) { if (CreateProcess(NULL, block->cmdline, opt_lpProcessAttributes, opt_lpThreadAttributes, bInheritHandles, dwCreationFlags | kNtCreateUnicodeEnvironment, diff --git a/libc/calls/ntspawn.h b/libc/calls/ntspawn.h index 6933ed293..b794d5cce 100644 --- a/libc/calls/ntspawn.h +++ b/libc/calls/ntspawn.h @@ -1,5 +1,5 @@ -#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_ -#define COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_ +#ifndef COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_ +#define COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_ #include "libc/nt/struct/processinformation.h" #include "libc/nt/struct/securityattributes.h" #include "libc/nt/struct/startupinfo.h" @@ -7,12 +7,12 @@ COSMOPOLITAN_C_START_ int mkntcmdline(char16_t[ARG_MAX], const char *, char *const[]) hidden; -int mkntenvblock(char16_t[ARG_MAX], char *const[]) hidden; -int ntspawn(const char *, char *const[], char *const[], +int mkntenvblock(char16_t[ARG_MAX], char *const[], const char *) hidden; +int ntspawn(const char *, char *const[], char *const[], const char *, struct NtSecurityAttributes *, struct NtSecurityAttributes *, bool32, uint32_t, const char16_t *, const struct NtStartupInfo *, struct NtProcessInformation *) hidden; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_ */ +#endif /* COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_ */ diff --git a/libc/calls/openat.c b/libc/calls/openat.c index ccac9b901..5955a85cb 100644 --- a/libc/calls/openat.c +++ b/libc/calls/openat.c @@ -37,6 +37,7 @@ * ignored if O_CREAT or O_TMPFILE weren't passed * @return number needing close(), or -1 w/ errno * @asyncsignalsafe + * @vforksafe */ nodiscard int openat(int dirfd, const char *file, int flags, ...) { va_list va; @@ -47,11 +48,9 @@ nodiscard int openat(int dirfd, const char *file, int flags, ...) { va_end(va); if (!file) return efault(); if (weaken(__zipos_open) && weaken(__zipos_parseuri)(file, &zipname) != -1) { - if (dirfd == AT_FDCWD) { - return weaken(__zipos_open)(&zipname, flags, mode); - } else { - return eopnotsupp(); /* TODO */ - } + if (__vforked) return einval(); + if (dirfd != AT_FDCWD) return einval(); + return weaken(__zipos_open)(&zipname, flags, mode); } else if (!IsWindows()) { return openat$sysv(dirfd, file, flags, mode); } else { diff --git a/libc/calls/sigaction.c b/libc/calls/sigaction.c index 5a6b94f1b..8ea675b3e 100644 --- a/libc/calls/sigaction.c +++ b/libc/calls/sigaction.c @@ -118,6 +118,7 @@ static void sigaction$native2cosmo(union metasigaction *sa) { * * @see xsigaction() for a much better api * @asyncsignalsafe + * @vforksafe */ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) { _Static_assert(sizeof(struct sigaction) > sizeof(struct sigaction$linux) && diff --git a/libc/calls/hefty/ttyname.c b/libc/calls/ttyname.c similarity index 100% rename from libc/calls/hefty/ttyname.c rename to libc/calls/ttyname.c diff --git a/libc/calls/hefty/ttyname_r.c b/libc/calls/ttyname_r.c similarity index 100% rename from libc/calls/hefty/ttyname_r.c rename to libc/calls/ttyname_r.c diff --git a/libc/log/backtrace2.c b/libc/log/backtrace2.c index eb34bc68d..8d28e0ea2 100644 --- a/libc/log/backtrace2.c +++ b/libc/log/backtrace2.c @@ -48,7 +48,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) { struct Garbages *garbage; sigset_t chldmask, savemask; const struct StackFrame *frame; - struct sigaction ignore, saveint, savequit; const char *debugbin, *p1, *p2, *p3, *addr2line; char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames]; if (IsOpenbsd()) return -1; @@ -77,18 +76,11 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) { j += uint64toarray_radix16(addr - 1, buf + j) + 1; } argv[i++] = NULL; - ignore.sa_flags = 0; - ignore.sa_handler = SIG_IGN; - sigemptyset(&ignore.sa_mask); - sigaction(SIGINT, &ignore, &saveint); - sigaction(SIGQUIT, &ignore, &savequit); sigemptyset(&chldmask); sigaddset(&chldmask, SIGCHLD); sigprocmask(SIG_BLOCK, &chldmask, &savemask); pipe(pipefds); if (!(pid = vfork())) { - sigaction(SIGINT, &saveint, NULL); - sigaction(SIGQUIT, &savequit, NULL); sigprocmask(SIG_SETMASK, &savemask, NULL); dup2(pipefds[1], 1); close(pipefds[0]); @@ -124,8 +116,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) { if (errno == EINTR) continue; return -1; } - sigaction(SIGINT, &saveint, NULL); - sigaction(SIGQUIT, &savequit, NULL); sigprocmask(SIG_SETMASK, &savemask, NULL); if (WIFEXITED(ws) && !WEXITSTATUS(ws)) { return 0; diff --git a/libc/log/commandvenv.c b/libc/log/commandvenv.c index 13d1ca39a..38b89131d 100644 --- a/libc/log/commandvenv.c +++ b/libc/log/commandvenv.c @@ -25,19 +25,30 @@ /** * Finds full executable path in overridable way. + * + * This is a higher level version of the commandv() function. Programs + * that spawn subprocesses can use this function to determine the path + * at startup. + * + * @param var is environment variable which may be used to override + * PATH search, and it can force a NULL result if it's empty + * @param cmd is name of program, which is returned asap if it's an + * absolute path + * @return pointer to exe path string, or NULL if it couldn't be found + * or the environment variable was empty; noting that the caller + * should copy this string before saving it */ -nodiscard char *commandvenv(const char *var, const char *cmd) { +const char *commandvenv(const char *var, const char *cmd) { const char *exepath; - char pathbuf[PATH_MAX]; + static char pathbuf[PATH_MAX]; + if (*cmd == '/' || *cmd == '\\') return cmd; if ((exepath = getenv(var))) { - if (!isempty(exepath) && access(exepath, X_OK) != -1) { - return strdup(exepath); + if (isempty(exepath)) return NULL; + if (access(exepath, X_OK) != -1) { + return exepath; } else { return NULL; } - } else if ((exepath = commandv(cmd, pathbuf))) { - return strdup(exepath); - } else { - return NULL; } + return commandv(cmd, pathbuf); } diff --git a/libc/log/log.h b/libc/log/log.h index c92f29776..48424363e 100644 --- a/libc/log/log.h +++ b/libc/log/log.h @@ -40,7 +40,7 @@ void memsummary(int); /* light version of same thing */ uint16_t getttycols(uint16_t); int getttysize(int, struct winsize *) paramsnonnull(); bool IsTerminalInarticulate(void) nosideeffect; -char *commandvenv(const char *, const char *) nodiscard; +const char *commandvenv(const char *, const char *); const char *GetAddr2linePath(void); const char *GetGdbPath(void); diff --git a/libc/log/log.mk b/libc/log/log.mk index f0aa754f1..9418a904d 100644 --- a/libc/log/log.mk +++ b/libc/log/log.mk @@ -28,7 +28,6 @@ LIBC_LOG_A_CHECKS = \ LIBC_LOG_A_DIRECTDEPS = \ LIBC_ALG \ LIBC_CALLS \ - LIBC_CALLS_HEFTY \ LIBC_ELF \ LIBC_FMT \ LIBC_INTRIN \ diff --git a/libc/calls/hefty/fork-nt.c b/libc/runtime/fork-nt.c similarity index 86% rename from libc/calls/hefty/fork-nt.c rename to libc/runtime/fork-nt.c index ed465a2ff..e0be9f52d 100644 --- a/libc/calls/hefty/fork-nt.c +++ b/libc/runtime/fork-nt.c @@ -46,13 +46,14 @@ #include "libc/sysv/consts/sig.h" #include "libc/sysv/errfuns.h" -static textwindows int64_t ParseInt(char16_t **p) { - uint64_t x = 0; - while ('0' <= **p && **p <= '9') { - x *= 10; - x += *(*p)++ - '0'; +static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) { + *x = 0; + while (*p == ' ') p++; + while ('0' <= *p && *p <= '9') { + *x *= 10; + *x += *p++ - '0'; } - return x; + return p; } static noinline textwindows void ForkIo(int64_t h, void *buf, size_t n, @@ -74,32 +75,28 @@ static noinline textwindows void ReadAll(int64_t h, void *buf, size_t n) { } textwindows void WinMainForked(void) { - int64_t h; void *addr; jmp_buf jb; - char16_t *p; uint64_t size; uint32_t i, varlen; struct DirectMap dm; + int64_t reader, writer; char16_t var[21 + 1 + 21 + 1]; varlen = GetEnvironmentVariable(u"_FORK", var, ARRAYLEN(var)); + if (!varlen) return; + if (varlen >= ARRAYLEN(var)) ExitProcess(123); SetEnvironmentVariable(u"_FORK", NULL); - if (!varlen || varlen >= ARRAYLEN(var)) return; - p = var; - h = ParseInt(&p); - if (*p++ == ' ') CloseHandle(ParseInt(&p)); - ReadAll(h, jb, sizeof(jb)); - ReadAll(h, &_mmi.i, sizeof(_mmi.i)); + ParseInt(ParseInt(var, &reader), &writer); + ReadAll(reader, jb, sizeof(jb)); + ReadAll(reader, &_mmi.i, sizeof(_mmi.i)); for (i = 0; i < _mmi.i; ++i) { - ReadAll(h, &_mmi.p[i], sizeof(_mmi.p[i])); + ReadAll(reader, &_mmi.p[i], sizeof(_mmi.p[i])); addr = (void *)((uint64_t)_mmi.p[i].x << 16); size = ((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE; if (_mmi.p[i].flags & MAP_PRIVATE) { CloseHandle(_mmi.p[i].h); - _mmi.p[i].h = - __mmap$nt(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC, -1, 0) - .maphandle; - ReadAll(h, addr, size); + _mmi.p[i].h = __mmap$nt(addr, size, _mmi.p[i].prot, -1, 0).maphandle; + ReadAll(reader, addr, size); } else { MapViewOfFileExNuma( _mmi.p[i].h, @@ -109,9 +106,9 @@ textwindows void WinMainForked(void) { 0, 0, size, addr, kNtNumaNoPreferredNode); } } - ReadAll(h, _edata, _end - _edata); - CloseHandle(h); - unsetenv("_FORK"); + ReadAll(reader, _edata, _end - _edata); + CloseHandle(reader); + CloseHandle(writer); if (weaken(__wincrash$nt)) { AddVectoredExceptionHandler(1, (void *)weaken(__wincrash$nt)); } @@ -123,17 +120,16 @@ textwindows int fork$nt(void) { int i, rc, pid; char exe[PATH_MAX]; int64_t reader, writer; - char *p, buf[21 + 1 + 21 + 1]; + char *p, forkvar[6 + 21 + 1 + 21 + 1]; struct NtStartupInfo startinfo; struct NtProcessInformation procinfo; if ((pid = __getemptyfd()) == -1) return -1; if (!setjmp(jb)) { if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) { - p = buf; + p = stpcpy(forkvar, "_FORK="); p += uint64toarray_radix10(reader, p); *p++ = ' '; p += uint64toarray_radix10(writer, p); - setenv("_FORK", buf, true); memset(&startinfo, 0, sizeof(startinfo)); startinfo.cb = sizeof(struct NtStartupInfo); startinfo.dwFlags = kNtStartfUsestdhandles; @@ -141,8 +137,8 @@ textwindows int fork$nt(void) { startinfo.hStdOutput = g_fds.p[1].handle; startinfo.hStdError = g_fds.p[2].handle; GetModuleFileNameA(0, exe, ARRAYLEN(exe)); - if (ntspawn(exe, g_argv, environ, &kNtIsInheritable, NULL, true, 0, NULL, - &startinfo, &procinfo) != -1) { + if (ntspawn(exe, g_argv, environ, forkvar, &kNtIsInheritable, NULL, true, + 0, NULL, &startinfo, &procinfo) != -1) { CloseHandle(reader); CloseHandle(procinfo.hThread); if (weaken(__sighandrvas) && @@ -167,7 +163,6 @@ textwindows int fork$nt(void) { } else { rc = -1; } - unsetenv("_FORK"); rc = pid; } else { rc = __winerr(); diff --git a/libc/calls/hefty/fork.c b/libc/runtime/fork.c similarity index 100% rename from libc/calls/hefty/fork.c rename to libc/runtime/fork.c diff --git a/libc/calls/hefty/vfork.S b/libc/runtime/vfork.S similarity index 100% rename from libc/calls/hefty/vfork.S rename to libc/runtime/vfork.S diff --git a/libc/calls/hefty/dirstream.c b/libc/stdio/dirstream.c similarity index 100% rename from libc/calls/hefty/dirstream.c rename to libc/stdio/dirstream.c diff --git a/libc/calls/hefty/get_current_dir_name.c b/libc/stdio/get_current_dir_name.c similarity index 100% rename from libc/calls/hefty/get_current_dir_name.c rename to libc/stdio/get_current_dir_name.c diff --git a/libc/stdio/stdio.mk b/libc/stdio/stdio.mk index 221aa9f7f..e2fb92791 100644 --- a/libc/stdio/stdio.mk +++ b/libc/stdio/stdio.mk @@ -27,7 +27,6 @@ LIBC_STDIO_A_DIRECTDEPS = \ LIBC_ALG \ LIBC_BITS \ LIBC_CALLS \ - LIBC_CALLS_HEFTY \ LIBC_FMT \ LIBC_INTRIN \ LIBC_MEM \ diff --git a/libc/calls/hefty/filecmp.c b/libc/x/filecmp.c similarity index 100% rename from libc/calls/hefty/filecmp.c rename to libc/x/filecmp.c diff --git a/libc/calls/hefty/replaceuser.c b/libc/x/replaceuser.c similarity index 100% rename from libc/calls/hefty/replaceuser.c rename to libc/x/replaceuser.c diff --git a/libc/x/x.mk b/libc/x/x.mk index 8471121ae..6a8ca91ef 100644 --- a/libc/x/x.mk +++ b/libc/x/x.mk @@ -34,7 +34,6 @@ LIBC_X_A_CHECKS = \ LIBC_X_A_DIRECTDEPS = \ LIBC_CALLS \ - LIBC_CALLS_HEFTY \ LIBC_FMT \ LIBC_INTRIN \ LIBC_MEM \ diff --git a/test/libc/calls/hefty/fork_test.c b/test/libc/calls/fork_test.c similarity index 100% rename from test/libc/calls/hefty/fork_test.c rename to test/libc/calls/fork_test.c diff --git a/test/libc/calls/mkntenvblock_test.c b/test/libc/calls/mkntenvblock_test.c index cd4e395a8..cdc9e77cd 100644 --- a/test/libc/calls/mkntenvblock_test.c +++ b/test/libc/calls/mkntenvblock_test.c @@ -24,13 +24,13 @@ char16_t envvars[ARG_MAX]; TEST(mkntenvblock, emptyList_onlyOutputsDoubleNulStringTerminator) { char *envp[] = {NULL}; - ASSERT_NE(-1, mkntenvblock(envvars, envp)); + ASSERT_NE(-1, mkntenvblock(envvars, envp, NULL)); ASSERT_BINEQ(u"  ", envvars); } TEST(mkntenvblock, envp_becomesSortedDoubleNulTerminatedUtf16String) { char *envp[] = {"u=b", "c=d", "韩=非", "uh=d", "hduc=d", NULL}; - ASSERT_NE(-1, mkntenvblock(envvars, envp)); + ASSERT_NE(-1, mkntenvblock(envvars, envp, NULL)); ASSERT_BINEQ(u"c = d   " u"h d u c = d   " u"u = b   " @@ -39,3 +39,16 @@ TEST(mkntenvblock, envp_becomesSortedDoubleNulTerminatedUtf16String) { u"  ", envvars); } + +TEST(mkntenvblock, extraVar_getsAdded) { + char *envp[] = {"u=b", "c=d", "韩=非", "uh=d", "hduc=d", NULL}; + ASSERT_NE(-1, mkntenvblock(envvars, envp, "a=a")); + ASSERT_BINEQ(u"a = a   " + u"c = d   " + u"h d u c = d   " + u"u = b   " + u"u h = d   " + u"Θù= ^ù  " + u"  ", + envvars); +} diff --git a/test/libc/calls/test.mk b/test/libc/calls/test.mk index 49c60e349..92080975a 100644 --- a/test/libc/calls/test.mk +++ b/test/libc/calls/test.mk @@ -4,8 +4,7 @@ PKGS += TEST_LIBC_CALLS TEST_LIBC_CALLS_SRCS := \ - $(wildcard test/libc/calls/*.c) \ - $(wildcard test/libc/calls/hefty/*.c) + $(wildcard test/libc/calls/*.c) TEST_LIBC_CALLS_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_CALLS_SRCS)) TEST_LIBC_CALLS_OBJS = \ @@ -26,13 +25,13 @@ TEST_LIBC_CALLS_CHECKS = \ TEST_LIBC_CALLS_DIRECTDEPS = \ LIBC_CALLS \ - LIBC_CALLS_HEFTY \ LIBC_FMT \ LIBC_INTRIN \ LIBC_LOG \ LIBC_MEM \ LIBC_NEXGEN32E \ LIBC_RAND \ + LIBC_STDIO \ LIBC_RUNTIME \ LIBC_STR \ LIBC_STUBS \ diff --git a/test/libc/calls/hefty/vfork_test.c b/test/libc/calls/vfork_test.c similarity index 100% rename from test/libc/calls/hefty/vfork_test.c rename to test/libc/calls/vfork_test.c diff --git a/test/libc/calls/hefty/dirstream_test.c b/test/libc/stdio/dirstream_test.c similarity index 100% rename from test/libc/calls/hefty/dirstream_test.c rename to test/libc/stdio/dirstream_test.c diff --git a/test/libc/stdio/test.mk b/test/libc/stdio/test.mk index 565fa0c01..5a727767b 100644 --- a/test/libc/stdio/test.mk +++ b/test/libc/stdio/test.mk @@ -29,6 +29,7 @@ TEST_LIBC_STDIO_DIRECTDEPS = \ LIBC_INTRIN \ LIBC_MEM \ LIBC_NEXGEN32E \ + LIBC_RAND \ LIBC_RUNTIME \ LIBC_STDIO \ LIBC_STR \ diff --git a/third_party/chibicc/chibicc.mk b/third_party/chibicc/chibicc.mk index 2dad14334..afede2673 100644 --- a/third_party/chibicc/chibicc.mk +++ b/third_party/chibicc/chibicc.mk @@ -51,7 +51,6 @@ THIRD_PARTY_CHIBICC_A_DIRECTDEPS = \ LIBC_ALG \ LIBC_BITS \ LIBC_CALLS \ - LIBC_CALLS_HEFTY \ LIBC_FMT \ LIBC_INTRIN \ LIBC_LOG \ diff --git a/third_party/musl/musl.mk b/third_party/musl/musl.mk index d1b5b69bb..0e592f927 100644 --- a/third_party/musl/musl.mk +++ b/third_party/musl/musl.mk @@ -19,7 +19,6 @@ THIRD_PARTY_MUSL_A_OBJS = \ THIRD_PARTY_MUSL_A_DIRECTDEPS = \ LIBC_ALG \ LIBC_CALLS \ - LIBC_CALLS_HEFTY \ LIBC_INTRIN \ LIBC_MEM \ LIBC_NEXGEN32E \ diff --git a/tool/build/build.mk b/tool/build/build.mk index 45da7c7ce..6210e701f 100644 --- a/tool/build/build.mk +++ b/tool/build/build.mk @@ -28,7 +28,6 @@ TOOL_BUILD_DIRECTDEPS = \ LIBC_ALG \ LIBC_BITS \ LIBC_CALLS \ - LIBC_CALLS_HEFTY \ LIBC_DNS \ LIBC_ELF \ LIBC_FMT \ diff --git a/tool/build/lib/buildlib.mk b/tool/build/lib/buildlib.mk index 97128341d..6bb6634e3 100644 --- a/tool/build/lib/buildlib.mk +++ b/tool/build/lib/buildlib.mk @@ -27,7 +27,6 @@ TOOL_BUILD_LIB_A_DIRECTDEPS = \ LIBC_ALG \ LIBC_BITS \ LIBC_CALLS \ - LIBC_CALLS_HEFTY \ LIBC_ELF \ LIBC_FMT \ LIBC_INTRIN \ diff --git a/tool/net/net.mk b/tool/net/net.mk index 93202deef..35fd28468 100644 --- a/tool/net/net.mk +++ b/tool/net/net.mk @@ -22,7 +22,6 @@ TOOL_NET_DIRECTDEPS = \ LIBC_ALG \ LIBC_BITS \ LIBC_CALLS \ - LIBC_CALLS_HEFTY \ LIBC_DNS \ LIBC_FMT \ LIBC_INTRIN \ diff --git a/tool/viz/printvideo.c b/tool/viz/printvideo.c index 51ce661e8..a6f39aa47 100644 --- a/tool/viz/printvideo.c +++ b/tool/viz/printvideo.c @@ -1473,8 +1473,8 @@ int main(int argc, char *argv[]) { if (!tuned_) PickDefaults(); if (optind == argc) PrintUsage(EX_USAGE, stderr); patharg_ = argv[optind]; - sox_ = commandvenv("SOX", "sox"); - ffplay_ = commandvenv("FFPLAY", "ffplay"); + sox_ = strdup(commandvenv("SOX", "sox")); + ffplay_ = strdup(commandvenv("FFPLAY", "ffplay")); infd_ = STDIN_FILENO; outfd_ = STDOUT_FILENO; if (!setjmp(jb_)) { diff --git a/tool/viz/viz.mk b/tool/viz/viz.mk index 811000a77..17aa48ae8 100644 --- a/tool/viz/viz.mk +++ b/tool/viz/viz.mk @@ -22,7 +22,6 @@ TOOL_VIZ_DIRECTDEPS = \ DSP_TTY \ LIBC_BITS \ LIBC_CALLS \ - LIBC_CALLS_HEFTY \ LIBC_DNS \ LIBC_FMT \ LIBC_INTRIN \ From 27c899af56c941c4cc4f233b1a07201677ac423e Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Wed, 3 Feb 2021 00:10:12 -0800 Subject: [PATCH 4/5] Make mmap() work better - Mapping file offsets now works on Windows - Mapping stack memory now works on OpenBSD --- libc/calls/open-nt.c | 19 +---------------- libc/runtime/directmapnt.c | 4 +++- libc/runtime/mmap.c | 14 +++++++++---- libc/sysv/consts.sh | 6 +++--- libc/sysv/consts/O_ACCMODE.s | 2 +- libc/sysv/consts/O_RDONLY.s | 2 +- libc/sysv/consts/O_RDWR.s | 2 +- test/libc/runtime/mmap_test.c | 36 ++++++++++++++++++++++++++++++++ third_party/chibicc/test/test.mk | 19 ++++++----------- third_party/chibicc/tokenize.c | 23 ++++++++------------ 10 files changed, 71 insertions(+), 56 deletions(-) diff --git a/libc/calls/open-nt.c b/libc/calls/open-nt.c index 5ada3e843..7bde0dc0d 100644 --- a/libc/calls/open-nt.c +++ b/libc/calls/open-nt.c @@ -42,16 +42,7 @@ static textwindows int64_t open$nt$impl(int dirfd, const char *path, char16_t path16[PATH_MAX]; if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1; if ((handle = CreateFile( - path16, - (flags & 0xf000000f) | - (/* this is needed if we mmap(rwx+cow) - nt is choosy about open() access */ - (flags & O_APPEND) - ? kNtFileAppendData - : (flags & O_ACCMODE) == O_RDONLY - ? kNtGenericExecute | kNtFileGenericRead - : kNtGenericExecute | kNtFileGenericRead | - kNtFileGenericWrite), + path16, flags & 0xf000000f, /* see consts.sh */ (flags & O_EXCL) ? kNtFileShareExclusive : kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, @@ -75,14 +66,6 @@ static textwindows int64_t open$nt$impl(int dirfd, const char *path, kNtFileFlagBackupSemantics | kNtFileFlagPosixSemantics | kNtFileAttributeTemporary)))), 0)) != -1) { - if (flags & O_SPARSE) { - /* - * TODO(jart): Can all files be sparse files? That seems to be the - * way Linux behaves out of the box. - * TODO(jart): Wow why does sparse wreak havoc? - */ - DeviceIoControl(handle, kNtFsctlSetSparse, NULL, 0, NULL, 0, &br, NULL); - } return handle; } else if (GetLastError() == kNtErrorFileExists && ((flags & O_CREAT) && diff --git a/libc/runtime/directmapnt.c b/libc/runtime/directmapnt.c index 490c0ce35..fb540a153 100644 --- a/libc/runtime/directmapnt.c +++ b/libc/runtime/directmapnt.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/internal.h" #include "libc/nt/enum/filemapflags.h" #include "libc/nt/enum/pageflags.h" @@ -30,7 +31,8 @@ textwindows struct DirectMap __mmap$nt(void *addr, size_t size, unsigned prot, if ((dm.maphandle = CreateFileMappingNuma( handle, &kNtIsInheritable, (prot & PROT_WRITE) ? kNtPageExecuteReadwrite : kNtPageExecuteRead, - size >> 32, size, NULL, kNtNumaNoPreferredNode))) { + handle != -1 ? 0 : size >> 32, handle != -1 ? 0 : size, NULL, + kNtNumaNoPreferredNode))) { if (!(dm.addr = MapViewOfFileExNuma( dm.maphandle, (prot & PROT_WRITE) diff --git a/libc/runtime/mmap.c b/libc/runtime/mmap.c index e375eb25d..a7bfc537c 100644 --- a/libc/runtime/mmap.c +++ b/libc/runtime/mmap.c @@ -52,13 +52,14 @@ * @param flags can have MAP_ANONYMOUS, MAP_SHARED, MAP_PRIVATE, etc. * @param fd is an open()'d file descriptor whose contents shall be * mapped, and is ignored if MAP_ANONYMOUS is specified - * @param offset specifies absolute byte index of fd's file for mapping, - * and should be zero if MAP_ANONYMOUS is specified + * @param off specifies absolute byte index of fd's file for mapping, + * should be zero if MAP_ANONYMOUS is specified, and sadly needs + * to be 64kb aligned too * @return virtual base address of new mapping, or MAP_FAILED w/ errno */ void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) { - int i, x, n, a, b; struct DirectMap dm; + int i, x, n, a, b, f; if (!size) return VIP(einval()); if (!ALIGNED(off)) return VIP(einval()); if (!ALIGNED(addr)) return VIP(einval()); @@ -84,7 +85,12 @@ void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) { } addr = (void *)(intptr_t)((int64_t)x << 16); } - dm = __mmap(addr, size, prot, flags | MAP_FIXED, fd, off); + f = flags | MAP_FIXED; + if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */ + dm = __mmap(addr, size, prot, f & ~MAP_GROWSDOWN, fd, off); + if (dm.addr == MAP_FAILED) return MAP_FAILED; + } + dm = __mmap(addr, size, prot, f, fd, off); if (dm.addr == MAP_FAILED || dm.addr != addr) { return MAP_FAILED; } diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index 3c3d458c4..451a081b5 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -205,10 +205,10 @@ syscon sig SIGRTMIN 0 0 65 0 0 # │││ │ ┌┴───dwDesiredAccess # N │││ │ │ # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD T │││┌─┴┐│ Commentary -syscon open O_RDONLY 0 0 0 0 0x80000000 # unix consensus & kNtGenericRead +syscon open O_RDONLY 0 0 0 0 0xA0000000 # unix consensus & kNtGenericRead|kNtGenericExecute syscon open O_WRONLY 1 1 1 1 0x40000000 # unix consensus & kNtGenericWrite -syscon open O_RDWR 2 2 2 2 0xc0000000 # unix consensus & kNtGenericRead|kNtGenericWrite -syscon open O_ACCMODE 3 3 3 3 0xc0000000 # O_RDONLY|O_WRONLY|O_RDWR +syscon open O_RDWR 2 2 2 2 0xE0000000 # unix consensus & kNtGenericRead|kNtGenericWrite|kNtGenericExecute +syscon open O_ACCMODE 3 3 3 3 0xE0000000 # O_RDONLY|O_WRONLY|O_RDWR syscon open O_APPEND 0x0400 8 8 8 0x00000004 # bsd consensus & kNtFileAppendData; won't pose issues w/ mknod(S_IFIFO) syscon open O_CREAT 0x40 0x0200 0x0200 0x0200 0x00000040 # bsd consensus & NT faked as Linux syscon open O_EXCL 0x80 0x0800 0x0800 0x0800 0x00000080 # bsd consensus & NT faked as Linux diff --git a/libc/sysv/consts/O_ACCMODE.s b/libc/sysv/consts/O_ACCMODE.s index ae0a401e6..d46a77153 100644 --- a/libc/sysv/consts/O_ACCMODE.s +++ b/libc/sysv/consts/O_ACCMODE.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon open O_ACCMODE 3 3 3 3 0xc0000000 +.syscon open O_ACCMODE 3 3 3 3 0xE0000000 diff --git a/libc/sysv/consts/O_RDONLY.s b/libc/sysv/consts/O_RDONLY.s index b6ca5801a..5bb4e01e7 100644 --- a/libc/sysv/consts/O_RDONLY.s +++ b/libc/sysv/consts/O_RDONLY.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon open O_RDONLY 0 0 0 0 0x80000000 +.syscon open O_RDONLY 0 0 0 0 0xA0000000 diff --git a/libc/sysv/consts/O_RDWR.s b/libc/sysv/consts/O_RDWR.s index b98945420..1a1dd54ba 100644 --- a/libc/sysv/consts/O_RDWR.s +++ b/libc/sysv/consts/O_RDWR.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon open O_RDWR 2 2 2 2 0xc0000000 +.syscon open O_RDWR 2 2 2 2 0xE0000000 diff --git a/test/libc/runtime/mmap_test.c b/test/libc/runtime/mmap_test.c index 9d4975a02..5977f46ea 100644 --- a/test/libc/runtime/mmap_test.c +++ b/test/libc/runtime/mmap_test.c @@ -88,6 +88,42 @@ TEST(mmap, testMapFixed_destroysEverythingInItsPath) { EXPECT_NE(-1, munmap((void *)kFixedmapStart, FRAMESIZE * 3)); } +TEST(mmap, customStackMemory_isAuthorized) { + char *stack; + uintptr_t w, r; + ASSERT_NE(MAP_FAILED, + (stack = mmap(NULL, STACKSIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN, -1, 0))); + asm("mov\t%%rsp,%0\n\t" + "mov\t%2,%%rsp\n\t" + "push\t%3\n\t" + "pop\t%1\n\t" + "mov\t%0,%%rsp" + : "=&r"(w), "=&r"(r) + : "rm"(stack + STACKSIZE - 8), "i"(123)); + ASSERT_EQ(123, r); +} + +TEST(mmap, fileOffset) { + int fd; + char *map; + char testdir[PATH_MAX]; + sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid()); + ASSERT_NE(-1, makedirs(testdir, 0755)); + ASSERT_NE(-1, chdir(testdir)); + ASSERT_NE(-1, (fd = open("foo", O_CREAT | O_RDWR, 0644))); + EXPECT_NE(-1, ftruncate(fd, FRAMESIZE * 2)); + EXPECT_NE(-1, pwrite(fd, "hello", 5, FRAMESIZE * 0)); + EXPECT_NE(-1, pwrite(fd, "there", 5, FRAMESIZE * 1)); + ASSERT_NE(MAP_FAILED, (map = mmap(NULL, FRAMESIZE, PROT_READ, MAP_PRIVATE, fd, + FRAMESIZE))); + EXPECT_EQ(0, memcmp(map, "there", 5), "%#.*s", 5, map); + EXPECT_NE(-1, munmap(map, FRAMESIZE)); + EXPECT_NE(-1, close(fd)); + ASSERT_NE(-1, chdir("../../..")); + ASSERT_NE(-1, rmrf(testdir)); +} + TEST(isheap, nullPtr) { ASSERT_FALSE(isheap(NULL)); } diff --git a/third_party/chibicc/test/test.mk b/third_party/chibicc/test/test.mk index 35c916ddb..142846f09 100644 --- a/third_party/chibicc/test/test.mk +++ b/third_party/chibicc/test/test.mk @@ -21,13 +21,8 @@ THIRD_PARTY_CHIBICC_TEST_HDRS = $(filter %.h,$(THIRD_PARTY_CHIBICC_TEST_FILES)) THIRD_PARTY_CHIBICC_TEST_TESTS = $(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.ok) THIRD_PARTY_CHIBICC_TEST_COMS = \ - $(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%.c=o/$(MODE)/%.com) - -# TODO(jart): make chibicc compiled chibicc work with asan runtime -ifneq ($(MODE),dbg) -THIRD_PARTY_CHIBICC_TEST_COMS += \ - $(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%.c=o/$(MODE)/%2.com) -endif + $(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%_test.c=o/$(MODE)/%_test.com) \ + $(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%_test.c=o/$(MODE)/%_test2.com) THIRD_PARTY_CHIBICC_TEST_OBJS = \ $(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc.o) @@ -62,21 +57,19 @@ THIRD_PARTY_CHIBICC_TEST_DEPS := \ $(call uniq,$(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)))) $(THIRD_PARTY_CHIBICC_TEST_A): \ - third_party/chibicc/test/ \ $(THIRD_PARTY_CHIBICC_TEST_A).pkg \ - $(THIRD_PARTY_CHIBICC_TEST_OBJS) + o/$(MODE)/third_party/chibicc/test/common.chibicc.o $(THIRD_PARTY_CHIBICC_TEST2_A): \ - third_party/chibicc/test/ \ $(THIRD_PARTY_CHIBICC_TEST2_A).pkg \ - $(THIRD_PARTY_CHIBICC_TEST2_OBJS) + o/$(MODE)/third_party/chibicc/test/common.chibicc2.o $(THIRD_PARTY_CHIBICC_TEST_A).pkg: \ - $(THIRD_PARTY_CHIBICC_TEST_OBJS) \ + o/$(MODE)/third_party/chibicc/test/common.chibicc.o \ $(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)_A).pkg) $(THIRD_PARTY_CHIBICC_TEST2_A).pkg: \ - $(THIRD_PARTY_CHIBICC_TEST2_OBJS) \ + o/$(MODE)/third_party/chibicc/test/common.chibicc2.o \ $(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)_A).pkg) o/$(MODE)/third_party/chibicc/test/%.com.dbg: \ diff --git a/third_party/chibicc/tokenize.c b/third_party/chibicc/tokenize.c index 568fafbc8..5f12b6367 100644 --- a/third_party/chibicc/tokenize.c +++ b/third_party/chibicc/tokenize.c @@ -136,21 +136,16 @@ static int read_ident(char *start) { } } -static int from_hex(char c) { - if ('0' <= c && c <= '9') return c - '0'; - if ('a' <= c && c <= 'f') return c - 'a' + 10; - return c - 'A' + 10; -} - // Read a punctuator token from p and returns its length. int read_punct(char *p) { - static char kw[][4] = {"<<=", ">>=", "...", "==", "!=", "<=", ">=", "->", - "+=", "-=", "*=", "/=", "++", "--", "%=", "&=", - "|=", "^=", "&&", "||", "<<", ">>", "##"}; - for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) { + static const char kPunct[][4] = { + "<<=", ">>=", "...", "==", "!=", "<=", ">=", "->", "+=", "-=", "*=", "/=", + "++", "--", "%=", "&=", "|=", "^=", "&&", "||", "<<", ">>", "##", + }; + for (int i = 0; i < sizeof(kPunct) / sizeof(*kPunct); i++) { for (int j = 0;;) { - if (p[j] != kw[i][j]) break; - if (!kw[i][++j]) return j; + if (p[j] != kPunct[i][j]) break; + if (!kPunct[i][++j]) return j; } } return ispunct(*p) ? 1 : 0; @@ -200,7 +195,7 @@ int read_escaped_char(char **new_pos, char *p) { if (!isxdigit(*p)) error_at(p, "invalid hex escape sequence"); unsigned c = 0; for (; isxdigit(*p); p++) { - c = (c << 4) + from_hex(*p); /* TODO(jart): overflow here unicode_test */ + c = (c << 4) + hextoint(*p); /* TODO(jart): overflow here unicode_test */ } *new_pos = p; return c; @@ -628,7 +623,7 @@ static uint32_t read_universal_char(char *p, int len) { uint32_t c = 0; for (int i = 0; i < len; i++) { if (!isxdigit(p[i])) return 0; - c = (c << 4) | from_hex(p[i]); + c = (c << 4) | hextoint(p[i]); } return c; } From 4e56d89dcdf227070b42aa684a0817874589dde2 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Wed, 3 Feb 2021 06:22:51 -0800 Subject: [PATCH 5/5] Eliminate some flakes - Get ASAN working on Windows. - Deleting directories and then recreating them with the same name in a short period of time appears to be a no-no on Windows. - There's no reason to call FlushFileBuffers on close() for pipes, and it's harmful since it might block indefinitely for no good reason. --- Makefile | 42 +-- libc/calls/calls.mk | 1 - libc/calls/close-nt.c | 8 +- libc/calls/close.c | 3 +- libc/calls/dup-nt.c | 20 +- libc/calls/{growfds.c => ensurefds.c} | 38 ++- libc/calls/internal.h | 4 +- libc/calls/ioctl-tcsets-nt.c | 1 - libc/calls/isdebuggerpresent.c | 15 +- libc/calls/mkntcmdline.c | 4 +- libc/calls/mkntenvblock.c | 25 +- libc/calls/open-nt.c | 13 +- libc/calls/open.c | 2 +- libc/calls/openanon.c | 5 +- libc/calls/pipe-nt.c | 8 +- libc/calls/releasefd.c | 29 ++ libc/calls/{getemptyfd.c => reservefd.c} | 15 +- libc/calls/sigaction.c | 26 +- libc/calls/sigenter.S | 2 +- libc/calls/winerr.greg.c | 2 +- libc/calls/write-nt.c | 1 - libc/integral/c.inc | 2 +- libc/intrin/asan.c | 55 ++-- libc/intrin/intrin.mk | 4 +- libc/intrin/ntgetversion.c | 24 ++ libc/intrin/somanyasan.S | 129 +++++--- libc/nt/struct/teb.h | 17 +- libc/rand/rand.mk | 8 +- libc/rand/rand64.c | 2 +- libc/rand/winrandish.c | 4 +- libc/runtime/arememoryintervalsok.c | 2 +- libc/runtime/assertfail.c | 79 ++++- libc/runtime/cxaatexit.c | 4 +- libc/runtime/directmap.c | 4 +- libc/runtime/directmapnt.c | 5 +- libc/runtime/findmemoryinterval.c | 2 +- libc/runtime/fork-nt.c | 22 +- libc/runtime/getdosargv.c | 8 +- libc/runtime/getdosenviron.c | 30 +- libc/runtime/memtrack.c | 19 +- libc/runtime/memtrack.h | 1 - libc/runtime/memtracknt.c | 4 +- libc/runtime/print.greg.c | 1 - libc/runtime/runtime.h | 1 + libc/runtime/stackchkfail.c | 3 +- libc/runtime/winmain.greg.c | 13 +- libc/sock/accept-nt.c | 4 +- libc/sock/epoll.c | 11 +- libc/sock/kntwsadata.c | 7 +- libc/sock/socket-nt.c | 2 +- libc/stubs/asan.S | 388 ----------------------- libc/testlib/testlib.h | 117 ++++--- libc/testlib/testrunner.c | 24 +- test/libc/calls/commandv_test.c | 11 +- test/libc/calls/fcntl_test.c | 15 +- test/libc/calls/getcwd_test.c | 15 +- test/libc/calls/lseek_test.c | 13 +- test/libc/calls/mkdir_test.c | 13 +- test/libc/runtime/mmap_test.c | 8 +- tool/viz/printpeb.c | 4 +- 60 files changed, 588 insertions(+), 751 deletions(-) rename libc/calls/{growfds.c => ensurefds.c} (76%) create mode 100644 libc/calls/releasefd.c rename libc/calls/{getemptyfd.c => reservefd.c} (88%) create mode 100644 libc/intrin/ntgetversion.c delete mode 100644 libc/stubs/asan.S diff --git a/Makefile b/Makefile index 37cf9490d..a133bdc5b 100644 --- a/Makefile +++ b/Makefile @@ -82,17 +82,19 @@ o: o/$(MODE)/ape \ PKGS = --include ~/.cosmo.mk #──No.1 +-include ~/.cosmo.mk include build/functions.mk #─┐ -include build/definitions.mk # ├──meta -include build/config.mk # │ -include build/rules.mk # │ +include build/definitions.mk # ├──META +include build/config.mk # │ You can build +include build/rules.mk # │ You can topologically order include build/online.mk # │ include libc/stubs/stubs.mk #─┘ include libc/nexgen32e/nexgen32e.mk #─┐ -include libc/intrin/intrin.mk # │ -include libc/linux/linux.mk # │ -include libc/tinymath/tinymath.mk # ├──metal +include libc/sysv/sysv.mk # ├──SYSTEM SUPPORT +include libc/nt/nt.mk # │ You can do math +include libc/intrin/intrin.mk # │ You can use the stack +include libc/linux/linux.mk # │ You can manipulate arrays +include libc/tinymath/tinymath.mk # │ You can issue raw system calls include third_party/compiler_rt/compiler_rt.mk # │ include libc/bits/bits.mk # │ include libc/str/str.mk # │ @@ -100,20 +102,18 @@ include third_party/xed/xed.mk # │ include third_party/zlib/zlib.mk # │ include libc/elf/elf.mk # │ include ape/lib/apelib.mk # │ -include ape/ape.mk #─┘ -include libc/sysv/sysv.mk #─┐ -include libc/nt/nt.mk # ├──system -include libc/fmt/fmt.mk # │ -include libc/rand/rand.mk #─┘ +include ape/ape.mk # │ +include libc/fmt/fmt.mk #─┘ include libc/calls/calls.mk #─┐ -include libc/runtime/runtime.mk # ├──systems -include libc/crt/crt.mk # │ +include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME +include libc/crt/crt.mk # │ You can issue system calls +include libc/rand/rand.mk # │ include libc/unicode/unicode.mk # │ -include third_party/dlmalloc/dlmalloc.mk # │ -include libc/mem/mem.mk # │ -include libc/ohmyplus/ohmyplus.mk # │ -include libc/zipos/zipos.mk # │ -include third_party/gdtoa/gdtoa.mk # │ +include third_party/dlmalloc/dlmalloc.mk #─┘ +include libc/mem/mem.mk #─┐ +include libc/ohmyplus/ohmyplus.mk # ├──DYNAMIC RUNTIME +include libc/zipos/zipos.mk # │ You can now use stdio +include third_party/gdtoa/gdtoa.mk # │ You can finally call malloc() include libc/time/time.mk # │ include libc/alg/alg.mk # │ include libc/stdio/stdio.mk # │ @@ -131,8 +131,8 @@ include third_party/musl/musl.mk # │ include third_party/getopt/getopt.mk # │ include libc/libc.mk #─┘ include libc/sock/sock.mk #─┐ -include dsp/tty/tty.mk # ├──online -include libc/dns/dns.mk # │ +include dsp/tty/tty.mk # ├──ONLINE RUNTIME +include libc/dns/dns.mk # │ You can communicate with the network include libc/crypto/crypto.mk # │ include net/http/http.mk #─┘ include third_party/lemon/lemon.mk diff --git a/libc/calls/calls.mk b/libc/calls/calls.mk index ec5993a26..ae2afe0e1 100644 --- a/libc/calls/calls.mk +++ b/libc/calls/calls.mk @@ -44,7 +44,6 @@ LIBC_CALLS_A_DIRECTDEPS = \ LIBC_NT_ADVAPI32 \ LIBC_NT_KERNEL32 \ LIBC_NT_NTDLL \ - LIBC_RAND \ LIBC_STR \ LIBC_STUBS \ LIBC_SYSV_CALLS \ diff --git a/libc/calls/close-nt.c b/libc/calls/close-nt.c index b477f86dd..5c500b0b4 100644 --- a/libc/calls/close-nt.c +++ b/libc/calls/close-nt.c @@ -17,13 +17,15 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/nt/enum/filetype.h" #include "libc/nt/files.h" #include "libc/nt/runtime.h" #include "libc/sysv/errfuns.h" textwindows int close$nt(int fd) { bool32 ok; - if (g_fds.p[fd].kind == kFdFile) { + if (g_fds.p[fd].kind == kFdFile && + GetFileType(g_fds.p[fd].handle) == kNtFileTypeDisk) { /* * Like Linux, closing a file on Windows doesn't guarantee it's * immediately synced to disk. But unlike Linux, this could cause @@ -32,6 +34,8 @@ textwindows int close$nt(int fd) { FlushFileBuffers(g_fds.p[fd].handle); } ok = CloseHandle(g_fds.p[fd].handle); - if (g_fds.p[fd].kind == kFdConsole) ok &= CloseHandle(g_fds.p[fd].extra); + if (g_fds.p[fd].kind == kFdConsole) { + ok &= CloseHandle(g_fds.p[fd].extra); + } return ok ? 0 : __winerr(); } diff --git a/libc/calls/close.c b/libc/calls/close.c index 3b7b83c07..b5e83c52a 100644 --- a/libc/calls/close.c +++ b/libc/calls/close.c @@ -53,8 +53,7 @@ int close(int fd) { rc = ebadf(); } if (!__vforked && fd < g_fds.n) { - g_fds.p[fd].kind = kFdEmpty; - g_fds.f = MIN(g_fds.f, fd); + __releasefd(fd); } return rc; } diff --git a/libc/calls/dup-nt.c b/libc/calls/dup-nt.c index 33b4abaed..1e8437009 100644 --- a/libc/calls/dup-nt.c +++ b/libc/calls/dup-nt.c @@ -30,17 +30,18 @@ */ textwindows int dup$nt(int oldfd, int newfd, int flags) { int64_t proc; - if (!__isfdkind(oldfd, kFdFile)) return ebadf(); + if (oldfd < 0) return einval(); + if (oldfd >= g_fds.n || + (g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket && + g_fds.p[oldfd].kind != kFdConsole)) { + return ebadf(); + } if (newfd == -1) { - if ((newfd = __getemptyfd()) == -1) { - return -1; - } - } else if (__ensurefds(newfd) != -1) { - if (g_fds.p[newfd].kind != kFdEmpty) { - close(newfd); - } + if ((newfd = __reservefd()) == -1) return -1; } else { - return -1; + if (__ensurefds(newfd) == -1) return -1; + if (g_fds.p[newfd].kind) close(newfd); + g_fds.p[newfd].kind = kFdReserved; } proc = GetCurrentProcess(); if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc, &g_fds.p[newfd].handle, @@ -49,6 +50,7 @@ textwindows int dup$nt(int oldfd, int newfd, int flags) { g_fds.p[newfd].flags = flags; return newfd; } else { + __releasefd(newfd); return __winerr(); } } diff --git a/libc/calls/growfds.c b/libc/calls/ensurefds.c similarity index 76% rename from libc/calls/growfds.c rename to libc/calls/ensurefds.c index d1503801c..1114bddc4 100644 --- a/libc/calls/growfds.c +++ b/libc/calls/ensurefds.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/bits/bits.h" #include "libc/bits/weaken.h" #include "libc/calls/internal.h" #include "libc/mem/mem.h" @@ -24,24 +25,29 @@ #include "libc/sysv/errfuns.h" int __ensurefds(int fd) { - size_t n; - struct Fd *p; - if (fd < g_fds.n) return fd; - if (weaken(malloc)) { - n = MAX(fd + 1, g_fds.n + (g_fds.n << 1)); - if ((p = weaken(malloc)(n * sizeof(*p)))) { - memcpy(p, g_fds.p, g_fds.n * sizeof(*p)); - memset(p + g_fds.n, 0, (n - g_fds.n) * sizeof(*p)); - if (g_fds.p != g_fds.__init_p && weaken(free)) { - weaken(free)(g_fds.p); + size_t n1, n2; + struct Fd *p1, *p2; + for (;;) { + p1 = g_fds.p; + n1 = g_fds.n; + if (fd < n1) return fd; + if (weaken(malloc)) { + n2 = MAX(fd + 1, n1 + (n1 << 1)); + if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) { + memcpy(p2, p1, n1 * sizeof(*p1)); + memset(p2 + n1, 0, (n2 - n1) * sizeof(*p1)); + if (p1 != g_fds.__init_p && weaken(free)) weaken(free)(p1); + if (cmpxchg(&g_fds.p, p1, p2)) { + g_fds.n = n2; + return fd; + } else if (weaken(free)) { + weaken(free)(p2); + } + } else { + return enomem(); } - g_fds.p = p; - g_fds.n = n; - return fd; } else { - return enomem(); + return emfile(); } - } else { - return emfile(); } } diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 195d5acf9..c7eae122e 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -52,6 +52,7 @@ struct Fds { kFdSerial, kFdZip, kFdEpoll, + kFdReserved, } kind; unsigned flags; } * p; @@ -68,7 +69,8 @@ hidden extern struct NtSystemInfo g_ntsysteminfo; hidden extern struct NtStartupInfo g_ntstartupinfo; hidden extern const struct NtSecurityAttributes kNtIsInheritable; -ssize_t __getemptyfd(void) hidden; +int __reservefd(void) hidden; +void __releasefd(int) hidden; int __ensurefds(int) hidden; void __removefd(int) hidden; diff --git a/libc/calls/ioctl-tcsets-nt.c b/libc/calls/ioctl-tcsets-nt.c index 1d0fc0de3..abe4052c0 100644 --- a/libc/calls/ioctl-tcsets-nt.c +++ b/libc/calls/ioctl-tcsets-nt.c @@ -22,7 +22,6 @@ #include "libc/nt/console.h" #include "libc/nt/enum/consolemodeflags.h" #include "libc/nt/enum/version.h" -#include "libc/nt/struct/teb.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/termios.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/isdebuggerpresent.c b/libc/calls/isdebuggerpresent.c index 54c9b1c6c..844d128b1 100644 --- a/libc/calls/isdebuggerpresent.c +++ b/libc/calls/isdebuggerpresent.c @@ -32,7 +32,11 @@ #define kBufSize 1024 #define kProcStatus "/proc/self/status" -_Alignas(16) static const char kGdbPid[] = "TracerPid:\t"; +#define kPid "TracerPid:\t" + +static noasan int NtBeingDebugged(void) { + return NtGetPeb()->BeingDebugged; +} /** * Determines if gdb, strace, windbg, etc. is controlling process. @@ -42,19 +46,18 @@ int IsDebuggerPresent(bool force) { int fd, res; ssize_t got; char buf[1024]; - res = 0; + res = false; if (!force) { if (getenv("HEISENDEBUG")) return false; if (IsGenuineCosmo()) return false; } if (IsWindows()) { - res = NtGetPeb()->BeingDebugged; + res = NtBeingDebugged(); } else if (IsLinux()) { if ((fd = openat$sysv(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) { - if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kGdbPid))) != -1) { + if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kPid))) != -1) { buf[got] = '\0'; - res = - atoi(firstnonnull(strstr(buf, kGdbPid), kGdbPid) + strlen(kGdbPid)); + res = atoi(firstnonnull(strstr(buf, kPid), kPid) + strlen(kPid)); } close$sysv(fd); } diff --git a/libc/calls/mkntcmdline.c b/libc/calls/mkntcmdline.c index 1339cdcfb..eb52c3626 100644 --- a/libc/calls/mkntcmdline.c +++ b/libc/calls/mkntcmdline.c @@ -37,8 +37,8 @@ * @kudos Daniel Colascione for teaching how to quote * @see libc/runtime/dosargv.c */ -textwindows int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog, - char *const argv[]) { +textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog, + char *const argv[]) { char *arg; uint64_t w; wint_t x, y; diff --git a/libc/calls/mkntenvblock.c b/libc/calls/mkntenvblock.c index beae3b238..4fb63e6b1 100644 --- a/libc/calls/mkntenvblock.c +++ b/libc/calls/mkntenvblock.c @@ -29,21 +29,18 @@ #include "libc/str/utf16.h" #include "libc/sysv/errfuns.h" -static int CompareStrings(const char *l, const char *r) { +static noasan int CompareStrings(const char *l, const char *r) { size_t i = 0; while (l[i] == r[i] && r[i]) ++i; return (l[i] & 0xff) - (r[i] & 0xff); } -static void SortStrings(char **a, size_t n) { - char *t; - size_t i, j; - for (i = 1; i < n; ++i) { - for (t = a[i], j = i; j > 0 && CompareStrings(t, a[j - 1]) < 0; --j) { - a[j] = a[j - 1]; - } - a[j] = t; +static noasan void InsertString(char **a, size_t i, char *s) { + size_t j; + for (j = i; j > 0 && CompareStrings(s, a[j - 1]) < 0; --j) { + a[j] = a[j - 1]; } + a[j] = s; } /** @@ -57,8 +54,9 @@ static void SortStrings(char **a, size_t n) { * @return 0 on success, or -1 w/ errno * @error E2BIG if total number of shorts exceeded ARG_MAX (0x8000) */ -textwindows int mkntenvblock(char16_t envvars[ARG_MAX], char *const envp[], - const char *extravar) { +textwindows noasan int mkntenvblock(char16_t envvars[ARG_MAX], + char *const envp[], const char *extravar) { + char *t; axdx_t rc; uint64_t w; char **vars; @@ -66,9 +64,8 @@ textwindows int mkntenvblock(char16_t envvars[ARG_MAX], char *const envp[], size_t i, j, k, n, m; for (n = 0; envp[n];) n++; vars = alloca((n + 1) * sizeof(char *)); - memcpy(vars, envp, n * sizeof(char *)); - if (extravar) vars[n++] = extravar; - SortStrings(vars, n); + for (i = 0; i < n; ++i) InsertString(vars, i, envp[i]); + if (extravar) InsertString(vars, n++, extravar); for (k = i = 0; i < n; ++i) { j = 0; do { diff --git a/libc/calls/open-nt.c b/libc/calls/open-nt.c index 7bde0dc0d..1a381b0c0 100644 --- a/libc/calls/open-nt.c +++ b/libc/calls/open-nt.c @@ -112,11 +112,16 @@ static textwindows ssize_t open$nt$file(int dirfd, const char *file, textwindows ssize_t open$nt(int dirfd, const char *file, uint32_t flags, int32_t mode) { - size_t fd; - if ((fd = __getemptyfd()) == -1) return -1; + int fd; + ssize_t rc; + if ((fd = __reservefd()) == -1) return -1; if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) { - return open$nt$console(dirfd, &kNtMagicPaths, flags, mode, fd); + rc = open$nt$console(dirfd, &kNtMagicPaths, flags, mode, fd); } else { - return open$nt$file(dirfd, file, flags, mode, fd); + rc = open$nt$file(dirfd, file, flags, mode, fd); } + if (rc == -1) { + __releasefd(fd); + } + return rc; } diff --git a/libc/calls/open.c b/libc/calls/open.c index edf7c46b5..5f1e783ea 100644 --- a/libc/calls/open.c +++ b/libc/calls/open.c @@ -31,7 +31,7 @@ * @asyncsignalsafe * @vforksafe */ -nodiscard int open(const char *file, int flags, ...) { +int open(const char *file, int flags, ...) { va_list va; unsigned mode; va_start(va, flags); diff --git a/libc/calls/openanon.c b/libc/calls/openanon.c index a2ecae59b..f86061501 100644 --- a/libc/calls/openanon.c +++ b/libc/calls/openanon.c @@ -67,8 +67,8 @@ static int openanon$impl(const char *name, unsigned flags, } return fd; } else { - if ((fd = __getemptyfd()) != -1 && - (g_fds.p[fd].handle = CreateFileA( + if ((fd = __reservefd()) == -1) return -1; + if ((g_fds.p[fd].handle = CreateFileA( pathbuf, kNtGenericRead | kNtGenericWrite, kNtFileShareExclusive, &kNtIsInheritable, kNtCreateAlways, (kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal | @@ -78,6 +78,7 @@ static int openanon$impl(const char *name, unsigned flags, g_fds.p[fd].flags = flags; return fd; } else { + __releasefd(fd); return __winerr(); } } diff --git a/libc/calls/pipe-nt.c b/libc/calls/pipe-nt.c index 042d1172a..fad391c1e 100644 --- a/libc/calls/pipe-nt.c +++ b/libc/calls/pipe-nt.c @@ -58,16 +58,19 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) { int reader, writer; char16_t pipename[64]; CreatePipeName(pipename); + if ((reader = __reservefd()) == -1) return -1; + if ((writer = __reservefd()) == -1) { + __releasefd(reader); + return -1; + } if ((hin = CreateNamedPipe(pipename, kNtPipeAccessInbound, kNtPipeWait | kNtPipeReadmodeByte, 1, 65536, 65536, 0, &kNtIsInheritable)) != -1) { if ((hout = CreateFile(pipename, kNtGenericWrite, kNtFileShareWrite, &kNtIsInheritable, kNtOpenExisting, 0, 0)) != -1) { - reader = __getemptyfd(); g_fds.p[reader].kind = kFdFile; g_fds.p[reader].flags = flags; g_fds.p[reader].handle = hin; - writer = __getemptyfd(); g_fds.p[writer].kind = kFdFile; g_fds.p[writer].flags = flags; g_fds.p[writer].handle = hout; @@ -78,5 +81,6 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) { CloseHandle(hin); } } + __releasefd(reader); return __winerr(); } diff --git a/libc/calls/releasefd.c b/libc/calls/releasefd.c new file mode 100644 index 000000000..0577d7c76 --- /dev/null +++ b/libc/calls/releasefd.c @@ -0,0 +1,29 @@ +/*-*- 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/bits/bits.h" +#include "libc/calls/internal.h" + +void __releasefd(int fd) { + int x; + g_fds.p[fd].kind = kFdEmpty; + do { + x = g_fds.f; + if (fd >= x) break; + } while (!cmpxchg(&g_fds.f, x, fd)); +} diff --git a/libc/calls/getemptyfd.c b/libc/calls/reservefd.c similarity index 88% rename from libc/calls/getemptyfd.c rename to libc/calls/reservefd.c index 0a49c8386..d6b5ba473 100644 --- a/libc/calls/getemptyfd.c +++ b/libc/calls/reservefd.c @@ -24,11 +24,16 @@ /** * Finds open file descriptor slot. */ -ssize_t __getemptyfd(void) { - for (; g_fds.f < g_fds.n; ++g_fds.f) { - if (g_fds.p[g_fds.f].kind == kFdEmpty) { - return g_fds.f; +int __reservefd(void) { + int fd; + for (;;) { + fd = g_fds.f; + if (fd >= g_fds.n) { + if (__ensurefds(fd) == -1) return -1; + } + cmpxchg(&g_fds.f, fd, fd + 1); + if (cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) { + return fd; } } - return __ensurefds(g_fds.f); } diff --git a/libc/calls/sigaction.c b/libc/calls/sigaction.c index 8ea675b3e..f23c7532e 100644 --- a/libc/calls/sigaction.c +++ b/libc/calls/sigaction.c @@ -19,6 +19,7 @@ #include "libc/bits/bits.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/sigbits.h" #include "libc/calls/struct/sigaction-freebsd.internal.h" #include "libc/calls/struct/sigaction-linux.internal.h" #include "libc/calls/struct/sigaction-openbsd.internal.h" @@ -128,9 +129,8 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) { sizeof(struct sigaction) > sizeof(struct sigaction$openbsd)); int rc, rva, oldrva; struct sigaction *ap, copy; - if (!(0 < sig && sig < NSIG) || sig == SIGKILL || sig == SIGSTOP) { - return einval(); - } + if (!(0 < sig && sig < NSIG)) return einval(); + if (sig == SIGKILL || sig == SIGSTOP) return einval(); if (!act) { rva = (int32_t)(intptr_t)SIG_DFL; } else if ((intptr_t)act->sa_handler < kSigactionMinRva) { @@ -141,6 +141,9 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) { } else { return efault(); } + if (__vforked && rva != (intptr_t)SIG_DFL && rva != (intptr_t)SIG_IGN) { + return einval(); + } if (!IsWindows()) { if (!IsMetal()) { if (act) { @@ -149,16 +152,13 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) { if (IsXnu()) { ap->sa_restorer = (void *)&xnutrampoline; ap->sa_handler = (void *)&xnutrampoline; - } else { - if (IsLinux()) { - if (!(ap->sa_flags & SA_RESTORER)) { - ap->sa_flags |= SA_RESTORER; - ap->sa_restorer = &__restore_rt; - } - } - if (rva >= kSigactionMinRva) { - ap->sa_sigaction = (sigaction_f)__sigenter; + } else if (IsLinux()) { + if (!(ap->sa_flags & SA_RESTORER)) { + ap->sa_flags |= SA_RESTORER; + ap->sa_restorer = &__restore_rt; } + } else if (rva >= kSigactionMinRva) { + ap->sa_sigaction = (sigaction_f)__sigenter; } sigaction$cosmo2native((union metasigaction *)ap); } else { @@ -178,7 +178,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) { } rc = 0; } - if (rc != -1) { + if (rc != -1 && !__vforked) { if (oldact) { oldrva = __sighandrvas[sig]; oldact->sa_sigaction = (sigaction_f)( diff --git a/libc/calls/sigenter.S b/libc/calls/sigenter.S index 0a28fb5cc..a11a27ae6 100644 --- a/libc/calls/sigenter.S +++ b/libc/calls/sigenter.S @@ -20,7 +20,7 @@ #include "libc/macros.h" .source __FILE__ -/ System Five signal handler. +/ BSD signal handler. / / This is needed because (1) a signal is allowed to trigger at / just about any time, and leaf functions (e.g. memcpy) aren't diff --git a/libc/calls/winerr.greg.c b/libc/calls/winerr.greg.c index 1462f5829..5fc3e4e6a 100644 --- a/libc/calls/winerr.greg.c +++ b/libc/calls/winerr.greg.c @@ -28,7 +28,7 @@ * @return -1 w/ few exceptions * @note this is a code-size saving device */ -privileged int64_t __winerr(void) { +privileged noasan int64_t __winerr(void) { if (IsWindows()) { errno = GetLastError(); return -1; diff --git a/libc/calls/write-nt.c b/libc/calls/write-nt.c index a7e1d0818..bc414cd08 100644 --- a/libc/calls/write-nt.c +++ b/libc/calls/write-nt.c @@ -42,7 +42,6 @@ textwindows ssize_t write$nt(struct Fd *fd, const struct iovec *iov, iovlen ? clampio(iov[0].iov_len) : 0, &wrote, offset2overlap(opt_offset, &overlap))) { if (!wrote) assert(!SumIovecLen(iov, iovlen)); - FlushFileBuffers(fd->handle); return wrote; } else { return __winerr(); diff --git a/libc/integral/c.inc b/libc/integral/c.inc index 1a7e9dd85..24a287834 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -618,7 +618,7 @@ typedef uint64_t uintmax_t; #define textexit _Section(".text.exit") noinstrument #define textreal _Section(".text.real") #define textwindows _Section(".text.windows") -#define textsyscall _Section(".text.syscall") +#define textsyscall _Section(".text.syscall") noinline #define antiquity _Section(".text.antiquity") #else #define testonly diff --git a/libc/intrin/asan.c b/libc/intrin/asan.c index 3983a2a7a..e9c604c58 100644 --- a/libc/intrin/asan.c +++ b/libc/intrin/asan.c @@ -20,17 +20,19 @@ #include "libc/bits/bits.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" +#include "libc/dce.h" #include "libc/intrin/asan.internal.h" -#include "libc/linux/exit.h" -#include "libc/linux/write.h" #include "libc/log/log.h" #include "libc/macros.h" #include "libc/mem/hook/hook.h" +#include "libc/nt/enum/version.h" +#include "libc/nt/runtime.h" #include "libc/runtime/directmap.h" #include "libc/runtime/memtrack.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/prot.h" #include "third_party/dlmalloc/dlmalloc.internal.h" @@ -409,29 +411,40 @@ static const char *__asan_describe_access_poison(char *p) { } } +static textsyscall wontreturn void __asan_exit(int rc) { + if (!IsWindows()) { + asm volatile("syscall" + : /* no outputs */ + : "a"(__NR_exit_group), "D"(rc) + : "memory"); + unreachable; + } else { + ExitProcess(rc); + } +} + static textsyscall ssize_t __asan_write(const void *data, size_t size) { ssize_t rc; - if (weaken(write)) { - if ((rc = weaken(write)(2, data, size)) != -1) { - return rc; + uint32_t wrote; + if (!IsWindows()) { + asm volatile("syscall" + : "=a"(rc) + : "0"(__NR_write), "D"(2), "S"(data), "d"(size) + : "rcx", "r11", "memory"); + return rc; + } else { + if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) { + return wrote; + } else { + return -1; } } - return LinuxWrite(2, data, size); } static ssize_t __asan_write_string(const char *s) { return __asan_write(s, __asan_strlen(s)); } -static textsyscall wontreturn void __asan_exit(int rc) { - if (weaken(_Exit)) { - weaken(_Exit)(rc); - } else { - LinuxExit(rc); - } - for (;;) asm("hlt"); -} - static wontreturn void __asan_abort(void) { if (weaken(__die)) weaken(__die)(); if (weaken(abort)) weaken(abort)(); @@ -640,7 +653,9 @@ void __asan_stack_free(char *p, size_t size, int classid) { __asan_deallocate(p, kAsanStackFree); } -void __asan_handle_no_return_impl(uintptr_t rsp) { +void __asan_handle_no_return(void) { + uintptr_t rsp; + rsp = (uintptr_t)__builtin_frame_address(0); __asan_unpoison(rsp, ROUNDUP(rsp, STACKSIZE) - rsp); } @@ -660,11 +675,11 @@ void __asan_unregister_globals(struct AsanGlobal g[], int n) { } } -void __asan_report_load_impl(uint8_t *addr, int size) { +void __asan_report_load(uint8_t *addr, int size) { __asan_report_memory_fault(addr, size, "load"); } -void __asan_report_store_impl(uint8_t *addr, int size) { +void __asan_report_store(uint8_t *addr, int size) { __asan_report_memory_fault(addr, size, "store"); } @@ -790,6 +805,10 @@ textstartup void __asan_init(int argc, char **argv, char **envp, intptr_t *auxv) { static bool once; if (!cmpxchg(&once, false, true)) return; + if (IsWindows() && NtGetVersion() < kNtVersionWindows10) { + __asan_write_string("error: asan binaries require windows10\n"); + __asan_exit(0); /* So `make MODE=dbg test` passes w/ Windows7 */ + } REQUIRE(_mmi); REQUIRE(__mmap); REQUIRE(MAP_ANONYMOUS); diff --git a/libc/intrin/intrin.mk b/libc/intrin/intrin.mk index 4506a7ab8..d71f495e7 100644 --- a/libc/intrin/intrin.mk +++ b/libc/intrin/intrin.mk @@ -25,7 +25,9 @@ LIBC_INTRIN_A_CHECKS = \ LIBC_INTRIN_A_DIRECTDEPS = \ LIBC_STUBS \ - LIBC_NEXGEN32E + LIBC_SYSV \ + LIBC_NEXGEN32E \ + LIBC_NT_KERNEL32 LIBC_INTRIN_A_DEPS := \ $(call uniq,$(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x)))) diff --git a/libc/intrin/ntgetversion.c b/libc/intrin/ntgetversion.c new file mode 100644 index 000000000..60b4fae7a --- /dev/null +++ b/libc/intrin/ntgetversion.c @@ -0,0 +1,24 @@ +/*-*- 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/nt/struct/teb.h" +#include "libc/runtime/runtime.h" + +textwindows noasan int NtGetVersion(void) { + return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion; +} diff --git a/libc/intrin/somanyasan.S b/libc/intrin/somanyasan.S index 17df1d7d4..6678f2e2f 100644 --- a/libc/intrin/somanyasan.S +++ b/libc/intrin/somanyasan.S @@ -25,6 +25,18 @@ / since ASAN has the same stylistic hugeness as UBSAN. / We also guard all the functions, against reentrancy. + .rodata.cst4 +__asan_option_detect_stack_use_after_return: + .long 0 + .endobj __asan_option_detect_stack_use_after_return,globl + .previous + + .bss +__asan_noreentry: + .byte 0 + .endobj __asan_noreentry + .previous + __asan_report_load1: push $1 jmp OnReportLoad @@ -43,14 +55,18 @@ __asan_report_load8: .endfn __asan_report_load8,globl __asan_report_load16: push $16 -/ 𝑠𝑙𝑖𝑑𝑒 + jmp OnReportLoad .endfn __asan_report_load16,globl +__asan_report_load32: + push $32 +/ 𝑠𝑙𝑖𝑑𝑒 + .endfn __asan_report_load32,globl OnReportLoad: pop %rsi / 𝑠𝑙𝑖𝑑𝑒 .endfn OnReportLoad __asan_report_load_n: - lea __asan_report_load_impl(%rip),%r11 + lea __asan_report_load(%rip),%r11 jmp __asan_report_noreentry .endfn __asan_report_load_n,globl @@ -83,7 +99,7 @@ ReportStore: / 𝑠𝑙𝑖𝑑𝑒 .endfn ReportStore __asan_report_store_n: - lea __asan_report_store_impl(%rip),%r11 + lea __asan_report_store(%rip),%r11 / 𝑠𝑙𝑖𝑑𝑒 .endfn __asan_report_store_n,globl @@ -198,31 +214,6 @@ OnStackMalloc: jmp __asan_stack_malloc .endfn OnStackMalloc -__asan_handle_no_return: - push %rbp - mov %rsp,%rbp - lea 8(%rsp),%rdi - call __asan_handle_no_return_impl - pop %rbp - ret - .endfn __asan_handle_no_return,globl - -__asan_before_dynamic_init: - push %rbp - mov %rsp,%rbp - ud2 - pop %rbp - ret - .endfn __asan_before_dynamic_init,globl - -__asan_after_dynamic_init: - push %rbp - mov %rsp,%rbp - ud2 - pop %rbp - ret - .endfn __asan_after_dynamic_init,globl - __asan_version_mismatch_check_v8: ret .endfn __asan_version_mismatch_check_v8,globl @@ -240,14 +231,76 @@ __asan_version_mismatch_check_v8: pop %rdi .init.end 301,_init_asan - .rodata.cst4 -__asan_option_detect_stack_use_after_return: - .long 0 - .endobj __asan_option_detect_stack_use_after_return,globl - .previous +__asan_before_dynamic_init: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_before_dynamic_init,globl - .bss -__asan_noreentry: - .byte 0 - .endobj __asan_noreentry - .previous +__asan_after_dynamic_init: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_after_dynamic_init,globl + +__asan_load1: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_load1,globl +__asan_load2: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_load2,globl +__asan_load4: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_load4,globl +__asan_load8: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_load8,globl +__asan_load16: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_load16,globl +__asan_load32: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_load32,globl + +__asan_store1: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_store1,globl +__asan_store2: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_store2,globl +__asan_store4: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_store4,globl +__asan_store8: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_store8,globl +__asan_store16: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_store16,globl +__asan_store32: + push %rbp + mov %rsp,%rbp + ud2 + .endfn __asan_store32,globl diff --git a/libc/nt/struct/teb.h b/libc/nt/struct/teb.h index 972b9c5e3..38d870229 100644 --- a/libc/nt/struct/teb.h +++ b/libc/nt/struct/teb.h @@ -4,14 +4,15 @@ #include "libc/nt/struct/peb.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) -/* These macros address directly into NT's TEB a.k.a. TIB */ -#define NtGetPeb() gs((struct NtPeb **)(0x60ULL)) -#define NtGetTeb() gs((void **)(0x30)) /* %gs:0 linear address */ -#define NtGetPid() gs((uint32_t *)(0x40)) /* GetCurrentProcessId() */ -#define NtGetTid() gs((uint32_t *)(0x48)) /* GetCurrentThreadId() */ -#define NtGetErr() gs((int *)(0x68)) -#define NtGetVersion() \ - ((NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion) +/* + * These macros address directly into NT's TEB a.k.a. TIB + * Any function that does this needs the `noasan` keyword + */ +#define NtGetPeb() gs((struct NtPeb **)(0x60ULL)) +#define NtGetTeb() gs((void **)(0x30)) /* %gs:0 linear address */ +#define NtGetPid() gs((uint32_t *)(0x40)) /* GetCurrentProcessId() */ +#define NtGetTid() gs((uint32_t *)(0x48)) /* GetCurrentThreadId() */ +#define NtGetErr() gs((int *)(0x68)) #define _NtGetSeh() gs((void **)(0x00)) #define _NtGetStackHigh() gs((void **)(0x08)) #define _NtGetStackLow() gs((void **)(0x10)) diff --git a/libc/rand/rand.mk b/libc/rand/rand.mk index 90f631f06..1fb297001 100644 --- a/libc/rand/rand.mk +++ b/libc/rand/rand.mk @@ -24,14 +24,14 @@ LIBC_RAND_A_CHECKS = \ $(LIBC_RAND_A_HDRS:%=o/$(MODE)/%.ok) LIBC_RAND_A_DIRECTDEPS = \ - LIBC_STUBS \ - LIBC_INTRIN \ - LIBC_TINYMATH \ + LIBC_CALLS \ LIBC_NEXGEN32E \ LIBC_NT_KERNEL32 \ LIBC_STR \ + LIBC_STUBS \ + LIBC_SYSV \ LIBC_SYSV_CALLS \ - LIBC_SYSV + LIBC_TINYMATH LIBC_RAND_A_DEPS := \ $(call uniq,$(foreach x,$(LIBC_RAND_A_DIRECTDEPS),$($(x)))) diff --git a/libc/rand/rand64.c b/libc/rand/rand64.c index daa2b409e..b3e1d163a 100644 --- a/libc/rand/rand64.c +++ b/libc/rand/rand64.c @@ -33,7 +33,7 @@ hidden extern uint64_t g_rando64; * * @see rngset() */ -nodebuginfo uint64_t(rand64)(void) { +nodebuginfo uint64_t rand64(void) { uint64_t res; if (X86_HAVE(RDRND)) { res = rdrand(); diff --git a/libc/rand/winrandish.c b/libc/rand/winrandish.c index 2beed4539..cd959e15a 100644 --- a/libc/rand/winrandish.c +++ b/libc/rand/winrandish.c @@ -16,11 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/nt/dll.h" #include "libc/nt/events.h" #include "libc/nt/struct/point.h" -#include "libc/nt/struct/teb.h" #include "libc/rand/rand.h" /** @@ -29,7 +29,7 @@ textwindows int64_t winrandish(void) { int64_t res; struct NtPoint point; - res = ((int64_t)NtGetPid() << 17) ^ NtGetTid() ^ rdtsc(); + res = ((int64_t)getpid() << 17) ^ gettid() ^ rdtsc(); /* * This function is intended for older CPUs built before 2012, so * let's avoid having our CUI apps yoink USER32.DLL until we're diff --git a/libc/runtime/arememoryintervalsok.c b/libc/runtime/arememoryintervalsok.c index 47ec948ab..66943a1ff 100644 --- a/libc/runtime/arememoryintervalsok.c +++ b/libc/runtime/arememoryintervalsok.c @@ -19,7 +19,7 @@ #include "libc/runtime/memtrack.h" #include "libc/runtime/runtime.h" -bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) { +noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) { int i; for (i = 0; i < mm->i; ++i) { if (mm->p[i].y < mm->p[i].x) return false; diff --git a/libc/runtime/assertfail.c b/libc/runtime/assertfail.c index 51e7f64be..215f1ece5 100644 --- a/libc/runtime/assertfail.c +++ b/libc/runtime/assertfail.c @@ -17,38 +17,83 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/bits/bits.h" #include "libc/bits/weaken.h" -#include "libc/calls/calls.h" +#include "libc/dce.h" #include "libc/log/log.h" #include "libc/macros.h" #include "libc/mem/alloca.h" -#include "libc/runtime/runtime.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/fileno.h" +#include "libc/nt/runtime.h" +#include "libc/sysv/consts/nr.h" + +static noasan size_t __assert_strlen(const char *s) { + size_t i = 0; + while (s[i]) ++i; + return i; +} + +static noasan char *__assert_stpcpy(char *d, const char *s) { + size_t i; + for (i = 0;; ++i) { + if (!(d[i] = s[i])) { + return d + i; + } + } +} + +static textsyscall noasan wontreturn void __assert_exit(int rc) { + if (!IsWindows()) { + asm volatile("syscall" + : /* no outputs */ + : "a"(__NR_exit_group), "D"(rc) + : "memory"); + unreachable; + } else { + ExitProcess(rc); + } +} + +static textsyscall noasan ssize_t __assert_write(const void *data, + size_t size) { + ssize_t rc; + uint32_t wrote; + if (!IsWindows()) { + asm volatile("syscall" + : "=a"(rc) + : "0"(__NR_write), "D"(2), "S"(data), "d"(size) + : "rcx", "r11", "memory"); + return rc; + } else { + if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) { + return wrote; + } else { + return -1; + } + } +} /** * Handles failure of assert() macro. */ -relegated void __assert_fail(const char *expr, const char *file, int line) { +relegated wontreturn noasan void __assert_fail(const char *expr, + const char *file, int line) { static bool once; char *msg, *p, linebuf[16]; unsigned i, exprlen, filelen; - if (!once) { - once = true; - exprlen = expr ? strlen(expr) : 0; - filelen = file ? strlen(file) : 0; + if (cmpxchg(&once, false, true)) { + exprlen = expr ? __assert_strlen(expr) : 0; + filelen = file ? __assert_strlen(file) : 0; p = msg = alloca(MIN(512, exprlen + filelen + 64)); - p = mempcpy(p, file, filelen); - p = stpcpy(p, ":"); + p = __assert_stpcpy(p, file); + p = __assert_stpcpy(p, ":"); if (line < 1) line = 1; for (i = 0; line; line /= 10) linebuf[i++] = '0' + line % 10; while (i) *p++ = linebuf[--i]; - p = stpcpy(p, ":"); - p = mempcpy(p, expr, exprlen); - p = stpcpy(p, "\r\n"); - write(STDERR_FILENO, msg, p - msg); + p = __assert_stpcpy(p, ":"); + p = __assert_stpcpy(p, expr); + p = __assert_stpcpy(p, "\r\n"); + __assert_write(msg, p - msg); if (weaken(__die)) weaken(__die)(); } - abort(); - unreachable; + __assert_exit(23); } diff --git a/libc/runtime/cxaatexit.c b/libc/runtime/cxaatexit.c index d68f9e5ba..444c611bd 100644 --- a/libc/runtime/cxaatexit.c +++ b/libc/runtime/cxaatexit.c @@ -51,7 +51,7 @@ static struct CxaAtexitBlocks { * @return 0 on success or nonzero w/ errno * @note folks have forked libc in past just to unbloat atexit() */ -int __cxa_atexit(void *fp, void *arg, void *pred) { +noasan int __cxa_atexit(void *fp, void *arg, void *pred) { unsigned i; struct CxaAtexitBlock *b, *b2; b = __cxa_blocks.p; @@ -83,7 +83,7 @@ int __cxa_atexit(void *fp, void *arg, void *pred) { * * @param pred can be null to match all */ -void __cxa_finalize(void *pred) { +noasan void __cxa_finalize(void *pred) { unsigned i; unsigned long mask; struct CxaAtexitBlock *b, *b2; diff --git a/libc/runtime/directmap.c b/libc/runtime/directmap.c index 9a4c8d6c1..c72769e18 100644 --- a/libc/runtime/directmap.c +++ b/libc/runtime/directmap.c @@ -28,8 +28,8 @@ * bypassed by calling this function. However the caller is responsible * for passing the magic memory handle on Windows NT to CloseHandle(). */ -struct DirectMap __mmap(void *addr, size_t size, unsigned prot, unsigned flags, - int fd, int64_t off) { +noasan struct DirectMap __mmap(void *addr, size_t size, unsigned prot, + unsigned flags, int fd, int64_t off) { if (!IsWindows()) { return (struct DirectMap){mmap$sysv(addr, size, prot, flags, fd, off), kNtInvalidHandleValue}; diff --git a/libc/runtime/directmapnt.c b/libc/runtime/directmapnt.c index fb540a153..19833004b 100644 --- a/libc/runtime/directmapnt.c +++ b/libc/runtime/directmapnt.c @@ -25,8 +25,9 @@ #include "libc/runtime/directmap.h" #include "libc/sysv/consts/prot.h" -textwindows struct DirectMap __mmap$nt(void *addr, size_t size, unsigned prot, - int64_t handle, int64_t off) { +textwindows noasan struct DirectMap __mmap$nt(void *addr, size_t size, + unsigned prot, int64_t handle, + int64_t off) { struct DirectMap dm; if ((dm.maphandle = CreateFileMappingNuma( handle, &kNtIsInheritable, diff --git a/libc/runtime/findmemoryinterval.c b/libc/runtime/findmemoryinterval.c index 9342e5e43..7e37d39f0 100644 --- a/libc/runtime/findmemoryinterval.c +++ b/libc/runtime/findmemoryinterval.c @@ -18,7 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/runtime/memtrack.h" -unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) { +noasan unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) { unsigned l, m, r; l = 0; r = mm->i; diff --git a/libc/runtime/fork-nt.c b/libc/runtime/fork-nt.c index e0be9f52d..4ecefb6b1 100644 --- a/libc/runtime/fork-nt.c +++ b/libc/runtime/fork-nt.c @@ -46,7 +46,7 @@ #include "libc/sysv/consts/sig.h" #include "libc/sysv/errfuns.h" -static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) { +static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) { *x = 0; while (*p == ' ') p++; while ('0' <= *p && *p <= '9') { @@ -56,8 +56,8 @@ static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) { return p; } -static noinline textwindows void ForkIo(int64_t h, void *buf, size_t n, - bool32 (*f)()) { +static noinline textwindows noasan void ForkIo(int64_t h, void *buf, size_t n, + bool32 (*f)()) { char *p; size_t i; uint32_t x; @@ -66,15 +66,17 @@ static noinline textwindows void ForkIo(int64_t h, void *buf, size_t n, } } -static noinline textwindows void WriteAll(int64_t h, void *buf, size_t n) { +static noinline textwindows noasan void WriteAll(int64_t h, void *buf, + size_t n) { ForkIo(h, buf, n, WriteFile); } -static noinline textwindows void ReadAll(int64_t h, void *buf, size_t n) { +static textwindows noinline noasan void ReadAll(int64_t h, void *buf, + size_t n) { ForkIo(h, buf, n, ReadFile); } -textwindows void WinMainForked(void) { +textwindows noasan void WinMainForked(void) { void *addr; jmp_buf jb; uint64_t size; @@ -117,13 +119,13 @@ textwindows void WinMainForked(void) { textwindows int fork$nt(void) { jmp_buf jb; - int i, rc, pid; char exe[PATH_MAX]; int64_t reader, writer; + int i, rc, pid, releaseme; char *p, forkvar[6 + 21 + 1 + 21 + 1]; struct NtStartupInfo startinfo; struct NtProcessInformation procinfo; - if ((pid = __getemptyfd()) == -1) return -1; + if ((pid = releaseme = __reservefd()) == -1) return -1; if (!setjmp(jb)) { if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) { p = stpcpy(forkvar, "_FORK="); @@ -148,6 +150,7 @@ textwindows int fork$nt(void) { g_fds.p[pid].kind = kFdProcess; g_fds.p[pid].handle = procinfo.hProcess; g_fds.p[pid].flags = O_CLOEXEC; + releaseme = -1; } WriteAll(writer, jb, sizeof(jb)); WriteAll(writer, &_mmi.i, sizeof(_mmi.i)); @@ -170,5 +173,8 @@ textwindows int fork$nt(void) { } else { rc = 0; } + if (releaseme != -1) { + __releasefd(releaseme); + } return rc; } diff --git a/libc/runtime/getdosargv.c b/libc/runtime/getdosargv.c index ea084bd15..3dcc50427 100644 --- a/libc/runtime/getdosargv.c +++ b/libc/runtime/getdosargv.c @@ -32,7 +32,7 @@ struct DosArgv { wint_t wc; }; -static textwindows wint_t DecodeDosArgv(const char16_t **s) { +static textwindows noasan wint_t DecodeDosArgv(const char16_t **s) { wint_t x, y; for (;;) { if (!(x = *(*s)++)) break; @@ -50,7 +50,7 @@ static textwindows wint_t DecodeDosArgv(const char16_t **s) { return x; } -static textwindows void AppendDosArgv(struct DosArgv *st, wint_t wc) { +static textwindows noasan void AppendDosArgv(struct DosArgv *st, wint_t wc) { uint64_t w; w = tpenc(wc); do { @@ -78,8 +78,8 @@ static textwindows void AppendDosArgv(struct DosArgv *st, wint_t wc) { * @see libc/runtime/ntspawn.c * @note kudos to Simon Tatham for figuring out quoting behavior */ -textwindows int GetDosArgv(const char16_t *cmdline, char *buf, size_t size, - char **argv, size_t max) { +textwindows noasan int GetDosArgv(const char16_t *cmdline, char *buf, + size_t size, char **argv, size_t max) { bool inquote; size_t i, argc, slashes, quotes; struct DosArgv st; diff --git a/libc/runtime/getdosenviron.c b/libc/runtime/getdosenviron.c index 595648bb2..764f07429 100644 --- a/libc/runtime/getdosenviron.c +++ b/libc/runtime/getdosenviron.c @@ -18,6 +18,30 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/runtime/runtime.h" #include "libc/str/str.h" +#include "libc/str/tpenc.h" +#include "libc/str/utf16.h" + +static textwindows noasan axdx_t Recode16to8(char *dst, size_t dstsize, + const char16_t *src) { + axdx_t r; + uint64_t w; + wint_t x, y; + for (r.ax = 0, r.dx = 0;;) { + if (!(x = src[r.dx++])) break; + if (IsUtf16Cont(x)) continue; + if (!IsUcs2(x)) { + if (!(y = src[r.dx++])) break; + x = MergeUtf16(x, y); + } + for (w = tpenc(x); w && r.ax + 1 < dstsize; w >>= 8) { + dst[r.ax++] = w & 0xFF; + } + } + if (r.ax < dstsize) { + dst[r.ax] = 0; + } + return r; +} /** * Transcodes NT environment variable block from UTF-16 to UTF-8. @@ -29,8 +53,8 @@ * @param max is the pointer count capacity of envp * @return number of variables decoded, excluding NULL-terminator */ -textwindows int GetDosEnviron(const char16_t *env, char *buf, size_t size, - char **envp, size_t max) { +textwindows noasan int GetDosEnviron(const char16_t *env, char *buf, + size_t size, char **envp, size_t max) { int i; axdx_t r; i = 0; @@ -38,7 +62,7 @@ textwindows int GetDosEnviron(const char16_t *env, char *buf, size_t size, --size; while (*env) { if (i + 1 < max) envp[i++] = buf; - r = tprecode16to8(buf, size, env); + r = Recode16to8(buf, size, env); size -= r.ax + 1; buf += r.ax + 1; env += r.dx; diff --git a/libc/runtime/memtrack.c b/libc/runtime/memtrack.c index d49eb276c..46a7924ab 100644 --- a/libc/runtime/memtrack.c +++ b/libc/runtime/memtrack.c @@ -24,7 +24,8 @@ #include "libc/str/str.h" #include "libc/sysv/errfuns.h" -static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) { +static noasan void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, + int n) { assert(i >= 0); assert(i + n <= mm->i); memcpy(mm->p + i, mm->p + i + n, @@ -32,7 +33,7 @@ static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) { mm->i -= n; } -static void CreateMemoryInterval(struct MemoryIntervals *mm, int i) { +static noasan void CreateMemoryInterval(struct MemoryIntervals *mm, int i) { assert(i >= 0); assert(i <= mm->i); assert(mm->i < ARRAYLEN(mm->p)); @@ -41,7 +42,7 @@ static void CreateMemoryInterval(struct MemoryIntervals *mm, int i) { ++mm->i; } -static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) { +static noasan int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) { if (mm->i == ARRAYLEN(mm->p)) return enomem(); CreateMemoryInterval(mm, i); mm->p[i].y = x - 1; @@ -49,8 +50,8 @@ static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) { return 0; } -int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y, - void wincb(struct MemoryIntervals *, int, int)) { +noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y, + void wf(struct MemoryIntervals *, int, int)) { unsigned l, r; assert(y >= x); assert(AreMemoryIntervalsOk(mm)); @@ -81,16 +82,16 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y, --r; } if (l <= r) { - if (IsWindows() && wincb) { - wincb(mm, l, r); + if (IsWindows() && wf) { + wf(mm, l, r); } RemoveMemoryIntervals(mm, l, r - l + 1); } return 0; } -int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h, - int prot, int flags) { +noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h, + int prot, int flags) { unsigned i; assert(y >= x); assert(AreMemoryIntervalsOk(mm)); diff --git a/libc/runtime/memtrack.h b/libc/runtime/memtrack.h index 45a93e843..6490e5e48 100644 --- a/libc/runtime/memtrack.h +++ b/libc/runtime/memtrack.h @@ -3,7 +3,6 @@ #include "libc/dce.h" #include "libc/macros.h" #include "libc/nt/enum/version.h" -#include "libc/nt/struct/teb.h" #include "libc/runtime/runtime.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ diff --git a/libc/runtime/memtracknt.c b/libc/runtime/memtracknt.c index 2f09d536d..307bbd071 100644 --- a/libc/runtime/memtracknt.c +++ b/libc/runtime/memtracknt.c @@ -22,14 +22,14 @@ #include "libc/runtime/memtrack.h" #include "libc/runtime/runtime.h" -static void *GetFrameAddr(int f) { +static noasan void *GetFrameAddr(int f) { intptr_t a; a = f; a *= FRAMESIZE; return (void *)a; } -void ReleaseMemoryNt(struct MemoryIntervals *mm, int l, int r) { +noasan void ReleaseMemoryNt(struct MemoryIntervals *mm, int l, int r) { int i, ok; for (i = l; i <= r; ++i) { ok = UnmapViewOfFile(GetFrameAddr(mm->p[i].x)); diff --git a/libc/runtime/print.greg.c b/libc/runtime/print.greg.c index 8e18dda60..7b176dd89 100644 --- a/libc/runtime/print.greg.c +++ b/libc/runtime/print.greg.c @@ -35,7 +35,6 @@ static void __print$nt(const void *data, size_t len) { savexmm(xmm + 128); hand = __imp_GetStdHandle(kNtStdErrorHandle); __imp_WriteFile(hand, data, len, &wrote, NULL); - __imp_FlushFileBuffers(hand); loadxmm(xmm + 128); } diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index 015b02592..8fcc2c48f 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -72,6 +72,7 @@ void __print_string(const char *); void __fast_math(void); void *sbrk(intptr_t); int brk(void *); +int NtGetVersion(void); /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § runtime » optimizations ─╬─│┼ diff --git a/libc/runtime/stackchkfail.c b/libc/runtime/stackchkfail.c index ff2c1da82..48f245a81 100644 --- a/libc/runtime/stackchkfail.c +++ b/libc/runtime/stackchkfail.c @@ -19,7 +19,6 @@ #include "libc/bits/pushpop.h" #include "libc/nt/enum/version.h" #include "libc/nt/runtime.h" -#include "libc/nt/struct/teb.h" #include "libc/runtime/internal.h" #include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/nr.h" @@ -29,7 +28,7 @@ /** * Aborts program under enemy fire to avoid being taken alive. */ -textsyscall void __stack_chk_fail(void) { +textsyscall noasan void __stack_chk_fail(void) { size_t len; const char *msg; int64_t ax, cx, si; diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 97e7a94ec..d0e2e8944 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -35,7 +35,6 @@ #include "libc/nt/pedef.internal.h" #include "libc/nt/process.h" #include "libc/nt/runtime.h" -#include "libc/nt/struct/teb.h" #include "libc/runtime/directmap.h" #include "libc/runtime/internal.h" #include "libc/runtime/memtrack.h" @@ -56,16 +55,16 @@ struct WinArgs { char envblock[ARG_MAX]; }; -static textwindows void SetTrueColor(void) { +static noasan textwindows void SetTrueColor(void) { SetEnvironmentVariable(u"TERM", u"xterm-truecolor"); } -static textwindows void MakeLongDoubleLongAgain(void) { +static noasan textwindows void MakeLongDoubleLongAgain(void) { int x87cw = 0x037f; /* let's hope win32 won't undo this */ asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw)); } -static textwindows void NormalizeCmdExe(void) { +static noasan textwindows void NormalizeCmdExe(void) { uint32_t mode; int64_t handle, hstdin, hstdout, hstderr; if ((int)weakaddr("v_ntsubsystem") == kNtImageSubsystemWindowsCui && @@ -96,7 +95,7 @@ static textwindows void NormalizeCmdExe(void) { } } -static textwindows wontreturn void WinMainNew(void) { +static noasan textwindows wontreturn void WinMainNew(void) { int64_t h; size_t size; int i, count; @@ -165,8 +164,8 @@ static textwindows wontreturn void WinMainNew(void) { * * @param hInstance call GetModuleHandle(NULL) from main if you need it */ -textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance, - const char *lpCmdLine, int nCmdShow) { +noasan textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance, + const char *lpCmdLine, int nCmdShow) { MakeLongDoubleLongAgain(); if (weaken(winsockinit)) weaken(winsockinit)(); if (weaken(WinMainForked)) weaken(WinMainForked)(); diff --git a/libc/sock/accept-nt.c b/libc/sock/accept-nt.c index faf33fb27..76aaaa332 100644 --- a/libc/sock/accept-nt.c +++ b/libc/sock/accept-nt.c @@ -34,12 +34,13 @@ textwindows int accept$nt(struct Fd *fd, void *addr, uint32_t *addrsize, uint32_t yes; for (;;) { if (!WSAPoll(&(struct pollfd$nt){fd->handle, POLLIN}, 1, 1000)) continue; - if ((client = __getemptyfd()) == -1) return -1; + if ((client = __reservefd()) == -1) return -1; if ((h = WSAAccept(fd->handle, addr, (int32_t *)addrsize, 0, 0)) != -1) { if (flags & SOCK_NONBLOCK) { yes = 1; if (__ioctlsocket$nt(g_fds.p[client].handle, FIONBIO, &yes) == -1) { __closesocket$nt(g_fds.p[client].handle); + __releasefd(client); return __winsockerr(); } } @@ -48,6 +49,7 @@ textwindows int accept$nt(struct Fd *fd, void *addr, uint32_t *addrsize, g_fds.p[client].handle = h; return client; } else { + __releasefd(client); return __winsockerr(); } } diff --git a/libc/sock/epoll.c b/libc/sock/epoll.c index 1964e90c0..63de0727e 100644 --- a/libc/sock/epoll.c +++ b/libc/sock/epoll.c @@ -1323,15 +1323,20 @@ static textwindows noinline int epoll_create1$nt(uint32_t flags) { int64_t ephnd; struct PortState *port_state; struct TsTreeNode *tree_node; - if ((fd = __getemptyfd()) == -1) return -1; if (wepoll_init() < 0) return -1; + if ((fd = __reservefd()) == -1) return -1; port_state = port_new(&ephnd); - if (!port_state) return -1; + if (!port_state) { + __releasefd(fd); + return -1; + } tree_node = port_state_to_handle_tree_node(port_state); if (ts_tree_add(&epoll__handle_tree, tree_node, (uintptr_t)ephnd) < 0) { /* This should never happen. */ port_delete(port_state); - RETURN_SET_ERROR(-1, kNtErrorAlreadyExists); + err_set_win_error(kNtErrorAlreadyExists); + __releasefd(fd); + return -1; } g_fds.p[fd].kind = kFdEpoll; g_fds.p[fd].handle = ephnd; diff --git a/libc/sock/kntwsadata.c b/libc/sock/kntwsadata.c index b7c9711ec..bf21ef8fc 100644 --- a/libc/sock/kntwsadata.c +++ b/libc/sock/kntwsadata.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/dce.h" +#include "libc/nt/runtime.h" #include "libc/nt/winsock.h" #include "libc/runtime/runtime.h" #include "libc/sock/internal.h" @@ -32,15 +33,15 @@ */ hidden struct NtWsaData kNtWsaData; -textwindows static void winsockfini(void) { +static textwindows void winsockfini(void) { WSACleanup(); } -textwindows void winsockinit(void) { +textwindows noasan void winsockinit(void) { int rc; atexit(winsockfini); if ((rc = WSAStartup(VERSION, &kNtWsaData)) != 0 || kNtWsaData.wVersion != VERSION) { - abort(); + ExitProcess(123); } } diff --git a/libc/sock/socket-nt.c b/libc/sock/socket-nt.c index 82fc1e02e..31254eb40 100644 --- a/libc/sock/socket-nt.c +++ b/libc/sock/socket-nt.c @@ -29,7 +29,7 @@ textwindows int socket$nt(int family, int type, int protocol) { int fd; uint32_t yes; - if ((fd = __getemptyfd()) == -1) return -1; + if ((fd = __reservefd()) == -1) return -1; if ((g_fds.p[fd].handle = WSASocket(family, type & ~(CLOEXEC | NONBLOCK), protocol, NULL, 0, 0)) != -1) { if (type & NONBLOCK) { diff --git a/libc/stubs/asan.S b/libc/stubs/asan.S deleted file mode 100644 index 3cd9388d4..000000000 --- a/libc/stubs/asan.S +++ /dev/null @@ -1,388 +0,0 @@ -/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ -│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 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/macros.h" -.source __FILE__ - -/ @fileoverview Address Sanitizer Linker Poison - -__asan_addr_is_in_fake_stack: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_addr_is_in_fake_stack,weak - -__asan_after_dynamic_init: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_after_dynamic_init,weak - -__asan_alloca_poison: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_alloca_poison,weak - -__asan_allocas_unpoison: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_allocas_unpoison,weak - -__asan_before_dynamic_init: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_before_dynamic_init,weak - -__asan_get_current_fake_stack: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_get_current_fake_stack,weak - -__asan_handle_no_return: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_handle_no_return,weak - -__asan_init: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_init,weak - -__asan_load1: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_load1,weak - -__asan_load2: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_load2,weak - -__asan_load4: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_load4,weak - -__asan_load8: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_load8,weak - -__asan_load16: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_load16,weak - -__asan_load32: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_load32,weak - -__asan_option_detect_stack_use_after_return: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_option_detect_stack_use_after_return,weak - -__asan_register_globals: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_register_globals,weak - -__asan_report_load1: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_report_load1,weak - -__asan_report_load2: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_report_load2,weak - -__asan_report_load4: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_report_load4,weak - -__asan_report_load8: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_report_load8,weak - -__asan_report_load16: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_report_load16,weak - -__asan_report_load_n: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_report_load_n,weak - -__asan_report_store1: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_report_store1,weak - -__asan_report_store2: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_report_store2,weak - -__asan_report_store4: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_report_store4,weak - -__asan_report_store8: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_report_store8,weak - -__asan_report_store16: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_report_store16,weak - -__asan_report_store32: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_report_store32,weak - -__asan_report_store_n: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_report_store_n,weak - -__asan_stack_free: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_free,weak - -__asan_stack_free_0: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_free_0,weak - -__asan_stack_free_1: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_free_1,weak - -__asan_stack_free_10: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_free_10,weak - -__asan_stack_free_2: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_free_2,weak - -__asan_stack_free_3: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_free_3,weak - -__asan_stack_free_4: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_free_4,weak - -__asan_stack_free_5: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_free_5,weak - -__asan_stack_free_6: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_free_6,weak - -__asan_stack_free_7: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_free_7,weak - -__asan_stack_free_8: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_free_8,weak - -__asan_stack_free_9: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_free_9,weak - -__asan_stack_malloc: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_malloc,weak - -__asan_stack_malloc_0: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_malloc_0,weak - -__asan_stack_malloc_1: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_malloc_1,weak - -__asan_stack_malloc_2: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_malloc_2,weak - -__asan_stack_malloc_3: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_malloc_3,weak - -__asan_stack_malloc_4: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_malloc_4,weak - -__asan_stack_malloc_5: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_malloc_5,weak - -__asan_stack_malloc_6: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_malloc_6,weak - -__asan_stack_malloc_7: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_malloc_7,weak - -__asan_stack_malloc_8: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_malloc_8,weak - -__asan_stack_malloc_9: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_malloc_9,weak - -__asan_stack_malloc_10: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_stack_malloc_10,weak - -__asan_store1: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_store1,weak - -__asan_store2: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_store2,weak - -__asan_store4: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_store4,weak - -__asan_store8: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_store8,weak - -__asan_store16: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_store16,weak - -__asan_store32: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_store32,weak - -__asan_unregister_globals: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_unregister_globals,weak - -__asan_version_mismatch_check_v8: - push %rbp - mov %rsp,%rbp - ud2 - .endfn __asan_version_mismatch_check_v8,weak diff --git a/libc/testlib/testlib.h b/libc/testlib/testlib.h index b14dabdba..a42358c99 100644 --- a/libc/testlib/testlib.h +++ b/libc/testlib/testlib.h @@ -59,16 +59,31 @@ COSMOPOLITAN_C_START_ #define EXPECT_LE(C, X) _TEST2("EXPECT_LE", C, <=, (X), #C, " ≤ ", #X, 0) #define EXPECT_LT(C, X) _TEST2("EXPECT_LT", C, <, (X), #C, " < ", #X, 0) -#define _TEST2(NAME, WANT, OP, GOT, WANTCODE, OPSTR, GOTCODE, ISFATAL) \ - do { \ - autotype(WANT) Want = (WANT); \ - autotype(GOT) Got = (GOT); \ - if (!(Want OP Got)) { \ - testlib_showerror(FILIFU NAME, OPSTR, WANTCODE OPSTR GOTCODE, \ - testlib_formatint(Want), testlib_formatint(Got)); \ - testlib_onfail2(ISFATAL); \ - } \ - } while (0) +/** + * Enables setup and teardown of test directories. + * + * If the linker says this symbol exists then, regardless of its value, + * a unique test directory will be created at the start of each test, + * the test will be run with that directory as its working directory, + * and if the test succeeds it'll be removed along with any contents. + */ +extern char testlib_enable_tmp_setup_teardown; + +/** + * User-defined test setup function. + * + * The test runner will call this function before each TEST() if it's + * defined by the linkage. + */ +void SetUp(void); + +/** + * User-defined test cleanup function. + * + * The test runner will call this function after each TEST() if it's + * defined by the linkage. + */ +void TearDown(void); /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § testing library » assert or die ─╬─│┼ @@ -87,39 +102,12 @@ COSMOPOLITAN_C_START_ __TEST_EQ(expect, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \ __VA_ARGS__) -#define __TEST_EQ(KIND, FILE, LINE, FUNC, WANTCODE, GOTCODE, WANT, GOT, ...) \ - ({ \ - autotype(GOT) Got = _I(GOT); \ - typeof(Got) Want = _I(WANT); \ - testlib_ontest(); \ - if (Want != Got) { \ - TESTLIB_ONFAIL(FILE, FUNC); \ - TESTLIB_SHOWERROR(testlib_showerror_##KIND##_eq, LINE, WANTCODE, \ - GOTCODE, testlib_formatint(_I(Want)), \ - testlib_formatint(_I(Got)), "" __VA_ARGS__); \ - } \ - (void)0; \ - }) - #define ASSERT_NE(WANT, GOT, ...) \ __TEST_NE(assert, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \ __VA_ARGS__) #define EXPECT_NE(WANT, GOT, ...) \ __TEST_NE(expect, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \ __VA_ARGS__) -#define __TEST_NE(KIND, FILE, LINE, FUNC, WANTCODE, GOTCODE, WANT, GOT, ...) \ - ({ \ - autotype(GOT) Got = (GOT); \ - typeof(Got) Want = (WANT); \ - testlib_ontest(); \ - if (Want == Got) { \ - TESTLIB_ONFAIL(FILE, FUNC); \ - TESTLIB_SHOWERROR(testlib_showerror_##KIND##_ne, LINE, WANTCODE, \ - GOTCODE, testlib_formatint(_I(Want)), \ - testlib_formatint(_I(Got)), "" __VA_ARGS__); \ - } \ - (void)0; \ - }) #define ASSERT_BETWEEN(BEG, END, GOT) \ assertBetween(FILIFU _I(BEG), _I(END), _I(GOT), \ @@ -245,6 +233,53 @@ COSMOPOLITAN_C_START_ const char *file; \ int line +#define TESTLIB_ONFAIL(FILE, FUNC) \ + if (g_testlib_shoulddebugbreak) DebugBreak(); \ + testlib_showerror_file = FILE; \ + testlib_showerror_func = FUNC + +#define TESTLIB_SHOWERROR(THUNK, ...) \ + (((typeof(&testlib_showerror_))strongaddr(#THUNK)))(__VA_ARGS__) + +#define __TEST_EQ(KIND, FILE, LINE, FUNC, WANTCODE, GOTCODE, WANT, GOT, ...) \ + ({ \ + autotype(GOT) Got = _I(GOT); \ + typeof(Got) Want = _I(WANT); \ + testlib_ontest(); \ + if (Want != Got) { \ + TESTLIB_ONFAIL(FILE, FUNC); \ + TESTLIB_SHOWERROR(testlib_showerror_##KIND##_eq, LINE, WANTCODE, \ + GOTCODE, testlib_formatint(_I(Want)), \ + testlib_formatint(_I(Got)), "" __VA_ARGS__); \ + } \ + (void)0; \ + }) + +#define __TEST_NE(KIND, FILE, LINE, FUNC, WANTCODE, GOTCODE, WANT, GOT, ...) \ + ({ \ + autotype(GOT) Got = (GOT); \ + typeof(Got) Want = (WANT); \ + testlib_ontest(); \ + if (Want == Got) { \ + TESTLIB_ONFAIL(FILE, FUNC); \ + TESTLIB_SHOWERROR(testlib_showerror_##KIND##_ne, LINE, WANTCODE, \ + GOTCODE, testlib_formatint(_I(Want)), \ + testlib_formatint(_I(Got)), "" __VA_ARGS__); \ + } \ + (void)0; \ + }) + +#define _TEST2(NAME, WANT, OP, GOT, WANTCODE, OPSTR, GOTCODE, ISFATAL) \ + do { \ + autotype(WANT) Want = (WANT); \ + autotype(GOT) Got = (GOT); \ + if (!(Want OP Got)) { \ + testlib_showerror(FILIFU NAME, OPSTR, WANTCODE OPSTR GOTCODE, \ + testlib_formatint(Want), testlib_formatint(Got)); \ + testlib_onfail2(ISFATAL); \ + } \ + } while (0) + typedef void (*testfn_t)(void); struct TestFixture { @@ -265,14 +300,6 @@ extern const testfn_t __testcase_start[], __testcase_end[]; extern const struct TestFixture __fixture_start[], __fixture_end[]; extern const struct TestFixture __combo_start[], __combo_end[]; -#define TESTLIB_ONFAIL(FILE, FUNC) \ - if (g_testlib_shoulddebugbreak) DebugBreak(); \ - testlib_showerror_file = FILE; \ - testlib_showerror_func = FUNC - -#define TESTLIB_SHOWERROR(THUNK, ...) \ - (((typeof(&testlib_showerror_))strongaddr(#THUNK)))(__VA_ARGS__) - void testlib_showerror_(int line, const char *wantcode, const char *gotcode, char *FREED_want, char *FREED_got, const char *fmt, ...) relegated; diff --git a/libc/testlib/testrunner.c b/libc/testlib/testrunner.c index 7f7de41de..6a226016b 100644 --- a/libc/testlib/testrunner.c +++ b/libc/testlib/testrunner.c @@ -17,15 +17,17 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" +#include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/errno.h" +#include "libc/fmt/fmt.h" +#include "libc/log/check.h" #include "libc/macros.h" #include "libc/nt/process.h" +#include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/testlib/testlib.h" - -void SetUp(void); -void TearDown(void); +#include "libc/x/x.h" void testlib_finish(void) { if (g_testlib_failed) { @@ -60,8 +62,18 @@ testonly void testlib_runtestcases(testfn_t *start, testfn_t *end, * * @see ape/ape.lds */ + int x; + char cwd[PATH_MAX]; + char tmp[PATH_MAX]; const testfn_t *fn; - for (fn = start; fn != end; ++fn) { + for (x = 0, fn = start; fn != end; ++fn) { + if (weaken(testlib_enable_tmp_setup_teardown)) { + CHECK_NOTNULL(getcwd(cwd, sizeof(cwd))); + snprintf(tmp, sizeof(tmp), "o/tmp/%s.%d.%d", + program_invocation_short_name, getpid(), x++); + CHECK_NE(-1, makedirs(tmp, 0755), "tmp=%s", tmp); + CHECK_NE(-1, chdir(tmp), "tmp=%s", tmp); + } if (weaken(SetUp)) weaken(SetUp)(); errno = 0; SetLastError(0); @@ -71,5 +83,9 @@ testonly void testlib_runtestcases(testfn_t *start, testfn_t *end, (*fn)(); getpid$sysv(); if (weaken(TearDown)) weaken(TearDown)(); + if (weaken(testlib_enable_tmp_setup_teardown)) { + CHECK_NE(-1, chdir(cwd)); + CHECK_NE(-1, rmrf(tmp)); + } } } diff --git a/test/libc/calls/commandv_test.c b/test/libc/calls/commandv_test.c index b25256767..329f8c6cc 100644 --- a/test/libc/calls/commandv_test.c +++ b/test/libc/calls/commandv_test.c @@ -34,12 +34,13 @@ #include "libc/x/x.h" uint64_t i; -char pathbuf[PATH_MAX], testdir[PATH_MAX], *oldpath; +char *oldpath; +char tmp[PATH_MAX]; +char pathbuf[PATH_MAX]; +char testlib_enable_tmp_setup_teardown; void SetUp(void) { - sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid()); - makedirs(testdir, 0755); - CHECK_NE(-1, chdir(testdir)); + static int x; mkdir("bin", 0755); mkdir("home", 0755); oldpath = strdup(nulltoempty(getenv("PATH"))); @@ -48,8 +49,6 @@ void SetUp(void) { void TearDown(void) { CHECK_NE(-1, setenv("PATH", oldpath, true)); - CHECK_NE(-1, chdir("../../..")); - CHECK_NE(-1, rmrf(testdir)); } TEST(commandv, testPathSearch) { diff --git a/test/libc/calls/fcntl_test.c b/test/libc/calls/fcntl_test.c index 11f00e127..22fa325da 100644 --- a/test/libc/calls/fcntl_test.c +++ b/test/libc/calls/fcntl_test.c @@ -26,20 +26,7 @@ #include "libc/testlib/testlib.h" #include "libc/x/x.h" -char basedir[PATH_MAX]; -char testdir[PATH_MAX]; - -void SetUp(void) { - getcwd(basedir, ARRAYLEN(basedir)); - sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid()); - makedirs(testdir, 0755); - CHECK_NE(-1, chdir(testdir)); -} - -void TearDown(void) { - CHECK_NE(-1, chdir(basedir)); - CHECK_NE(-1, rmrf(testdir)); -} +char testlib_enable_tmp_setup_teardown; TEST(fcntl_getfl, testRemembersAccessMode) { int fd; diff --git a/test/libc/calls/getcwd_test.c b/test/libc/calls/getcwd_test.c index e7dcee02e..2d14c8410 100644 --- a/test/libc/calls/getcwd_test.c +++ b/test/libc/calls/getcwd_test.c @@ -26,20 +26,7 @@ #include "libc/testlib/testlib.h" #include "libc/x/x.h" -char basedir[PATH_MAX]; -char testdir[PATH_MAX]; - -void SetUp(void) { - getcwd(basedir, ARRAYLEN(basedir)); - sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid()); - makedirs(testdir, 0755); - CHECK_NE(-1, chdir(testdir)); -} - -void TearDown(void) { - CHECK_NE(-1, chdir(basedir)); - CHECK_NE(-1, rmrf(testdir)); -} +char testlib_enable_tmp_setup_teardown; TEST(getcwd, test) { char buf[PATH_MAX]; diff --git a/test/libc/calls/lseek_test.c b/test/libc/calls/lseek_test.c index 905b75dda..2522649e0 100644 --- a/test/libc/calls/lseek_test.c +++ b/test/libc/calls/lseek_test.c @@ -25,18 +25,7 @@ #include "libc/testlib/testlib.h" #include "libc/x/x.h" -char testdir[PATH_MAX]; - -void SetUp(void) { - sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid()); - makedirs(testdir, 0755); - CHECK_NE(-1, chdir(testdir)); -} - -void TearDown(void) { - CHECK_NE(-1, chdir("../../..")); - CHECK_NE(-1, rmrf(testdir)); -} +char testlib_enable_tmp_setup_teardown; TEST(lseek, wat) { int fd, pid; diff --git a/test/libc/calls/mkdir_test.c b/test/libc/calls/mkdir_test.c index a1f3bbc23..997ac9742 100644 --- a/test/libc/calls/mkdir_test.c +++ b/test/libc/calls/mkdir_test.c @@ -25,18 +25,7 @@ #include "libc/testlib/testlib.h" #include "libc/x/x.h" -char testdir[PATH_MAX]; - -void SetUp(void) { - sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid()); - makedirs(testdir, 0755); - CHECK_NE(-1, chdir(testdir)); -} - -void TearDown(void) { - CHECK_NE(-1, chdir("../../..")); - CHECK_NE(-1, rmrf(testdir)); -} +char testlib_enable_tmp_setup_teardown; TEST(mkdir, testNothingExists_ENOENT) { EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755)); diff --git a/test/libc/runtime/mmap_test.c b/test/libc/runtime/mmap_test.c index 5977f46ea..6fd36482b 100644 --- a/test/libc/runtime/mmap_test.c +++ b/test/libc/runtime/mmap_test.c @@ -34,6 +34,8 @@ #include "libc/testlib/testlib.h" #include "libc/x/x.h" +char testlib_enable_tmp_setup_teardown; + TEST(mmap, testMapFile) { int fd; char *p; @@ -107,10 +109,6 @@ TEST(mmap, customStackMemory_isAuthorized) { TEST(mmap, fileOffset) { int fd; char *map; - char testdir[PATH_MAX]; - sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid()); - ASSERT_NE(-1, makedirs(testdir, 0755)); - ASSERT_NE(-1, chdir(testdir)); ASSERT_NE(-1, (fd = open("foo", O_CREAT | O_RDWR, 0644))); EXPECT_NE(-1, ftruncate(fd, FRAMESIZE * 2)); EXPECT_NE(-1, pwrite(fd, "hello", 5, FRAMESIZE * 0)); @@ -120,8 +118,6 @@ TEST(mmap, fileOffset) { EXPECT_EQ(0, memcmp(map, "there", 5), "%#.*s", 5, map); EXPECT_NE(-1, munmap(map, FRAMESIZE)); EXPECT_NE(-1, close(fd)); - ASSERT_NE(-1, chdir("../../..")); - ASSERT_NE(-1, rmrf(testdir)); } TEST(isheap, nullPtr) { diff --git a/tool/viz/printpeb.c b/tool/viz/printpeb.c index 38cb67034..aee83de7a 100644 --- a/tool/viz/printpeb.c +++ b/tool/viz/printpeb.c @@ -80,7 +80,7 @@ const struct IdName kNtStartfFlagNames[] = { {0, 0}, }; -void PrintStartupInfo(void) { +noasan void PrintStartupInfo(void) { printf("\n\ ╔──────────────────────────────────────────────────────────────────────────────╗\n\ │ new technology § startup info │\n\ @@ -155,7 +155,7 @@ void PrintStdioInfo(void) { ft2str(GetFileType(g_fds.p[2].handle))); } -void PrintTeb(void) { +noasan void PrintTeb(void) { GetCurrentProcessId(); SetLastError(0x1234); printf("\n\