From 9208c83f7a39efc966bf3ce22043d2c008d40398 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Wed, 18 May 2022 16:41:29 -0700 Subject: [PATCH] Make some systemic improvements - add vdso dump utility - tests now log stack usage - rename g_ftrace to __ftrace - make internal spinlocks go faster - add conformant c11 atomics library - function tracing now logs stack usage - make function call tracing thread safe - add -X unsecure (no ssl) mode to redbean - munmap() has more consistent behavior now - pacify fsync() calls on python unit tests - make --strace flag work better in redbean - start minimizing and documenting compiler flags --- build/htags | 4 + examples/greenbean.c | 5 +- libc/atomic.h | 80 ++++ libc/bits/atomic-clang.h | 36 ++ libc/bits/atomic-gcc.h | 58 +++ libc/bits/atomic-gcc47.h | 34 ++ libc/bits/atomic.h | 74 ++-- libc/calls/calls.mk | 98 +++-- libc/calls/close-nt.c | 8 +- .../describesigaltstack.greg.c} | 41 +- libc/calls/dup-nt.c | 15 +- libc/calls/fdatasync.c | 17 +- libc/calls/fsync.c | 15 +- libc/calls/internal.h | 6 +- libc/calls/mkntcmdline.c | 6 +- libc/calls/mkntenvblock.c | 8 +- libc/calls/{sched_yield.c => nosync.c} | 23 +- libc/calls/poll-nt.c | 1 - libc/calls/printfds.c | 1 - libc/calls/readlinkat.c | 3 + libc/calls/realpath.c | 5 +- libc/calls/sigaltstack.c | 16 +- libc/calls/strace.internal.h | 3 +- libc/calls/sync.c | 13 +- libc/calls/weirdtypes.h | 61 --- libc/integral/c.inc | 6 +- libc/integral/normalize.inc | 3 + libc/intrin/asan.c | 65 ++-- libc/intrin/asan.internal.h | 4 +- libc/intrin/assertfail.greg.c | 4 +- libc/intrin/atomic_load.c | 53 --- libc/intrin/atomic_load.h | 22 -- libc/intrin/atomic_store.c | 54 --- libc/intrin/atomic_store.h | 23 -- .../{closehandle.greg.c => closehandle.c} | 0 ...eatedirectory.greg.c => createdirectory.c} | 0 .../{createfile.greg.c => createfile.c} | 0 ...filemapping.greg.c => createfilemapping.c} | 0 ...ingnuma.greg.c => createfilemappingnuma.c} | 0 ...eatenamedpipe.greg.c => createnamedpipe.c} | 0 .../{createpipe.greg.c => createpipe.c} | 0 .../{createprocess.greg.c => createprocess.c} | 0 ...mboliclink.greg.c => createsymboliclink.c} | 0 .../{createthread.greg.c => createthread.c} | 0 .../{deletefile.greg.c => deletefile.c} | 0 libc/intrin/describeflags.internal.h | 2 + libc/intrin/describeframe.c | 12 +- libc/intrin/describemapflags.greg.c | 2 +- libc/intrin/{findclose.greg.c => findclose.c} | 0 .../{findfirstfile.greg.c => findfirstfile.c} | 0 .../{findnextfile.greg.c => findnextfile.c} | 0 ...hfilebuffers.greg.c => flushfilebuffers.c} | 0 ...ushviewoffile.greg.c => flushviewoffile.c} | 0 libc/intrin/ftrace.c | 23 +- ...vent.greg.c => generateconsolectrlevent.c} | 0 ...odeprocess.greg.c => getexitcodeprocess.c} | 0 ...eattributes.greg.c => getfileattributes.c} | 0 libc/intrin/intrin.mk | 61 +-- libc/intrin/kopenflags.S | 1 + ...pviewoffileex.greg.c => mapviewoffileex.c} | 0 ...ileexnuma.greg.c => mapviewoffileexnuma.c} | 0 .../{movefileex.greg.c => movefileex.c} | 0 .../{openprocess.greg.c => openprocess.c} | 0 ...movedirectory.greg.c => removedirectory.c} | 0 .../{reopenfile.greg.c => reopenfile.c} | 0 libc/intrin/sched_yield.S | 54 +++ ...directory.greg.c => setcurrentdirectory.c} | 0 libc/intrin/spinlock.h | 26 +- libc/intrin/stracef.greg.c | 1 + ...inateprocess.greg.c => terminateprocess.c} | 0 ...mapviewoffile.greg.c => unmapviewoffile.c} | 0 ...virtualprotect.greg.c => virtualprotect.c} | 0 ...bjects.greg.c => waitformultipleobjects.c} | 0 ...gleobject.greg.c => waitforsingleobject.c} | 0 libc/isystem/stdatomic.h | 4 + libc/log/backtrace2.greg.c | 14 +- libc/log/checkfail.c | 4 +- libc/log/log.h | 76 ++-- libc/log/log.mk | 1 - libc/log/oncrash.c | 13 +- libc/log/showcrashreports.c | 23 +- libc/mem/putenv.c | 6 +- libc/runtime/arememoryintervalsok.c | 7 + libc/runtime/fork-nt.c | 2 - libc/runtime/ftrace-hook.S | 2 +- libc/runtime/ftraceinit.greg.c | 2 +- libc/runtime/ftracer.c | 64 ++-- libc/runtime/memtrack.greg.c | 63 +++- libc/runtime/memtrack.internal.h | 24 +- libc/runtime/munmap.c | 152 +++++--- libc/runtime/printargs.greg.c | 8 +- libc/runtime/printmemoryintervals.c | 10 +- libc/runtime/runtime.h | 7 +- libc/runtime/runtime.mk | 19 +- libc/runtime/stack.h | 7 +- libc/runtime/stackuse.c | 34 +- libc/runtime/untrackmemoryintervals.c | 9 +- libc/runtime/winmain.greg.c | 2 +- libc/sock/ntstdin.greg.c | 150 -------- libc/sock/ntstdin.internal.h | 24 -- libc/sock/sock.mk | 5 - libc/sysv/strace.greg.c | 26 +- libc/sysv/{g_syscount.S => syscount.S} | 18 +- libc/sysv/sysv.mk | 6 +- libc/testlib/testmain.c | 1 + libc/thread/sem.c | 7 +- libc/x/makedirs.c | 8 +- test/libc/calls/commandv_test.c | 8 +- test/libc/calls/mkdir_test.c | 45 ++- test/libc/fmt/lengthuint64_test.c | 12 +- test/libc/intrin/kprintf_test.c | 7 +- test/libc/rand/rand64_test.c | 17 +- test/libc/runtime/memtrack_test.c | 98 +++-- test/libc/runtime/mmap_test.c | 5 + test/libc/runtime/munmap_test.c | 232 ++++++++++++ test/libc/str/undeflate_test.c | 8 +- test/tool/plinko/plinko_test.c | 8 +- .../dlmalloc/{dlmalloc.greg.c => dlmalloc.c} | 9 +- third_party/dlmalloc/dlmalloc.mk | 11 +- third_party/dlmalloc/vespene.greg.c | 2 +- third_party/python/Include/ceval.h | 2 +- .../python/Lib/test/test_coroutines.py | 5 +- third_party/python/Lib/test/test_signal.py | 14 +- third_party/python/Python/cosmomodule.c | 6 +- third_party/python/python.c | 18 +- third_party/python/python.mk | 8 +- third_party/python/pythontester.c | 19 + third_party/python/repl.c | 351 +---------------- third_party/python/runpythonmodule.c | 356 ++++++++++++++++++ third_party/python/runpythonmodule.h | 10 + tool/args/args.c | 10 +- tool/emacs/cosmo-c-keywords.el | 3 +- tool/net/counters.inc | 2 + tool/net/help.txt | 9 +- tool/net/redbean.c | 135 ++++--- tool/plinko/lib/plinko.c | 4 +- tool/plinko/lib/printf.c | 4 +- tool/plinko/lib/read.c | 4 +- tool/plinko/plinko.c | 1 + .../viz/echoctl.c | 16 +- .../sched_yield-nt.c => tool/viz/vdsodump.c | 75 +++- 141 files changed, 1948 insertions(+), 1411 deletions(-) create mode 100644 libc/atomic.h create mode 100644 libc/bits/atomic-clang.h create mode 100644 libc/bits/atomic-gcc.h create mode 100644 libc/bits/atomic-gcc47.h rename libc/{sock/stdinworker.c => calls/describesigaltstack.greg.c} (71%) rename libc/calls/{sched_yield.c => nosync.c} (77%) delete mode 100644 libc/intrin/atomic_load.c delete mode 100644 libc/intrin/atomic_load.h delete mode 100644 libc/intrin/atomic_store.c delete mode 100644 libc/intrin/atomic_store.h rename libc/intrin/{closehandle.greg.c => closehandle.c} (100%) rename libc/intrin/{createdirectory.greg.c => createdirectory.c} (100%) rename libc/intrin/{createfile.greg.c => createfile.c} (100%) rename libc/intrin/{createfilemapping.greg.c => createfilemapping.c} (100%) rename libc/intrin/{createfilemappingnuma.greg.c => createfilemappingnuma.c} (100%) rename libc/intrin/{createnamedpipe.greg.c => createnamedpipe.c} (100%) rename libc/intrin/{createpipe.greg.c => createpipe.c} (100%) rename libc/intrin/{createprocess.greg.c => createprocess.c} (100%) rename libc/intrin/{createsymboliclink.greg.c => createsymboliclink.c} (100%) rename libc/intrin/{createthread.greg.c => createthread.c} (100%) rename libc/intrin/{deletefile.greg.c => deletefile.c} (100%) rename libc/intrin/{findclose.greg.c => findclose.c} (100%) rename libc/intrin/{findfirstfile.greg.c => findfirstfile.c} (100%) rename libc/intrin/{findnextfile.greg.c => findnextfile.c} (100%) rename libc/intrin/{flushfilebuffers.greg.c => flushfilebuffers.c} (100%) rename libc/intrin/{flushviewoffile.greg.c => flushviewoffile.c} (100%) rename libc/intrin/{generateconsolectrlevent.greg.c => generateconsolectrlevent.c} (100%) rename libc/intrin/{getexitcodeprocess.greg.c => getexitcodeprocess.c} (100%) rename libc/intrin/{getfileattributes.greg.c => getfileattributes.c} (100%) rename libc/intrin/{mapviewoffileex.greg.c => mapviewoffileex.c} (100%) rename libc/intrin/{mapviewoffileexnuma.greg.c => mapviewoffileexnuma.c} (100%) rename libc/intrin/{movefileex.greg.c => movefileex.c} (100%) rename libc/intrin/{openprocess.greg.c => openprocess.c} (100%) rename libc/intrin/{removedirectory.greg.c => removedirectory.c} (100%) rename libc/intrin/{reopenfile.greg.c => reopenfile.c} (100%) create mode 100644 libc/intrin/sched_yield.S rename libc/intrin/{setcurrentdirectory.greg.c => setcurrentdirectory.c} (100%) rename libc/intrin/{terminateprocess.greg.c => terminateprocess.c} (100%) rename libc/intrin/{unmapviewoffile.greg.c => unmapviewoffile.c} (100%) rename libc/intrin/{virtualprotect.greg.c => virtualprotect.c} (100%) rename libc/intrin/{waitformultipleobjects.greg.c => waitformultipleobjects.c} (100%) rename libc/intrin/{waitforsingleobject.greg.c => waitforsingleobject.c} (100%) create mode 100644 libc/isystem/stdatomic.h delete mode 100644 libc/sock/ntstdin.greg.c delete mode 100644 libc/sock/ntstdin.internal.h rename libc/sysv/{g_syscount.S => syscount.S} (91%) create mode 100644 test/libc/runtime/munmap_test.c rename third_party/dlmalloc/{dlmalloc.greg.c => dlmalloc.c} (99%) create mode 100644 third_party/python/pythontester.c create mode 100644 third_party/python/runpythonmodule.c create mode 100644 third_party/python/runpythonmodule.h rename libc/calls/getfdhandleactual.greg.c => tool/viz/echoctl.c (86%) rename libc/calls/sched_yield-nt.c => tool/viz/vdsodump.c (53%) diff --git a/build/htags b/build/htags index b5957145f..f1ffc2dd0 100755 --- a/build/htags +++ b/build/htags @@ -43,6 +43,10 @@ # '(progn # (add-hook 'c-mode-common-hook 'jart-c-mode-common-hook))) +# ctags doesn't understand atomics, e.g. +# extern char **environ; +set -- --regex-c='/_Atomic(\([^)]*\))/\1/b' "$@" + # ctags doesn't understand variable prototypes, e.g. # extern char **environ; set -- --regex-c='/^\(\(hidden\|extern\|const\) \)*[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)/\4/b' "$@" diff --git a/examples/greenbean.c b/examples/greenbean.c index 45e54f612..00d2fd4e8 100644 --- a/examples/greenbean.c +++ b/examples/greenbean.c @@ -24,6 +24,7 @@ #include "libc/mem/mem.h" #include "libc/nexgen32e/threaded.h" #include "libc/runtime/runtime.h" +#include "libc/runtime/stack.h" #include "libc/runtime/sysconf.h" #include "libc/sock/sock.h" #include "libc/str/str.h" @@ -268,9 +269,9 @@ int main(int argc, char *argv[]) { workers = threads; for (i = 0; i < threads; ++i) { char *tls = __initialize_tls(malloc(64)); - void *stack = mmap(0, 65536, PROT_READ | PROT_WRITE, + void *stack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, MAP_STACK | MAP_ANONYMOUS, -1, 0); - CHECK_NE(-1, clone(Worker, stack, 65536, + CHECK_NE(-1, clone(Worker, stack, GetStackSize(), CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SETTLS, (void *)(intptr_t)i, 0, tls, 64, 0)); diff --git a/libc/atomic.h b/libc/atomic.h new file mode 100644 index 000000000..10e5925a9 --- /dev/null +++ b/libc/atomic.h @@ -0,0 +1,80 @@ +#ifndef COSMOPOLITAN_LIBC_ATOMIC_H_ +#define COSMOPOLITAN_LIBC_ATOMIC_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +/** + * @fileoverview C11 Atomic Types + * + * We supoprt C++ and old C compilers. It's recommended you use macros + * like `_Atomic(int)` rather than `_Atomic int` or `atomic_int` since + * we only define a portability macro for the syntax `_Atomic(T)`. + * + * @see libc/integral/c.inc + * @see libc/bits/atomic.h + */ + +#define atomic_bool _Atomic(_Bool) +#define atomic_bool32 atomic_int32 +#define atomic_char _Atomic(char) +#define atomic_schar _Atomic(signed char) +#define atomic_uchar _Atomic(unsigned char) +#define atomic_short _Atomic(short) +#define atomic_ushort _Atomic(unsigned short) +#define atomic_int _Atomic(int) +#define atomic_uint _Atomic(unsigned int) +#define atomic_long _Atomic(long) +#define atomic_ulong _Atomic(unsigned long) +#define atomic_llong _Atomic(long long) +#define atomic_ullong _Atomic(unsigned long long) +#define atomic_char16_t _Atomic(char16_t) +#define atomic_char32_t _Atomic(char32_t) +#define atomic_wchar_t _Atomic(wchar_t) +#define atomic_intptr_t _Atomic(intptr_t) +#define atomic_uintptr_t _Atomic(uintptr_t) +#define atomic_size_t _Atomic(size_t) +#define atomic_ptrdiff_t _Atomic(ptrdiff_t) +#define atomic_int_fast8_t _Atomic(int_fast8_t) +#define atomic_uint_fast8_t _Atomic(uint_fast8_t) +#define atomic_int_fast16_t _Atomic(int_fast16_t) +#define atomic_uint_fast16_t _Atomic(uint_fast16_t) +#define atomic_int_fast32_t _Atomic(int_fast32_t) +#define atomic_uint_fast32_t _Atomic(uint_fast32_t) +#define atomic_int_fast64_t _Atomic(int_fast64_t) +#define atomic_uint_fast64_t _Atomic(uint_fast64_t) +#define atomic_int_least8_t _Atomic(int_least8_t) +#define atomic_uint_least8_t _Atomic(uint_least8_t) +#define atomic_int_least16_t _Atomic(int_least16_t) +#define atomic_uint_least16_t _Atomic(uint_least16_t) +#define atomic_int_least32_t _Atomic(int_least32_t) +#define atomic_uint_least32_t _Atomic(uint_least32_t) +#define atomic_int_least64_t _Atomic(int_least64_t) +#define atomic_uint_least64_t _Atomic(uint_least64_t) + +#ifdef __CLANG_ATOMIC_BOOL_LOCK_FREE +#define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE +#define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE +#define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE +#define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE +#define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE +#define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE +#define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE +#define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE +#define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE +#define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE +#else +#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE +#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE +#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE +#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE +#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE +#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE +#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE +#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE +#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE +#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE +#endif + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_ATOMIC_H_ */ diff --git a/libc/bits/atomic-clang.h b/libc/bits/atomic-clang.h new file mode 100644 index 000000000..6debe5e0d --- /dev/null +++ b/libc/bits/atomic-clang.h @@ -0,0 +1,36 @@ +#ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_CLANG_H_ +#define COSMOPOLITAN_LIBC_BITS_ATOMIC_CLANG_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +/*───────────────────────────────────────────────────────────────────────────│─╗ +│ cosmopolitan § atomics » clang ─╬─│┼ +╚────────────────────────────────────────────────────────────────────────────│*/ + +#define atomic_init(obj, value) __c11_atomic_init(obj, value) +#define atomic_thread_fence(order) __c11_atomic_thread_fence(order) +#define atomic_signal_fence(order) __c11_atomic_signal_fence(order) +#define atomic_compare_exchange_strong_explicit(object, expected, desired, \ + success, failure) \ + __c11_atomic_compare_exchange_strong(object, expected, desired, success, \ + failure) +#define atomic_compare_exchange_weak_explicit(object, expected, desired, \ + success, failure) \ + __c11_atomic_compare_exchange_weak(object, expected, desired, success, \ + failure) +#define atomic_exchange_explicit(object, desired, order) \ + __c11_atomic_exchange(object, desired, order) +#define atomic_fetch_add_explicit(object, operand, order) \ + __c11_atomic_fetch_add(object, operand, order) +#define atomic_fetch_and_explicit(object, operand, order) \ + __c11_atomic_fetch_and(object, operand, order) +#define atomic_fetch_or_explicit(object, operand, order) \ + __c11_atomic_fetch_or(object, operand, order) +#define atomic_fetch_sub_explicit(object, operand, order) \ + __c11_atomic_fetch_sub(object, operand, order) +#define atomic_fetch_xor_explicit(object, operand, order) \ + __c11_atomic_fetch_xor(object, operand, order) +#define atomic_load_explicit(object, order) __c11_atomic_load(object, order) +#define atomic_store_explicit(object, desired, order) \ + __c11_atomic_store(object, desired, order) + +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_BITS_ATOMIC_CLANG_H_ */ diff --git a/libc/bits/atomic-gcc.h b/libc/bits/atomic-gcc.h new file mode 100644 index 000000000..afc0c7458 --- /dev/null +++ b/libc/bits/atomic-gcc.h @@ -0,0 +1,58 @@ +#ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_GCC_H_ +#define COSMOPOLITAN_LIBC_BITS_ATOMIC_GCC_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +/*───────────────────────────────────────────────────────────────────────────│─╗ +│ cosmopolitan § atomics » old gnu ─╬─│┼ +╚────────────────────────────────────────────────────────────────────────────│*/ + +#define atomic_init(obj, value) ((void)(*(obj) = (value))) +#define atomic_thread_fence(order) __sync_synchronize() +#define atomic_signal_fence(order) __asm__ volatile("" ::: "memory") +#define __atomic_apply_stride(object, operand) \ + (((__typeof__(__atomic_val(object)))0) + (operand)) +#define atomic_compare_exchange_strong_explicit(object, expected, desired, \ + success, failure) \ + __extension__({ \ + __typeof__(expected) __ep = (expected); \ + __typeof__(*__ep) __e = *__ep; \ + (void)(success); \ + (void)(failure); \ + (_Bool)((*__ep = __sync_val_compare_and_swap(object, __e, desired)) == \ + __e); \ + }) +#define atomic_compare_exchange_weak_explicit(object, expected, desired, \ + success, failure) \ + atomic_compare_exchange_strong_explicit(object, expected, desired, success, \ + failure) +#if __has_builtin(__sync_swap) +#define atomic_exchange_explicit(object, desired, order) \ + ((void)(order), __sync_swap(object, desired)) +#else +#define atomic_exchange_explicit(object, desired, order) \ + __extension__({ \ + __typeof__(object) __o = (object); \ + __typeof__(desired) __d = (desired); \ + (void)(order); \ + __sync_synchronize(); \ + __sync_lock_test_and_set(&__atomic_val(__o), __d); \ + }) +#endif +#define atomic_fetch_add_explicit(object, operand, order) \ + ((void)(order), \ + __sync_fetch_and_add(object, __atomic_apply_stride(object, operand))) +#define atomic_fetch_and_explicit(object, operand, order) \ + ((void)(order), __sync_fetch_and_and(object, operand)) +#define atomic_fetch_or_explicit(object, operand, order) \ + ((void)(order), __sync_fetch_and_or(object, operand)) +#define atomic_fetch_sub_explicit(object, operand, order) \ + ((void)(order), \ + __sync_fetch_and_sub(object, __atomic_apply_stride(object, operand))) +#define atomic_fetch_xor_explicit(object, operand, order) \ + ((void)(order), __sync_fetch_and_xor(object, operand)) +#define atomic_load_explicit(object, order) \ + ((void)(order), __sync_fetch_and_add(object, 0)) +#define atomic_store_explicit(object, desired, order) \ + ((void)atomic_exchange_explicit(object, desired, order)) + +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_BITS_ATOMIC_GCC_H_ */ diff --git a/libc/bits/atomic-gcc47.h b/libc/bits/atomic-gcc47.h new file mode 100644 index 000000000..47928ec75 --- /dev/null +++ b/libc/bits/atomic-gcc47.h @@ -0,0 +1,34 @@ +#ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_GCC47_H_ +#define COSMOPOLITAN_LIBC_BITS_ATOMIC_GCC47_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +/*───────────────────────────────────────────────────────────────────────────│─╗ +│ cosmopolitan § atomics » gcc 4.7+ ─╬─│┼ +╚────────────────────────────────────────────────────────────────────────────│*/ + +#define atomic_init(obj, value) ((void)(*(obj) = (value))) +#define atomic_thread_fence(order) __atomic_thread_fence(order) +#define atomic_signal_fence(order) __atomic_signal_fence(order) +#define atomic_compare_exchange_strong_explicit(pObject, pExpected, desired, \ + success, failure) \ + __atomic_compare_exchange_n(pObject, pExpected, desired, 0, success, failure) +#define atomic_compare_exchange_weak_explicit(pObject, pExpected, desired, \ + success, failure) \ + __atomic_compare_exchange_n(pObject, pExpected, desired, 1, success, failure) +#define atomic_exchange_explicit(pObject, desired, order) \ + __atomic_exchange_n(pObject, desired, order) +#define atomic_fetch_add_explicit(pObject, operand, order) \ + __atomic_fetch_add(pObject, operand, order) +#define atomic_fetch_and_explicit(pObject, operand, order) \ + __atomic_fetch_and(pObject, operand, order) +#define atomic_fetch_or_explicit(pObject, operand, order) \ + __atomic_fetch_or(pObject, operand, order) +#define atomic_fetch_sub_explicit(pObject, operand, order) \ + __atomic_fetch_sub(pObject, operand, order) +#define atomic_fetch_xor_explicit(pObject, operand, order) \ + __atomic_fetch_xor(pObject, operand, order) +#define atomic_load_explicit(pObject, order) __atomic_load_n(pObject, order) +#define atomic_store_explicit(pObject, desired, order) \ + __atomic_store_n(pObject, desired, order) + +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_BITS_ATOMIC_GCC47_H_ */ diff --git a/libc/bits/atomic.h b/libc/bits/atomic.h index e2d628adf..d2073d886 100644 --- a/libc/bits/atomic.h +++ b/libc/bits/atomic.h @@ -1,18 +1,18 @@ #ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_H_ #define COSMOPOLITAN_LIBC_BITS_ATOMIC_H_ -#include "libc/bits/bits.h" -#include "libc/intrin/lockcmpxchg.h" +#include "libc/atomic.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ /** - * @fileoverview C11 version of The Cosmopolitan Atomics Library. + * @fileoverview Cosmopolitan C11 Atomics Library * * - Forty-two different ways to say MOV. * - Fourteen different ways to say XCHG. * - Twenty different ways to say LOCK CMPXCHG. * - * Living proof high-level languages can be lower-level than assembly. + * It's a lower level programming language than assembly! + * + * @see libc/atomic.h */ #define memory_order int @@ -23,31 +23,47 @@ COSMOPOLITAN_C_START_ #define memory_order_acq_rel 4 #define memory_order_seq_cst 5 -#define atomic_flag struct AtomicFlag -#define atomic_flag_clear(PTR) atomic_store((PTR)->__cacheline, 0) -#define atomic_flag_test_and_set(PTR) \ - ({ \ - uint32_t ax = 0; \ - lockcmpxchg((PTR)->__cacheline, &ax, 1); \ - }) -#define atomic_init(PTR, VAL) atomic_store(PTR, VAL) -#define atomic_exchange(PTR, VAL) lockxchg(PTR, &(VAL)) -#define atomic_compare_exchange_strong(X, Y, Z) _lockcmpxchg(X, Y, Z) -#define atomic_compare_exchange_weak(X, Y, Z) _lockcmpxchg(X, Y, Z) -#define atomic_load_explicit(PTR, ORDER) atomic_load(PTR) -#define atomic_store_explicit(PTR, VAL, ORDER) atomic_store(PTR, VAL) -#define atomic_flag_clear_explicit(PTR, ORDER) atomic_store(PTR, 0) -#define atomic_exchange_explicit(PTR, VAL, ORDER) lockxchg(PTR, &(VAL)) -#define atomic_flag_test_and_set_explicit(PTR, ORDER) lockcmpxchg(PTR, 0, 1) -#define atomic_compare_exchange_strong_explicit(X, Y, Z, S, F) \ - lockcmpxchg(X, Y, Z) -#define atomic_compare_exchange_weak_explicit(X, Y, Z, S, F) \ - lockcmpxchg(X, Y, Z) +#define ATOMIC_VAR_INIT(value) (value) +#define atomic_is_lock_free(obj) ((void)(obj), sizeof(obj) <= sizeof(void *)) -struct AtomicFlag { - uint32_t __cacheline[16]; /* Intel V.O §9.4.6 */ -} forcealign(64); +#define atomic_flag atomic_bool +#define ATOMIC_FLAG_INIT ATOMIC_VAR_INIT(0) +#define atomic_flag_test_and_set_explicit(x, order) \ + atomic_exchange_explicit(x, 1, order) +#define atomic_flag_clear_explicit(x, order) atomic_store_explicit(x, 0, order) + +#define atomic_compare_exchange_strong(pObject, pExpected, desired) \ + atomic_compare_exchange_strong_explicit( \ + pObject, pExpected, desired, memory_order_seq_cst, memory_order_seq_cst) +#define atomic_compare_exchange_weak(pObject, pExpected, desired) \ + atomic_compare_exchange_weak_explicit( \ + pObject, pExpected, desired, memory_order_seq_cst, memory_order_seq_cst) +#define atomic_exchange(pObject, desired) \ + atomic_exchange_explicit(pObject, desired, memory_order_seq_cst) +#define atomic_fetch_add(pObject, operand) \ + atomic_fetch_add_explicit(pObject, operand, memory_order_seq_cst) +#define atomic_fetch_and(pObject, operand) \ + atomic_fetch_and_explicit(pObject, operand, memory_order_seq_cst) +#define atomic_fetch_or(pObject, operand) \ + atomic_fetch_or_explicit(pObject, operand, memory_order_seq_cst) +#define atomic_fetch_sub(pObject, operand) \ + atomic_fetch_sub_explicit(pObject, operand, memory_order_seq_cst) +#define atomic_fetch_xor(pObject, operand) \ + atomic_fetch_xor_explicit(pObject, operand, memory_order_seq_cst) +#define atomic_load(pObject) atomic_load_explicit(pObject, memory_order_seq_cst) +#define atomic_store(pObject, desired) \ + atomic_store_explicit(pObject, desired, memory_order_seq_cst) +#define atomic_flag_test_and_set(x) \ + atomic_flag_test_and_set_explicit(x, memory_order_seq_cst) +#define atomic_flag_clear(x) atomic_flag_clear_explicit(x, memory_order_seq_cst) + +#if defined(__CLANG_ATOMIC_BOOL_LOCK_FREE) +#include "libc/bits/atomic-clang.h" +#elif (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 +#include "libc/bits/atomic-gcc47.h" +#else +#include "libc/bits/atomic-gcc.h" +#endif -COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_BITS_ATOMIC_H_ */ diff --git a/libc/calls/calls.mk b/libc/calls/calls.mk index c238eb5c1..1845696bf 100644 --- a/libc/calls/calls.mk +++ b/libc/calls/calls.mk @@ -65,31 +65,39 @@ $(LIBC_CALLS_A).pkg: \ $(LIBC_CALLS_A_OBJS) \ $(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg) -o/$(MODE)/libc/calls/sigenter-freebsd.o \ -o/$(MODE)/libc/calls/sigenter-netbsd.o \ -o/$(MODE)/libc/calls/sigenter-openbsd.o \ +# we can't use asan because: +# ucontext_t memory is owned by xnu kernel o/$(MODE)/libc/calls/sigenter-xnu.o: \ OVERRIDE_COPTS += \ - -mno-fentry \ - -fno-stack-protector \ - -fno-sanitize=all + -ffreestanding \ + -fno-sanitize=address -o/$(MODE)/libc/calls/sys_mprotect.greg.o \ -o/$(MODE)/libc/calls/vdsofunc.greg.o \ -o/$(MODE)/libc/calls/directmap.o \ -o/$(MODE)/libc/calls/directmap-nt.o \ -o/$(MODE)/libc/calls/mapstack.greg.o \ -o/$(MODE)/libc/calls/execve-nt.greg.o \ -o/$(MODE)/libc/calls/getcwd.greg.o \ -o/$(MODE)/libc/calls/getcwd-xnu.greg.o \ -o/$(MODE)/libc/calls/getprogramexecutablename.greg.o \ -o/$(MODE)/libc/calls/raise.o: \ +# we can't use asan because: +# vdso memory is owned by linux kernel +o/$(MODE)/libc/calls/vdsofunc.greg.o: \ OVERRIDE_COPTS += \ -ffreestanding \ - $(NO_MAGIC) + -fno-sanitize=address -o/$(MODE)/libc/calls/termios2linux.o \ -o/$(MODE)/libc/calls/termios2host.o \ +# we can't use asan because: +# asan guard pages haven't been allocated yet +o/$(MODE)/libc/calls/directmap.o \ +o/$(MODE)/libc/calls/directmap-nt.o: \ + OVERRIDE_COPTS += \ + -ffreestanding \ + -fno-sanitize=address + +# we can't use asan because: +# ntspawn allocates 128kb of heap memory via win32 +o/$(MODE)/libc/calls/ntspawn.o \ +o/$(MODE)/libc/calls/mkntcmdline.o \ +o/$(MODE)/libc/calls/mkntenvblock.o: \ + OVERRIDE_COPTS += \ + -ffreestanding \ + -fno-sanitize=address + +# we always want -O3 because: +# it makes the code size smaller too o/$(MODE)/libc/calls/sigenter-freebsd.o \ o/$(MODE)/libc/calls/sigenter-netbsd.o \ o/$(MODE)/libc/calls/sigenter-openbsd.o \ @@ -98,7 +106,36 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: \ OVERRIDE_COPTS += \ -O3 -# TODO(jart): make va_arg optimize well in default mode +# we must disable static stack safety because: +# these functions use alloca(n) +o/$(MODE)/libc/calls/execl.o \ +o/$(MODE)/libc/calls/execle.o \ +o/$(MODE)/libc/calls/execlp.o \ +o/$(MODE)/libc/calls/execve-sysv.o \ +o/$(MODE)/libc/calls/mkntenvblock.o: \ + OVERRIDE_CPPFLAGS += \ + -DSTACK_FRAME_UNLIMITED + +# we must disable static stack safety because: +# PATH_MAX*sizeof(char16_t)*2 exceeds 4096 byte frame limit +o/$(MODE)/libc/calls/copyfile.o \ +o/$(MODE)/libc/calls/symlinkat-nt.o \ +o/$(MODE)/libc/calls/readlinkat-nt.o \ +o/$(MODE)/libc/calls/linkat-nt.o \ +o/$(MODE)/libc/calls/renameat-nt.o: \ + OVERRIDE_CPPFLAGS += \ + -DSTACK_FRAME_UNLIMITED + +# we must segregate codegen because: +# file contains multiple independently linkable apis +o/$(MODE)/libc/calls/ioctl-siocgifconf.o \ +o/$(MODE)/libc/calls/ioctl-siocgifconf-nt.o: \ + OVERRIDE_COPTS += \ + -ffunction-sections \ + -fdata-sections + +# we always want -Os because: +# va_arg codegen is very bloated in default mode o//libc/calls/open.o \ o//libc/calls/openat.o \ o//libc/calls/prctl.o \ @@ -120,27 +157,6 @@ o//libc/calls/fcntl.o: \ OVERRIDE_CFLAGS += \ -Os -# must use alloca() or path_max*2*2 -o/$(MODE)/libc/calls/execl.o \ -o/$(MODE)/libc/calls/execle.o \ -o/$(MODE)/libc/calls/execlp.o \ -o/$(MODE)/libc/calls/copyfile.o \ -o/$(MODE)/libc/calls/execve-nt.greg.o \ -o/$(MODE)/libc/calls/linkat-nt.o \ -o/$(MODE)/libc/calls/renameat-nt.o \ -o/$(MODE)/libc/calls/execve-sysv.o \ -o/$(MODE)/libc/calls/symlinkat-nt.o \ -o/$(MODE)/libc/calls/readlinkat-nt.o \ -o/$(MODE)/libc/calls/mkntenvblock.o: \ - OVERRIDE_CPPFLAGS += \ - -DSTACK_FRAME_UNLIMITED - -o/$(MODE)/libc/calls/ioctl-siocgifconf.o \ -o/$(MODE)/libc/calls/ioctl-siocgifconf-nt.o: \ - OVERRIDE_COPTS += \ - -ffunction-sections \ - -fdata-sections - 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)) diff --git a/libc/calls/close-nt.c b/libc/calls/close-nt.c index a6270628a..ef9bfe2fd 100644 --- a/libc/calls/close-nt.c +++ b/libc/calls/close-nt.c @@ -21,7 +21,6 @@ #include "libc/nt/enum/filetype.h" #include "libc/nt/files.h" #include "libc/nt/runtime.h" -#include "libc/sock/ntstdin.internal.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/errfuns.h" @@ -42,12 +41,7 @@ textwindows int sys_close_nt(struct Fd *fd) { // if this file descriptor is wrapped in a named pipe worker thread // then we need to close our copy of the worker thread handle. it's // also required that whatever install a worker use malloc, so free - if (fd->worker) { - if (!weaken(UnrefNtStdinWorker)(fd->worker)) ok = false; - fd->worker = 0; - } else { - if (!CloseHandle(fd->handle)) ok = false; - } + if (!CloseHandle(fd->handle)) ok = false; if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) { if (!CloseHandle(fd->extra)) ok = false; } diff --git a/libc/sock/stdinworker.c b/libc/calls/describesigaltstack.greg.c similarity index 71% rename from libc/sock/stdinworker.c rename to libc/calls/describesigaltstack.greg.c index 0dc32fe94..dbfc830cb 100644 --- a/libc/sock/stdinworker.c +++ b/libc/calls/describesigaltstack.greg.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 2022 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 │ @@ -16,29 +16,22 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" -#include "libc/calls/strace.internal.h" -#include "libc/runtime/runtime.h" -#include "libc/sock/ntstdin.internal.h" -#include "libc/sock/sock.h" +#include "libc/calls/struct/sigaltstack.h" +#include "libc/dce.h" +#include "libc/intrin/asan.internal.h" +#include "libc/intrin/describeflags.internal.h" +#include "libc/intrin/kprintf.h" -/* STATIC_YOINK("StdinWorker"); */ - -static textexit void StdinWorkerFree(void) { - int i; - NTTRACE("StdinWorkerFree()"); - for (i = g_fds.n; i--;) { - if (g_fds.p[i].kind && g_fds.p[i].worker) { - close(i); - } +const char *DescribeSigaltstk(char *buf, size_t bufsize, int rc, + const struct sigaltstack *ss) { + if (rc == -1) return "n/a"; + if (!ss) return "NULL"; + if ((!IsAsan() && kisdangerous(ss)) || + (IsAsan() && !__asan_is_valid(ss, sizeof(*ss)))) { + ksnprintf(buf, sizeof(buf), "%p", ss); + } else { + ksnprintf(buf, bufsize, "{.ss_sp=%p, .ss_flags=%#lx, .ss_size=%'zu}", + ss->ss_sp, ss->ss_flags, ss->ss_size); } + return buf; } - -static textstartup void StdinWorkerInit(void) { - g_fds.p[0].worker = NewNtStdinWorker(0); - atexit(StdinWorkerFree); -} - -const void *const StdinWorker[] initarray = { - StdinWorkerInit, -}; diff --git a/libc/calls/dup-nt.c b/libc/calls/dup-nt.c index 865e28025..7fcfff765 100644 --- a/libc/calls/dup-nt.c +++ b/libc/calls/dup-nt.c @@ -25,7 +25,6 @@ #include "libc/nt/files.h" #include "libc/nt/runtime.h" #include "libc/sock/internal.h" -#include "libc/sock/ntstdin.internal.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/errfuns.h" @@ -67,16 +66,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) { g_fds.p[newfd].kind = kFdReserved; } - // if this file descriptor is wrapped in a named pipe worker thread - // then we should clone the original authentic handle rather than the - // stdin worker's named pipe. we won't clone the worker, since that - // can always be recreated again on demand. - if (g_fds.p[oldfd].worker) { - handle = g_fds.p[oldfd].worker->reader; - } else { - handle = g_fds.p[oldfd].handle; - } - + handle = g_fds.p[oldfd].handle; proc = GetCurrentProcess(); if (DuplicateHandle(proc, handle, proc, &g_fds.p[newfd].handle, 0, true, kNtDuplicateSameAccess)) { @@ -90,9 +80,6 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) { } else { g_fds.p[newfd].extra = g_fds.p[oldfd].extra; } - if (g_fds.p[oldfd].worker) { - g_fds.p[newfd].worker = weaken(RefNtStdinWorker)(g_fds.p[oldfd].worker); - } rc = newfd; } else { __releasefd(newfd); diff --git a/libc/calls/fdatasync.c b/libc/calls/fdatasync.c index 2f63c4281..6e72c1c2c 100644 --- a/libc/calls/fdatasync.c +++ b/libc/calls/fdatasync.c @@ -20,21 +20,28 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" +#include "libc/runtime/runtime.h" /** * Blocks until kernel flushes non-metadata buffers for fd to disk. * * @return 0 on success, or -1 w/ errno - * @see fsync(), sync_file_range() + * @see sync(), fsync(), sync_file_range() + * @see __nosync to secretly disable * @asyncsignalsafe */ int fdatasync(int fd) { int rc; - if (!IsWindows()) { - rc = sys_fdatasync(fd); + if (__nosync != 0x5453455454534146) { + if (!IsWindows()) { + rc = sys_fdatasync(fd); + } else { + rc = sys_fdatasync_nt(fd); + } + STRACE("fdatasync(%d) → %d% m", fd, rc); } else { - rc = sys_fdatasync_nt(fd); + rc = 0; + STRACE("fdatasync(%d) → disabled% m", fd); } - STRACE("%s(%d) → %d% m", "fdatasync", fd, rc); return rc; } diff --git a/libc/calls/fsync.c b/libc/calls/fsync.c index 99b6286ec..e3b251fbf 100644 --- a/libc/calls/fsync.c +++ b/libc/calls/fsync.c @@ -20,21 +20,28 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" +#include "libc/runtime/runtime.h" /** * Blocks until kernel flushes buffers for fd to disk. * * @return 0 on success, or -1 w/ errno * @see fdatasync(), sync_file_range() + * @see __nosync to secretly disable * @asyncsignalsafe */ int fsync(int fd) { int rc; - if (!IsWindows()) { - rc = sys_fsync(fd); + if (__nosync != 0x5453455454534146) { + if (!IsWindows()) { + rc = sys_fsync(fd); + } else { + rc = sys_fdatasync_nt(fd); + } + STRACE("fysnc(%d) → %d% m", fd, rc); } else { - rc = sys_fdatasync_nt(fd); + rc = 0; + STRACE("fsync(%d) → disabled% m", fd); } - STRACE("%s(%d) → %d% m", "fsync", fd, rc); return rc; } diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 5c4457c67..9d7ab37ea 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -62,7 +62,6 @@ struct Fd { unsigned mode; int64_t handle; int64_t extra; - struct NtStdinWorker *worker; bool zombie; }; @@ -90,9 +89,12 @@ void __releasefd(int) hidden; void __releasefd_unlocked(int) hidden; int __ensurefds(int) hidden; int __ensurefds_unlocked(int) hidden; -int64_t __getfdhandleactual(int) hidden; void __printfds(void) hidden; +forceinline int64_t __getfdhandleactual(int fd) { + return g_fds.p[fd].handle; +} + forceinline bool __isfdopen(int fd) { return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty; } diff --git a/libc/calls/mkntcmdline.c b/libc/calls/mkntcmdline.c index 29eacc9b1..372c392eb 100644 --- a/libc/calls/mkntcmdline.c +++ b/libc/calls/mkntcmdline.c @@ -31,7 +31,7 @@ } \ } while (0) -static noasan bool NeedsQuotes(const char *s) { +static bool NeedsQuotes(const char *s) { if (!*s) return true; do { if (*s == ' ' || *s == '\t') { @@ -54,8 +54,8 @@ static noasan bool NeedsQuotes(const char *s) { * @return freshly allocated lpCommandLine or NULL w/ errno * @see libc/runtime/dosargv.c */ -textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX / 2], - const char *prog, char *const argv[]) { +textwindows int mkntcmdline(char16_t cmdline[ARG_MAX / 2], 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 95287bb6d..f8315ad52 100644 --- a/libc/calls/mkntenvblock.c +++ b/libc/calls/mkntenvblock.c @@ -31,14 +31,14 @@ #define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c)) -static noasan int CompareStrings(const char *l, const char *r) { +static int CompareStrings(const char *l, const char *r) { int a, b; size_t i = 0; while ((a = ToUpper(l[i] & 255)) == (b = ToUpper(r[i] & 255)) && r[i]) ++i; return a - b; } -static noasan void InsertString(char **a, size_t i, char *s) { +static 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]; @@ -57,8 +57,8 @@ static noasan void InsertString(char **a, size_t i, char *s) { * @return 0 on success, or -1 w/ errno * @error E2BIG if total number of shorts exceeded ARG_MAX/2 (32767) */ -textwindows noasan int mkntenvblock(char16_t envvars[ARG_MAX / 2], - char *const envp[], const char *extravar) { +textwindows int mkntenvblock(char16_t envvars[ARG_MAX / 2], char *const envp[], + const char *extravar) { bool v; char *t; axdx_t rc; diff --git a/libc/calls/sched_yield.c b/libc/calls/nosync.c similarity index 77% rename from libc/calls/sched_yield.c rename to libc/calls/nosync.c index 04b744961..fd0a71df8 100644 --- a/libc/calls/sched_yield.c +++ b/libc/calls/nosync.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=8 sts=2 sw=2 fenc=utf-8 :vi│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ @@ -17,17 +17,14 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" -#include "libc/dce.h" /** - * Asks kernel to deschedule thread momentarily. + * Tunes sync system call availability. + * + * If this value is set to 0x5453455454534146, then the system calls + * sync(), fsync(), and fdatasync() system calls will do nothing and + * return success. This is intended to be used for things like making + * things like Python unit tests go faster because fsync is extremely + * slow and using tmpfs requires root privileges. */ -int sched_yield(void) { - /* TODO(jart): Add get_sched_yield() so we can STRACE() */ - if (!IsWindows()) { - return sys_sched_yield(); - } else { - return sys_sched_yield_nt(); - } -} +uint64_t __nosync; diff --git a/libc/calls/poll-nt.c b/libc/calls/poll-nt.c index a9536e4c1..c1a282992 100644 --- a/libc/calls/poll-nt.c +++ b/libc/calls/poll-nt.c @@ -38,7 +38,6 @@ #include "libc/nt/synchronization.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" -#include "libc/sock/ntstdin.internal.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/sig.h" diff --git a/libc/calls/printfds.c b/libc/calls/printfds.c index 26ad273b2..d9ff0a691 100644 --- a/libc/calls/printfds.c +++ b/libc/calls/printfds.c @@ -54,7 +54,6 @@ void __printfds(void) { if (g_fds.p[i].mode) kprintf(" mode=%#o", g_fds.p[i].mode); if (g_fds.p[i].handle) kprintf(" handle=%ld", g_fds.p[i].handle); if (g_fds.p[i].extra) kprintf(" extra=%ld", g_fds.p[i].extra); - if (g_fds.p[i].worker) kprintf(" worker=%p", g_fds.p[i].worker); kprintf("\n"); } _spunlock(&__fds_lock); diff --git a/libc/calls/readlinkat.c b/libc/calls/readlinkat.c index d35116378..4e90745ab 100644 --- a/libc/calls/readlinkat.c +++ b/libc/calls/readlinkat.c @@ -16,12 +16,14 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/bits/weaken.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" +#include "libc/runtime/runtime.h" #include "libc/sysv/errfuns.h" #include "libc/zipos/zipos.internal.h" @@ -50,6 +52,7 @@ ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) { (bytes = __zipos_notat(dirfd, path)) == -1) { STRACE("TOOD: zipos support for readlinkat"); } else if (!IsWindows()) { + assert(bufsiz); bytes = sys_readlinkat(dirfd, path, buf, bufsiz); } else { bytes = sys_readlinkat_nt(dirfd, path, buf, bufsiz); diff --git a/libc/calls/realpath.c b/libc/calls/realpath.c index cb79c7142..559529652 100644 --- a/libc/calls/realpath.c +++ b/libc/calls/realpath.c @@ -30,6 +30,7 @@ #include "libc/bits/safemacros.internal.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" +#include "libc/calls/strace.internal.h" #include "libc/errno.h" #include "libc/limits.h" #include "libc/log/backtrace.internal.h" @@ -81,7 +82,9 @@ char *realpath(const char *filename, char *resolved) ssize_t rc; int e, up, check_dir=0; size_t k, p, q, l, l0, cnt=0, nup=0; - char output[PATH_MAX], stack[PATH_MAX], *z; + char output[PATH_MAX], stack[PATH_MAX+1], *z; + + /* STRACE("realpath(%#s, %#s)", filename, resolved); */ if (!filename) { einval(); diff --git a/libc/calls/sigaltstack.c b/libc/calls/sigaltstack.c index 3f2a74eb0..4ec6f30f5 100644 --- a/libc/calls/sigaltstack.c +++ b/libc/calls/sigaltstack.c @@ -22,10 +22,11 @@ #include "libc/calls/struct/sigaltstack.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" +#include "libc/intrin/describeflags.internal.h" #include "libc/sysv/errfuns.h" -static noasan void sigaltstack2bsd(struct sigaltstack_bsd *bsd, - const struct sigaltstack *linux) { +static void sigaltstack2bsd(struct sigaltstack_bsd *bsd, + const struct sigaltstack *linux) { void *sp; int flags; size_t size; @@ -37,8 +38,8 @@ static noasan void sigaltstack2bsd(struct sigaltstack_bsd *bsd, bsd->ss_size = size; } -static noasan void sigaltstack2linux(struct sigaltstack *linux, - const struct sigaltstack_bsd *bsd) { +static void sigaltstack2linux(struct sigaltstack *linux, + const struct sigaltstack_bsd *bsd) { void *sp; int flags; size_t size; @@ -69,10 +70,11 @@ static noasan void sigaltstack2linux(struct sigaltstack *linux, * @param old if non-null will receive current signal alt stack * @return 0 on success, or -1 w/ errno */ -noasan int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) { +int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) { int rc; void *b; const void *a; + char buf[2][128]; struct sigaltstack_bsd bsd; if (IsAsan() && ((old && __asan_check(old, sizeof(*old)).kind) || (neu && (__asan_check(neu, sizeof(*neu)).kind || @@ -106,6 +108,8 @@ noasan int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) { } else { rc = enosys(); } - STRACE("sigaltstack() → %d% m", rc); + STRACE("sigaltstack(%s, [%s]) → %d% m", + DescribeSigaltstk(buf[0], sizeof(buf[0]), 0, neu), + DescribeSigaltstk(buf[0], sizeof(buf[0]), 0, old), rc); return rc; } diff --git a/libc/calls/strace.internal.h b/libc/calls/strace.internal.h index fbfa984a6..b8d3cc662 100644 --- a/libc/calls/strace.internal.h +++ b/libc/calls/strace.internal.h @@ -4,6 +4,7 @@ #include "libc/calls/struct/rlimit.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/stat.h" +#include "libc/runtime/runtime.h" #define _KERNTRACE 0 /* not configurable w/ flag yet */ #define _POLLTRACE 0 /* not configurable w/ flag yet */ @@ -50,8 +51,6 @@ COSMOPOLITAN_C_START_ #define NTTRACE(FMT, ...) (void)0 #endif -extern int __strace; - void __stracef(const char *, ...); COSMOPOLITAN_C_END_ diff --git a/libc/calls/sync.c b/libc/calls/sync.c index 231ae339f..842df3762 100644 --- a/libc/calls/sync.c +++ b/libc/calls/sync.c @@ -18,15 +18,22 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" #include "libc/dce.h" /** * Flushes file system changes to disk by any means necessary. + * @see __nosync to secretly disable */ void sync(void) { - if (!IsWindows()) { - sys_sync(); + if (__nosync != 0x5453455454534146) { + if (!IsWindows()) { + sys_sync(); + } else { + sys_sync_nt(); + } + STRACE("sync()% m"); } else { - sys_sync_nt(); + STRACE("sync() → disabled% m"); } } diff --git a/libc/calls/weirdtypes.h b/libc/calls/weirdtypes.h index de7973ae1..569e66226 100644 --- a/libc/calls/weirdtypes.h +++ b/libc/calls/weirdtypes.h @@ -68,66 +68,5 @@ typedef __UINT_FAST64_TYPE__ uint_fast64_t; #define INT_FAST64_MIN (-INT_FAST64_MAX - 1) #define UINT_FAST16_MIN (-UINT_FAST16_MAX - 1) -#define atomic_bool _Atomic(_Bool) -#define atomic_bool32 atomic_int_fast32_t -#define atomic_char _Atomic(char) -#define atomic_schar _Atomic(signed char) -#define atomic_uchar _Atomic(unsigned char) -#define atomic_short _Atomic(short) -#define atomic_ushort _Atomic(unsigned short) -#define atomic_int _Atomic(int) -#define atomic_uint _Atomic(unsigned int) -#define atomic_long _Atomic(long) -#define atomic_ulong _Atomic(unsigned long) -#define atomic_llong _Atomic(long long) -#define atomic_ullong _Atomic(unsigned long long) -#define atomic_char16_t _Atomic(char16_t) -#define atomic_char32_t _Atomic(char32_t) -#define atomic_wchar_t _Atomic(wchar_t) -#define atomic_int_least8_t _Atomic(int_least8_t) -#define atomic_uint_least8_t _Atomic(uint_least8_t) -#define atomic_int_least16_t _Atomic(int_least16_t) -#define atomic_uint_least16_t _Atomic(uint_least16_t) -#define atomic_int_least32_t _Atomic(int_least32_t) -#define atomic_uint_least32_t _Atomic(uint_least32_t) -#define atomic_int_least64_t _Atomic(int_least64_t) -#define atomic_uint_least64_t _Atomic(uint_least64_t) -#define atomic_int_fast8_t _Atomic(int_fast8_t) -#define atomic_uint_fast8_t _Atomic(uint_fast8_t) -#define atomic_int_fast16_t _Atomic(int_fast16_t) -#define atomic_uint_fast16_t _Atomic(uint_fast16_t) -#define atomic_int_fast32_t _Atomic(int_fast32_t) -#define atomic_uint_fast32_t _Atomic(uint_fast32_t) -#define atomic_int_fast64_t _Atomic(int_fast64_t) -#define atomic_uint_fast64_t _Atomic(uint_fast64_t) -#define atomic_intptr_t _Atomic(intptr_t) -#define atomic_uintptr_t _Atomic(uintptr_t) -#define atomic_size_t _Atomic(size_t) -#define atomic_ptrdiff_t _Atomic(ptrdiff_t) - -#ifdef __CLANG_ATOMIC_BOOL_LOCK_FREE -#define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE -#define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE -#define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE -#define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE -#define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE -#define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE -#define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE -#define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE -#define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE -#define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE -#else -#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE -#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE -#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE -#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE -#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE -#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE -#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE -#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE -#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE -#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE -#endif - #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_CALLS_WEIRDTYPES_H_ */ diff --git a/libc/integral/c.inc b/libc/integral/c.inc index c2186bdf3..57ea8b3d6 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -67,8 +67,8 @@ } while (0) #endif -#if __STDC_VERSION__ + 0 < 201112 && defined(__x86__) -#define _Atomic(TYPE) TYPE +#if __STDC_VERSION__ + 0 < 201112 +#define _Atomic(TYPE) TYPE volatile #endif #ifdef __llvm__ @@ -123,7 +123,7 @@ typedef __UINT64_TYPE__ uint64_t; typedef __INTMAX_TYPE__ intmax_t; typedef __UINTMAX_TYPE__ uintmax_t; -#if __GNUC__ * 100 + __GNUC_MINOR__ >= 406 || defined(__llvm__) +#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 406 || defined(__llvm__) typedef signed __int128 int128_t; typedef unsigned __int128 uint128_t; #endif diff --git a/libc/integral/normalize.inc b/libc/integral/normalize.inc index 4cf6d3d06..c675eff38 100644 --- a/libc/integral/normalize.inc +++ b/libc/integral/normalize.inc @@ -50,6 +50,9 @@ #ifndef __has_cpp_attribute #define __has_cpp_attribute(x) 0 #endif +#ifndef __has_extension +#define __has_extension(x) 0 +#endif #ifdef unix #undef unix diff --git a/libc/intrin/asan.c b/libc/intrin/asan.c index d88aaa3db..7b17daa53 100644 --- a/libc/intrin/asan.c +++ b/libc/intrin/asan.c @@ -128,7 +128,7 @@ struct AsanSourceLocation { }; struct AsanAccessInfo { - const uintptr_t addr; + const char *addr; const uintptr_t first_bad_addr; size_t size; bool iswrite; @@ -136,7 +136,7 @@ struct AsanAccessInfo { }; struct AsanGlobal { - const uintptr_t addr; + const char *addr; size_t size; size_t size_with_redzone; const void *name; @@ -339,10 +339,10 @@ dontdiscard static __asan_die_f *__asan_die(void) { } } -void __asan_poison(long p, long n, signed char t) { +void __asan_poison(void *p, long n, signed char t) { signed char k, *s; - s = (signed char *)((p >> 3) + 0x7fff8000); - if ((k = p & 7)) { + s = (signed char *)(((intptr_t)p >> 3) + 0x7fff8000); + if ((k = (intptr_t)p & 7)) { if ((!*s && n >= 8 - k) || *s > k) *s = k; n -= MIN(8 - k, n); s += 1; @@ -354,10 +354,10 @@ void __asan_poison(long p, long n, signed char t) { } } -void __asan_unpoison(long p, long n) { +void __asan_unpoison(void *p, long n) { signed char k, *s; - k = p & 7; - s = (signed char *)((p >> 3) + 0x7fff8000); + k = (intptr_t)p & 7; + s = (signed char *)(((intptr_t)p >> 3) + 0x7fff8000); if (UNLIKELY(k)) { if (k + n < 8) { if (n > 0) *s = MAX(*s, k + n); @@ -737,9 +737,9 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size, uint64_t x, y, z; char *p, *q, *base; struct MemoryIntervals *m; - ++g_ftrace; + --__ftrace; p = __fatalbuf; - kprintf("\n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p\n%s\n", + kprintf("\n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p\n", __asan_describe_access_poison(kind), size, message, addr, SHADOW(addr), __argv[0]); if (0 < size && size < 80) { @@ -759,19 +759,19 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size, for (c = i = 0; i < 80; ++i) { if (!(t = __asan_check(base + i, 1).kind)) { if (c != 32) { - p = __stpcpy(p, "\e[32m"); + *p++ = '\e', *p++ = '[', *p++ = '3', *p++ = '2', *p++ = 'm'; c = 32; } *p++ = '.'; } else { if (c != 31) { - p = __stpcpy(p, "\e[31m"); + *p++ = '\e', *p++ = '[', *p++ = '3', *p++ = '1', *p++ = 'm'; c = 31; } p = __asan_utf8cpy(p, __asan_symbolize_access_poison(t)); } } - p = __stpcpy(p, "\e[39m"); + *p++ = '\e', *p++ = '[', *p++ = '3', *p++ = '9', *p++ = 'm'; *p++ = '\n'; for (i = 0; (intptr_t)(base + i) & 7; ++i) *p++ = ' '; for (; i + 8 <= 80; i += 8) { @@ -814,7 +814,7 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size, kprintf("%s", __fatalbuf); __asan_report_memory_origin(addr, size, kind); kprintf("\nthe crash was caused by\n"); - --g_ftrace; + ++__ftrace; return __asan_die(); } @@ -840,7 +840,7 @@ dontdiscard __asan_die_f *__asan_report_memory_fault(void *addr, int size, void *__asan_morgue_add(void *p) { int i; void *r; - _spinlock_optimistic(&__asan_lock); + _spinlock_cooperative(&__asan_lock); i = __asan_morgue.i++ & (ARRAYLEN(__asan_morgue.p) - 1); r = __asan_morgue.p[i]; __asan_morgue.p[i] = p; @@ -851,7 +851,7 @@ void *__asan_morgue_add(void *p) { static void __asan_morgue_flush(void) { int i; void *p; - _spinlock_optimistic(&__asan_lock); + _spinlock_cooperative(&__asan_lock); for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) { if (weaken(dlfree)) { weaken(dlfree)(__asan_morgue.p[i]); @@ -943,9 +943,9 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun, if ((p = weaken(dlmemalign)(a, __asan_heap_size(n)))) { c = weaken(dlmalloc_usable_size)(p); e = (struct AsanExtra *)(p + c - sizeof(*e)); - __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_unpoison(p, n); + __asan_poison(p - 16, 16, underrun); /* see dlmalloc design */ + __asan_poison(p + n, c - n, overrun); __asan_memset(p, 0xF9, n); __asan_write48(&e->size, n); __asan_memcpy(&e->bt, bt, sizeof(*bt)); @@ -1030,7 +1030,7 @@ static void __asan_deallocate(char *p, long kind) { struct AsanExtra *e; if ((e = __asan_get_extra(p, &c))) { if (__asan_read48(e->size, &n)) { - __asan_poison((uintptr_t)p, c, kind); + __asan_poison(p, c, kind); if (c <= ASAN_MORGUE_THRESHOLD) { p = __asan_morgue_add(p); } @@ -1084,11 +1084,11 @@ static void *__asan_realloc_impl(void *p, size_t n, if ((e = __asan_get_extra(p, &c))) { if (__asan_read48(e->size, &m)) { if (n <= m) { /* shrink */ - __asan_poison((uintptr_t)p + n, m - n, kAsanHeapOverrun); + __asan_poison((char *)p + n, m - n, kAsanHeapOverrun); __asan_write48(&e->size, n); return p; } else if (n <= c - sizeof(struct AsanExtra)) { /* small growth */ - __asan_unpoison((uintptr_t)p + m, n - m); + __asan_unpoison((char *)p + m, n - m); __asan_write48(&e->size, n); return p; } else { /* exponential growth */ @@ -1175,13 +1175,12 @@ void __asan_handle_no_return(void) { void __asan_register_globals(struct AsanGlobal g[], int n) { int i; - __asan_poison((intptr_t)g, sizeof(*g) * n, kAsanProtected); + __asan_poison(g, sizeof(*g) * n, kAsanProtected); for (i = 0; i < n; ++i) { __asan_poison(g[i].addr + g[i].size, g[i].size_with_redzone - g[i].size, kAsanGlobalRedzone); if (g[i].location) { - __asan_poison((intptr_t)g[i].location, sizeof(*g[i].location), - kAsanProtected); + __asan_poison(g[i].location, sizeof(*g[i].location), kAsanProtected); } } } @@ -1228,15 +1227,15 @@ void __asan_report_store(uint8_t *addr, int size) { } } -void __asan_poison_stack_memory(uintptr_t addr, size_t size) { +void __asan_poison_stack_memory(char *addr, size_t size) { __asan_poison(addr, size, kAsanStackFree); } -void __asan_unpoison_stack_memory(uintptr_t addr, size_t size) { +void __asan_unpoison_stack_memory(char *addr, size_t size) { __asan_unpoison(addr, size); } -void __asan_alloca_poison(uintptr_t addr, uintptr_t size) { +void __asan_alloca_poison(char *addr, uintptr_t size) { __asan_poison(addr - 32, 32, kAsanAllocaUnderrun); __asan_poison(addr + size, 32, kAsanAllocaOverrun); } @@ -1255,8 +1254,8 @@ void *__asan_get_current_fake_stack(void) { return 0; } -void __sanitizer_annotate_contiguous_container(long beg, long end, long old_mid, - long new_mid) { +void __sanitizer_annotate_contiguous_container(char *beg, char *end, + char *old_mid, char *new_mid) { // the c++ stl uses this // TODO(jart): make me faster __asan_unpoison(beg, new_mid - beg); @@ -1317,11 +1316,11 @@ void __asan_map_shadow(uintptr_t p, size_t n) { __repstosb((void *)(intptr_t)((int64_t)((uint64_t)a << 32) >> 16), kAsanUnmapped, size); } - __asan_unpoison((uintptr_t)p, n); + __asan_unpoison((char *)p, n); } static textstartup void __asan_shadow_string(char *s) { - __asan_map_shadow((uintptr_t)s, __strlen(s) + 1); + __asan_map_shadow((intptr_t)s, __strlen(s) + 1); } static textstartup void __asan_shadow_auxv(intptr_t *auxv) { @@ -1359,7 +1358,7 @@ static textstartup void __asan_shadow_mapping(struct MemoryIntervals *m, static textstartup void __asan_shadow_existing_mappings(void) { __asan_shadow_mapping(&_mmi, 0); - __asan_map_shadow(GetStackAddr(0), GetStackSize()); + __asan_map_shadow((intptr_t)GetStackAddr(0), GetStackSize()); __asan_poison(GetStackAddr(0), PAGESIZE, kAsanStackOverflow); } diff --git a/libc/intrin/asan.internal.h b/libc/intrin/asan.internal.h index d74411c85..5dc92372f 100644 --- a/libc/intrin/asan.internal.h +++ b/libc/intrin/asan.internal.h @@ -16,8 +16,8 @@ struct AsanFault { const signed char *shadow; }; -void __asan_unpoison(long, long); -void __asan_poison(long, long, signed char); +void __asan_unpoison(void *, long); +void __asan_poison(void *, long, signed char); void __asan_verify(const void *, size_t); void __asan_map_shadow(uintptr_t, size_t); bool __asan_is_valid(const void *, long) nosideeffect; diff --git a/libc/intrin/assertfail.greg.c b/libc/intrin/assertfail.greg.c index 0579ff244..ceaa381db 100644 --- a/libc/intrin/assertfail.greg.c +++ b/libc/intrin/assertfail.greg.c @@ -33,8 +33,8 @@ relegated wontreturn void __assert_fail(const char *expr, const char *file, int line) { int rc; static bool noreentry; - __strace = 0; - g_ftrace = 0; + --__strace; + --__ftrace; kprintf("%s:%d: assert(%s) failed\n", file, line, expr); if (_lockcmpxchg(&noreentry, false, true)) { if (weaken(__die)) { diff --git a/libc/intrin/atomic_load.c b/libc/intrin/atomic_load.c deleted file mode 100644 index a384ce053..000000000 --- a/libc/intrin/atomic_load.c +++ /dev/null @@ -1,53 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2021 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/atomic_load.h" - -/** - * Reads scalar from memory w/ one operation. - * - * This macro is intended to prevent things like compiler load tearing - * optimizations. - * - * @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64} - * @return *(MEM) - * @note defeats compiler load tearing optimizations - * @note alignas(𝑘) is implied if compiler knows type - * @note alignas(𝑘) only avoids multi-core / cross-page edge cases - * @see Intel's Six-Thousand Page Manual V.3A §8.2.3.1 - * @see atomic_store() - */ -intptr_t(atomic_load)(void *p, size_t n) { - intptr_t x = 0; - switch (n) { - case 1: - __builtin_memcpy(&x, p, 1); - return x; - case 2: - __builtin_memcpy(&x, p, 2); - return x; - case 4: - __builtin_memcpy(&x, p, 4); - return x; - case 8: - __builtin_memcpy(&x, p, 8); - return x; - default: - return 0; - } -} diff --git a/libc/intrin/atomic_load.h b/libc/intrin/atomic_load.h deleted file mode 100644 index d5a292de9..000000000 --- a/libc/intrin/atomic_load.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_INTRIN_ATOMIC_LOAD_H_ -#define COSMOPOLITAN_LIBC_INTRIN_ATOMIC_LOAD_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -intptr_t atomic_load(void *, size_t); - -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) -#define atomic_load(MEM) \ - ({ \ - autotype(MEM) Mem = (MEM); \ - typeof(*Mem) Reg; \ - asm("mov\t%1,%0" : "=r"(Reg) : "m"(*Mem)); \ - Reg; \ - }) -#else -#define atomic_load(MEM) atomic_load(MEM, sizeof(*(MEM))) -#endif /* GNUC && !ANSI && x86 */ - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_INTRIN_ATOMIC_LOAD_H_ */ diff --git a/libc/intrin/atomic_store.c b/libc/intrin/atomic_store.c deleted file mode 100644 index c4c32e6b7..000000000 --- a/libc/intrin/atomic_store.c +++ /dev/null @@ -1,54 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2021 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/atomic_store.h" - -/** - * Saves scalar to memory w/ one operation. - * - * This is guaranteed to happen in either one or zero operations, - * depending on whether or not it's possible for *(MEM) to be read - * afterwards. This macro only forbids compiler from using >1 ops. - * - * @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64} - * @param VAL is uint𝑘_t w/ better encoding for immediates (constexpr) - * @return VAL - * @note alignas(𝑘) on nexgen32e only needed for end of page gotcha - * @note alignas(𝑘) is implied if compiler knows type - * @note needed to defeat store tearing optimizations - * @see Intel Six-Thousand Page Manual Manual V.3A §8.2.3.1 - * @see atomic_load() - */ -intptr_t(atomic_store)(void *p, intptr_t x, size_t n) { - switch (n) { - case 1: - __builtin_memcpy(p, &x, 1); - return x; - case 2: - __builtin_memcpy(p, &x, 2); - return x; - case 4: - __builtin_memcpy(p, &x, 4); - return x; - case 8: - __builtin_memcpy(p, &x, 8); - return x; - default: - return 0; - } -} diff --git a/libc/intrin/atomic_store.h b/libc/intrin/atomic_store.h deleted file mode 100644 index 9a83c407c..000000000 --- a/libc/intrin/atomic_store.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_INTRIN_ATOMIC_STORE_H_ -#define COSMOPOLITAN_LIBC_INTRIN_ATOMIC_STORE_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -intptr_t atomic_store(void *, intptr_t, size_t); - -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) -#define atomic_store(MEM, VAL) \ - ({ \ - autotype(VAL) Val = (VAL); \ - typeof(&Val) Mem = (MEM); \ - asm("mov%z1\t%1,%0" : "=m"(*Mem) : "r"(Val)); \ - Val; \ - }) -#else -#define atomic_store(MEM, VAL) \ - atomic_store(MEM, VAL, sizeof(*(MEM)) / (sizeof(*(MEM)) == sizeof(*(VAL)))) -#endif /* __GNUC__ && !__STRICT_ANSI__ */ - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_INTRIN_ATOMIC_STORE_H_ */ diff --git a/libc/intrin/closehandle.greg.c b/libc/intrin/closehandle.c similarity index 100% rename from libc/intrin/closehandle.greg.c rename to libc/intrin/closehandle.c diff --git a/libc/intrin/createdirectory.greg.c b/libc/intrin/createdirectory.c similarity index 100% rename from libc/intrin/createdirectory.greg.c rename to libc/intrin/createdirectory.c diff --git a/libc/intrin/createfile.greg.c b/libc/intrin/createfile.c similarity index 100% rename from libc/intrin/createfile.greg.c rename to libc/intrin/createfile.c diff --git a/libc/intrin/createfilemapping.greg.c b/libc/intrin/createfilemapping.c similarity index 100% rename from libc/intrin/createfilemapping.greg.c rename to libc/intrin/createfilemapping.c diff --git a/libc/intrin/createfilemappingnuma.greg.c b/libc/intrin/createfilemappingnuma.c similarity index 100% rename from libc/intrin/createfilemappingnuma.greg.c rename to libc/intrin/createfilemappingnuma.c diff --git a/libc/intrin/createnamedpipe.greg.c b/libc/intrin/createnamedpipe.c similarity index 100% rename from libc/intrin/createnamedpipe.greg.c rename to libc/intrin/createnamedpipe.c diff --git a/libc/intrin/createpipe.greg.c b/libc/intrin/createpipe.c similarity index 100% rename from libc/intrin/createpipe.greg.c rename to libc/intrin/createpipe.c diff --git a/libc/intrin/createprocess.greg.c b/libc/intrin/createprocess.c similarity index 100% rename from libc/intrin/createprocess.greg.c rename to libc/intrin/createprocess.c diff --git a/libc/intrin/createsymboliclink.greg.c b/libc/intrin/createsymboliclink.c similarity index 100% rename from libc/intrin/createsymboliclink.greg.c rename to libc/intrin/createsymboliclink.c diff --git a/libc/intrin/createthread.greg.c b/libc/intrin/createthread.c similarity index 100% rename from libc/intrin/createthread.greg.c rename to libc/intrin/createthread.c diff --git a/libc/intrin/deletefile.greg.c b/libc/intrin/deletefile.c similarity index 100% rename from libc/intrin/deletefile.greg.c rename to libc/intrin/deletefile.c diff --git a/libc/intrin/describeflags.internal.h b/libc/intrin/describeflags.internal.h index 2c822ac05..189dc829f 100644 --- a/libc/intrin/describeflags.internal.h +++ b/libc/intrin/describeflags.internal.h @@ -3,6 +3,7 @@ #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/rlimit.h" #include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/sigaltstack.h" #include "libc/calls/struct/sigset.h" #include "libc/calls/struct/stat.h" #include "libc/calls/struct/timespec.h" @@ -27,6 +28,7 @@ const char *DescribePollFlags(char *, size_t, int); const char *DescribeStat(int, const struct stat *); const char *DescribeDirfd(char[hasatleast 12], int); const char *DescribeSigaction(char *, size_t, int, const struct sigaction *); +const char *DescribeSigaltstk(char *, size_t, int, const struct sigaltstack *); const char *DescribeSigset(char *, size_t, int, const sigset_t *); const char *DescribeRlimit(char *, size_t, int, const struct rlimit *); const char *DescribeTimespec(char *, size_t, int, const struct timespec *); diff --git a/libc/intrin/describeframe.c b/libc/intrin/describeframe.c index 1dc78593f..f252ff429 100644 --- a/libc/intrin/describeframe.c +++ b/libc/intrin/describeframe.c @@ -30,17 +30,17 @@ noasan const char *DescribeFrame(int x) { char *p; static char buf[32]; if (IsShadowFrame(x)) { - ksnprintf(buf, sizeof(buf), " /*shadow:%.12p*/", UNSHADOW(ADDR(x))); + ksnprintf(buf, sizeof(buf), " shadow=%.8x", FRAME(UNSHADOW(ADDR(x)))); return buf; - return " /*shadow*/ "; + return " shadow "; } else if (IsAutoFrame(x)) { - return " /*automap*/"; + return " automap"; } else if (IsFixedFrame(x)) { - return " /*fixed*/ "; + return " fixed "; } else if (IsArenaFrame(x)) { - return " /*arena*/ "; + return " arena "; } else if (IsStaticStackFrame(x)) { - return " /*stack*/ "; + return " stack "; } else { return ""; } diff --git a/libc/intrin/describemapflags.greg.c b/libc/intrin/describemapflags.greg.c index f30c85fe9..b0fdefd50 100644 --- a/libc/intrin/describemapflags.greg.c +++ b/libc/intrin/describemapflags.greg.c @@ -26,8 +26,8 @@ const char *DescribeMapFlags(int x) { _Alignas(char) static char mapflags[256]; const struct DescribeFlags kMapFlags[] = { {MAP_STACK, "STACK"}, // order matters - {MAP_ANONYMOUS, "ANONYMOUS"}, // {MAP_PRIVATE, "PRIVATE"}, // + {MAP_ANONYMOUS, "ANONYMOUS"}, // {MAP_SHARED, "SHARED"}, // {MAP_FIXED, "FIXED"}, // {MAP_FIXED_NOREPLACE, "FIXED_NOREPLACE"}, // diff --git a/libc/intrin/findclose.greg.c b/libc/intrin/findclose.c similarity index 100% rename from libc/intrin/findclose.greg.c rename to libc/intrin/findclose.c diff --git a/libc/intrin/findfirstfile.greg.c b/libc/intrin/findfirstfile.c similarity index 100% rename from libc/intrin/findfirstfile.greg.c rename to libc/intrin/findfirstfile.c diff --git a/libc/intrin/findnextfile.greg.c b/libc/intrin/findnextfile.c similarity index 100% rename from libc/intrin/findnextfile.greg.c rename to libc/intrin/findnextfile.c diff --git a/libc/intrin/flushfilebuffers.greg.c b/libc/intrin/flushfilebuffers.c similarity index 100% rename from libc/intrin/flushfilebuffers.greg.c rename to libc/intrin/flushfilebuffers.c diff --git a/libc/intrin/flushviewoffile.greg.c b/libc/intrin/flushviewoffile.c similarity index 100% rename from libc/intrin/flushviewoffile.greg.c rename to libc/intrin/flushviewoffile.c diff --git a/libc/intrin/ftrace.c b/libc/intrin/ftrace.c index 58f88f986..202fe746c 100644 --- a/libc/intrin/ftrace.c +++ b/libc/intrin/ftrace.c @@ -18,4 +18,25 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/runtime/runtime.h" -int g_ftrace; +/** + * Function tracing enabled state. + * + * After ftrace_install() has been called, the logging of C function + * calls may be controlled by changing this variable. If `__ftrace` is + * greater than zero, functions are logged. Otherwise, they aren't. + * + * By convention, functions wishing to disable function tracing for a + * short time period should say: + * + * void foo() { + * --__ftrace; + * bar(); + * ++__ftrace; + * } + * + * This way you still have some flexibility to force function tracing, + * by setting `__ftrace` to a higher number like `2` or `200`. Even + * though under normal circumstances, `__ftrace` should only be either + * zero or one. + */ +_Atomic(int) __ftrace; diff --git a/libc/intrin/generateconsolectrlevent.greg.c b/libc/intrin/generateconsolectrlevent.c similarity index 100% rename from libc/intrin/generateconsolectrlevent.greg.c rename to libc/intrin/generateconsolectrlevent.c diff --git a/libc/intrin/getexitcodeprocess.greg.c b/libc/intrin/getexitcodeprocess.c similarity index 100% rename from libc/intrin/getexitcodeprocess.greg.c rename to libc/intrin/getexitcodeprocess.c diff --git a/libc/intrin/getfileattributes.greg.c b/libc/intrin/getfileattributes.c similarity index 100% rename from libc/intrin/getfileattributes.greg.c rename to libc/intrin/getfileattributes.c diff --git a/libc/intrin/intrin.mk b/libc/intrin/intrin.mk index b3f880840..f3f671ea5 100644 --- a/libc/intrin/intrin.mk +++ b/libc/intrin/intrin.mk @@ -66,50 +66,57 @@ o/$(MODE)/libc/intrin/kprintf.greg.o: \ o/$(MODE)/libc/intrin/tls.greg.o \ o/$(MODE)/libc/intrin/exit.greg.o \ -o/$(MODE)/libc/intrin/errno.greg.o \ o/$(MODE)/libc/intrin/exit1.greg.o \ o/$(MODE)/libc/intrin/gettid.greg.o \ o/$(MODE)/libc/intrin/getenv.greg.o \ -o/$(MODE)/libc/intrin/createfile.greg.o \ o/$(MODE)/libc/intrin/assertfail.greg.o \ -o/$(MODE)/libc/intrin/reopenfile.greg.o \ -o/$(MODE)/libc/intrin/deletefile.greg.o \ -o/$(MODE)/libc/intrin/createpipe.greg.o \ -o/$(MODE)/libc/intrin/closehandle.greg.o \ o/$(MODE)/libc/intrin/describeiov.greg.o \ -o/$(MODE)/libc/intrin/openprocess.greg.o \ -o/$(MODE)/libc/intrin/createthread.greg.o \ o/$(MODE)/libc/intrin/describestat.greg.o \ -o/$(MODE)/libc/intrin/findnextfile.greg.o \ -o/$(MODE)/libc/intrin/createprocess.greg.o \ -o/$(MODE)/libc/intrin/findfirstfile.greg.o \ o/$(MODE)/libc/intrin/describeflags.greg.o \ o/$(MODE)/libc/intrin/describerlimit.greg.o \ -o/$(MODE)/libc/intrin/removedirectory.greg.o \ -o/$(MODE)/libc/intrin/createnamedpipe.greg.o \ -o/$(MODE)/libc/intrin/unmapviewoffile.greg.o \ -o/$(MODE)/libc/intrin/flushviewoffile.greg.o \ o/$(MODE)/libc/intrin/deviceiocontrol.greg.o \ -o/$(MODE)/libc/intrin/createdirectory.greg.o \ -o/$(MODE)/libc/intrin/flushfilebuffers.greg.o \ -o/$(MODE)/libc/intrin/terminateprocess.greg.o \ o/$(MODE)/libc/intrin/describemapflags.greg.o \ o/$(MODE)/libc/intrin/describetimespec.greg.o \ -o/$(MODE)/libc/intrin/getfileattributes.greg.o \ -o/$(MODE)/libc/intrin/getexitcodeprocess.greg.o \ -o/$(MODE)/libc/intrin/waitforsingleobject.greg.o \ -o/$(MODE)/libc/intrin/setcurrentdirectory.greg.o \ -o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \ -o/$(MODE)/libc/intrin/createfilemappingnuma.greg.o \ -o/$(MODE)/libc/intrin/waitformultipleobjects.greg.o \ -o/$(MODE)/libc/intrin/generateconsolectrlevent.greg.o \ +o/$(MODE)/libc/intrin/createfile.o \ +o/$(MODE)/libc/intrin/reopenfile.o \ +o/$(MODE)/libc/intrin/deletefile.o \ +o/$(MODE)/libc/intrin/createpipe.o \ +o/$(MODE)/libc/intrin/closehandle.o \ +o/$(MODE)/libc/intrin/openprocess.o \ +o/$(MODE)/libc/intrin/createthread.o \ +o/$(MODE)/libc/intrin/findclose.o \ +o/$(MODE)/libc/intrin/findnextfile.o \ +o/$(MODE)/libc/intrin/createprocess.o \ +o/$(MODE)/libc/intrin/findfirstfile.o \ +o/$(MODE)/libc/intrin/removedirectory.o \ +o/$(MODE)/libc/intrin/createsymboliclink.o \ +o/$(MODE)/libc/intrin/createnamedpipe.o \ +o/$(MODE)/libc/intrin/unmapviewoffile.o \ +o/$(MODE)/libc/intrin/virtualprotect.o \ +o/$(MODE)/libc/intrin/flushviewoffile.o \ +o/$(MODE)/libc/intrin/createdirectory.o \ +o/$(MODE)/libc/intrin/flushfilebuffers.o \ +o/$(MODE)/libc/intrin/terminateprocess.o \ +o/$(MODE)/libc/intrin/getfileattributes.o \ +o/$(MODE)/libc/intrin/getexitcodeprocess.o \ +o/$(MODE)/libc/intrin/waitforsingleobject.o \ +o/$(MODE)/libc/intrin/setcurrentdirectory.o \ +o/$(MODE)/libc/intrin/mapviewoffileex.o \ +o/$(MODE)/libc/intrin/movefileex.o \ +o/$(MODE)/libc/intrin/mapviewoffileexnuma.o \ +o/$(MODE)/libc/intrin/createfilemapping.o \ +o/$(MODE)/libc/intrin/createfilemappingnuma.o \ +o/$(MODE)/libc/intrin/waitformultipleobjects.o \ +o/$(MODE)/libc/intrin/generateconsolectrlevent.o \ o/$(MODE)/libc/intrin/kstarttsc.o \ o/$(MODE)/libc/intrin/nomultics.o \ o/$(MODE)/libc/intrin/ntconsolemode.o: \ OVERRIDE_CFLAGS += \ -Os \ + -fwrapv \ -ffreestanding \ - $(NO_MAGIC) + -fno-stack-protector \ + -fno-sanitize=all o/$(MODE)/libc/intrin/describeopenflags.greg.o: \ OVERRIDE_CPPFLAGS += \ diff --git a/libc/intrin/kopenflags.S b/libc/intrin/kopenflags.S index a0749a5af..e00ebf792 100644 --- a/libc/intrin/kopenflags.S +++ b/libc/intrin/kopenflags.S @@ -40,6 +40,7 @@ kOpenFlags: .e O_TRUNC,"TRUNC" // .e O_CLOEXEC,"CLOEXEC" // .e O_NONBLOCK,"NONBLOCK" // + .e O_DIRECTORY,"DIRECTORY" // .e O_DIRECT,"DIRECT" // no-op on xnu/openbsd .e O_APPEND,"APPEND" // weird on nt .e O_TMPFILE,"TMPFILE" // linux, windows diff --git a/libc/intrin/mapviewoffileex.greg.c b/libc/intrin/mapviewoffileex.c similarity index 100% rename from libc/intrin/mapviewoffileex.greg.c rename to libc/intrin/mapviewoffileex.c diff --git a/libc/intrin/mapviewoffileexnuma.greg.c b/libc/intrin/mapviewoffileexnuma.c similarity index 100% rename from libc/intrin/mapviewoffileexnuma.greg.c rename to libc/intrin/mapviewoffileexnuma.c diff --git a/libc/intrin/movefileex.greg.c b/libc/intrin/movefileex.c similarity index 100% rename from libc/intrin/movefileex.greg.c rename to libc/intrin/movefileex.c diff --git a/libc/intrin/openprocess.greg.c b/libc/intrin/openprocess.c similarity index 100% rename from libc/intrin/openprocess.greg.c rename to libc/intrin/openprocess.c diff --git a/libc/intrin/removedirectory.greg.c b/libc/intrin/removedirectory.c similarity index 100% rename from libc/intrin/removedirectory.greg.c rename to libc/intrin/removedirectory.c diff --git a/libc/intrin/reopenfile.greg.c b/libc/intrin/reopenfile.c similarity index 100% rename from libc/intrin/reopenfile.greg.c rename to libc/intrin/reopenfile.c diff --git a/libc/intrin/sched_yield.S b/libc/intrin/sched_yield.S new file mode 100644 index 000000000..9f6059da9 --- /dev/null +++ b/libc/intrin/sched_yield.S @@ -0,0 +1,54 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/dce.h" +#include "libc/sysv/consts/nr.h" +#include "libc/macros.internal.h" + +// Asks kernel to let other threads be scheduled. +// +// @return 0 on success, or -1 w/ errno +sched_yield: + push %rbp + mov %rsp,%rbp + testb IsWindows() + jnz 1f + +// UNIX Support + mov __NR_sched_yield,%eax + syscall + jmp 2f + +// Windows Support +// +// A value of zero, together with the bAlertable parameter set to +// FALSE, causes the thread to relinquish the remainder of its time +// slice to any other thread that is ready to run, if there are no +// pending user APCs on the calling thread. If there are no other +// threads ready to run and no user APCs are queued, the function +// returns immediately, and the thread continues execution. +// ──Quoth MSDN +1: xor %ecx,%ecx + xor %edx,%edx + ntcall __imp_SleepEx + xor %eax,%eax + +2: pop %rbp + ret + .endfn sched_yield,globl + .previous diff --git a/libc/intrin/setcurrentdirectory.greg.c b/libc/intrin/setcurrentdirectory.c similarity index 100% rename from libc/intrin/setcurrentdirectory.greg.c rename to libc/intrin/setcurrentdirectory.c diff --git a/libc/intrin/spinlock.h b/libc/intrin/spinlock.h index e85051b36..c58c72f23 100644 --- a/libc/intrin/spinlock.h +++ b/libc/intrin/spinlock.h @@ -1,13 +1,8 @@ #ifndef COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ #define COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ -#include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/dce.h" #include "libc/intrin/kprintf.h" #include "libc/intrin/lockcmpxchg.h" -#include "libc/log/backtrace.internal.h" -#include "libc/log/log.h" -#include "libc/runtime/symbols.internal.h" #if IsModeDbg() && !defined(_SPINLOCK_DEBUG) #define _SPINLOCK_DEBUG @@ -15,13 +10,13 @@ #if defined(_SPINLOCK_DEBUG) #define _spinlock(lock) _spinlock_ndebug(lock) -#define _spinlock_ndebug(lock) _spinlock_optimistic(lock) +#define _spinlock_ndebug(lock) _spinlock_cooperative(lock) #elif defined(TINY) #define _spinlock(lock) _spinlock_tiny(lock) #define _spinlock_ndebug(lock) _spinlock_tiny(lock) #else -#define _spinlock(lock) _spinlock_optimistic(lock) -#define _spinlock_ndebug(lock) _spinlock_optimistic(lock) +#define _spinlock(lock) _spinlock_cooperative(lock) +#define _spinlock_ndebug(lock) _spinlock_cooperative(lock) #endif #define _spunlock(lock) __atomic_clear(lock, __ATOMIC_RELAXED) @@ -41,15 +36,18 @@ } \ } while (0) -#define _spinlock_optimistic(lock) \ +#define _spinlock_cooperative(lock) \ do { \ + int __tries = 0; \ for (;;) { \ typeof(*(lock)) x; \ __atomic_load(lock, &x, __ATOMIC_RELAXED); \ if (!x && !_trylock(lock)) { \ break; \ - } else { \ + } else if (++__tries & 7) { \ __builtin_ia32_pause(); \ + } else { \ + sched_yield(); \ } \ } \ } while (0) @@ -57,7 +55,7 @@ #define _spinlock_debug(lock) \ do { \ typeof(*(lock)) me, owner; \ - unsigned long warntries = 10000000; \ + unsigned long warntries = 16777216; \ me = gettid(); \ if (!_lockcmpxchg(lock, 0, me)) { \ __atomic_load(lock, &owner, __ATOMIC_RELAXED); \ @@ -71,7 +69,11 @@ kprintf("%s:%d: warning: possible deadlock on %s in %s()\n", \ __FILE__, __LINE__, #lock, __FUNCTION__); \ } \ - __builtin_ia32_pause(); \ + if (warntries & 7) { \ + __builtin_ia32_pause(); \ + } else { \ + sched_yield(); \ + } \ } \ } \ } while (0) diff --git a/libc/intrin/stracef.greg.c b/libc/intrin/stracef.greg.c index ab5fbc4fe..6ca880dbf 100644 --- a/libc/intrin/stracef.greg.c +++ b/libc/intrin/stracef.greg.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/strace.internal.h" #include "libc/intrin/kprintf.h" +#include "libc/runtime/runtime.h" privileged void __stracef(const char *fmt, ...) { va_list v; diff --git a/libc/intrin/terminateprocess.greg.c b/libc/intrin/terminateprocess.c similarity index 100% rename from libc/intrin/terminateprocess.greg.c rename to libc/intrin/terminateprocess.c diff --git a/libc/intrin/unmapviewoffile.greg.c b/libc/intrin/unmapviewoffile.c similarity index 100% rename from libc/intrin/unmapviewoffile.greg.c rename to libc/intrin/unmapviewoffile.c diff --git a/libc/intrin/virtualprotect.greg.c b/libc/intrin/virtualprotect.c similarity index 100% rename from libc/intrin/virtualprotect.greg.c rename to libc/intrin/virtualprotect.c diff --git a/libc/intrin/waitformultipleobjects.greg.c b/libc/intrin/waitformultipleobjects.c similarity index 100% rename from libc/intrin/waitformultipleobjects.greg.c rename to libc/intrin/waitformultipleobjects.c diff --git a/libc/intrin/waitforsingleobject.greg.c b/libc/intrin/waitforsingleobject.c similarity index 100% rename from libc/intrin/waitforsingleobject.greg.c rename to libc/intrin/waitforsingleobject.c diff --git a/libc/isystem/stdatomic.h b/libc/isystem/stdatomic.h new file mode 100644 index 000000000..319a98beb --- /dev/null +++ b/libc/isystem/stdatomic.h @@ -0,0 +1,4 @@ +#ifndef COSMOPOLITAN_LIBC_ISYSTEM_STDATOMIC_H_ +#define COSMOPOLITAN_LIBC_ISYSTEM_STDATOMIC_H_ +#include "libc/bits/atomic.h" +#endif /* COSMOPOLITAN_LIBC_ISYSTEM_STDATOMIC_H_ */ diff --git a/libc/log/backtrace2.greg.c b/libc/log/backtrace2.greg.c index 05aee9fa4..8512da804 100644 --- a/libc/log/backtrace2.greg.c +++ b/libc/log/backtrace2.greg.c @@ -21,6 +21,7 @@ #include "libc/bits/safemacros.internal.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" +#include "libc/calls/internal.h" #include "libc/calls/sigbits.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" @@ -86,6 +87,11 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) { return -1; } + if (IsLinux() && !__is_linux_2_6_23()) { + // we need the `addr2line -a` option + return -1; + } + i = 0; j = 0; argv[i++] = "addr2line"; @@ -177,12 +183,12 @@ static int PrintBacktrace(int fd, const struct StackFrame *bp) { void ShowBacktrace(int fd, const struct StackFrame *bp) { #ifdef __FNO_OMIT_FRAME_POINTER__ /* asan runtime depends on this function */ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); - __atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED); + --__ftrace; + --__strace; if (!bp) bp = __builtin_frame_address(0); PrintBacktrace(fd, bp); - __atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED); - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); + ++__strace; + ++__ftrace; #else (fprintf)(stderr, "ShowBacktrace() needs these flags to show C backtrace:\n" "\t-D__FNO_OMIT_FRAME_POINTER__\n" diff --git a/libc/log/checkfail.c b/libc/log/checkfail.c index d98055e7e..ba43b5123 100644 --- a/libc/log/checkfail.c +++ b/libc/log/checkfail.c @@ -45,8 +45,8 @@ relegated void __check_fail(const char *suffix, const char *opstr, size_t i; va_list va; char hostname[32]; - __strace = 0; - g_ftrace = 0; + --__strace; + --__ftrace; e = errno; __start_fatal(file, line); __stpcpy(hostname, "unknown"); diff --git a/libc/log/log.h b/libc/log/log.h index 1c9c8b93b..18be04844 100644 --- a/libc/log/log.h +++ b/libc/log/log.h @@ -78,15 +78,15 @@ extern unsigned __log_level; /* log level for runtime check */ // log a message with the specified log level (not checking if LOGGABLE) #define LOGF(LEVEL, FMT, ...) \ do { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(LEVEL, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } while (0) // die with an error message without backtrace and debugger invocation #define DIEF(FMT, ...) \ do { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ if (weaken(__die)) weaken(__die)(); \ exit(1); \ @@ -95,7 +95,7 @@ extern unsigned __log_level; /* log level for runtime check */ #define FATALF(FMT, ...) \ do { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ ffatalf(kLogFatal, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ unreachable; \ } while (0) @@ -103,78 +103,78 @@ extern unsigned __log_level; /* log level for runtime check */ #define ERRORF(FMT, ...) \ do { \ if (LOGGABLE(kLogError)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define WARNF(FMT, ...) \ do { \ if (LOGGABLE(kLogWarn)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define INFOF(FMT, ...) \ do { \ if (LOGGABLE(kLogInfo)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define VERBOSEF(FMT, ...) \ do { \ if (LOGGABLE(kLogVerbose)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ fverbosef(kLogVerbose, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define DEBUGF(FMT, ...) \ do { \ if (UNLIKELY(LOGGABLE(kLogDebug))) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ fdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define NOISEF(FMT, ...) \ do { \ if (UNLIKELY(LOGGABLE(kLogNoise))) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ fnoisef(kLogNoise, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define FLOGF(F, FMT, ...) \ do { \ if (LOGGABLE(kLogInfo)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(kLogInfo, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define FWARNF(F, FMT, ...) \ do { \ if (LOGGABLE(kLogWarn)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(kLogWarn, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define FFATALF(F, FMT, ...) \ do { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ ffatalf(kLogFatal, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ unreachable; \ } while (0) @@ -182,18 +182,18 @@ extern unsigned __log_level; /* log level for runtime check */ #define FDEBUGF(F, FMT, ...) \ do { \ if (UNLIKELY(LOGGABLE(kLogDebug))) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ fdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define FNOISEF(F, FMT, ...) \ do { \ if (UNLIKELY(LOGGABLE(kLogNoise))) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ fnoisef(kLogNoise, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) @@ -206,25 +206,25 @@ extern unsigned __log_level; /* log level for runtime check */ int e = errno; \ autotype(FORM) Ax = (FORM); \ if (UNLIKELY(Ax == (typeof(Ax))(-1)) && LOGGABLE(kLogWarn)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ __logerrno(__FILE__, __LINE__, #FORM); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ errno = e; \ } \ Ax; \ }) -#define LOGIFNULL(FORM) \ - ({ \ - int e = errno; \ - autotype(FORM) Ax = (FORM); \ - if (Ax == NULL && LOGGABLE(kLogWarn)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ - __logerrno(__FILE__, __LINE__, #FORM); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ - errno = e; \ - } \ - Ax; \ +#define LOGIFNULL(FORM) \ + ({ \ + int e = errno; \ + autotype(FORM) Ax = (FORM); \ + if (Ax == NULL && LOGGABLE(kLogWarn)) { \ + --__ftrace; \ + __logerrno(__FILE__, __LINE__, #FORM); \ + ++__ftrace; \ + errno = e; \ + } \ + Ax; \ }) /*───────────────────────────────────────────────────────────────────────────│─╗ diff --git a/libc/log/log.mk b/libc/log/log.mk index 593dd3982..36930a76f 100644 --- a/libc/log/log.mk +++ b/libc/log/log.mk @@ -75,7 +75,6 @@ o/$(MODE)/libc/log/backtrace3.o \ o/$(MODE)/libc/log/checkaligned.o \ o/$(MODE)/libc/log/checkfail.o \ o/$(MODE)/libc/log/checkfail_ndebug.o \ -o/$(MODE)/libc/log/getsymboltable.o \ o/$(MODE)/libc/log/restoretty.o \ o/$(MODE)/libc/log/oncrash.o \ o/$(MODE)/libc/log/onkill.o \ diff --git a/libc/log/oncrash.c b/libc/log/oncrash.c index dce6c0fb2..325d0273a 100644 --- a/libc/log/oncrash.c +++ b/libc/log/oncrash.c @@ -206,8 +206,9 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si, " %m\n" " %s %s %s %s\n", !__nocolor ? "\e[30;101m" : "", !__nocolor ? "\e[0m" : "", sig, - (ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) && - ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE)) + (ctx && + (ctx->uc_mcontext.rsp >= (intptr_t)GetStaticStackAddr(0) && + ctx->uc_mcontext.rsp <= (intptr_t)GetStaticStackAddr(0) + PAGESIZE)) ? "Stack Overflow" : GetSiCodeName(sig, si->si_code), host, getpid(), gettid(), program_invocation_name, names.sysname, @@ -278,8 +279,8 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si, int gdbpid, err; static bool noreentry, notpossible; STRACE("__oncrash rip %x", ctx->uc_mcontext.rip); - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); - __atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED); + --__ftrace; + --__strace; if (_lockcmpxchg(&noreentry, false, true)) { if (!__vforked) { rip = ctx ? ctx->uc_mcontext.rip : 0; @@ -317,6 +318,6 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si, } noreentry = false; ItsATrap: - __atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED); - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); + ++__strace; + ++__ftrace; } diff --git a/libc/log/showcrashreports.c b/libc/log/showcrashreports.c index 66edf6490..86efb79ad 100644 --- a/libc/log/showcrashreports.c +++ b/libc/log/showcrashreports.c @@ -31,8 +31,14 @@ STATIC_YOINK("__die"); /* for backtracing */ STATIC_YOINK("malloc_inspect_all"); /* for asan memory origin */ STATIC_YOINK("__get_symbol_by_addr"); /* for asan memory origin */ +static struct sigaltstack oldsigaltstack; extern const unsigned char __oncrash_thunks[8][11]; +static void FreeSigAltStack(void *p) { + sigaltstack(&oldsigaltstack, 0); + free(p); +} + /** * Installs crash signal handlers. * @@ -63,17 +69,24 @@ void ShowCrashReports(void) { kCrashSigs[5] = SIGABRT; /* abort() called */ kCrashSigs[6] = SIGBUS; /* misaligned, noncanonical ptr, etc. */ /* : showcrashreports.c, oncrashthunks.S, oncrash.c */ + if (!IsWindows()) { + bzero(&ss, sizeof(ss)); + ss.ss_flags = 0; + ss.ss_size = SIGSTKSZ; + if ((ss.ss_sp = malloc(SIGSTKSZ))) { + if (!sigaltstack(&ss, &oldsigaltstack)) { + __cxa_atexit(FreeSigAltStack, ss.ss_sp, 0); + } else { + free(ss.ss_sp); + } + } + } bzero(&sa, sizeof(sa)); - ss.ss_flags = 0; - ss.ss_size = SIGSTKSZ; - ss.ss_sp = malloc(SIGSTKSZ); - __cxa_atexit(free, ss.ss_sp, 0); sa.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK; sigfillset(&sa.sa_mask); for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) { sigdelset(&sa.sa_mask, kCrashSigs[i]); } - if (!IsWindows()) sigaltstack(&ss, 0); for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) { if (kCrashSigs[i]) { sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i]; diff --git a/libc/mem/putenv.c b/libc/mem/putenv.c index 27ff77240..be407b1b9 100644 --- a/libc/mem/putenv.c +++ b/libc/mem/putenv.c @@ -105,10 +105,14 @@ Fail: return einval(); } +static void UnsetenvFree(void *p) { + free(p); +} + /* weakly called by unsetenv() when removing a pointer */ void __freeenv(void *p) { if (once) { - __cxa_atexit(free, p, 0); + __cxa_atexit(UnsetenvFree, p, 0); } } diff --git a/libc/runtime/arememoryintervalsok.c b/libc/runtime/arememoryintervalsok.c index 1a4969a14..5b7d4fe9c 100644 --- a/libc/runtime/arememoryintervalsok.c +++ b/libc/runtime/arememoryintervalsok.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/strace.internal.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/memtrack.internal.h" noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) { @@ -27,6 +28,12 @@ noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) { STRACE("AreMemoryIntervalsOk() y should be >= x!"); return false; } + if (!(mm->p[i].size <= + (size_t)(mm->p[i].y - mm->p[i].x) * FRAMESIZE + FRAMESIZE && + mm->p[i].size > (size_t)(mm->p[i].y - mm->p[i].x) * FRAMESIZE)) { + STRACE("AreMemoryIntervalsOk() size is wrong!"); + return false; + } if (i) { if (mm->p[i].h != -1 || mm->p[i - 1].h != -1) { if (mm->p[i].x <= mm->p[i - 1].y) { diff --git a/libc/runtime/fork-nt.c b/libc/runtime/fork-nt.c index e737f6f3e..39b464562 100644 --- a/libc/runtime/fork-nt.c +++ b/libc/runtime/fork-nt.c @@ -45,7 +45,6 @@ #include "libc/runtime/internal.h" #include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" -#include "libc/sock/ntstdin.internal.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" @@ -222,7 +221,6 @@ textwindows void WinMainForked(void) { // rewrap the stdin named pipe hack // since the handles closed on fork - if (weaken(ForkNtStdinWorker)) weaken(ForkNtStdinWorker)(); struct Fds *fds = VEIL("r", &g_fds); fds->p[0].handle = fds->__init_p[0].handle = GetStdHandle(kNtStdInputHandle); fds->p[1].handle = fds->__init_p[1].handle = GetStdHandle(kNtStdOutputHandle); diff --git a/libc/runtime/ftrace-hook.S b/libc/runtime/ftrace-hook.S index a679c52b1..b4d7f2885 100644 --- a/libc/runtime/ftrace-hook.S +++ b/libc/runtime/ftrace-hook.S @@ -20,7 +20,7 @@ .privileged ftrace_hook: - cmp $0,g_ftrace(%rip) + cmp $0,__ftrace(%rip) jg 1f ret 1: push %rbp diff --git a/libc/runtime/ftraceinit.greg.c b/libc/runtime/ftraceinit.greg.c index 48bbc05aa..cb212bda1 100644 --- a/libc/runtime/ftraceinit.greg.c +++ b/libc/runtime/ftraceinit.greg.c @@ -35,7 +35,7 @@ textstartup int ftrace_init(void) { if (__intercept_flag(&__argc, __argv, "--ftrace")) { ftrace_install(); - ++g_ftrace; + ++__ftrace; } return __argc; } diff --git a/libc/runtime/ftracer.c b/libc/runtime/ftracer.c index d3a63c7c0..c3494741a 100644 --- a/libc/runtime/ftracer.c +++ b/libc/runtime/ftracer.c @@ -17,24 +17,26 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/safemacros.internal.h" +#include "libc/fmt/itoa.h" #include "libc/intrin/cmpxchg.h" #include "libc/intrin/kprintf.h" +#include "libc/intrin/spinlock.h" #include "libc/log/libfatal.internal.h" #include "libc/macros.internal.h" +#include "libc/math.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/rdtscp.h" #include "libc/nexgen32e/stackframe.h" #include "libc/nexgen32e/x86feature.h" #include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" +#include "libc/runtime/stack.h" #include "libc/runtime/symbols.internal.h" #include "libc/stdio/stdio.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/o.h" #include "libc/time/clockstonanos.internal.h" -#pragma weak stderr - #define MAX_NESTING 512 /** @@ -47,13 +49,16 @@ void ftrace_hook(void); -bool ftrace_enabled; -static int g_skew; -static int64_t g_lastaddr; -static uint64_t g_laststamp; +_Alignas(64) char ftrace_lock; -static privileged noinstrument noasan noubsan int GetNestingLevelImpl( - struct StackFrame *frame) { +static struct Ftrace { + int skew; + int stackdigs; + int64_t lastaddr; + uint64_t laststamp; +} g_ftrace; + +static privileged int GetNestingLevelImpl(struct StackFrame *frame) { int nesting = -2; while (frame) { ++nesting; @@ -62,12 +67,11 @@ static privileged noinstrument noasan noubsan int GetNestingLevelImpl( return MAX(0, nesting); } -static privileged noinstrument noasan noubsan int GetNestingLevel( - struct StackFrame *frame) { +static privileged int GetNestingLevel(struct StackFrame *frame) { int nesting; nesting = GetNestingLevelImpl(frame); - if (nesting < g_skew) g_skew = nesting; - nesting -= g_skew; + if (nesting < g_ftrace.skew) g_ftrace.skew = nesting; + nesting -= g_ftrace.skew; return MIN(MAX_NESTING, nesting); } @@ -78,32 +82,30 @@ static privileged noinstrument noasan noubsan int GetNestingLevel( * prologues of other functions. We assume those functions behave * according to the System Five NexGen32e ABI. */ -privileged noinstrument noasan noubsan void ftracer(void) { - /* asan runtime depends on this function */ +privileged void ftracer(void) { uint64_t stamp; - static bool noreentry; + size_t stackuse; struct StackFrame *frame; - if (!_cmpxchg(&noreentry, 0, 1)) return; - if (ftrace_enabled) { - stamp = rdtsc(); - frame = __builtin_frame_address(0); - frame = frame->next; - if (frame->addr != g_lastaddr) { - kprintf("%rFUN %5P %'18T %*s%t\r\n", GetNestingLevel(frame) * 2, "", - frame->addr); - g_laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc(); - g_lastaddr = frame->addr; - } + _spinlock_cooperative(&ftrace_lock); + stamp = rdtsc(); + frame = __builtin_frame_address(0); + frame = frame->next; + if (frame->addr != g_ftrace.lastaddr) { + stackuse = ROUNDUP((intptr_t)frame, GetStackSize()) - (intptr_t)frame; + kprintf("%rFUN %5P %'13T %'*lu %*s%t\r\n", g_ftrace.stackdigs, stackuse, + GetNestingLevel(frame) * 2, "", frame->addr); + g_ftrace.laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc(); + g_ftrace.lastaddr = frame->addr; } - noreentry = 0; + _spunlock(&ftrace_lock); } textstartup int ftrace_install(void) { if (GetSymbolTable()) { - g_lastaddr = -1; - g_laststamp = kStartTsc; - g_skew = GetNestingLevelImpl(__builtin_frame_address(0)); - ftrace_enabled = 1; + g_ftrace.lastaddr = -1; + g_ftrace.laststamp = kStartTsc; + g_ftrace.stackdigs = LengthInt64Thousands(GetStackSize()); + g_ftrace.skew = GetNestingLevelImpl(__builtin_frame_address(0)); return __hook(ftrace_hook, GetSymbolTable()); } else { kprintf("error: --ftrace failed to open symbol table\r\n"); diff --git a/libc/runtime/memtrack.greg.c b/libc/runtime/memtrack.greg.c index 2d69982d6..e4f58c759 100644 --- a/libc/runtime/memtrack.greg.c +++ b/libc/runtime/memtrack.greg.c @@ -26,6 +26,7 @@ #include "libc/errno.h" #include "libc/intrin/asan.internal.h" #include "libc/log/libfatal.internal.h" +#include "libc/log/log.h" #include "libc/macros.internal.h" #include "libc/mem/mem.h" #include "libc/runtime/directmap.internal.h" @@ -112,7 +113,9 @@ int CreateMemoryInterval(struct MemoryIntervals *mm, int i) { static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) { if (CreateMemoryInterval(mm, i) == -1) return -1; - mm->p[i].y = x - 1; + mm->p[i + 0].size -= (size_t)(mm->p[i + 0].y - (x - 1)) * FRAMESIZE; + mm->p[i + 0].y = x - 1; + mm->p[i + 1].size -= (size_t)((y + 1) - mm->p[i + 1].x) * FRAMESIZE; mm->p[i + 1].x = y + 1; return 0; } @@ -123,31 +126,60 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y, assert(y >= x); assert(AreMemoryIntervalsOk(mm)); if (!mm->i) return 0; + + // binary search for the lefthand side l = FindMemoryInterval(mm, x); if (l == mm->i) return 0; - if (!l && y < mm->p[l].x) return 0; if (y < mm->p[l].x) return 0; + + // binary search for the righthand side r = FindMemoryInterval(mm, y); if (r == mm->i || (r > l && y < mm->p[r].x)) --r; assert(r >= l); assert(x <= mm->p[r].y); + + // remove the middle of an existing map + // + // ----|mmmmmmmmmmmmmmmm|--------- before + // xxxxx + // ----|mmmm|-----|mmmmm|--------- after + // + // this isn't possible on windows because we track each + // 64kb segment on that platform using a separate entry if (l == r && x > mm->p[l].x && y < mm->p[l].y) { return PunchHole(mm, x, y, l); } + + // trim the right side of the lefthand map + // + // ----|mmmmmmm|-------------- before + // xxxxx + // ----|mmmm|----------------- after + // if (x > mm->p[l].x && x <= mm->p[l].y) { assert(y >= mm->p[l].y); if (IsWindows()) return einval(); + mm->p[l].size -= (size_t)(mm->p[l].y - (x - 1)) * FRAMESIZE; mm->p[l].y = x - 1; assert(mm->p[l].x <= mm->p[l].y); ++l; } + + // trim the left side of the righthand map + // + // ------------|mmmmm|-------- before + // xxxxx + // ---------------|mm|-------- after + // if (y >= mm->p[r].x && y < mm->p[r].y) { assert(x <= mm->p[r].x); if (IsWindows()) return einval(); + mm->p[r].size -= (size_t)((y + 1) - mm->p[r].x) * FRAMESIZE; mm->p[r].x = y + 1; assert(mm->p[r].x <= mm->p[r].y); --r; } + if (l <= r) { if (IsWindows() && wf) { wf(mm, l, r); @@ -164,19 +196,38 @@ int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h, unsigned i; assert(y >= x); assert(AreMemoryIntervalsOk(mm)); + i = FindMemoryInterval(mm, x); + + // try to extend the righthand side of the lefthand entry + // we can't do that if we're tracking independent handles + // we can't do that if it's a file map with a small size! if (i && x == mm->p[i - 1].y + 1 && h == mm->p[i - 1].h && - prot == mm->p[i - 1].prot && flags == mm->p[i - 1].flags) { + prot == mm->p[i - 1].prot && flags == mm->p[i - 1].flags && + mm->p[i - 1].size == + (size_t)(mm->p[i - 1].y - mm->p[i - 1].x) * FRAMESIZE + FRAMESIZE) { + mm->p[i - 1].size += (size_t)(y - mm->p[i - 1].y) * FRAMESIZE; mm->p[i - 1].y = y; + // if we filled the hole then merge the two mappings if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h && prot == mm->p[i].prot && flags == mm->p[i].flags) { mm->p[i - 1].y = mm->p[i].y; + mm->p[i - 1].size += mm->p[i].size; RemoveMemoryIntervals(mm, i, 1); } - } else if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h && - prot == mm->p[i].prot && flags == mm->p[i].flags) { + } + + // try to extend the lefthand side of the righthand entry + // we can't do that if we're creating a smaller file map! + else if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h && + prot == mm->p[i].prot && flags == mm->p[i].flags && + size == (size_t)(y - x) * FRAMESIZE + FRAMESIZE) { + mm->p[i].size += (size_t)(mm->p[i].x - x) * FRAMESIZE; mm->p[i].x = x; - } else { + } + + // otherwise, create a new entry and memmove the items + else { if (CreateMemoryInterval(mm, i) == -1) return -1; mm->p[i].x = x; mm->p[i].y = y; diff --git a/libc/runtime/memtrack.internal.h b/libc/runtime/memtrack.internal.h index 97a38801d..72c3fb3e3 100644 --- a/libc/runtime/memtrack.internal.h +++ b/libc/runtime/memtrack.internal.h @@ -34,10 +34,10 @@ struct MemoryInterval { int x; int y; long h; + long size; int prot; int flags; long offset; - long size; bool iscow; bool readonlyfile; }; @@ -90,25 +90,27 @@ forceinline pureconst bool IsShadowFrame(int x) { } forceinline pureconst bool IsKernelFrame(int x) { - return (int)(GetStaticStackAddr(0) >> 16) <= x && - x <= (int)((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >> - 16); + intptr_t stack = (intptr_t)GetStaticStackAddr(0); + return (int)(stack >> 16) <= x && + x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16); } forceinline pureconst bool IsStaticStackFrame(int x) { - return (int)(GetStaticStackAddr(0) >> 16) <= x && - x <= (int)((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >> - 16); + intptr_t stack = (intptr_t)GetStaticStackAddr(0); + return (int)(stack >> 16) <= x && + x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16); } forceinline pureconst bool IsStackFrame(int x) { - return (int)(GetStackAddr(0) >> 16) <= x && - x <= (int)((GetStackAddr(0) + (GetStackSize() - FRAMESIZE)) >> 16); + intptr_t stack = (intptr_t)GetStackAddr(0); + return (int)(stack >> 16) <= x && + x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16); } forceinline pureconst bool IsSigAltStackFrame(int x) { - return (int)(GetStackAddr(0) >> 16) <= x && - x <= (int)((GetStackAddr(0) + (SIGSTKSZ - FRAMESIZE)) >> 16); + intptr_t stack = (intptr_t)GetStackAddr(0); + return (int)(stack >> 16) <= x && + x <= (int)((stack + (SIGSTKSZ - FRAMESIZE)) >> 16); } forceinline pureconst bool IsOldStackFrame(int x) { diff --git a/libc/runtime/munmap.c b/libc/runtime/munmap.c index 19146c221..51c43e546 100644 --- a/libc/runtime/munmap.c +++ b/libc/runtime/munmap.c @@ -16,16 +16,22 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/bits/likely.h" +#include "libc/bits/weaken.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/asan.internal.h" +#include "libc/intrin/kprintf.h" #include "libc/intrin/spinlock.h" +#include "libc/log/backtrace.internal.h" #include "libc/log/libfatal.internal.h" +#include "libc/log/log.h" #include "libc/macros.internal.h" #include "libc/runtime/directmap.internal.h" +#include "libc/runtime/internal.h" #include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" @@ -36,89 +42,123 @@ #define ADDR(x) ((int64_t)((uint64_t)(x) << 32) >> 16) #define FRAME(x) ((int)((intptr_t)(x) >> 16)) -static noasan int Munmap(void *v, size_t n) { - char poison, *p = v; +static noasan int Munmap(char *, size_t); + +static noasan void MunmapShadow(char *p, size_t n) { + intptr_t a, b, x, y; + KERNTRACE("MunmapShadow(%p, %'zu)", p, n); + a = ((intptr_t)p >> 3) + 0x7fff8000; + b = a + (n >> 3); + if (IsMemtracked(FRAME(a), FRAME(b - 1))) { + x = ROUNDUP(a, FRAMESIZE); + y = ROUNDDOWN(b, FRAMESIZE); + if (0 && x < y) { + // delete shadowspace if unmapping ≥512kb. in practice it has + // to be >1mb since we can only unmap it if it's aligned, and + // as such we poison the edges if there are any. + __repstosb((void *)a, kAsanUnmapped, x - a); + Munmap((void *)x, y - x); + __repstosb((void *)y, kAsanUnmapped, b - y); + } else { + // otherwise just poison and assume reuse + __repstosb((void *)a, kAsanUnmapped, b - a); + } + } else { + STRACE("unshadow(%.12p, %p) EFAULT", a, b - a); + } +} + +// our api supports doing things like munmap(0, 0x7fffffffffff) but some +// platforms (e.g. openbsd) require that we know the specific intervals +// or else it returns EINVAL. so we munmap a piecewise. +static noasan void MunmapImpl(char *p, size_t n) { + char *q; + size_t m; + intptr_t a, b, c; + int i, l, r, rc, beg, end; + KERNTRACE("MunmapImpl(%p, %'zu)", p, n); + l = FRAME(p); + r = FRAME(p + n - 1); + i = FindMemoryInterval(&_mmi, l); + for (; i < _mmi.i && r >= _mmi.p[i].x; ++i) { + if (l >= _mmi.p[i].x && r <= _mmi.p[i].y) { + + // it's contained within the entry + beg = l; + end = r; + } else if (l <= _mmi.p[i].x && r >= _mmi.p[i].x) { + + // it overlaps with the lefthand side of the entry + beg = _mmi.p[i].x; + end = MIN(r, _mmi.p[i].y); + } else if (l <= _mmi.p[i].y && r >= _mmi.p[i].y) { + + // it overlaps with the righthand side of the entry + beg = MAX(_mmi.p[i].x, l); + end = _mmi.p[i].y; + } else { + // shouldn't be possible + assert(!"binary search panic"); + continue; + } + // openbsd even requires that if we mapped, for instance a 5 byte + // file, that we be sure to call munmap(file, 5). let's abstract! + a = ADDR(beg); + b = ADDR(end) + FRAMESIZE; + c = ADDR(_mmi.p[i].x) + _mmi.p[i].size; + q = (char *)a; + m = MIN(b, c) - a; + if (!IsWindows()) { + rc = sys_munmap(q, m); + assert(!rc); + } else { + // Handled by UntrackMemoryIntervals() on Windows + } + if (IsAsan() && !OverlapsShadowSpace(p, n)) { + MunmapShadow(q, m); + } + } +} + +static noasan int Munmap(char *p, size_t n) { + unsigned i; + char poison; intptr_t a, b, x, y; assert(!__vforked); - if (UNLIKELY(!n)) { - STRACE("munmap(%.12p, %'zu) %s (n=0)", p, n); + STRACE("munmap(%.12p, %'zu) EINVAL (n=0)", p, n); return einval(); } - if (UNLIKELY(!IsLegalSize(n))) { STRACE("munmap(%.12p, %'zu) EINVAL (n isn't 48-bit)", p, n); return einval(); } - if (UNLIKELY(!IsLegalPointer(p))) { STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 48-bit)", p, n); return einval(); } - if (UNLIKELY(!IsLegalPointer(p + (n - 1)))) { STRACE("munmap(%.12p, %'zu) EINVAL (p+(n-1) isn't 48-bit)", p, n); return einval(); } - if (UNLIKELY(!ALIGNED(p))) { STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 64kb aligned)", p, n); return einval(); } - - if (!IsMemtracked(FRAME(p), FRAME(p + (n - 1)))) { - STRACE("munmap(%.12p, %'zu) EFAULT (interval not tracked)", p, n); - return efault(); - } - - if (UntrackMemoryIntervals(p, n) == -1) { - return -1; - } - - if (IsWindows()) { - return 0; // UntrackMemoryIntervals does it for NT - } - - if (sys_munmap(p, n) == -1) { - return -1; // ouch - } - - if (IsAsan() && !OverlapsShadowSpace(p, n)) { - a = ((intptr_t)p >> 3) + 0x7fff8000; - b = a + (n >> 3); - if (IsMemtracked(FRAME(a), FRAME(b - 1))) { - x = ROUNDUP(a, FRAMESIZE); - y = ROUNDDOWN(b, FRAMESIZE); - if (x < y) { - // delete shadowspace if unmapping ≥512kb - __repstosb((void *)a, kAsanUnmapped, x - a); - Munmap((void *)x, y - x); - __repstosb((void *)y, kAsanUnmapped, b - y); - } else { - // otherwise just poison and assume reuse - __repstosb((void *)a, kAsanUnmapped, b - a); - } - } else { - STRACE("unshadow(%.12p, %p) EFAULT", a, b - a); - } - } - - return 0; + MunmapImpl(p, n); + return UntrackMemoryIntervals(p, n); } /** * Releases memory pages. * - * This function may be used to punch holes in existing mappings, but - * your mileage may vary on Windows. - * - * @param p is a pointer within any memory mapped region the process - * has permission to control, such as address ranges returned by - * mmap(), the program image itself, etc. - * @param n is the number of bytes to be unmapped, and needs to be a - * multiple of FRAMESIZE for anonymous mappings, because windows - * and for files size needs to be perfect to the byte bc openbsd + * @param p is the beginning of the memory region to unmap + * @param n is the number of bytes to be unmapped * @return 0 on success, or -1 w/ errno + * @raises EINVAL if `n == 0` + * @raises EINVAL if `n` isn't 48-bit + * @raises EINVAL if `p+(n-1)` isn't 48-bit + * @raises EINVAL if `p` isn't 65536-byte aligned */ noasan int munmap(void *p, size_t n) { int rc; diff --git a/libc/runtime/printargs.greg.c b/libc/runtime/printargs.greg.c index 3d871d8fb..168597e99 100644 --- a/libc/runtime/printargs.greg.c +++ b/libc/runtime/printargs.greg.c @@ -147,8 +147,8 @@ textstartup void __printargs(const char *prologue) { struct pollfd pfds[128]; } u; - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); - __atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED); + --__ftrace; + --__strace; e = errno; PRINT(""); @@ -547,7 +547,7 @@ textstartup void __printargs(const char *prologue) { } PRINT(""); - __atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED); - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); + ++__strace; + ++__ftrace; errno = e; } diff --git a/libc/runtime/printmemoryintervals.c b/libc/runtime/printmemoryintervals.c index 2fdfebce4..00a1e5825 100644 --- a/libc/runtime/printmemoryintervals.c +++ b/libc/runtime/printmemoryintervals.c @@ -41,10 +41,16 @@ void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) { for (i = 0; i < mm->i; ++i) { frames = mm->p[i].y + 1 - mm->p[i].x; maptally += frames; - kprintf("%012lx-%012lx %s %'*ldx%s", ADDR(mm->p[i].x), ADDR(mm->p[i].y + 1), + kprintf("%08x-%08x %s %'*ldx%s", mm->p[i].x, mm->p[i].y, DescribeMapping(mm->p[i].prot, mm->p[i].flags, mode), w, frames, DescribeFrame(mm->p[i].x)); - if (i + 1 < _mmi.i) { + if (mm->p[i].iscow) kprintf(" cow"); + if (mm->p[i].readonlyfile) kprintf(" readonlyfile"); + if (mm->p[i].size != + (size_t)(mm->p[i].y - mm->p[i].x) * FRAMESIZE + FRAMESIZE) { + kprintf(" size=%'zu", mm->p[i].size); + } + if (i + 1 < mm->i) { frames = mm->p[i + 1].x - mm->p[i].y - 1; if (frames && IsNoteworthyHole(i, mm)) { gaptally += frames; diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index e813ad377..a5b4d50cc 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -14,10 +14,12 @@ extern char **__argv; /* CRT */ extern char **__envp; /* CRT */ extern unsigned long *__auxv; /* CRT */ extern intptr_t __oldstack; /* CRT */ +extern uint64_t __nosync; /* SYS */ +extern _Atomic(int) __ftrace; /* SYS */ +extern _Atomic(int) __strace; /* SYS */ extern char *program_invocation_name; /* RII */ extern char *program_invocation_short_name; /* RII */ -extern int g_ftrace; /* CRT */ -extern uint64_t g_syscount; /* RII */ +extern uint64_t __syscount; /* RII */ extern const uint64_t kStartTsc; /* RII */ extern const char kTmpPath[]; /* RII */ extern const char kNtSystemDirectory[]; /* RII */ @@ -38,7 +40,6 @@ extern unsigned char *__relo_start[]; /* αpε */ extern unsigned char *__relo_end[]; /* αpε */ extern uint8_t __zip_start[]; /* αpε */ extern uint8_t __zip_end[]; /* αpε */ -extern bool ftrace_enabled; extern size_t __virtualmax; extern bool __isworker; diff --git a/libc/runtime/runtime.mk b/libc/runtime/runtime.mk index d7d49bf55..63fc71036 100644 --- a/libc/runtime/runtime.mk +++ b/libc/runtime/runtime.mk @@ -58,24 +58,25 @@ $(LIBC_RUNTIME_A).pkg: \ $(LIBC_RUNTIME_A_OBJS) \ $(foreach x,$(LIBC_RUNTIME_A_DIRECTDEPS),$($(x)_A).pkg) +# we can't use asan and ubsan because: +# asan and ubsan can be function traced +# we can't use function tracing because: +# this is the function tracing runtime +o/$(MODE)/libc/runtime/ftracer.o: \ + OVERRIDE_CFLAGS += \ + -mno-fentry \ + -ffreestanding \ + -fno-sanitize=all + o/$(MODE)/libc/runtime/fork-nt.o \ o/$(MODE)/libc/runtime/printmemoryintervals.o \ o/$(MODE)/libc/runtime/arememoryintervalsok.o \ -o/$(MODE)/libc/runtime/directmap.o \ -o/$(MODE)/libc/runtime/directmapnt.o \ o/$(MODE)/libc/runtime/findmemoryinterval.o \ -o/$(MODE)/libc/runtime/ftrace.greg.o \ o/$(MODE)/libc/runtime/sys_mprotect.greg.o \ -o/$(MODE)/libc/runtime/ftracer.o \ -o/$(MODE)/libc/runtime/ezmap.o \ o/$(MODE)/libc/runtime/getdosargv.o \ o/$(MODE)/libc/runtime/getdosenviron.o \ o/$(MODE)/libc/runtime/hook.greg.o \ -o/$(MODE)/libc/runtime/morph.greg.o \ -o/$(MODE)/libc/runtime/mprotect.greg.o \ -o/$(MODE)/libc/runtime/mprotect-nt.greg.o \ o/$(MODE)/libc/runtime/ismemtracked.greg.o \ -o/$(MODE)/libc/runtime/isheap.o \ o/$(MODE)/libc/runtime/memtracknt.o \ o/$(MODE)/libc/runtime/memtrack.greg.o \ o/$(MODE)/libc/runtime/metalprintf.greg.o \ diff --git a/libc/runtime/stack.h b/libc/runtime/stack.h index 789094553..4e231d54a 100644 --- a/libc/runtime/stack.h +++ b/libc/runtime/stack.h @@ -61,8 +61,9 @@ extern char ape_stack_align[] __attribute__((__weak__)); /** * Returns address of bottom of stack. */ -#define GetStackAddr(ADDEND) \ - ((((intptr_t)__builtin_frame_address(0) - 1) & -GetStackSize()) + (ADDEND)) +#define GetStackAddr(ADDEND) \ + ((void *)((((intptr_t)__builtin_frame_address(0) - 1) & -GetStackSize()) + \ + (ADDEND))) /** * Returns preferred bottom address of stack. @@ -78,7 +79,7 @@ extern char ape_stack_align[] __attribute__((__weak__)); } else { \ vAddr = 0x10000000; \ } \ - vAddr; \ + (void *)vAddr; \ }) COSMOPOLITAN_C_END_ diff --git a/libc/runtime/stackuse.c b/libc/runtime/stackuse.c index 9e7138ae0..dbb1cb51a 100644 --- a/libc/runtime/stackuse.c +++ b/libc/runtime/stackuse.c @@ -16,9 +16,12 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/atomic.h" #include "libc/calls/calls.h" +#include "libc/calls/internal.h" #include "libc/dce.h" #include "libc/fmt/itoa.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" #include "libc/runtime/stack.h" #include "libc/str/str.h" @@ -26,16 +29,23 @@ static char stacklog[1024]; -static size_t NullLength(const char *s) { - typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16))); - size_t n; - xmm_t v, z = {0}; - unsigned m, k = (uintptr_t)s & 15; - const xmm_t *p = (const xmm_t *)((uintptr_t)s & -16); - m = (__builtin_ia32_pmovmskb128(*p == z) ^ 0xffff) >> k << k; - while (!m) m = __builtin_ia32_pmovmskb128(*++p == z) ^ 0xffff; - n = (const char *)p + __builtin_ctzl(m) - s; - return n; +size_t GetStackUsage(char *s, size_t n) { + // RHEL5 MAP_GROWSDOWN seems to only grow to 68kb :'( + // So we count non-zero bytes down from the top + // First clear 64 bytes is considered the end + long *p; + size_t got; + p = (long *)(s + n); + got = 0; + for (;;) { + p -= 8; + if (p[0] | p[1] | p[2] | p[3] | p[4] | p[5] | p[6] | p[7]) { + ++got; + } else { + break; + } + } + return got * 8 * sizeof(long); } static textexit void LogStackUse(void) { @@ -43,10 +53,8 @@ static textexit void LogStackUse(void) { bool quote; char *p, *q; size_t n, usage; - const char *stack; + usage = GetStackUsage(GetStackAddr(0), GetStackSize()); fd = open(stacklog, O_APPEND | O_CREAT | O_WRONLY, 0644); - stack = (char *)GetStackAddr(0); - usage = GetStackSize() - (NullLength(stack + PAGESIZE) + PAGESIZE); p = FormatUint64(stacklog, usage); for (i = 0; i < __argc; ++i) { n = strlen(__argv[i]); diff --git a/libc/runtime/untrackmemoryintervals.c b/libc/runtime/untrackmemoryintervals.c index 58d757ce4..16ccca652 100644 --- a/libc/runtime/untrackmemoryintervals.c +++ b/libc/runtime/untrackmemoryintervals.c @@ -16,17 +16,16 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/dce.h" #include "libc/macros.internal.h" #include "libc/runtime/memtrack.internal.h" int UntrackMemoryIntervals(void *addr, size_t size) { int a, b; + assert(size > 0); a = ROUNDDOWN((intptr_t)addr, FRAMESIZE) >> 16; b = ROUNDDOWN((intptr_t)addr + size - 1, FRAMESIZE) >> 16; - if (SupportsWindows()) { - return ReleaseMemoryIntervals(&_mmi, a, b, ReleaseMemoryNt); - } else { - return ReleaseMemoryIntervals(&_mmi, a, b, 0); - } + return ReleaseMemoryIntervals(&_mmi, a, b, + SupportsWindows() ? ReleaseMemoryNt : 0); } diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 36c54d12c..12e599b0d 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -198,7 +198,7 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) { _mmi.p = _mmi.s; _mmi.n = ARRAYLEN(_mmi.s); argsize = ROUNDUP(sizeof(struct WinArgs), FRAMESIZE); - stackaddr = GetStaticStackAddr(0); + stackaddr = (intptr_t)GetStaticStackAddr(0); stacksize = GetStackSize(); allocsize = argsize + stacksize; allocaddr = stackaddr - argsize; diff --git a/libc/sock/ntstdin.greg.c b/libc/sock/ntstdin.greg.c deleted file mode 100644 index b435a91da..000000000 --- a/libc/sock/ntstdin.greg.c +++ /dev/null @@ -1,150 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2022 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/calls/calls.h" -#include "libc/calls/internal.h" -#include "libc/calls/strace.internal.h" -#include "libc/intrin/kprintf.h" -#include "libc/intrin/refcount.h" -#include "libc/intrin/spinlock.h" -#include "libc/mem/mem.h" -#include "libc/nexgen32e/nt2sysv.h" -#include "libc/nt/createfile.h" -#include "libc/nt/enum/accessmask.h" -#include "libc/nt/enum/creationdisposition.h" -#include "libc/nt/enum/fileflagandattributes.h" -#include "libc/nt/errors.h" -#include "libc/nt/events.h" -#include "libc/nt/ipc.h" -#include "libc/nt/runtime.h" -#include "libc/nt/synchronization.h" -#include "libc/nt/thread.h" -#include "libc/nt/thunk/msabi.h" -#include "libc/sock/ntstdin.internal.h" - -/** - * @fileoverview Pollable Standard Input for the New Technology. - */ - -static textwindows uint32_t StdinWorkerThread(void *arg) { - char buf[512]; - bool32 ok = true; - uint32_t i, rc, got, err, wrote; - struct NtStdinWorker w, *wp = arg; - NTTRACE("StdinWorkerThread(%ld → %ld → %ld) pid %d tid %d", wp->reader, - wp->writer, wp->consumer, getpid(), gettid()); - _spunlock(&wp->sync); - w = *wp; - do { - ok = ReadFile(w.reader, buf, sizeof(buf), &got, 0); - /* When writing to a non-blocking, byte-mode pipe handle with - insufficient buffer space, WriteFile returns TRUE with - *lpNumberOfBytesWritten < nNumberOfBytesToWrite. - ──Quoth MSDN WriteFile() */ - for (i = 0; ok && i < got; i += wrote) { - ok = WriteFile(w.writer, buf + i, got - i, &wrote, 0); - } - } while (ok && got); - err = GetLastError(); - if (!ok) { - if (err == kNtErrorHandleEof || err == kNtErrorBrokenPipe || - err == kNtErrorNoData) { - ok = true; - } - } - NTTRACE("StdinWorkerThread(%ld → %ld → %ld) → %hhhd %u", w.reader, w.writer, - w.consumer, err); - return !ok; -} - -/** - * Converts read-only file descriptor to pollable named pipe. - * - * @param fd is open file descriptor to convert - * @return new object on success, or 0 w/ errno - */ -textwindows struct NtStdinWorker *NewNtStdinWorker(int fd) { - struct NtStdinWorker *w; - NTTRACE("LaunchNtStdinWorker(%d) pid %d tid %d", fd, getpid(), gettid()); - assert(!g_fds.p[fd].worker); - assert(__isfdopen(fd)); - if (!(w = calloc(1, sizeof(struct NtStdinWorker)))) return 0; - w->refs = 1; - w->sync = 1; - w->reader = g_fds.p[fd].handle; - if ((w->consumer = CreateNamedPipe( - CreatePipeName(w->name), - kNtPipeAccessInbound | kNtFileFlagOverlapped, - kNtPipeTypeByte | kNtPipeReadmodeByte | kNtPipeRejectRemoteClients, - 1, 512, 512, 0, 0)) != -1) { - if ((w->writer = CreateFile(w->name, kNtGenericWrite, 0, 0, kNtOpenExisting, - kNtFileFlagOverlapped, 0)) != -1) { - if ((w->worker = CreateThread(0, 0, NT2SYSV(StdinWorkerThread), w, 0, - &w->tid)) != -1) { - _spinlock(&w->sync); - g_fds.p[fd].handle = w->consumer; - g_fds.p[fd].worker = w; - return w; - } - CloseHandle(w->writer); - } - CloseHandle(w->consumer); - } - free(w); - return w; -} - -/** - * References stdin worker on the New Technology. - * @param w is non-null worker object - * @return worker object for new fd - */ -textwindows struct NtStdinWorker *RefNtStdinWorker(struct NtStdinWorker *w) { - _incref(&w->refs); - return w; -} - -/** - * Dereferences stdin worker on the New Technology. - * @param w is non-null worker object - * @return true if ok otherwise false - */ -textwindows bool UnrefNtStdinWorker(struct NtStdinWorker *w) { - bool ok = true; - if (_decref(&w->refs)) return true; - if (!CloseHandle(w->consumer)) ok = false; - if (!CloseHandle(w->writer)) ok = false; - if (!CloseHandle(w->reader)) ok = false; - if (!CloseHandle(w->worker)) ok = false; - free(w); - return ok; -} - -/** - * Runs post fork for stdin workers on the New Technology. - */ -textwindows void ForkNtStdinWorker(void) { - for (int i = 0; i < g_fds.n; ++i) { - if (g_fds.p[i].kind && g_fds.p[i].worker) { - g_fds.p[i].handle = g_fds.p[i].worker->reader; - free(g_fds.p[i].worker); - g_fds.p[i].worker = 0; - } - } -} diff --git a/libc/sock/ntstdin.internal.h b/libc/sock/ntstdin.internal.h deleted file mode 100644 index 4afd2d023..000000000 --- a/libc/sock/ntstdin.internal.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_SOCK_NTSTDIN_INTERNAL_H_ -#define COSMOPOLITAN_LIBC_SOCK_NTSTDIN_INTERNAL_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -struct NtStdinWorker { /* non-inherited */ - volatile char sync; /* spin sync start */ - int refs; /* reference count */ - uint32_t tid; /* of the worker */ - int64_t reader; /* the real handle */ - int64_t writer; /* for the worker */ - int64_t worker; /* thread handle */ - int64_t consumer; /* same as Fd::handle */ - char16_t name[64]; /* for named pipe */ -}; - -struct NtStdinWorker *NewNtStdinWorker(int) hidden; -struct NtStdinWorker *RefNtStdinWorker(struct NtStdinWorker *) hidden; -bool UnrefNtStdinWorker(struct NtStdinWorker *) hidden; -void ForkNtStdinWorker(void) hidden; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_SOCK_NTSTDIN_INTERNAL_H_ */ diff --git a/libc/sock/sock.mk b/libc/sock/sock.mk index 4ffe02852..49205fc56 100644 --- a/libc/sock/sock.mk +++ b/libc/sock/sock.mk @@ -59,11 +59,6 @@ $(LIBC_SOCK_A).pkg: \ $(LIBC_SOCK_A_OBJS) \ $(foreach x,$(LIBC_SOCK_A_DIRECTDEPS),$($(x)_A).pkg) -o/$(MODE)/libc/sock/ntstdin.greg.o: \ - OVERRIDE_COPTS += \ - -ffreestanding \ - $(NO_MAGIC) - 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)) diff --git a/libc/sysv/strace.greg.c b/libc/sysv/strace.greg.c index cd75bfa5f..0822d65cb 100644 --- a/libc/sysv/strace.greg.c +++ b/libc/sysv/strace.greg.c @@ -16,6 +16,28 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/strace.internal.h" +#include "libc/runtime/runtime.h" -int __strace; +/** + * System call logging enabled state. + * + * If Cosmopolitan was compiled with the `SYSDEBUG` macro (this is the + * default behavior, except in tiny and release modes) then `__strace` + * shall control whether or not system calls are logged to fd 2. If it's + * greater than zero, syscalls are logged. Otherwise, they're aren't. + * + * By convention, functions wishing to disable syscall tracing for a + * short time period should say: + * + * void foo() { + * --__strace; + * bar(); + * ++__strace; + * } + * + * This way you still have some flexibility to force syscall tracing, by + * setting `__strace` to a higher number like `2` or `200`. Even though + * under normal circumstances, `__strace` should only be either zero or + * one. + */ +_Atomic(int) __strace; diff --git a/libc/sysv/g_syscount.S b/libc/sysv/syscount.S similarity index 91% rename from libc/sysv/g_syscount.S rename to libc/sysv/syscount.S index ff253c0cf..5e14eb44f 100644 --- a/libc/sysv/g_syscount.S +++ b/libc/sysv/syscount.S @@ -26,26 +26,26 @@ // wouldn't impact this counter. .bss .align 8 -g_syscount: +__syscount: .quad 0 - .endobj g_syscount,globl + .endobj __syscount,globl .previous - .initbss 701,_init_g_syscount -g_syscount_next: + .initbss 701,_init___syscount +__syscount_next: .quad 0 - .endobj g_syscount_next + .endobj __syscount_next .previous syscount: - incq g_syscount(%rip) - jmp *g_syscount_next(%rip) + incq __syscount(%rip) + jmp *__syscount_next(%rip) .endfn syscount .previous - .init.start 701,_init_g_syscount + .init.start 701,_init___syscount mov __systemfive(%rip),%rax stosq ezlea syscount,ax mov %rax,__systemfive(%rip) - .init.end 701,_init_g_syscount + .init.end 701,_init___syscount diff --git a/libc/sysv/sysv.mk b/libc/sysv/sysv.mk index 5811daee5..65062f721 100644 --- a/libc/sysv/sysv.mk +++ b/libc/sysv/sysv.mk @@ -33,7 +33,7 @@ LIBC_SYSV_A_DIRECTDEPS = \ LIBC_SYSV_A_FILES := \ libc/sysv/macros.internal.h \ libc/sysv/errfuns.h \ - libc/sysv/g_syscount.S \ + libc/sysv/syscount.S \ libc/sysv/restorert.S \ libc/sysv/syscall.S \ libc/sysv/systemfive.S \ @@ -75,9 +75,11 @@ o/libc/sysv/consts/syscon.internal.inc: \ libc/macros-cpp.internal.inc \ libc/macros.internal.inc +# we can't use asan and ubsan because: +# we're higher in the topological order of things o/$(MODE)/libc/sysv/errno.greg.o: \ OVERRIDE_CFLAGS += \ - $(NO_MAGIC) + -fno-sanitize=all #─────────────────────────────────────────────────────────────────────────────── diff --git a/libc/testlib/testmain.c b/libc/testlib/testmain.c index caa89a114..cfe23c8e2 100644 --- a/libc/testlib/testmain.c +++ b/libc/testlib/testmain.c @@ -67,6 +67,7 @@ Flags:\n\ STATIC_YOINK("__die"); STATIC_YOINK("__get_symbol_by_addr"); STATIC_YOINK("testlib_quota_handlers"); +STATIC_YOINK("stack_usage_logging"); static bool runbenchmarks_; diff --git a/libc/thread/sem.c b/libc/thread/sem.c index e1b5bfa81..2355b8be4 100644 --- a/libc/thread/sem.c +++ b/libc/thread/sem.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/atomic.h" -#include "libc/intrin/atomic_load.h" #include "libc/thread/sem.h" #include "libc/thread/wait.h" #include "libc/thread/yield.h" @@ -74,7 +73,7 @@ int cthread_sem_wait_futex(cthread_sem_t* sem, const struct timespec* timeout) { while ((uint32_t)count > 0) { // without spin, we could miss a futex wake if (atomic_compare_exchange_weak( - &sem->linux.count, count, + &sem->linux.count, &count, count - 1 - ((uint64_t)1 << CTHREAD_THREAD_VAL_BITS))) { return 0; } @@ -97,7 +96,7 @@ int cthread_sem_wait_spin(cthread_sem_t* sem, uint64_t count, int spin, while ((uint32_t)count > 0) { // spin is useful if multiple waiters can acquire the semaphore at the // same time - if (atomic_compare_exchange_weak(&sem->linux.count, count, count - 1)) { + if (atomic_compare_exchange_weak(&sem->linux.count, &count, count - 1)) { return 0; } } @@ -115,7 +114,7 @@ int cthread_sem_wait(cthread_sem_t* sem, int spin, while ((uint32_t)count > 0) { // spin is useful if multiple waiters can acquire the semaphore at the same // time - if (atomic_compare_exchange_weak(&sem->linux.count, count, count - 1)) { + if (atomic_compare_exchange_weak(&sem->linux.count, &count, count - 1)) { return 0; } } diff --git a/libc/x/makedirs.c b/libc/x/makedirs.c index 1d3fd2eb8..6255bf9ff 100644 --- a/libc/x/makedirs.c +++ b/libc/x/makedirs.c @@ -29,11 +29,13 @@ static int MakeDirs(const char *path, unsigned mode, int e) { int rc; char *dir; - if (mkdir(path, mode) != -1) { + if (mkdir(path, mode) != -1 || errno == EEXIST) { errno = e; return 0; } - if (errno != ENOENT) return -1; + if (errno != ENOENT) { + return -1; + } dir = xdirname(path); if (strcmp(dir, path)) { rc = MakeDirs(dir, mode, e); @@ -49,6 +51,8 @@ static int MakeDirs(const char *path, unsigned mode, int e) { /** * Recursively creates directory a.k.a. folder. * + * This function won't fail if the directory already exists. + * * @param path is a UTF-8 string, preferably relative w/ forward slashes * @param mode can be, for example, 0755 * @return 0 on success or -1 w/ errno diff --git a/test/libc/calls/commandv_test.c b/test/libc/calls/commandv_test.c index 955d41266..6f3694a30 100644 --- a/test/libc/calls/commandv_test.c +++ b/test/libc/calls/commandv_test.c @@ -64,16 +64,16 @@ TEST(commandv, testPathSearch_appendsComExtension) { TEST(commandv, testSlashes_wontSearchPath_butChecksAccess) { EXPECT_NE(-1, touch("home/sh", 0755)); - i = g_syscount; + i = __syscount; EXPECT_STREQ("home/sh", commandv("home/sh", pathbuf, sizeof(pathbuf))); - if (!IsWindows()) EXPECT_EQ(i + 1, g_syscount); + if (!IsWindows()) EXPECT_EQ(i + 1, __syscount); } TEST(commandv, testSlashes_wontSearchPath_butStillAppendsComExtension) { EXPECT_NE(-1, touch("home/sh.com", 0755)); - i = g_syscount; + i = __syscount; EXPECT_STREQ("home/sh.com", commandv("home/sh", pathbuf, sizeof(pathbuf))); - if (!IsWindows()) EXPECT_EQ(i + 2, g_syscount); + if (!IsWindows()) EXPECT_EQ(i + 2, __syscount); } TEST(commandv, testSameDir_doesntHappenByDefaultUnlessItsWindows) { diff --git a/test/libc/calls/mkdir_test.c b/test/libc/calls/mkdir_test.c index e0037d558..07aa908f2 100644 --- a/test/libc/calls/mkdir_test.c +++ b/test/libc/calls/mkdir_test.c @@ -34,30 +34,31 @@ void SetUp(void) { } TEST(mkdir, testNothingExists_ENOENT) { - EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755)); - EXPECT_EQ(ENOENT, errno); + EXPECT_SYS(ENOENT, -1, mkdir("yo/yo/yo", 0755)); } TEST(mkdir, testDirectoryComponentIsFile_ENOTDIR) { - EXPECT_NE(-1, touch("yo", 0644)); - EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755)); - EXPECT_EQ(ENOTDIR, errno); + EXPECT_SYS(0, 0, touch("yo", 0644)); + EXPECT_SYS(ENOTDIR, -1, mkdir("yo/yo/yo", 0755)); } TEST(mkdir, testPathIsFile_EEXIST) { - EXPECT_NE(-1, mkdir("yo", 0755)); - EXPECT_NE(-1, mkdir("yo/yo", 0755)); - EXPECT_NE(-1, touch("yo/yo/yo", 0644)); - EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755)); - EXPECT_EQ(EEXIST, errno); + EXPECT_SYS(0, 0, mkdir("yo", 0755)); + EXPECT_SYS(0, 0, mkdir("yo/yo", 0755)); + EXPECT_SYS(0, 0, touch("yo/yo/yo", 0644)); + EXPECT_SYS(EEXIST, -1, mkdir("yo/yo/yo", 0755)); } TEST(mkdir, testPathIsDirectory_EEXIST) { - EXPECT_NE(-1, mkdir("yo", 0755)); - EXPECT_NE(-1, mkdir("yo/yo", 0755)); - EXPECT_NE(-1, mkdir("yo/yo/yo", 0755)); - EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755)); - EXPECT_EQ(EEXIST, errno); + EXPECT_SYS(0, 0, mkdir("yo", 0755)); + EXPECT_SYS(0, 0, mkdir("yo/yo", 0755)); + EXPECT_SYS(0, 0, mkdir("yo/yo/yo", 0755)); + EXPECT_SYS(EEXIST, -1, mkdir("yo/yo/yo", 0755)); +} + +TEST(makedirs, pathExists_isSuccess) { + EXPECT_SYS(0, 0, makedirs("foo/bar", 0755)); + EXPECT_SYS(0, 0, makedirs("foo/bar", 0755)); } TEST(mkdir, enametoolong) { @@ -69,19 +70,17 @@ TEST(mkdir, enametoolong) { EXPECT_SYS(ENAMETOOLONG, -1, mkdir(s, 0644)); } -TEST(makedirs, testEmptyString_EEXIST) { - EXPECT_EQ(-1, mkdir("", 0755)); - EXPECT_EQ(ENOENT, errno); +TEST(makedirs, testEmptyString_ENOENT) { + EXPECT_SYS(ENOENT, -1, mkdir("", 0755)); } TEST(mkdirat, testRelativePath_opensRelativeToDirFd) { int dirfd; - ASSERT_NE(-1, mkdir("foo", 0755)); - ASSERT_NE(-1, (dirfd = open("foo", O_RDONLY | O_DIRECTORY))); - EXPECT_NE(-1, mkdirat(dirfd, "bar", 0755)); + ASSERT_SYS(0, 0, mkdir("foo", 0755)); + ASSERT_SYS(0, 3, (dirfd = open("foo", O_RDONLY | O_DIRECTORY))); + EXPECT_SYS(0, 0, mkdirat(dirfd, "bar", 0755)); EXPECT_TRUE(isdirectory("foo/bar")); - EXPECT_EQ(-1, makedirs("", 0755)); - EXPECT_NE(-1, close(dirfd)); + EXPECT_SYS(0, 0, close(dirfd)); } TEST(mkdir, longname) { diff --git a/test/libc/fmt/lengthuint64_test.c b/test/libc/fmt/lengthuint64_test.c index f0ddbd48f..7c4b2cee9 100644 --- a/test/libc/fmt/lengthuint64_test.c +++ b/test/libc/fmt/lengthuint64_test.c @@ -94,9 +94,13 @@ TEST(LengthInt64Thousands, test) { } BENCH(LengthInt64, bench) { - EZBENCH2("LengthInt64", donothing, LengthInt64(INT64_MIN)); - EZBENCH2("LengthUint64", donothing, LengthUint64(UINT64_MAX)); - EZBENCH2("LengthInt64Thousands", donothing, LengthInt64Thousands(INT64_MIN)); + unsigned LengthInt64_(int64_t) asm("LengthInt64"); + unsigned LengthUint64_(uint64_t) asm("LengthUint64"); + unsigned LengthInt64Thousands_(int64_t) asm("LengthInt64Thousands"); + unsigned LengthUint64Thousands_(uint64_t) asm("LengthUint64Thousands"); + EZBENCH2("LengthInt64", donothing, LengthInt64_(INT64_MIN)); + EZBENCH2("LengthUint64", donothing, LengthUint64_(UINT64_MAX)); + EZBENCH2("LengthInt64Thousands", donothing, LengthInt64Thousands_(INT64_MIN)); EZBENCH2("LengthUint64Thousands", donothing, - LengthUint64Thousands(UINT64_MAX)); + LengthUint64Thousands_(UINT64_MAX)); } diff --git a/test/libc/intrin/kprintf_test.c b/test/libc/intrin/kprintf_test.c index 071c15f5d..7618d68da 100644 --- a/test/libc/intrin/kprintf_test.c +++ b/test/libc/intrin/kprintf_test.c @@ -43,8 +43,7 @@ */ static uint64_t Rando(void) { uint64_t x; - do - x = lemur64(); + do x = lemur64(); while (((x ^ READ64LE("!!!!!!!!")) - 0x0101010101010101) & ~(x ^ READ64LE("!!!!!!!!")) & 0x8080808080808080); return x; @@ -249,9 +248,9 @@ TEST(kprintf, testFailure_wontClobberErrnoAndBypassesSystemCallSupport) { ASSERT_EQ(0, errno); EXPECT_SYS(0, 3, dup(2)); EXPECT_SYS(0, 0, close(2)); - n = g_syscount; + n = __syscount; kprintf("hello%n"); - EXPECT_EQ(n, g_syscount); + EXPECT_EQ(n, __syscount); EXPECT_EQ(0, errno); EXPECT_SYS(0, 2, dup2(3, 2)); EXPECT_SYS(0, 0, close(3)); diff --git a/test/libc/rand/rand64_test.c b/test/libc/rand/rand64_test.c index 90885a554..7311543a4 100644 --- a/test/libc/rand/rand64_test.c +++ b/test/libc/rand/rand64_test.c @@ -22,6 +22,7 @@ #include "libc/calls/struct/sigset.h" #include "libc/dce.h" #include "libc/errno.h" +#include "libc/intrin/kprintf.h" #include "libc/intrin/spinlock.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/threaded.h" @@ -40,20 +41,26 @@ #define ENTRIES 256 char locks[THREADS]; -volatile bool ready; +_Atomic(bool) ready; volatile uint64_t A[THREADS * ENTRIES]; void OnChld(int sig) { // do nothing } +dontinline void Pause(void) { + __builtin_ia32_pause(); +} + +dontinline void Generate(int i) { + A[i] = rand64(); +} + int Thrasher(void *arg) { int i, id = (intptr_t)arg; - while (!ready) { - __builtin_ia32_pause(); - } + while (!ready) Pause(); for (i = 0; i < ENTRIES; ++i) { - A[id * ENTRIES + i] = rand64(); + Generate(id * ENTRIES + i); } _spunlock(locks + id); return 0; diff --git a/test/libc/runtime/memtrack_test.c b/test/libc/runtime/memtrack_test.c index 200ec8a2e..a9c9a4888 100644 --- a/test/libc/runtime/memtrack_test.c +++ b/test/libc/runtime/memtrack_test.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/errno.h" +#include "libc/intrin/kprintf.h" #include "libc/limits.h" #include "libc/log/check.h" #include "libc/mem/mem.h" @@ -26,6 +27,9 @@ #include "libc/str/str.h" #include "libc/testlib/testlib.h" +#define I(x, y) \ + { x, y, 0, (y - x) * FRAMESIZE + FRAMESIZE } + static bool AreMemoryIntervalsEqual(const struct MemoryIntervals *mm1, const struct MemoryIntervals *mm2) { if (mm1->i != mm2->i) return false; @@ -45,8 +49,10 @@ static void PrintMemoryInterval(const struct MemoryIntervals *mm) { static void CheckMemoryIntervalsEqual(const struct MemoryIntervals *mm1, const struct MemoryIntervals *mm2) { if (!AreMemoryIntervalsEqual(mm1, mm2)) { - PrintMemoryInterval(mm1); - PrintMemoryInterval(mm2); + kprintf("got:\n"); + PrintMemoryIntervals(2, mm1); + kprintf("want:\n"); + PrintMemoryIntervals(2, mm2); CHECK(!"memory intervals not equal"); exit(1); } @@ -65,7 +71,8 @@ static void RunTrackMemoryIntervalTest(const struct MemoryIntervals t[2], int x, struct MemoryIntervals *mm; mm = memcpy(memalign(64, sizeof(*t)), t, sizeof(*t)); CheckMemoryIntervalsAreOk(mm); - CHECK_NE(-1, TrackMemoryInterval(mm, x, y, h, 0, 0, 0, 0, 0, 0)); + CHECK_NE(-1, TrackMemoryInterval(mm, x, y, h, 0, 0, 0, 0, 0, + (y - x) * FRAMESIZE + FRAMESIZE)); CheckMemoryIntervalsAreOk(mm); CheckMemoryIntervalsEqual(mm, t + 1); free(mm); @@ -88,7 +95,7 @@ static int RunReleaseMemoryIntervalsTest(const struct MemoryIntervals t[2], TEST(TrackMemoryInterval, TestEmpty) { static struct MemoryIntervals mm[2] = { {0, OPEN_MAX, 0, {}}, - {1, OPEN_MAX, 0, {{2, 2, 0}}}, + {1, OPEN_MAX, 0, {{2, 2, 0, FRAMESIZE}}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -114,8 +121,8 @@ TEST(TrackMemoryInterval, TestFull) { TEST(TrackMemoryInterval, TestAppend) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{2, 2}}}, - {1, OPEN_MAX, 0, {{2, 3}}}, + {1, OPEN_MAX, 0, {I(2, 2)}}, + {1, OPEN_MAX, 0, {I(2, 3)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -124,8 +131,8 @@ TEST(TrackMemoryInterval, TestAppend) { TEST(TrackMemoryInterval, TestPrepend) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{2, 2}}}, - {1, OPEN_MAX, 0, {{1, 2}}}, + {1, OPEN_MAX, 0, {I(2, 2)}}, + {1, OPEN_MAX, 0, {I(1, 2)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -134,8 +141,8 @@ TEST(TrackMemoryInterval, TestPrepend) { TEST(TrackMemoryInterval, TestFillHole) { static struct MemoryIntervals mm[2] = { - {4, OPEN_MAX, 0, {{1, 1}, {3, 4}, {5, 5, 1}, {6, 8}}}, - {3, OPEN_MAX, 0, {{1, 4}, {5, 5, 1}, {6, 8}}}, + {4, OPEN_MAX, 0, {I(1, 1), I(3, 4), {5, 5, 1, FRAMESIZE}, I(6, 8)}}, + {3, OPEN_MAX, 0, {I(1, 4), {5, 5, 1, FRAMESIZE}, I(6, 8)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -144,8 +151,8 @@ TEST(TrackMemoryInterval, TestFillHole) { TEST(TrackMemoryInterval, TestAppend2) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{2, 2}}}, - {2, OPEN_MAX, 0, {{2, 2}, {3, 3, 1}}}, + {1, OPEN_MAX, 0, {I(2, 2)}}, + {2, OPEN_MAX, 0, {I(2, 2), {3, 3, 1, FRAMESIZE}}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -154,8 +161,8 @@ TEST(TrackMemoryInterval, TestAppend2) { TEST(TrackMemoryInterval, TestPrepend2) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{2, 2}}}, - {2, OPEN_MAX, 0, {{1, 1, 1}, {2, 2}}}, + {1, OPEN_MAX, 0, {I(2, 2)}}, + {2, OPEN_MAX, 0, {{1, 1, 1, FRAMESIZE}, I(2, 2)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -164,8 +171,25 @@ TEST(TrackMemoryInterval, TestPrepend2) { TEST(TrackMemoryInterval, TestFillHole2) { static struct MemoryIntervals mm[2] = { - {4, OPEN_MAX, 0, {{1, 1}, {3, 4}, {5, 5, 1}, {6, 8}}}, - {5, OPEN_MAX, 0, {{1, 1}, {2, 2, 1}, {3, 4}, {5, 5, 1}, {6, 8}}}, + {4, + OPEN_MAX, + 0, + { + I(1, 1), + I(3, 4), + {5, 5, 1, FRAMESIZE}, + I(6, 8), + }}, + {5, + OPEN_MAX, + 0, + { + I(1, 1), + {2, 2, 1, FRAMESIZE}, + {3, 4, 0, FRAMESIZE * 2}, + {5, 5, 1, FRAMESIZE}, + {6, 8, 0, FRAMESIZE * 3}, + }}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -211,8 +235,8 @@ TEST(ReleaseMemoryIntervals, TestEmpty) { TEST(ReleaseMemoryIntervals, TestRemoveElement_UsesInclusiveRange) { static struct MemoryIntervals mm[2] = { - {3, OPEN_MAX, 0, {{0, 0}, {2, 2}, {4, 4}}}, - {2, OPEN_MAX, 0, {{0, 0}, {4, 4}}}, + {3, OPEN_MAX, 0, {I(0, 0), I(2, 2), I(4, 4)}}, + {2, OPEN_MAX, 0, {I(0, 0), I(4, 4)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -221,8 +245,8 @@ TEST(ReleaseMemoryIntervals, TestRemoveElement_UsesInclusiveRange) { TEST(ReleaseMemoryIntervals, TestPunchHole) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{0, 9}}}, - {2, OPEN_MAX, 0, {{0, 3}, {6, 9}}}, + {1, OPEN_MAX, 0, {I(0, 9)}}, + {2, OPEN_MAX, 0, {I(0, 3), I(6, 9)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -232,8 +256,8 @@ TEST(ReleaseMemoryIntervals, TestPunchHole) { TEST(ReleaseMemoryIntervals, TestShortenLeft) { if (IsWindows()) return; static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{0, 9}}}, - {1, OPEN_MAX, 0, {{0, 7}}}, + {1, OPEN_MAX, 0, {I(0, 9)}}, + {1, OPEN_MAX, 0, {I(0, 7)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -243,8 +267,8 @@ TEST(ReleaseMemoryIntervals, TestShortenLeft) { TEST(ReleaseMemoryIntervals, TestShortenRight) { if (IsWindows()) return; static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{0, 9}}}, - {1, OPEN_MAX, 0, {{3, 9}}}, + {1, OPEN_MAX, 0, {I(0, 9)}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -254,8 +278,8 @@ TEST(ReleaseMemoryIntervals, TestShortenRight) { TEST(ReleaseMemoryIntervals, TestShortenLeft2) { if (IsWindows()) return; static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{0, 9}}}, - {1, OPEN_MAX, 0, {{0, 7}}}, + {1, OPEN_MAX, 0, {I(0, 9)}}, + {1, OPEN_MAX, 0, {I(0, 7)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -265,8 +289,8 @@ TEST(ReleaseMemoryIntervals, TestShortenLeft2) { TEST(ReleaseMemoryIntervals, TestShortenRight2) { if (IsWindows()) return; static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{0, 9}}}, - {1, OPEN_MAX, 0, {{3, 9}}}, + {1, OPEN_MAX, 0, {I(0, 9)}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -275,8 +299,8 @@ TEST(ReleaseMemoryIntervals, TestShortenRight2) { TEST(ReleaseMemoryIntervals, TestZeroZero) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{3, 9}}}, - {1, OPEN_MAX, 0, {{3, 9}}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -285,8 +309,8 @@ TEST(ReleaseMemoryIntervals, TestZeroZero) { TEST(ReleaseMemoryIntervals, TestNoopLeft) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{3, 9}}}, - {1, OPEN_MAX, 0, {{3, 9}}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -295,8 +319,8 @@ TEST(ReleaseMemoryIntervals, TestNoopLeft) { TEST(ReleaseMemoryIntervals, TestNoopRight) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{3, 9}}}, - {1, OPEN_MAX, 0, {{3, 9}}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -305,7 +329,7 @@ TEST(ReleaseMemoryIntervals, TestNoopRight) { TEST(ReleaseMemoryIntervals, TestBigFree) { static struct MemoryIntervals mm[2] = { - {2, OPEN_MAX, 0, {{0, 3}, {6, 9}}}, + {2, OPEN_MAX, 0, {I(0, 3), I(6, 9)}}, {0, OPEN_MAX, 0, {}}, }; mm[0].p = mm[0].s; @@ -315,8 +339,8 @@ TEST(ReleaseMemoryIntervals, TestBigFree) { TEST(ReleaseMemoryIntervals, TestWeirdGap) { static struct MemoryIntervals mm[2] = { - {3, OPEN_MAX, 0, {{10, 10}, {20, 20}, {30, 30}}}, - {2, OPEN_MAX, 0, {{10, 10}, {30, 30}}}, + {3, OPEN_MAX, 0, {I(10, 10), I(20, 20), I(30, 30)}}, + {2, OPEN_MAX, 0, {I(10, 10), I(30, 30)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; diff --git a/test/libc/runtime/mmap_test.c b/test/libc/runtime/mmap_test.c index a777fdcc2..046eba15d 100644 --- a/test/libc/runtime/mmap_test.c +++ b/test/libc/runtime/mmap_test.c @@ -16,9 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/atomic.h" #include "libc/bits/bits.h" #include "libc/bits/xchg.internal.h" #include "libc/calls/calls.h" +#include "libc/calls/ucontext.h" #include "libc/dce.h" #include "libc/fmt/fmt.h" #include "libc/intrin/kprintf.h" @@ -36,9 +38,12 @@ #include "libc/sysv/consts/msync.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" +#include "libc/sysv/consts/sa.h" +#include "libc/sysv/consts/sig.h" #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" #include "libc/x/x.h" +#include "third_party/xed/x86.h" char testlib_enable_tmp_setup_teardown; diff --git a/test/libc/runtime/munmap_test.c b/test/libc/runtime/munmap_test.c new file mode 100644 index 000000000..9c2998e68 --- /dev/null +++ b/test/libc/runtime/munmap_test.c @@ -0,0 +1,232 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/atomic.h" +#include "libc/calls/calls.h" +#include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/ucontext.h" +#include "libc/intrin/kprintf.h" +#include "libc/runtime/memtrack.internal.h" +#include "libc/runtime/runtime.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/prot.h" +#include "libc/sysv/consts/sa.h" +#include "libc/testlib/testlib.h" +#include "third_party/xed/x86.h" + +int gotsignal; +char testlib_enable_tmp_setup_teardown; + +void ContinueOnError(int sig, siginfo_t *si, ucontext_t *ctx) { + struct XedDecodedInst xedd; + xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); + xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15); + ctx->uc_mcontext.rip += xedd.length; + gotsignal = sig; +} + +noasan bool MemoryExists(char *p) { + volatile char c; + struct sigaction old[2]; + struct sigaction sa = { + .sa_sigaction = ContinueOnError, + .sa_flags = SA_SIGINFO, + }; + gotsignal = 0; + sigaction(SIGSEGV, &sa, old + 0); + sigaction(SIGBUS, &sa, old + 1); + c = atomic_load(p); + sigaction(SIGSEGV, old + 0, 0); + sigaction(SIGBUS, old + 1, 0); + return !gotsignal; +} + +TEST(munmap, doesntExist_doesntCare) { + EXPECT_SYS(0, 0, munmap(0, FRAMESIZE * 8)); + if (IsAsan()) { + // make sure it didn't unmap the null pointer shadow memory + EXPECT_TRUE(MemoryExists((char *)0x7fff8000)); + } +} + +TEST(munmap, test) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_TRUE(MemoryExists(p)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); + EXPECT_FALSE(MemoryExists(p)); +} + +TEST(munmap, invalidParams) { + EXPECT_SYS(EINVAL, -1, munmap(0, 0)); + EXPECT_SYS(EINVAL, -1, munmap((void *)0x100080000000, 0)); + EXPECT_SYS(EINVAL, -1, munmap((void *)0x100080000001, FRAMESIZE)); +} + +TEST(munmap, punchHoleInMemory) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 3, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 2)); + EXPECT_SYS(0, 0, munmap(p + FRAMESIZE, FRAMESIZE)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 2)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); + EXPECT_SYS(0, 0, munmap(p + FRAMESIZE * 2, FRAMESIZE)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 2)); +} + +TEST(munmap, memoryHasHole) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 3, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_SYS(0, 0, munmap(p + FRAMESIZE, FRAMESIZE)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 2)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE * 3)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 2)); +} + +TEST(munmap, blanketFree) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 3, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 2)); + EXPECT_SYS(0, 0, munmap(p + FRAMESIZE * 0, FRAMESIZE)); + EXPECT_SYS(0, 0, munmap(p + FRAMESIZE * 2, FRAMESIZE)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 2)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE * 3)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 2)); +} + +TEST(munmap, trimLeft) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 2, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE * 2)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); +} + +TEST(munmap, trimRight) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 2, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_SYS(0, 0, munmap(p + FRAMESIZE, FRAMESIZE)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE * 2)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); +} + +TEST(munmap, memoryGone) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); +} + +TEST(munmap, testTooSmallToUnmapAsan) { + if (!IsAsan()) return; + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_TRUE(MemoryExists((char *)(((intptr_t)p >> 3) + 0x7fff8000))); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); + EXPECT_TRUE(MemoryExists((char *)(((intptr_t)p >> 3) + 0x7fff8000))); +} + +TEST(munmap, testLargeEnoughToUnmapAsan) { + if (!IsAsan()) return; + if (IsWindows()) { + // we're unfortunately never able to unmap asan pages on windows + // because the memtrack array items always have to be 64kb so we + // we're able to store a handle for each + return; + } + char *p; + size_t n; + n = FRAMESIZE * 8 * 2; + ASSERT_NE(MAP_FAILED, (p = mmap(0, n, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_SYS(0, 0, munmap(p, n)); +#if 0 + EXPECT_FALSE( + MemoryExists((char *)(((intptr_t)(p + n / 2) >> 3) + 0x7fff8000))); +#endif +} + +TEST(munmap, tinyFile_roundupUnmapSize) { + char *p; + ASSERT_SYS(0, 3, open("doge", O_WRONLY | O_CREAT | O_TRUNC, 0644)); + ASSERT_SYS(0, 5, write(3, "hello", 5)); + ASSERT_SYS(0, 0, close(3)); + ASSERT_SYS(0, 3, open("doge", O_RDONLY)); + ASSERT_NE(MAP_FAILED, (p = mmap(0, 5, PROT_READ, MAP_PRIVATE, 3, 0))); + ASSERT_SYS(0, 0, close(3)); + EXPECT_TRUE(MemoryExists(p)); + // some kernels/versions support this, some don't + // EXPECT_FALSE(MemoryExists(p + 5)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); + EXPECT_FALSE(MemoryExists(p)); + EXPECT_FALSE(MemoryExists(p + 5)); +} + +TEST(munmap, tinyFile_preciseUnmapSize) { + char *p, *q; + ASSERT_SYS(0, 3, open("doge", O_WRONLY | O_CREAT | O_TRUNC, 0644)); + ASSERT_SYS(0, 5, write(3, "hello", 5)); + ASSERT_SYS(0, 0, close(3)); + ASSERT_SYS(0, 3, open("doge", O_RDONLY)); + ASSERT_NE(MAP_FAILED, (p = mmap(0, 5, PROT_READ, MAP_PRIVATE, 3, 0))); + ASSERT_NE(MAP_FAILED, (q = mmap(0, 5, PROT_READ, MAP_PRIVATE, 3, 0))); + ASSERT_SYS(0, 0, close(3)); + EXPECT_TRUE(MemoryExists(p)); + EXPECT_TRUE(MemoryExists(q)); + EXPECT_SYS(0, 0, munmap(p, 5)); + EXPECT_FALSE(MemoryExists(p)); + EXPECT_TRUE(MemoryExists(q)); + EXPECT_SYS(0, 0, munmap(q, 5)); + EXPECT_FALSE(MemoryExists(q)); +} diff --git a/test/libc/str/undeflate_test.c b/test/libc/str/undeflate_test.c index 2b2c0c9a1..742e34083 100644 --- a/test/libc/str/undeflate_test.c +++ b/test/libc/str/undeflate_test.c @@ -53,20 +53,20 @@ TEST(undeflate, testStatCentralDirectory_notFound_noSysCalls) { uint64_t c; struct stat st; stat("/zip/doge.txt", &st); /* warmup */ - c = g_syscount; + c = __syscount; ASSERT_EQ(-1, stat("/zip/doge.txt", &st)); - ASSERT_EQ(0, g_syscount - c); + ASSERT_EQ(0, __syscount - c); ASSERT_EQ(ENOENT, errno); } TEST(undeflate, testStatCentralDirectory_isFound_noSysCalls) { uint64_t c; struct stat st = {0}; - c = g_syscount; + c = __syscount; ASSERT_NE(-1, stat("/zip/libc/testlib/hyperion.txt", &st)); ASSERT_TRUE(S_ISREG(st.st_mode)); ASSERT_EQ(kHyperionSize, st.st_size); - ASSERT_EQ(0, g_syscount - c); + ASSERT_EQ(0, __syscount - c); } TEST(undeflate, testOpenReadCloseEmbeddedZip) { diff --git a/test/tool/plinko/plinko_test.c b/test/tool/plinko/plinko_test.c index 4b95011b0..f9f11a036 100644 --- a/test/tool/plinko/plinko_test.c +++ b/test/tool/plinko/plinko_test.c @@ -70,7 +70,6 @@ TEST(plinko, worksOrPrintsNiceError) { sigset_t chldmask, savemask; int i, pid, fdin, wstatus, pfds[2][2]; struct sigaction ignore, saveint, savequit, savepipe; - bzero(buf, sizeof(buf)); ignore.sa_flags = 0; ignore.sa_handler = SIG_IGN; EXPECT_EQ(0, sigemptyset(&ignore.sa_mask)); @@ -82,8 +81,10 @@ TEST(plinko, worksOrPrintsNiceError) { EXPECT_EQ(0, sigprocmask(SIG_BLOCK, &chldmask, &savemask)); ASSERT_NE(-1, pipe2(pfds[0], O_CLOEXEC)); ASSERT_NE(-1, pipe2(pfds[1], O_CLOEXEC)); - ASSERT_NE(-1, (pid = vfork())); + ASSERT_NE(-1, (pid = fork())); if (!pid) { + __strace = 0; + __ftrace = 0; close(0), dup(pfds[0][0]); close(1), dup(pfds[1][1]); close(2), dup(pfds[1][1]); @@ -104,7 +105,8 @@ TEST(plinko, worksOrPrintsNiceError) { EXPECT_NE(-1, close(fdin)); } EXPECT_NE(-1, close(pfds[0][1])); - EXPECT_NE(-1, (got = read(pfds[1][0], buf, sizeof(buf) - 1))); + bzero(buf, sizeof(buf)); + ASSERT_NE(-1, (got = read(pfds[1][0], buf, sizeof(buf) - 1))); EXPECT_NE(0, got); while (read(pfds[1][0], drain, sizeof(drain)) > 0) donothing; EXPECT_NE(-1, close(pfds[1][0])); diff --git a/third_party/dlmalloc/dlmalloc.greg.c b/third_party/dlmalloc/dlmalloc.c similarity index 99% rename from third_party/dlmalloc/dlmalloc.greg.c rename to third_party/dlmalloc/dlmalloc.c index 5d34cc0e2..b5f76f6b4 100644 --- a/third_party/dlmalloc/dlmalloc.greg.c +++ b/third_party/dlmalloc/dlmalloc.c @@ -20,7 +20,7 @@ #include "third_party/dlmalloc/dlmalloc.h" // clang-format off -#define FOOTERS 1 +#define FOOTERS 0 #define MSPACES 0 #define HAVE_MMAP 1 @@ -351,7 +351,7 @@ unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); # endif # endif # ifdef _SC_PAGE_SIZE -# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# define malloc_getpagesize 4096 /*sysconf(_SC_PAGE_SIZE)*/ # else # if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) extern size_t getpagesize(); @@ -1514,7 +1514,10 @@ static int init_mparams(void) { size_t psize; size_t gsize; -#ifndef WIN32 +#if defined(__COSMOPOLITAN__) + psize = 4096; + gsize = 65536; +#elif !defined(WIN32) psize = malloc_getpagesize; gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize); #else /* WIN32 */ diff --git a/third_party/dlmalloc/dlmalloc.mk b/third_party/dlmalloc/dlmalloc.mk index 2c27169fa..d2cc826bb 100644 --- a/third_party/dlmalloc/dlmalloc.mk +++ b/third_party/dlmalloc/dlmalloc.mk @@ -49,10 +49,17 @@ $(THIRD_PARTY_DLMALLOC_A).pkg: \ $(THIRD_PARTY_DLMALLOC_A_OBJS) \ $(foreach x,$(THIRD_PARTY_DLMALLOC_A_DIRECTDEPS),$($(x)_A).pkg) -$(THIRD_PARTY_DLMALLOC_A_OBJS): \ +# we can't use address sanitizer because: +# address sanitizer depends on dlmalloc +o/$(MODE)/third_party/dlmalloc/dlmalloc.o: \ OVERRIDE_CFLAGS += \ - $(NO_MAGIC) \ -ffreestanding \ + -fno-sanitize=address + +# we must segregate codegen because: +# file contains multiple independently linkable apis +o/$(MODE)/third_party/dlmalloc/dlmalloc.greg.o: \ + OVERRIDE_CFLAGS += \ -ffunction-sections \ -fdata-sections diff --git a/third_party/dlmalloc/vespene.greg.c b/third_party/dlmalloc/vespene.greg.c index bbcbd0989..da84f24cc 100644 --- a/third_party/dlmalloc/vespene.greg.c +++ b/third_party/dlmalloc/vespene.greg.c @@ -33,7 +33,7 @@ void *dlmalloc_requires_more_vespene_gas(size_t size) { if ((p = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) { if (weaken(__asan_poison)) { - weaken(__asan_poison)((uintptr_t)p, size, kAsanHeapFree); + weaken(__asan_poison)(p, size, kAsanHeapFree); } } return p; diff --git a/third_party/python/Include/ceval.h b/third_party/python/Include/ceval.h index 0822e0c78..47eaf797b 100644 --- a/third_party/python/Include/ceval.h +++ b/third_party/python/Include/ceval.h @@ -119,7 +119,7 @@ int _Py_CheckRecursiveCall(const char *); rc = _Py_CheckRecursiveCall(where); \ } else { \ rsp = (intptr_t)__builtin_frame_address(0); \ - bot = GetStackAddr(32768); \ + bot = (intptr_t)GetStackAddr(32768); \ if (UNLIKELY(rsp < bot)) { \ PyErr_Format(PyExc_MemoryError, "Stack overflow%s", where); \ rc = -1; \ diff --git a/third_party/python/Lib/test/test_coroutines.py b/third_party/python/Lib/test/test_coroutines.py index 291af248e..5bc5a1d80 100644 --- a/third_party/python/Lib/test/test_coroutines.py +++ b/third_party/python/Lib/test/test_coroutines.py @@ -1199,7 +1199,10 @@ class CoroutineTest(unittest.TestCase): with self.assertRaisesRegex(AttributeError, '__aexit__'): run_async(foo()) - @unittest.skipIf("tiny" in cosmo.MODE, "TODO: figure out error") + # TODO(jart,ahgamut): Figure out this error. + @unittest.skipIf(cosmo.MODE in ('tiny', 'rel'), + "No docstrings in MODE=tiny/rel") + @unittest.skipIf("tiny" in cosmo.MODE, "") def test_with_5(self): # While this test doesn't make a lot of sense, # it's a regression test for an early bug with opcodes diff --git a/third_party/python/Lib/test/test_signal.py b/third_party/python/Lib/test/test_signal.py index 7c2db9890..37d10e56b 100644 --- a/third_party/python/Lib/test/test_signal.py +++ b/third_party/python/Lib/test/test_signal.py @@ -488,7 +488,6 @@ class SiginterruptTest(unittest.TestCase): try: # wait until the child process is loaded and has started first_line = process.stdout.readline() - stdout, stderr = process.communicate(timeout=5.0) except subprocess.TimeoutExpired: process.kill() @@ -515,12 +514,13 @@ class SiginterruptTest(unittest.TestCase): interrupted = self.readpipe_interrupted(True) self.assertTrue(interrupted) - def test_siginterrupt_off(self): - # If a signal handler is installed and siginterrupt is called with - # a false value for the second argument, when that signal arrives, it - # does not interrupt a syscall that's in progress. - interrupted = self.readpipe_interrupted(False) - self.assertFalse(interrupted) + # [jart]: lool a test that takes 5 seconds by design + # def test_siginterrupt_off(self): + # # If a signal handler is installed and siginterrupt is called with + # # a false value for the second argument, when that signal arrives, it + # # does not interrupt a syscall that's in progress. + # interrupted = self.readpipe_interrupted(False) + # self.assertFalse(interrupted) @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") diff --git a/third_party/python/Python/cosmomodule.c b/third_party/python/Python/cosmomodule.c index 71f795805..b6ea626c5 100644 --- a/third_party/python/Python/cosmomodule.c +++ b/third_party/python/Python/cosmomodule.c @@ -80,7 +80,7 @@ polyfilled yet."); static PyObject * cosmo_syscount(PyObject *self, PyObject *noargs) { - return PyLong_FromSize_t(g_syscount); + return PyLong_FromSize_t(__syscount); } PyDoc_STRVAR(rdtsc_doc, @@ -215,13 +215,13 @@ static int FtracerObject_init(PyObject* self, PyObject *args, PyObject *kwargs) static PyObject* FtracerObject_enter(PyObject *self, PyObject *Py_UNUSED(ignored)) { - ++g_ftrace; + ++__ftrace; return self; } static PyObject* FtracerObject_exit(PyObject *self, PyObject *args) { - --g_ftrace; + --__ftrace; return self; } diff --git a/third_party/python/python.c b/third_party/python/python.c index cb3cf1aeb..feab2bbda 100644 --- a/third_party/python/python.c +++ b/third_party/python/python.c @@ -1,6 +1,13 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Python 3 │ +│ https://docs.python.org/3/license.html │ +╚─────────────────────────────────────────────────────────────────────────────*/ #include "third_party/python/Include/yoink.h" - -STATIC_YOINK("RunPythonModule"); +#include "third_party/python/runpythonmodule.h" +#include "tool/args/args.h" +// clang-format off PYTHON_YOINK("xed"); PYTHON_YOINK("xterm"); @@ -516,3 +523,10 @@ PYTHON_YOINK("asyncio.unix_events"); PYTHON_YOINK("asyncio.windows_events"); PYTHON_YOINK("asyncio.windows_utils"); #endif + +int +main(int argc, char **argv) +{ + LoadZipArgs(&argc, &argv); + return RunPythonModule(argc, argv); +} diff --git a/third_party/python/python.mk b/third_party/python/python.mk index 7d193ca23..34f4d6b8f 100644 --- a/third_party/python/python.mk +++ b/third_party/python/python.mk @@ -47,6 +47,7 @@ THIRD_PARTY_PYTHON_STAGE1_A_OBJS = \ $(THIRD_PARTY_PYTHON_STAGE1_A_SRCS:%.c=o/$(MODE)/%.o) THIRD_PARTY_PYTHON_HDRS = \ + third_party/python/runpythonmodule.h \ third_party/python/Include/ezprint.h \ third_party/python/Include/yoink.h \ third_party/python/Include/object.h \ @@ -509,7 +510,7 @@ THIRD_PARTY_PYTHON_STAGE2_A_DATA_OBJS = \ third_party/python/Lib/.zip.o THIRD_PARTY_PYTHON_STAGE2_A_SRCS = \ - third_party/python/repl.c \ + third_party/python/runpythonmodule.c \ third_party/python/launch.c \ third_party/python/Objects/fromfd.c \ third_party/python/Objects/unicodeobject-deadcode.c \ @@ -2086,6 +2087,7 @@ THIRD_PARTY_PYTHON_PYTEST_PYMAINS_DIRECTDEPS = \ LIBC_STR \ LIBC_UNICODE \ LIBC_STDIO \ + LIBC_CALLS \ LIBC_RUNTIME \ THIRD_PARTY_PYTHON_STAGE1 \ THIRD_PARTY_PYTHON_STAGE2 \ @@ -2099,7 +2101,7 @@ THIRD_PARTY_PYTHON_PYTEST_PYMAINS_DEPS = \ o/$(MODE)/third_party/python/pythontester.pkg: \ $(THIRD_PARTY_PYTHON_PYTEST_PYMAINS_OBJS) \ - o/$(MODE)/third_party/python/repl.o \ + o/$(MODE)/third_party/python/pythontester.o \ $(foreach x,$(THIRD_PARTY_PYTHON_PYTEST_PYMAINS_DIRECTDEPS),$($(x)_A).pkg) o/$(MODE)/third_party/python/pythontester.com.dbg: \ @@ -2107,7 +2109,7 @@ o/$(MODE)/third_party/python/pythontester.com.dbg: \ $(THIRD_PARTY_PYTHON_PYTEST_PYMAINS_DEPS) \ $(THIRD_PARTY_PYTHON_PYTEST_PYMAINS_OBJS) \ $(THIRD_PARTY_PYTHON_PYTEST_TODOS:%.py=o/$(MODE)/%.o) \ - o/$(MODE)/third_party/python/repl.o \ + o/$(MODE)/third_party/python/pythontester.o \ $(CRT) \ $(APE) @$(APELINK) diff --git a/third_party/python/pythontester.c b/third_party/python/pythontester.c new file mode 100644 index 000000000..45db63426 --- /dev/null +++ b/third_party/python/pythontester.c @@ -0,0 +1,19 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Python 3 │ +│ https://docs.python.org/3/license.html │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/runtime/runtime.h" +#include "third_party/python/Include/yoink.h" +#include "third_party/python/runpythonmodule.h" +#include "tool/args/args.h" +// clang-format off + +int +main(int argc, char **argv) +{ + LoadZipArgs(&argc, &argv); + __nosync = 0x5453455454534146; + return RunPythonModule(argc, argv); +} diff --git a/third_party/python/repl.c b/third_party/python/repl.c index d488fc408..412790e79 100644 --- a/third_party/python/repl.c +++ b/third_party/python/repl.c @@ -4,357 +4,10 @@ │ Python 3 │ │ https://docs.python.org/3/license.html │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#define PY_SSIZE_T_CLEAN -#include "libc/bits/bits.h" -#include "libc/bits/safemacros.internal.h" -#include "libc/bits/weaken.h" -#include "libc/calls/calls.h" -#include "libc/calls/internal.h" -#include "libc/calls/sigbits.h" -#include "libc/calls/struct/siginfo.h" -#include "libc/calls/struct/sigset.h" -#include "libc/calls/ucontext.h" -#include "libc/dce.h" -#include "libc/errno.h" -#include "libc/intrin/kprintf.h" -#include "libc/log/check.h" -#include "libc/log/log.h" -#include "libc/macros.internal.h" -#include "libc/mem/mem.h" -#include "libc/runtime/gc.internal.h" -#include "libc/runtime/runtime.h" -#include "libc/runtime/symbols.internal.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/fileno.h" -#include "libc/sysv/consts/prot.h" -#include "libc/sysv/consts/sig.h" -#include "libc/time/time.h" -#include "libc/unicode/locale.h" -#include "libc/x/x.h" -#include "third_party/linenoise/linenoise.h" -#include "third_party/python/Include/abstract.h" -#include "third_party/python/Include/ceval.h" -#include "third_party/python/Include/dictobject.h" -#include "third_party/python/Include/fileutils.h" -#include "third_party/python/Include/funcobject.h" -#include "third_party/python/Include/import.h" -#include "third_party/python/Include/listobject.h" -#include "third_party/python/Include/moduleobject.h" -#include "third_party/python/Include/object.h" -#include "third_party/python/Include/pydebug.h" -#include "third_party/python/Include/pyerrors.h" -#include "third_party/python/Include/pylifecycle.h" -#include "third_party/python/Include/pymem.h" -#include "third_party/python/Include/pyport.h" -#include "third_party/python/Include/pythonrun.h" -#include "third_party/python/Include/unicodeobject.h" #include "third_party/python/Include/yoink.h" -#include "third_party/xed/x86.h" +#include "third_party/python/runpythonmodule.h" #include "tool/args/args.h" -/* clang-format off */ - -STATIC_STACK_SIZE(0x100000); - -STATIC_YOINK("__die"); -STATIC_YOINK("zip_uri_support"); - -PYTHON_YOINK("cosmo"); -PYTHON_YOINK("_locale"); -PYTHON_YOINK("_bootlocale"); -PYTHON_YOINK("encodings.aliases"); -PYTHON_YOINK("encodings.latin_1"); -PYTHON_YOINK("encodings.utf_8"); - -extern char kLaunchPythonModuleName[]; /* optionally generated by pyobj.com */ -const struct _frozen *PyImport_FrozenModules = _PyImport_FrozenModules; -struct _inittab *PyImport_Inittab = _PyImport_Inittab; -static int g_gotint; - -static void -OnKeyboardInterrupt(int sig) -{ - g_gotint = sig; -} - -static void -AddCompletion(linenoiseCompletions *c, char *s) -{ - char **p = c->cvec; - size_t n = c->len + 1; - if ((p = realloc(p, n * sizeof(*p)))) { - p[n - 1] = s; - c->cvec = p; - c->len = n; - } -} - -static void -CompleteModule(const char *s, const char *p, linenoiseCompletions *c) -{ - const char *name; - struct _inittab *it; - Py_ssize_t plen, namelen; - PyObject *m, *f, *g, *i, *v, *n; - plen = strlen(p); - for (it = PyImport_Inittab; it->name; ++it) { - if (startswithi(it->name, p)) { - AddCompletion(c, xasprintf("%s%s", s, it->name + plen)); - } - } - if ((m = PyImport_ImportModule("pkgutil"))) { - if ((f = PyObject_GetAttrString(m, "iter_modules"))) { - if ((g = PyObject_CallFunctionObjArgs(f, 0))) { - if ((i = PyObject_GetIter(g))) { - while ((v = PyIter_Next(i))) { - if ((n = PyObject_GetAttrString(v, "name"))) { - if (((name = PyUnicode_AsUTF8AndSize(n, &namelen)) && - namelen >= plen && !memcasecmp(name, p, plen))) { - AddCompletion(c, xasprintf("%s%s", s, name + plen)); - } - Py_DECREF(n); - } - Py_DECREF(v); - } - Py_DECREF(i); - } - Py_DECREF(g); - } - Py_DECREF(f); - } - Py_DECREF(m); - } -} - -static void -CompleteDict(const char *b, const char *q, const char *p, - linenoiseCompletions *c, PyObject *o) -{ - const char *s; - PyObject *k, *v; - Py_ssize_t i, m; - for (i = 0; PyDict_Next(o, &i, &k, &v);) { - if ((v != Py_None && PyUnicode_Check(k) && - (s = PyUnicode_AsUTF8AndSize(k, &m)) && - m >= q - p && !memcasecmp(s, p, q - p))) { - AddCompletion(c, xasprintf("%.*s%.*s", p - b, b, m, s)); - } - } -} - -static void -CompleteDir(const char *b, const char *q, const char *p, - linenoiseCompletions *c, PyObject *o) -{ - Py_ssize_t m; - const char *s; - PyObject *d, *i, *k; - if ((d = PyObject_Dir(o))) { - if ((i = PyObject_GetIter(d))) { - while ((k = PyIter_Next(i))) { - if (((s = PyUnicode_AsUTF8AndSize(k, &m)) && - m >= q - p && !memcasecmp(s, p, q - p) && - !(q - p == 0 && m > 4 && - (s[0+0] == '_' && s[0+1] == '_' && - s[m-1] == '_' && s[m-2] == '_')))) { - AddCompletion(c, xasprintf("%.*s%.*s", p - b, b, m, s)); - } - Py_DECREF(k); - } - Py_DECREF(i); - } - Py_DECREF(d); - } -} - -static void -Complete(const char *p, linenoiseCompletions *c) -{ - PyObject *o, *t, *i; - const char *q, *s, *b; - if (startswith(p, "import ")) { - for (q = p + 7; *q; ++q) { - if (!isalnum(*q) && *q != '_') { - return; - } - } - CompleteModule(p, p + 7, c); - return; - } - for (b = p, p += strlen(p); p > b; --p) { - if (!isalnum(p[-1]) && p[-1] != '.' && p[-1] != '_') { - break; - } - } - o = PyModule_GetDict(PyImport_AddModule("__main__")); - if (!*(q = strchrnul(p, '.'))) { - CompleteDict(b, q, p, c, o); - CompleteDir(b, q, p, c, PyDict_GetItemString(o, "__builtins__")); - } else { - s = strndup(p, q - p); - if ((t = PyDict_GetItemString(o, s))) { - Py_INCREF(t); - } else { - o = PyDict_GetItemString(o, "__builtins__"); - if (PyObject_HasAttrString(o, s)) { - t = PyObject_GetAttrString(o, s); - } - } - while ((p = q + 1), (o = t)) { - if (*(q = strchrnul(p, '.'))) { - t = PyObject_GetAttrString(o, gc(strndup(p, q - p))); - Py_DECREF(o); - } else { - CompleteDir(b, q, p, c, o); - Py_DECREF(o); - break; - } - } - free(s); - } -} - -static void -TerminalCompletion(const char *p, linenoiseCompletions *c) -{ - Complete(p, c); - if (PyErr_Occurred()) { - PyErr_Clear(); - } -} - -static char * -TerminalHint(const char *p, const char **ansi1, const char **ansi2) -{ - char *h = 0; - linenoiseCompletions c = {0}; - TerminalCompletion(p, &c); - if (c.len == 1) h = strdup(c.cvec[0] + strlen(p)); - linenoiseFreeCompletions(&c); - return h; -} - -static char * -ReinterpretCommand(const char *line) -{ - size_t n; - n = strlen(line); - if (n && line[n - 1] == '?') { - return xstrcat("help(", gc(strndup(gc(line), n - 1)), ')'); - } else { - return line; - } -} - -static char * -TerminalReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) -{ - size_t n; - char *p, *q; - PyOS_sighandler_t saint; - saint = PyOS_setsig(SIGINT, OnKeyboardInterrupt); - p = linenoiseWithHistory(prompt, "python"); - PyOS_setsig(SIGINT, saint); - if (g_gotint) { - PyOS_setsig(SIGINT, saint); - g_gotint = 0; - q = 0; - } else if (p) { - p = ReinterpretCommand(p); - n = strlen(p); - q = PyMem_RawMalloc(n + 2); - strcpy(mempcpy(q, p, n), "\n"); - clearerr(sys_stdin); - } else if ((q = PyMem_RawMalloc(1))) { - *q = 0; - } - free(p); - return q; -} - -int -RunPythonModule(int argc, char **argv) -{ - char *launchargs[4]; - wchar_t **argv_copy; - /* We need a second copy, as Python might modify the first one. */ - wchar_t **argv_copy2; - int i, res; - char *oldloc; - - if (argc == 1 && weaken(kLaunchPythonModuleName)) { - launchargs[0] = argv[0]; - launchargs[1] = strdup("-m"); - launchargs[2] = strdup(kLaunchPythonModuleName); - launchargs[3] = 0; - argc = 3; - argv = launchargs; - } - - PyOS_ReadlineFunctionPointer = TerminalReadline; - linenoiseSetCompletionCallback(TerminalCompletion); - linenoiseSetHintsCallback(TerminalHint); - linenoiseSetFreeHintsCallback(free); - -#if IsModeDbg() - /* Force malloc() allocator to bootstrap Python */ - _PyMem_SetupAllocators("malloc"); -#endif - - argv_copy = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); - argv_copy2 = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); - if (!argv_copy || !argv_copy2) { - fprintf(stderr, "out of memory\n"); - return 1; - } - - /* 754 requires that FP exceptions run in "no stop" mode by default, - * and until C vendors implement C99's ways to control FP exceptions, - * Python requires non-stop mode. Alas, some platforms enable FP - * exceptions by default. Here we disable them. - */ -#ifdef __FreeBSD__ - fedisableexcept(FE_OVERFLOW); -#endif - - oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL)); - if (!oldloc) { - fprintf(stderr, "out of memory\n"); - return 1; - } - - setlocale(LC_ALL, ""); - for (i = 0; i < argc; i++) { - argv_copy[i] = Py_DecodeLocale(argv[i], NULL); - if (!argv_copy[i]) { - PyMem_RawFree(oldloc); - fprintf(stderr, "Fatal Python error: " - "unable to decode the command line argument #%i\n", - i + 1); - return 1; - } - argv_copy2[i] = argv_copy[i]; - } - argv_copy2[argc] = argv_copy[argc] = NULL; - - setlocale(LC_ALL, oldloc); - PyMem_RawFree(oldloc); - - res = Py_Main(argc, argv_copy); - -#if IsModeDbg() - /* Force again malloc() allocator to release memory blocks allocated - before Py_Main() */ - _PyMem_SetupAllocators("malloc"); -#endif - - for (i = 0; i < argc; i++) { - PyMem_RawFree(argv_copy2[i]); - } - PyMem_RawFree(argv_copy); - PyMem_RawFree(argv_copy2); - return res; -} +// clang-format off int main(int argc, char **argv) diff --git a/third_party/python/runpythonmodule.c b/third_party/python/runpythonmodule.c new file mode 100644 index 000000000..52f4e5f46 --- /dev/null +++ b/third_party/python/runpythonmodule.c @@ -0,0 +1,356 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Python 3 │ +│ https://docs.python.org/3/license.html │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#define PY_SSIZE_T_CLEAN +#include "libc/bits/bits.h" +#include "libc/bits/safemacros.internal.h" +#include "libc/bits/weaken.h" +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" +#include "libc/calls/sigbits.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/struct/sigset.h" +#include "libc/calls/ucontext.h" +#include "libc/dce.h" +#include "libc/errno.h" +#include "libc/intrin/kprintf.h" +#include "libc/log/check.h" +#include "libc/log/log.h" +#include "libc/macros.internal.h" +#include "libc/mem/mem.h" +#include "libc/runtime/gc.internal.h" +#include "libc/runtime/runtime.h" +#include "libc/runtime/symbols.internal.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/fileno.h" +#include "libc/sysv/consts/prot.h" +#include "libc/sysv/consts/sig.h" +#include "libc/time/time.h" +#include "libc/unicode/locale.h" +#include "libc/x/x.h" +#include "third_party/linenoise/linenoise.h" +#include "third_party/python/Include/abstract.h" +#include "third_party/python/Include/ceval.h" +#include "third_party/python/Include/dictobject.h" +#include "third_party/python/Include/fileutils.h" +#include "third_party/python/Include/funcobject.h" +#include "third_party/python/Include/import.h" +#include "third_party/python/Include/listobject.h" +#include "third_party/python/Include/moduleobject.h" +#include "third_party/python/Include/object.h" +#include "third_party/python/Include/pydebug.h" +#include "third_party/python/Include/pyerrors.h" +#include "third_party/python/Include/pylifecycle.h" +#include "third_party/python/Include/pymem.h" +#include "third_party/python/Include/pyport.h" +#include "third_party/python/Include/pythonrun.h" +#include "third_party/python/Include/unicodeobject.h" +#include "third_party/python/Include/yoink.h" +#include "third_party/xed/x86.h" +// clang-format off + +STATIC_STACK_SIZE(0x100000); + +STATIC_YOINK("__die"); +STATIC_YOINK("zip_uri_support"); + +PYTHON_YOINK("cosmo"); +PYTHON_YOINK("_locale"); +PYTHON_YOINK("_bootlocale"); +PYTHON_YOINK("encodings.aliases"); +PYTHON_YOINK("encodings.latin_1"); +PYTHON_YOINK("encodings.utf_8"); + +extern char kLaunchPythonModuleName[]; /* optionally generated by pyobj.com */ +const struct _frozen *PyImport_FrozenModules = _PyImport_FrozenModules; +struct _inittab *PyImport_Inittab = _PyImport_Inittab; +static int g_gotint; + +static void +OnKeyboardInterrupt(int sig) +{ + g_gotint = sig; +} + +static void +AddCompletion(linenoiseCompletions *c, char *s) +{ + char **p = c->cvec; + size_t n = c->len + 1; + if ((p = realloc(p, n * sizeof(*p)))) { + p[n - 1] = s; + c->cvec = p; + c->len = n; + } +} + +static void +CompleteModule(const char *s, const char *p, linenoiseCompletions *c) +{ + const char *name; + struct _inittab *it; + Py_ssize_t plen, namelen; + PyObject *m, *f, *g, *i, *v, *n; + plen = strlen(p); + for (it = PyImport_Inittab; it->name; ++it) { + if (startswithi(it->name, p)) { + AddCompletion(c, xasprintf("%s%s", s, it->name + plen)); + } + } + if ((m = PyImport_ImportModule("pkgutil"))) { + if ((f = PyObject_GetAttrString(m, "iter_modules"))) { + if ((g = PyObject_CallFunctionObjArgs(f, 0))) { + if ((i = PyObject_GetIter(g))) { + while ((v = PyIter_Next(i))) { + if ((n = PyObject_GetAttrString(v, "name"))) { + if (((name = PyUnicode_AsUTF8AndSize(n, &namelen)) && + namelen >= plen && !memcasecmp(name, p, plen))) { + AddCompletion(c, xasprintf("%s%s", s, name + plen)); + } + Py_DECREF(n); + } + Py_DECREF(v); + } + Py_DECREF(i); + } + Py_DECREF(g); + } + Py_DECREF(f); + } + Py_DECREF(m); + } +} + +static void +CompleteDict(const char *b, const char *q, const char *p, + linenoiseCompletions *c, PyObject *o) +{ + const char *s; + PyObject *k, *v; + Py_ssize_t i, m; + for (i = 0; PyDict_Next(o, &i, &k, &v);) { + if ((v != Py_None && PyUnicode_Check(k) && + (s = PyUnicode_AsUTF8AndSize(k, &m)) && + m >= q - p && !memcasecmp(s, p, q - p))) { + AddCompletion(c, xasprintf("%.*s%.*s", p - b, b, m, s)); + } + } +} + +static void +CompleteDir(const char *b, const char *q, const char *p, + linenoiseCompletions *c, PyObject *o) +{ + Py_ssize_t m; + const char *s; + PyObject *d, *i, *k; + if ((d = PyObject_Dir(o))) { + if ((i = PyObject_GetIter(d))) { + while ((k = PyIter_Next(i))) { + if (((s = PyUnicode_AsUTF8AndSize(k, &m)) && + m >= q - p && !memcasecmp(s, p, q - p) && + !(q - p == 0 && m > 4 && + (s[0+0] == '_' && s[0+1] == '_' && + s[m-1] == '_' && s[m-2] == '_')))) { + AddCompletion(c, xasprintf("%.*s%.*s", p - b, b, m, s)); + } + Py_DECREF(k); + } + Py_DECREF(i); + } + Py_DECREF(d); + } +} + +static void +Complete(const char *p, linenoiseCompletions *c) +{ + PyObject *o, *t, *i; + const char *q, *s, *b; + if (startswith(p, "import ")) { + for (q = p + 7; *q; ++q) { + if (!isalnum(*q) && *q != '_') { + return; + } + } + CompleteModule(p, p + 7, c); + return; + } + for (b = p, p += strlen(p); p > b; --p) { + if (!isalnum(p[-1]) && p[-1] != '.' && p[-1] != '_') { + break; + } + } + o = PyModule_GetDict(PyImport_AddModule("__main__")); + if (!*(q = strchrnul(p, '.'))) { + CompleteDict(b, q, p, c, o); + CompleteDir(b, q, p, c, PyDict_GetItemString(o, "__builtins__")); + } else { + s = strndup(p, q - p); + if ((t = PyDict_GetItemString(o, s))) { + Py_INCREF(t); + } else { + o = PyDict_GetItemString(o, "__builtins__"); + if (PyObject_HasAttrString(o, s)) { + t = PyObject_GetAttrString(o, s); + } + } + while ((p = q + 1), (o = t)) { + if (*(q = strchrnul(p, '.'))) { + t = PyObject_GetAttrString(o, gc(strndup(p, q - p))); + Py_DECREF(o); + } else { + CompleteDir(b, q, p, c, o); + Py_DECREF(o); + break; + } + } + free(s); + } +} + +static void +TerminalCompletion(const char *p, linenoiseCompletions *c) +{ + Complete(p, c); + if (PyErr_Occurred()) { + PyErr_Clear(); + } +} + +static char * +TerminalHint(const char *p, const char **ansi1, const char **ansi2) +{ + char *h = 0; + linenoiseCompletions c = {0}; + TerminalCompletion(p, &c); + if (c.len == 1) h = strdup(c.cvec[0] + strlen(p)); + linenoiseFreeCompletions(&c); + return h; +} + +static char * +ReinterpretCommand(const char *line) +{ + size_t n; + n = strlen(line); + if (n && line[n - 1] == '?') { + return xstrcat("help(", gc(strndup(gc(line), n - 1)), ')'); + } else { + return line; + } +} + +static char * +TerminalReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) +{ + size_t n; + char *p, *q; + PyOS_sighandler_t saint; + saint = PyOS_setsig(SIGINT, OnKeyboardInterrupt); + p = linenoiseWithHistory(prompt, "python"); + PyOS_setsig(SIGINT, saint); + if (g_gotint) { + PyOS_setsig(SIGINT, saint); + g_gotint = 0; + q = 0; + } else if (p) { + p = ReinterpretCommand(p); + n = strlen(p); + q = PyMem_RawMalloc(n + 2); + strcpy(mempcpy(q, p, n), "\n"); + clearerr(sys_stdin); + } else if ((q = PyMem_RawMalloc(1))) { + *q = 0; + } + free(p); + return q; +} + +int +RunPythonModule(int argc, char **argv) +{ + char *launchargs[4]; + wchar_t **argv_copy; + /* We need a second copy, as Python might modify the first one. */ + wchar_t **argv_copy2; + int i, res; + char *oldloc; + + if (argc == 1 && weaken(kLaunchPythonModuleName)) { + launchargs[0] = argv[0]; + launchargs[1] = strdup("-m"); + launchargs[2] = strdup(kLaunchPythonModuleName); + launchargs[3] = 0; + argc = 3; + argv = launchargs; + } + + PyOS_ReadlineFunctionPointer = TerminalReadline; + linenoiseSetCompletionCallback(TerminalCompletion); + linenoiseSetHintsCallback(TerminalHint); + linenoiseSetFreeHintsCallback(free); + +#if IsModeDbg() + /* Force malloc() allocator to bootstrap Python */ + _PyMem_SetupAllocators("malloc"); +#endif + + argv_copy = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); + argv_copy2 = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); + if (!argv_copy || !argv_copy2) { + fprintf(stderr, "out of memory\n"); + return 1; + } + + /* 754 requires that FP exceptions run in "no stop" mode by default, + * and until C vendors implement C99's ways to control FP exceptions, + * Python requires non-stop mode. Alas, some platforms enable FP + * exceptions by default. Here we disable them. + */ +#ifdef __FreeBSD__ + fedisableexcept(FE_OVERFLOW); +#endif + + oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL)); + if (!oldloc) { + fprintf(stderr, "out of memory\n"); + return 1; + } + + setlocale(LC_ALL, ""); + for (i = 0; i < argc; i++) { + argv_copy[i] = Py_DecodeLocale(argv[i], NULL); + if (!argv_copy[i]) { + PyMem_RawFree(oldloc); + fprintf(stderr, "Fatal Python error: " + "unable to decode the command line argument #%i\n", + i + 1); + return 1; + } + argv_copy2[i] = argv_copy[i]; + } + argv_copy2[argc] = argv_copy[argc] = NULL; + + setlocale(LC_ALL, oldloc); + PyMem_RawFree(oldloc); + + res = Py_Main(argc, argv_copy); + +#if IsModeDbg() + /* Force again malloc() allocator to release memory blocks allocated + before Py_Main() */ + _PyMem_SetupAllocators("malloc"); +#endif + + for (i = 0; i < argc; i++) { + PyMem_RawFree(argv_copy2[i]); + } + PyMem_RawFree(argv_copy); + PyMem_RawFree(argv_copy2); + return res; +} diff --git a/third_party/python/runpythonmodule.h b/third_party/python/runpythonmodule.h new file mode 100644 index 000000000..2aa150780 --- /dev/null +++ b/third_party/python/runpythonmodule.h @@ -0,0 +1,10 @@ +#ifndef COSMOPOLITAN_THIRD_PARTY_PYTHON_RUNPYTHONMODULE_H_ +#define COSMOPOLITAN_THIRD_PARTY_PYTHON_RUNPYTHONMODULE_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +int RunPythonModule(int, char **); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_THIRD_PARTY_PYTHON_RUNPYTHONMODULE_H_ */ diff --git a/tool/args/args.c b/tool/args/args.c index 4bed2a002..aec1c73ff 100644 --- a/tool/args/args.c +++ b/tool/args/args.c @@ -29,7 +29,7 @@ STATIC_YOINK("zip_uri_support"); static struct ZipArgs { - bool registered; + bool initialized; bool loaded; int oldargc; char *data; @@ -76,15 +76,15 @@ int LoadZipArgsImpl(int *argc, char ***argv, char *data) { start = 0; } if (founddots || *argc <= 1) { - if (!g_zipargs.registered) { + if (!g_zipargs.initialized) { atexit(FreeZipArgs); - g_zipargs.registered = true; + g_zipargs.oldargc = __argc; + g_zipargs.oldargv = __argv; + g_zipargs.initialized = true; } g_zipargs.loaded = true; g_zipargs.data = data; g_zipargs.args = args; - g_zipargs.oldargc = *argc; - g_zipargs.oldargv = *argv; *argc = n; *argv = args; __argc = n; diff --git a/tool/emacs/cosmo-c-keywords.el b/tool/emacs/cosmo-c-keywords.el index 441b7c977..11ee51b9f 100644 --- a/tool/emacs/cosmo-c-keywords.el +++ b/tool/emacs/cosmo-c-keywords.el @@ -99,7 +99,8 @@ "_Vector_size")) (gnu - '("__inline" + '("__extension__" + "__inline" "__thread" "__alignof" "__typeof" diff --git a/tool/net/counters.inc b/tool/net/counters.inc index 96b3579a0..4f55e94f8 100644 --- a/tool/net/counters.inc +++ b/tool/net/counters.inc @@ -1,4 +1,5 @@ C(accepterrors) +C(acceptflakes) C(acceptinterrupts) C(acceptresets) C(badlengths) @@ -74,6 +75,7 @@ C(sslunknownca) C(sslunknowncert) C(sslupgrades) C(sslverifyfailed) +C(stackuse) C(statfails) C(staticrequests) C(stats) diff --git a/tool/net/help.txt b/tool/net/help.txt index 4cef7ae1a..15814bd41 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -54,6 +54,7 @@ FLAGS -Z log worker system calls -f log worker function calls -B only use stronger cryptography + -X disable ssl server and client support -s increase silence [repeatable] -v increase verbosity [repeatable] -V increase ssl verbosity [repeatable] @@ -1980,13 +1981,15 @@ UNIX MODULE Makes directories. + Unlike mkdir() this convenience wrapper will automatically create + parent parent directories as needed. If the directory already exists + then, unlike mkdir() which returns EEXIST, the makedirs() function + will return success. + `path` is the path of the directory you wish to create. `mode` is octal permission bits, e.g. `0755`. - Unlike mkdir() this convenience wrapper will automatically create - parent parent directories as needed. - unix.chdir(path:str) ├─→ true └─→ nil, unix.Errno diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 45a58f589..d5e3ce614 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "dsp/scale/cdecimate2xuint8x8.h" +#include "libc/bits/atomic.h" #include "libc/bits/bits.h" #include "libc/bits/likely.h" #include "libc/bits/popcnt.h" @@ -204,34 +205,26 @@ STATIC_YOINK("zip_uri_support"); #define HeaderEqualCase(H, S) \ SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H)) -#define TRACE_BEGIN \ - do { \ - if (!IsTiny()) { \ - if (funtrace) { \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ - } \ - if (systrace) { \ - __atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED); \ - } \ - } \ +#define TRACE_BEGIN \ + do { \ + if (!IsTiny()) { \ + if (funtrace) ++__ftrace; \ + if (systrace) ++__strace; \ + } \ } while (0) -#define TRACE_END \ - do { \ - if (!IsTiny()) { \ - if (funtrace) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ - } \ - if (systrace) { \ - __atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED); \ - } \ - } \ +#define TRACE_END \ + do { \ + if (!IsTiny()) { \ + if (funtrace) --__ftrace; \ + if (systrace) --__strace; \ + } \ } while (0) -// letters not used: EIJNOQXYnoqwxy +// letters not used: EIJNOQYnoqwxy // digits not used: 0123456789 // puncts not used: !"#$%&'()*+,-./;<=>@[\]^_`{|}~ -#define GETOPTS "BSVZabdfghijkmsuvzA:C:D:F:G:H:K:L:M:P:R:T:U:W:c:e:l:p:r:t:" +#define GETOPTS "BSVXZabdfghijkmsuvzA:C:D:F:G:H:K:L:M:P:R:T:U:W:c:e:l:p:r:t:" extern unsigned long long __kbirth; @@ -403,6 +396,7 @@ static bool branded; static bool funtrace; static bool systrace; static bool meltdown; +static bool unsecure; static bool printport; static bool daemonize; static bool logrusage; @@ -425,7 +419,6 @@ static bool sslclientverify; static bool connectionclose; static bool hasonworkerstop; static bool isexitingworker; -static bool terminatemonitor; static bool hasonworkerstart; static bool leakcrashreports; static bool hasonhttprequest; @@ -437,6 +430,7 @@ static bool loggednetworkorigin; static bool ishandlingconnection; static bool hasonclientconnection; static bool evadedragnetsurveillance; +static _Atomic(bool) terminatemonitor; static int zfd; static int frags; @@ -1213,7 +1207,7 @@ static void CallSimpleHookIfDefined(const char *s) { static void ReportWorkerExit(int pid, int ws) { int workers; - workers = __atomic_sub_fetch(&shared->workers, 1, __ATOMIC_SEQ_CST); + workers = atomic_fetch_sub(&shared->workers, 1) - 1; if (WIFEXITED(ws)) { if (WEXITSTATUS(ws)) { LockInc(&shared->c.failedchildren); @@ -3696,6 +3690,7 @@ static int LuaStoreAsset(lua_State *L) { static void ReseedRng(mbedtls_ctr_drbg_context *r, const char *s) { #ifndef UNSECURE + if (unsecure) return; CHECK_EQ(0, mbedtls_ctr_drbg_reseed(r, (void *)s, strlen(s))); #endif } @@ -3848,7 +3843,8 @@ static int LuaFetch(lua_State *L) { usessl = false; if (url.scheme.n) { #ifndef UNSECURE - if (url.scheme.n == 5 && !memcasecmp(url.scheme.p, "https", 5)) { + if (!unsecure && url.scheme.n == 5 && + !memcasecmp(url.scheme.p, "https", 5)) { usessl = true; } else #endif @@ -3858,14 +3854,20 @@ static int LuaFetch(lua_State *L) { } } +#ifndef UNSECURE if (usessl && !sslinitialized) TlsInit(); +#endif if (url.host.n) { host = gc(strndup(url.host.p, url.host.n)); if (url.port.n) { port = gc(strndup(url.port.p, url.port.n)); +#ifndef UNSECURE + } else if (usessl) { + port = "443"; +#endif } else { - port = usessl ? "443" : "80"; + port = "80"; } } else { ip = servers.n ? ntohl(servers.p[0].addr.sin_addr.s_addr) : INADDR_LOOPBACK; @@ -3932,6 +3934,7 @@ static int LuaFetch(lua_State *L) { unreachable; } +#ifndef UNSECURE if (usessl) { if (sslcliused) { mbedtls_ssl_session_reset(&sslcli); @@ -3966,11 +3969,13 @@ static int LuaFetch(lua_State *L) { mbedtls_ssl_get_ciphersuite(&sslcli), mbedtls_ssl_get_version(&sslcli)); } +#endif /* UNSECURE */ /* * Send HTTP Message. */ DEBUGF("(ftch) client sending %s request", method); +#ifndef UNSECURE if (usessl) { ret = mbedtls_ssl_write(&sslcli, request, requestlen); if (ret != requestlen) { @@ -3979,7 +3984,9 @@ static int LuaFetch(lua_State *L) { LuaThrowTlsError(L, "write", ret); unreachable; } - } else if (WRITE(sock, request, requestlen) != requestlen) { + } else +#endif + if (WRITE(sock, request, requestlen) != requestlen) { close(sock); luaL_error(L, "write error: %s", strerror(errno)); unreachable; @@ -4000,6 +4007,7 @@ static int LuaFetch(lua_State *L) { inbuf.p = realloc(inbuf.p, inbuf.c); } NOISEF("(ftch) client reading"); +#ifndef UNSECURE if (usessl) { if ((rc = mbedtls_ssl_read(&sslcli, inbuf.p + inbuf.n, inbuf.c - inbuf.n)) < 0) { @@ -4013,7 +4021,9 @@ static int LuaFetch(lua_State *L) { unreachable; } } - } else if ((rc = READ(sock, inbuf.p + inbuf.n, inbuf.c - inbuf.n)) == -1) { + } else +#endif + if ((rc = READ(sock, inbuf.p + inbuf.n, inbuf.c - inbuf.n)) == -1) { close(sock); free(inbuf.p); DestroyHttpMessage(&msg); @@ -4163,6 +4173,7 @@ TransportError: close(sock); luaL_error(L, "transport error"); unreachable; +#ifndef UNSECURE VerifyFailed: LockInc(&shared->c.sslverifyfailed); close(sock); @@ -4170,6 +4181,7 @@ VerifyFailed: L, gc(DescribeSslVerifyFailure(sslcli.session_negotiate->verify_result)), ret); unreachable; +#endif #undef ssl } @@ -4828,8 +4840,11 @@ static int LuaEvadeDragnetSurveillance(lua_State *L) { static int LuaProgramSslCompression(lua_State *L) { #ifndef UNSECURE - OnlyCallFromInitLua(L, "ProgramSslCompression"); - conf.disable_compression = confcli.disable_compression = !lua_toboolean(L, 1); + if (!unsecure) { + OnlyCallFromInitLua(L, "ProgramSslCompression"); + conf.disable_compression = confcli.disable_compression = + !lua_toboolean(L, 1); + } #endif return 0; } @@ -5071,6 +5086,7 @@ static const luaL_Reg kLuaFuncs[] = { {"EscapePath", LuaEscapePath}, // {"EscapeSegment", LuaEscapeSegment}, // {"EscapeUser", LuaEscapeUser}, // + {"Fetch", LuaFetch}, // {"FormatHttpDateTime", LuaFormatHttpDateTime}, // {"FormatIp", LuaFormatIp}, // {"GetAssetComment", LuaGetAssetComment}, // @@ -5194,7 +5210,6 @@ static const luaL_Reg kLuaFuncs[] = { {"hex", LuaHex}, // {"oct", LuaOct}, // #ifndef UNSECURE - {"Fetch", LuaFetch}, // {"EvadeDragnetSurveillance", LuaEvadeDragnetSurveillance}, // {"GetSslIdentity", LuaGetSslIdentity}, // {"ProgramSslCiphersuite", LuaProgramSslCiphersuite}, // @@ -5541,6 +5556,7 @@ static char *HandleMapFailed(struct Asset *a, int fd) { } static void LogAcceptError(const char *s) { + LockInc(&shared->c.accepterrors); WARNF("(srvr) %s accept error: %s", DescribeServer(), s); } @@ -6270,14 +6286,16 @@ static void HandleMessages(void) { #ifndef UNSECURE if (!once) { once = true; - if (IsSsl(inbuf.p[0])) { - if (TlsSetup()) { - continue; + if (!unsecure) { + if (IsSsl(inbuf.p[0])) { + if (TlsSetup()) { + continue; + } else { + return; + } } else { - return; + WipeServingKeys(); } - } else { - WipeServingKeys(); } } #endif @@ -6300,15 +6318,15 @@ static void HandleMessages(void) { LockInc(&shared->c.readtimeouts); if (amtread) SendTimeout(); NotifyClose(); - LogClose("timeout"); + LogClose("readtimeout"); return; } else if (errno == ECONNRESET) { LockInc(&shared->c.readresets); - LogClose("reset"); + LogClose("readreset"); return; } else { LockInc(&shared->c.readerrors); - WARNF("(clnt) %s read error: %m", DescribeClient()); + WARNF("(clnt) %s readerror: %m", DescribeClient()); return; } if (killed || (terminated && !amtread) || @@ -6339,7 +6357,7 @@ static void HandleMessages(void) { } else { CHECK_LT(msgsize, amtread); LockInc(&shared->c.pipelinedrequests); - DEBUGF("(stat) %,ld pipelined bytes", amtread - msgsize); + DEBUGF("(stat) %,ld pipelinedrequest bytes", amtread - msgsize); memmove(inbuf.p, inbuf.p + msgsize, amtread - msgsize); amtread -= msgsize; if (killed) { @@ -6488,7 +6506,7 @@ static int MemoryMonitor(void *arg) { long i, j, k, n, x, y, pi, gen, pages; int rc, id, color, color2, workers; _spinlock(&memmonalive); - __atomic_load(&shared->workers, &id, __ATOMIC_SEQ_CST); + id = atomic_load_explicit(&shared->workers, memory_order_relaxed); DEBUGF("(memv) started for pid %d on tid %d", getpid(), gettid()); sigemptyset(&ss); @@ -6521,9 +6539,8 @@ static int MemoryMonitor(void *arg) { if (tty != -1) { for (gen = 0, mi = 0, b = 0;;) { - __atomic_load(&terminatemonitor, &done, __ATOMIC_SEQ_CST); - if (done) break; - __atomic_load(&shared->workers, &workers, __ATOMIC_SEQ_CST); + if (terminatemonitor) break; + workers = atomic_load_explicit(&shared->workers, memory_order_relaxed); if (id) id = MAX(1, MIN(id, workers)); if (!id && workers) { usleep(50000); @@ -6531,7 +6548,7 @@ static int MemoryMonitor(void *arg) { } ++gen; - __atomic_load(&_mmi.i, &intervals, __ATOMIC_SEQ_CST); + intervals = atomic_load_explicit(&_mmi.i, memory_order_relaxed); if ((mi2 = realloc(mi, (intervals += 3) * sizeof(*mi)))) { mi = mi2; mi[0].x = (intptr_t)_base >> 16; @@ -6713,35 +6730,37 @@ static int HandleConnection(size_t i) { LockInc(&shared->c.acceptinterrupts); } else if (errno == ENFILE) { LockInc(&shared->c.enfiles); - LogAcceptError("too many open files"); + LogAcceptError("enfile: too many open files"); meltdown = true; } else if (errno == EMFILE) { LockInc(&shared->c.emfiles); - LogAcceptError("ran out of open file quota"); + LogAcceptError("emfile: ran out of open file quota"); meltdown = true; } else if (errno == ENOMEM) { LockInc(&shared->c.enomems); - LogAcceptError("ran out of memory"); + LogAcceptError("enomem: ran out of memory"); meltdown = true; } else if (errno == ENOBUFS) { LockInc(&shared->c.enobufs); - LogAcceptError("ran out of buffer"); + LogAcceptError("enobuf: ran out of buffer"); meltdown = true; } else if (errno == ENONET) { LockInc(&shared->c.enonets); - LogAcceptError("network gone"); + LogAcceptError("enonet: network gone"); polls[i].fd = -polls[i].fd; } else if (errno == ENETDOWN) { LockInc(&shared->c.enetdowns); - LogAcceptError("network down"); + LogAcceptError("enetdown: network down"); polls[i].fd = -polls[i].fd; } else if (errno == ECONNABORTED) { + LockInc(&shared->c.accepterrors); LockInc(&shared->c.acceptresets); WARNF("(srvr) %S accept error: %s", DescribeServer(), - "connection reset before accept"); + "acceptreset: connection reset before accept"); } else if (errno == ENETUNREACH || errno == EHOSTUNREACH || errno == EOPNOTSUPP || errno == ENOPROTOOPT || errno == EPROTO) { LockInc(&shared->c.accepterrors); + LockInc(&shared->c.acceptflakes); WARNF("(srvr) accept error: %s ephemeral accept error: %m", DescribeServer()); } else { @@ -6753,6 +6772,7 @@ static int HandleConnection(size_t i) { } static void RestoreApe(void) { + int ft; char *p; size_t n; struct Asset *a; @@ -6764,9 +6784,15 @@ static void RestoreApe(void) { if (endswith(zpath, ".com.dbg")) return; if ((a = GetAssetZip("/.ape", 5)) && (p = LoadAsset(a, &n))) { close(zfd); + ft = __ftrace; if ((zfd = OpenExecutable()) == -1 || WRITE(zfd, p, n) == -1) { WARNF("(srvr) can't restore .ape"); } + if (ft > 0) { + __ftrace = 0; + ftrace_install(); + __ftrace = ft; + } free(p); } else { DEBUGF("(srvr) /.ape not found"); @@ -7036,6 +7062,7 @@ static void SigInit(void) { static void TlsInit(void) { #ifndef UNSECURE int suite; + if (unsecure) return; if (!sslinitialized) { InitializeRng(&rng); @@ -7095,6 +7122,7 @@ static void TlsInit(void) { static void TlsDestroy(void) { #ifndef UNSECURE + if (unsecure) return; mbedtls_ssl_free(&ssl); mbedtls_ssl_free(&sslcli); mbedtls_ctr_drbg_free(&rng); @@ -7139,6 +7167,7 @@ static void GetOpts(int argc, char *argv[]) { CASE('S', ++sandboxed); CASE('v', ++__log_level); CASE('s', --__log_level); + CASE('X', unsecure = true); CASE('Z', systrace = true); CASE('b', logbodies = true); CASE('z', printport = true); diff --git a/tool/plinko/lib/plinko.c b/tool/plinko/lib/plinko.c index 5f6e6379c..5035420b3 100644 --- a/tool/plinko/lib/plinko.c +++ b/tool/plinko/lib/plinko.c @@ -674,9 +674,9 @@ struct T DispatchTrace(dword ea, dword tm, dword r, dword p1, dword p2, struct T DispatchFtrace(dword ea, dword tm, dword r, dword p1, dword p2, dword d) { ftrace_install(); - ++g_ftrace; + ++__ftrace; ea = MAKE(recurse(MAKE(Cadr(LO(ea)), HI(ea)), p1, p2), 0); - --g_ftrace; + --__ftrace; return Ret(ea, tm, r); } diff --git a/tool/plinko/lib/printf.c b/tool/plinko/lib/printf.c index 839ef7216..43fceab34 100644 --- a/tool/plinko/lib/printf.c +++ b/tool/plinko/lib/printf.c @@ -80,7 +80,7 @@ int Vfnprintf(const char *f, va_list va, int fd, int n) { int b, c, i, x, y, si, prec, cols, sign; gotr = false; t = rdtsc(); - --g_ftrace; + --__ftrace; --__strace; ++recursive; for (ansi = 0;;) { @@ -290,7 +290,7 @@ int Vfnprintf(const char *f, va_list va, int fd, int n) { } } --recursive; - ++g_ftrace; + ++__ftrace; ++__strace; if (!recursive) { u = rdtsc(); diff --git a/tool/plinko/lib/read.c b/tool/plinko/lib/read.c index f35c06a6f..ac0a7b76c 100644 --- a/tool/plinko/lib/read.c +++ b/tool/plinko/lib/read.c @@ -280,10 +280,10 @@ static int Read1(int fd) { int Read(int fd) { int r; - --g_ftrace; + --__ftrace; --__strace; r = Read1(fd); - ++g_ftrace; + ++__ftrace; ++__strace; return r; } diff --git a/tool/plinko/plinko.c b/tool/plinko/plinko.c index eaa47a2ce..90158369e 100644 --- a/tool/plinko/plinko.c +++ b/tool/plinko/plinko.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/intrin/kprintf.h" #include "libc/log/log.h" +#include "libc/stdio/stdio.h" #include "tool/plinko/lib/plinko.h" STATIC_YOINK("__zipos_get"); diff --git a/libc/calls/getfdhandleactual.greg.c b/tool/viz/echoctl.c similarity index 86% rename from libc/calls/getfdhandleactual.greg.c rename to tool/viz/echoctl.c index b0f797b12..281909034 100644 --- a/libc/calls/getfdhandleactual.greg.c +++ b/tool/viz/echoctl.c @@ -16,13 +16,13 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" -#include "libc/sock/ntstdin.internal.h" +#include "libc/calls/struct/termios.h" +#include "libc/calls/termios.h" +#include "libc/sysv/consts/termios.h" -int64_t __getfdhandleactual(int fd) { - if (g_fds.p[fd].worker) { - return g_fds.p[fd].worker->reader; - } else { - return g_fds.p[fd].handle; - } +int main(int argc, char *argv[]) { + struct termios t; + if (tcgetattr(0, &t) == -1) return 1; + t.c_lflag ^= ECHOCTL; + if (tcsetattr(0, TCSANOW, &t) == -1) return 2; } diff --git a/libc/calls/sched_yield-nt.c b/tool/viz/vdsodump.c similarity index 53% rename from libc/calls/sched_yield-nt.c rename to tool/viz/vdsodump.c index fc6fbb0fb..f5042a241 100644 --- a/libc/calls/sched_yield-nt.c +++ b/tool/viz/vdsodump.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 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ @@ -16,19 +16,66 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" -#include "libc/nt/enum/status.h" -#include "libc/nt/ntdll.h" -#include "libc/nt/synchronization.h" +#include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/ucontext.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/sysv/consts/auxv.h" +#include "libc/sysv/consts/sa.h" +#include "libc/sysv/consts/sig.h" +#include "third_party/xed/x86.h" + +#define OUTPATH "vdso.elf" + +volatile bool finished; + +void OnSegmentationFault(int sig, siginfo_t *si, ucontext_t *ctx) { + struct XedDecodedInst xedd; + xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); + xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15); + ctx->uc_mcontext.rip += xedd.length; + finished = true; +} + +int main(int argc, char *argv[]) { + FILE *f; + int byte; + volatile unsigned char *vdso, *p; + + vdso = (unsigned char *)getauxval(AT_SYSINFO_EHDR); + if (vdso) { + fprintf(stderr, "vdso found at address %p\n", vdso); + } else { + fprintf(stderr, "error: AT_SYSINFO_EHDR was not in auxiliary values\n"); + return 1; + } + + f = fopen(OUTPATH, "wb"); + if (!f) { + fprintf(stderr, "error: fopen(%`'s) failed\n", OUTPATH); + return 1; + } + + struct sigaction sa = { + .sa_sigaction = OnSegmentationFault, + .sa_flags = SA_SIGINFO, + }; + sigaction(SIGSEGV, &sa, 0); + sigaction(SIGBUS, &sa, 0); + + p = vdso; + for (;;) { + byte = *p++; + if (!finished) { + fputc(byte, f); + } else { + break; + } + } + + fclose(f); + fprintf(stderr, "%zu bytes dumped to %s\n", p - vdso, OUTPATH); -textwindows int sys_sched_yield_nt(void) { - // A value of zero, together with the bAlertable parameter set to - // FALSE, causes the thread to relinquish the remainder of its time - // slice to any other thread that is ready to run, if there are no - // pending user APCs on the calling thread. If there are no other - // threads ready to run and no user APCs are queued, the function - // returns immediately, and the thread continues execution. - // ──Quoth MSDN - SleepEx(0, false); return 0; }