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
This commit is contained in:
Justine Tunney 2022-05-18 16:41:29 -07:00
parent c6bbca55e9
commit 9208c83f7a
141 changed files with 1948 additions and 1411 deletions

View file

@ -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' "$@"

View file

@ -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));

80
libc/atomic.h Normal file
View file

@ -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_ */

36
libc/bits/atomic-clang.h Normal file
View file

@ -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_ */

58
libc/bits/atomic-gcc.h Normal file
View file

@ -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_ */

34
libc/bits/atomic-gcc47.h Normal file
View file

@ -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_ */

View file

@ -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_ */

View file

@ -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))

View file

@ -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 (fd->kind == kFdConsole && fd->extra && fd->extra != -1) {
if (!CloseHandle(fd->extra)) ok = false;
}

View file

@ -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,
};

View file

@ -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;
}
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);

View file

@ -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 (__nosync != 0x5453455454534146) {
if (!IsWindows()) {
rc = sys_fdatasync(fd);
} else {
rc = sys_fdatasync_nt(fd);
}
STRACE("%s(%d) → %d% m", "fdatasync", fd, rc);
STRACE("fdatasync(%d) → %d% m", fd, rc);
} else {
rc = 0;
STRACE("fdatasync(%d) → disabled% m", fd);
}
return rc;
}

View file

@ -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 (__nosync != 0x5453455454534146) {
if (!IsWindows()) {
rc = sys_fsync(fd);
} else {
rc = sys_fdatasync_nt(fd);
}
STRACE("%s(%d) → %d% m", "fsync", fd, rc);
STRACE("fysnc(%d) → %d% m", fd, rc);
} else {
rc = 0;
STRACE("fsync(%d) → disabled% m", fd);
}
return rc;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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"

View file

@ -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);

View file

@ -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);

View file

@ -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();

View file

@ -22,9 +22,10 @@
#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,
static void sigaltstack2bsd(struct sigaltstack_bsd *bsd,
const struct sigaltstack *linux) {
void *sp;
int flags;
@ -37,7 +38,7 @@ static noasan void sigaltstack2bsd(struct sigaltstack_bsd *bsd,
bsd->ss_size = size;
}
static noasan void sigaltstack2linux(struct sigaltstack *linux,
static void sigaltstack2linux(struct sigaltstack *linux,
const struct sigaltstack_bsd *bsd) {
void *sp;
int flags;
@ -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;
}

View file

@ -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_

View file

@ -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 (__nosync != 0x5453455454534146) {
if (!IsWindows()) {
sys_sync();
} else {
sys_sync_nt();
}
STRACE("sync()% m");
} else {
STRACE("sync() → disabled% m");
}
}

View file

@ -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_ */

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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;

View file

@ -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)) {

View file

@ -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;
}
}

View file

@ -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_ */

View file

@ -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;
}
}

View file

@ -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_ */

View file

@ -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 *);

View file

@ -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 "";
}

View file

@ -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"}, //

View file

@ -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;

View file

@ -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 += \

View file

@ -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

54
libc/intrin/sched_yield.S Normal file
View file

@ -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

View file

@ -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__); \
} \
if (warntries & 7) { \
__builtin_ia32_pause(); \
} else { \
sched_yield(); \
} \
} \
} \
} while (0)

View file

@ -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;

4
libc/isystem/stdatomic.h Normal file
View file

@ -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_ */

View file

@ -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"

View file

@ -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");

View file

@ -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,9 +206,9 @@ 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; \
@ -219,9 +219,9 @@ extern unsigned __log_level; /* log level for runtime check */
int e = errno; \
autotype(FORM) Ax = (FORM); \
if (Ax == NULL && 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; \

View file

@ -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 \

View file

@ -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;
}

View file

@ -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. */
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
bzero(&sa, sizeof(sa));
if (!IsWindows()) {
bzero(&ss, sizeof(ss));
ss.ss_flags = 0;
ss.ss_size = SIGSTKSZ;
ss.ss_sp = malloc(SIGSTKSZ);
__cxa_atexit(free, ss.ss_sp, 0);
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));
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];

View file

@ -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);
}
}

View file

@ -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) {

View file

@ -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);

View file

@ -20,7 +20,7 @@
.privileged
ftrace_hook:
cmp $0,g_ftrace(%rip)
cmp $0,__ftrace(%rip)
jg 1f
ret
1: push %rbp

View file

@ -35,7 +35,7 @@
textstartup int ftrace_init(void) {
if (__intercept_flag(&__argc, __argv, "--ftrace")) {
ftrace_install();
++g_ftrace;
++__ftrace;
}
return __argc;
}

View file

@ -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) {
_spinlock_cooperative(&ftrace_lock);
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;
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");

View file

@ -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;

View file

@ -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) {

View file

@ -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,61 +42,20 @@
#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;
assert(!__vforked);
if (UNLIKELY(!n)) {
STRACE("munmap(%.12p, %'zu) %s (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)) {
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 (x < y) {
// delete shadowspace if unmapping ≥512kb
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);
@ -101,24 +66,99 @@ static noasan int Munmap(void *v, size_t n) {
} else {
STRACE("unshadow(%.12p, %p) EFAULT", a, b - a);
}
}
}
return 0;
// 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) 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();
}
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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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 \

View file

@ -62,7 +62,8 @@ 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))
((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_

View file

@ -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]);

View file

@ -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);
}

View file

@ -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;

View file

@ -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;
}
}
}

View file

@ -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_ */

Some files were not shown because too many files have changed in this diff Show more