Improve memory safety

This commit makes numerous refinements to cosmopolitan memory handling.

The default stack size has been reduced from 2mb to 128kb. A new macro
is now provided so you can easily reconfigure the stack size to be any
value you want. Work around the breaking change by adding to your main:

    STATIC_STACK_SIZE(0x00200000);  // 2mb stack

If you're not sure how much stack you need, then you can use:

    STATIC_YOINK("stack_usage_logging");

After which you can `sort -nr o/$MODE/stack.log`. Based on the unit test
suite, nothing in the Cosmopolitan repository (except for Python) needs
a stack size greater than 30kb. There are also new macros for detecting
the size and address of the stack at runtime, e.g. GetStackAddr(). We
also now support sigaltstack() so if you want to see nice looking crash
reports whenever a stack overflow happens, you can put this in main():

    ShowCrashReports();

Under `make MODE=dbg` and `make MODE=asan` the unit testing framework
will now automatically print backtraces of memory allocations when
things like memory leaks happen. Bugs are now fixed in ASAN global
variable overrun detection. The memtrack and asan runtimes also handle
edge cases now. The new tools helped to identify a few memory leaks,
which are fixed by this change.

This change should fix an issue reported in #288 with ARG_MAX limits.
Fixing this doubled the performance of MKDEPS.COM and AR.COM yet again.
This commit is contained in:
Justine Tunney 2021-10-13 17:27:13 -07:00
parent a0b39f886c
commit 226aaf3547
317 changed files with 6474 additions and 3993 deletions

View file

@ -216,30 +216,25 @@ tags: TAGS HTAGS
o/$(MODE)/.x: o/$(MODE)/.x:
@mkdir -p $(@D) && touch $@ @mkdir -p $(@D) && touch $@
ifneq ($(findstring 4.,,$(MAKE_VERSION)),$(MAKE_VERSION))
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x)))) o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x))) $(file >$@,$(SRCS))
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x)))) o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x))) $(file >$@,$(HDRS) $(INCS))
o/$(MODE)/incs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(INCS) $(INCS),$(dir $(x)))) o/$(MODE)/incs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(INCS) $(INCS),$(dir $(x))))
$(file >$@) $(foreach x,$(INCS) $(INCS),$(file >>$@,$(x))) $(file >$@,$(INCS))
else
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
$(MAKE) MODE=rel -j8 -pn bopit 2>/dev/null | sed -ne '/^SRCS/ {s/.*:= //;s/ */\n/g;p;q}' >$@
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
$(MAKE) MODE=rel -j8 -pn bopit 2>/dev/null | sed -ne '/^HDRS/ {s/.*:= //;s/ */\n/g;p;q}' >$@
o/$(MODE)/incs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(INCS) $(INCS),$(dir $(x))))
$(MAKE) MODE=rel -j8 -pn bopit 2>/dev/null | sed -ne '/^INCS/ {s/.*:= //;s/ */\n/g;p;q}' >$@
endif
o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt o/$(MODE)/incs.txt $(SRCS) $(HDRS) $(INCS) o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt o/$(MODE)/incs.txt $(SRCS) $(HDRS) $(INCS)
@$(COMPILE) -AMKDEPS $(MKDEPS) -o $@ -r o/$(MODE)/ o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt o/$(MODE)/incs.txt @$(COMPILE) -AMKDEPS $(MKDEPS) -o $@ -r o/$(MODE)/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt @o/$(MODE)/incs.txt
TAGS: o/$(MODE)/srcs.txt $(SRCS) o/$(MODE)/srcs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
o/$(MODE)/hdrs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
TAGS: o/$(MODE)/srcs-old.txt $(SRCS)
@rm -f $@ @rm -f $@
@$(COMPILE) -ATAGS -T$@ $(TAGS) $(TAGSFLAGS) -L $< -o $@ @$(COMPILE) -ATAGS -T$@ $(TAGS) $(TAGSFLAGS) -L $< -o $@
HTAGS: o/$(MODE)/hdrs.txt $(HDRS) HTAGS: o/$(MODE)/hdrs-old.txt $(HDRS)
@rm -f $@ @rm -f $@
@$(COMPILE) -ATAGS -T$@ build/htags -L $< -o $@ @$(COMPILE) -ATAGS -T$@ build/htags -L $< -o $@
@ -326,14 +321,15 @@ COSMOPOLITAN_HEADERS = \
THIRD_PARTY_ZLIB \ THIRD_PARTY_ZLIB \
THIRD_PARTY_REGEX THIRD_PARTY_REGEX
o/$(MODE)/cosmopolitan.a.txt: o/$(MODE)/cosmopolitan.a: \
printf "%s\n" $(call reverse,$(call uniq,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x))))) $(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_A_OBJS))
o/$(MODE)/cosmopolitan.a: $(filter-out o/libc/stubs/exit11.o,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_A_OBJS)))
o/cosmopolitan.h: \ o/cosmopolitan.h: \
o/$(MODE)/tool/build/rollup.com \ o/$(MODE)/tool/build/rollup.com \
libc/integral/normalize.inc \ libc/integral/normalize.inc \
$(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)) $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS))
@$(COMPILE) -AROLLUP -T$@ $^ >$@ $(file >$@.args,libc/integral/normalize.inc $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)))
@$(COMPILE) -AROLLUP -T$@ o/$(MODE)/tool/build/rollup.com @$@.args >$@
o/cosmopolitan.html: \ o/cosmopolitan.html: \
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \ o/$(MODE)/third_party/chibicc/chibicc.com.dbg \

View file

@ -92,4 +92,4 @@ find o -name \*.com | xargs ls -rShal | less
| FreeBSD | 12 | 2018 | | FreeBSD | 12 | 2018 |
| OpenBSD | 6.4 | 2018 | | OpenBSD | 6.4 | 2018 |
| NetBSD | 9.1 | 2020 | | NetBSD | 9.1 | 2020 |
| GNU Make | 3.80 | 2010 | | GNU Make | 4.0 | 2015 |

View file

@ -485,10 +485,10 @@ HIDDEN(ape_ram_align = PAGESIZE);
HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr)); HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr));
HIDDEN(ape_stack_offset = ape_ram_offset + ape_ram_filesz); HIDDEN(ape_stack_offset = ape_ram_offset + ape_ram_filesz);
HIDDEN(ape_stack_vaddr = 0x700000000000 - STACKSIZE); HIDDEN(ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000 - STACKSIZE);
HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz); HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz);
HIDDEN(ape_stack_filesz = 0); HIDDEN(ape_stack_filesz = 0);
HIDDEN(ape_stack_memsz = STACKSIZE); HIDDEN(ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : STACKSIZE);
HIDDEN(ape_stack_align = 16); HIDDEN(ape_stack_align = 16);
HIDDEN(ape_note_offset = ape_rom_offset + (ape_note - ape_rom_vaddr)); HIDDEN(ape_note_offset = ape_rom_offset + (ape_note - ape_rom_vaddr));

10
ape/config.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef COSMOPOLITAN_APE_CONFIG_H_
#define COSMOPOLITAN_APE_CONFIG_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define STATIC_SYMBOL(NAME, VALUE) \
asm(".equ\t" NAME "," VALUE "\n\t" \
".globl\t" NAME)
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_APE_CONFIG_H_ */

View file

@ -68,59 +68,59 @@ static wontreturn void Exit(int os, long rc) {
} }
static void Close(int os, long fd) { static void Close(int os, long fd) {
long ax; long ax, di;
asm volatile("syscall" asm volatile("syscall"
: "=a"(ax) : "=a"(ax), "=D"(di)
: "0"(__NR_close), "D"(fd) : "0"(__NR_close), "1"(fd)
: "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc"); : "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc");
} }
static long Read(int os, long fd, void *data, unsigned long size) { static long Read(int os, long fd, void *data, unsigned long size) {
bool cf; bool cf;
long ax; long ax, di, si, dx;
asm volatile("clc\n\t" asm volatile("clc\n\t"
"syscall" "syscall"
: "=@ccc"(cf), "=a"(ax) : "=@ccc"(cf), "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
: "1"(__NR_read), "D"(fd), "S"(data), "d"(size) : "1"(__NR_read), "2"(fd), "3"(data), "4"(size)
: "rcx", "r8", "r9", "r10", "r11", "memory"); : "rcx", "r8", "r9", "r10", "r11", "memory");
if (cf) ax = -ax; if (cf) ax = -ax;
return ax; return ax;
} }
static void Write(int os, long fd, const void *data, unsigned long size) { static void Write(int os, long fd, const void *data, unsigned long size) {
long ax; long ax, di, si, dx;
asm volatile("syscall" asm volatile("syscall"
: "=a"(ax) : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
: "0"(__NR_write), "D"(fd), "S"(data), "d"(size) : "0"(__NR_write), "1"(fd), "2"(data), "3"(size)
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); : "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
} }
static long Fstat(int os, long fd, union metastat *st) { static long Fstat(int os, long fd, union metastat *st) {
long ax; long ax, di, si;
asm volatile("syscall" asm volatile("syscall"
: "=a"(ax) : "=a"(ax), "=D"(di), "=S"(si)
: "0"(__NR_fstat), "D"(fd), "S"(st) : "0"(__NR_fstat), "1"(fd), "2"(st)
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory"); : "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc");
return ax; return ax;
} }
static void Msyscall(int os, long p, long n) { static void Msyscall(int os, long p, long n) {
long ax; long ax, di, si;
if (os == OPENBSD) { if (os == OPENBSD) {
asm volatile("syscall" asm volatile("syscall"
: "=a"(ax) : "=a"(ax), "=D"(di), "=S"(si)
: "0"(37), "D"(p), "S"(n) : "0"(37), "1"(p), "2"(n)
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc"); : "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc");
} }
} }
static long Open(int os, const char *path, long flags, long mode) { static long Open(int os, const char *path, long flags, long mode) {
bool cf; bool cf;
long ax; long ax, di, si, dx;
asm volatile("clc\n\t" asm volatile("clc\n\t"
"syscall" "syscall"
: "=@ccc"(cf), "=a"(ax) : "=@ccc"(cf), "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
: "1"(__NR_open), "D"(path), "S"(flags), "d"(mode) : "1"(__NR_open), "2"(path), "3"(flags), "4"(mode)
: "rcx", "r8", "r9", "r10", "r11", "memory"); : "rcx", "r8", "r9", "r10", "r11", "memory");
if (cf) ax = -ax; if (cf) ax = -ax;
return ax; return ax;

Binary file not shown.

Binary file not shown.

View file

@ -41,6 +41,7 @@ CONFIG_CPPFLAGS += \
CONFIG_CCFLAGS += \ CONFIG_CCFLAGS += \
$(BACKTRACES) \ $(BACKTRACES) \
$(FTRACE) \
-O3 -O3
TARGET_ARCH ?= \ TARGET_ARCH ?= \
@ -122,7 +123,8 @@ CONFIG_CPPFLAGS += \
CONFIG_CCFLAGS += \ CONFIG_CCFLAGS += \
$(BACKTRACES) \ $(BACKTRACES) \
$(FTRACE) \ $(FTRACE) \
-O2 -O2 \
-fno-inline
CONFIG_COPTS += \ CONFIG_COPTS += \
-fsanitize=address -fsanitize=address
@ -159,7 +161,6 @@ CONFIG_CCFLAGS += \
-fno-align-labels \ -fno-align-labels \
-fno-align-loops \ -fno-align-loops \
-fschedule-insns2 \ -fschedule-insns2 \
-fomit-frame-pointer \
-momit-leaf-frame-pointer \ -momit-leaf-frame-pointer \
-foptimize-sibling-calls -foptimize-sibling-calls
TARGET_ARCH ?= \ TARGET_ARCH ?= \

View file

@ -88,6 +88,10 @@ export TMPDIR
FTRACE = \ FTRACE = \
-pg -pg
BACKTRACES = \
-fno-optimize-sibling-calls \
-mno-omit-leaf-frame-pointer
SANITIZER = \ SANITIZER = \
-fsanitize=address -fsanitize=address
@ -126,8 +130,7 @@ DEFAULT_COPTS = \
-fstrict-aliasing \ -fstrict-aliasing \
-fstrict-overflow \ -fstrict-overflow \
-fno-omit-frame-pointer \ -fno-omit-frame-pointer \
-fno-semantic-interposition \ -fno-semantic-interposition
-mno-omit-leaf-frame-pointer
MATHEMATICAL = \ MATHEMATICAL = \
-O3 \ -O3 \

View file

@ -16,7 +16,6 @@
MAKEFLAGS += --no-builtin-rules MAKEFLAGS += --no-builtin-rules
o/%.a: ; @$(COMPILE) -AARCHIVE -T$@ $(AR) $(ARFLAGS) $@ $^
o/%.o: %.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $< o/%.o: %.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
o/%.o: o/%.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $< o/%.o: o/%.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
o/%.s: %.S ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) $< o/%.s: %.S ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) $<
@ -36,7 +35,6 @@ o/%.h.okk: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++
o/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $< o/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
o/%.zip.o: o/% ; @$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $< o/%.zip.o: o/% ; @$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
o/$(MODE)/%.a: ; @$(COMPILE) -AARCHIVE -T$@ $(AR) $(ARFLAGS) $@ $^
o/$(MODE)/%: o/$(MODE)/%.dbg ; @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ o/$(MODE)/%: o/$(MODE)/%.dbg ; @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
o/$(MODE)/%.o: %.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $< o/$(MODE)/%.o: %.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
o/$(MODE)/%.o: o/$(MODE)/%.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $< o/$(MODE)/%.o: o/$(MODE)/%.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
@ -82,6 +80,10 @@ o/$(MODE)/%-gcc.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S
o/$(MODE)/%-clang.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $< o/$(MODE)/%-clang.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-clang.asm: CC = $(CLANG) o/$(MODE)/%-clang.asm: CC = $(CLANG)
o/%.a:
$(file >$@.args,$^)
@$(COMPILE) -AARCHIVE -T$@ $(AR) $(ARFLAGS) $@ @$@.args
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj.com o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj.com
@$(COMPILE) -APYOBJ o/$(MODE)/third_party/python/pyobj.com $(PYFLAGS) -o $@ $< @$(COMPILE) -APYOBJ o/$(MODE)/third_party/python/pyobj.com $(PYFLAGS) -o $@ $<

View file

@ -47,7 +47,8 @@ __m128 tty2rgbf_(struct TtyRgb rgbxt) {
static int rgb2xterm256_(int r, int g, int b) { static int rgb2xterm256_(int r, int g, int b) {
int cerr, gerr, ir, ig, ib, gray, grai, cr, cg, cb, gv; int cerr, gerr, ir, ig, ib, gray, grai, cr, cg, cb, gv;
gray = round(r * .299 + g * .587 + b * .114); gray = round(871024 / 4096299. * r + 8788810 / 12288897. * g +
887015 / 12288897. * b);
grai = gray > 238 ? 23 : (gray - 3) / 10; grai = gray > 238 ? 23 : (gray - 3) / 10;
ir = r < 48 ? 0 : r < 115 ? 1 : (r - 35) / 40; ir = r < 48 ? 0 : r < 115 ? 1 : (r - 35) / 40;
ig = g < 48 ? 0 : g < 115 ? 1 : (g - 35) / 40; ig = g < 48 ? 0 : g < 115 ? 1 : (g - 35) / 40;

View file

@ -8,6 +8,7 @@
*/ */
#endif #endif
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/log/check.h" #include "libc/log/check.h"
#include "libc/log/color.internal.h" #include "libc/log/color.internal.h"

View file

@ -9,6 +9,7 @@
#endif #endif
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/log/check.h" #include "libc/log/check.h"

View file

@ -10,6 +10,7 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/sigbits.h" #include "libc/calls/sigbits.h"
#include "libc/calls/struct/rusage.h" #include "libc/calls/struct/rusage.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/log/check.h" #include "libc/log/check.h"
#include "libc/log/log.h" #include "libc/log/log.h"

77
examples/stackoverflow.c Normal file
View file

@ -0,0 +1,77 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/runtime/stack.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/prot.h"
/**
* @fileoverview Stack Overflow Demo
*/
#define N INT_MAX
STATIC_STACK_SIZE(FRAMESIZE);
int A(int f(), int n) {
if (n < N) {
return f(f, n + 1) - 1;
} else {
return N;
}
}
int (*Ap)(int (*)(), int) = A;
int main(int argc, char *argv[]) {
ShowCrashReports();
return !!Ap(Ap, 0);
}
/*
error: Uncaught SIGSEGV (Stack Overflow) on rhel5 pid 368
./o//examples/stackoverflow.com
EUNKNOWN[No error information][0]
Linux rhel5 2.6.18-8.el5 #1 SMP Thu Mar 15 19:46:53 EDT 2007
0x0000000000406896: A at examples/stackoverflow.c:24
0x0000000000406898: A at examples/stackoverflow.c:24
0x0000000000406898: A at examples/stackoverflow.c:24
0x0000000000406898: A at examples/stackoverflow.c:24
0x0000000000406898: A at examples/stackoverflow.c:24
0x0000000000406898: A at examples/stackoverflow.c:24
0x0000000000406898: A at examples/stackoverflow.c:24
0x0000000000406898: A at examples/stackoverflow.c:24
0x0000000000406898: A at examples/stackoverflow.c:24
etc. etc.
RAX 0000000000000000 RBX 0000000000000001 RDI 000000000040687e ST(0) 0.0
RCX 0000000000417125 RDX 000000000041cd70 RSI 0000000000000efe ST(1) 0.0
RBP 00006ffffffe1000 RSP 00006ffffffe1000 RIP 0000000000406897 ST(2) 0.0
R8 0000000000000000 R9 0000000000000022 R10 0000000000000008 ST(3) 0.0
R11 0000000000000293 R12 0000000000000001 R13 00007ffc70b4fc48 ST(4) 0.0
R14 00007ffc70b4fc58 R15 00007ffc70b4fd18 VF IF
XMM0 00000000000000000000000000000000 XMM8 00000000000000000000000000000000
XMM1 ffffffffffffeb030000000000000000 XMM9 00000000000000000000000000000000
XMM2 0000000000000000ffffffffffffffff XMM10 00000000000000000000000000000000
XMM3 00000000000000000000000000000000 XMM11 00000000000000000000000000000000
XMM4 00000000000000000000000000000000 XMM12 00000000000000000000000000000000
XMM5 00000000000000000000000000000000 XMM13 00000000000000000000000000000000
XMM6 00000000000000000000000000000000 XMM14 00000000000000000000000000000000
XMM7 00000000000000000000000000000000 XMM15 00000000000000000000000000000000
100080000000-100080030000 rw-pa-- 3x automap
6ffffffe0000-6fffffff0000 rw-paSF 1x stack
# 4 frames mapped w/ 0 frames gapped
*/

View file

@ -602,30 +602,16 @@
* shell. If SHELL is defined, we try to map the standard UNIX library * shell. If SHELL is defined, we try to map the standard UNIX library
* routines to ash routines using defines. * routines to ash routines using defines.
*/ */
/* #undef stdout /\* TODO(jart): XXX *\/ */ #define Printf out1fmt
/* #undef stderr */
/* #undef putc */
/* #undef putchar */
#undef fileno
/* #define stdout out1 */
/* #define stderr out2 */
#undef printf
#define printf out1fmt
/* #define putc(c, file) outc(c, file) */
/* #define putchar(c) out1c(c) */
#define FILE struct output
#define fileno(f) ((f)->fd)
/* #define ferror outerr */
#define INITARGS(argv) #define INITARGS(argv)
#define setprogname(s) #define setprogname(s)
#define getprogname() commandname #define getprogname() commandname
#define setlocate(l, s) 0 #define setlocate(l, s) 0
#define equal(s1, s2) (strcmp(s1, s2) == 0) #define equal(s1, s2) (!strcmp(s1, s2))
/* #define getenv(p) bltinlookup((p), 0) */ #define isodigit(c) ((c) >= '0' && (c) <= '7')
#define isodigit(c) ((c) >= '0' && (c) <= '7') #define octtobin(c) ((c) - '0')
#define octtobin(c) ((c) - '0') #define scopy(s1, s2) ((void)strcpy(s2, s1))
#define scopy(s1, s2) ((void)strcpy(s2, s1))
#define TRACE(param) #define TRACE(param)
/* #define TRACE(param) \ */ /* #define TRACE(param) \ */
@ -9483,13 +9469,13 @@ static void sigblockall(sigset_t *oldmask) {
{ \ { \
switch ((char *)param - (char *)array) { \ switch ((char *)param - (char *)array) { \
default: \ default: \
(void)printf(f, array[0], array[1], func); \ (void)Printf(f, array[0], array[1], func); \
break; \ break; \
case sizeof(*param): \ case sizeof(*param): \
(void)printf(f, array[0], func); \ (void)Printf(f, array[0], func); \
break; \ break; \
case 0: \ case 0: \
(void)printf(f, func); \ (void)Printf(f, func); \
break; \ break; \
} \ } \
} }
@ -10118,7 +10104,7 @@ static int timescmd() {
struct tms buf; struct tms buf;
long int clk_tck = sysconf(_SC_CLK_TCK); long int clk_tck = sysconf(_SC_CLK_TCK);
times(&buf); times(&buf);
printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", (int)(buf.tms_utime / clk_tck / 60), Printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", (int)(buf.tms_utime / clk_tck / 60),
((double)buf.tms_utime) / clk_tck, (int)(buf.tms_stime / clk_tck / 60), ((double)buf.tms_utime) / clk_tck, (int)(buf.tms_stime / clk_tck / 60),
((double)buf.tms_stime) / clk_tck, (int)(buf.tms_cutime / clk_tck / 60), ((double)buf.tms_stime) / clk_tck, (int)(buf.tms_cutime / clk_tck / 60),
((double)buf.tms_cutime) / clk_tck, (int)(buf.tms_cstime / clk_tck / 60), ((double)buf.tms_cutime) / clk_tck, (int)(buf.tms_cstime / clk_tck / 60),

View file

@ -5,13 +5,13 @@
#include "libc/calls/struct/rlimit.h" #include "libc/calls/struct/rlimit.h"
#include "libc/calls/struct/rusage.h" #include "libc/calls/struct/rusage.h"
#include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigval.h" #include "libc/calls/struct/sigval.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/calls/struct/sysinfo.h" #include "libc/calls/struct/sysinfo.h"
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/tms.h" #include "libc/calls/struct/tms.h"
#include "libc/calls/struct/utsname.h" #include "libc/calls/struct/utsname.h"
#include "libc/calls/typedef/sighandler_t.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/fmt/pflink.h" #include "libc/fmt/pflink.h"
#include "libc/sysv/consts/s.h" #include "libc/sysv/consts/s.h"
@ -178,7 +178,6 @@ int setreuid(uint32_t, uint32_t);
int setrlimit(int, const struct rlimit *); int setrlimit(int, const struct rlimit *);
int setsid(void); int setsid(void);
int setuid(uint32_t); int setuid(uint32_t);
int sigaction(int, const struct sigaction *, struct sigaction *);
int sigignore(int); int sigignore(int);
int siginterrupt(int, int); int siginterrupt(int, int);
int sigprocmask(int, const struct sigset *, struct sigset *); int sigprocmask(int, const struct sigset *, struct sigset *);
@ -206,7 +205,6 @@ intptr_t syscall(int, ...);
long ptrace(int, int, void *, void *); long ptrace(int, int, void *, void *);
long telldir(DIR *); long telldir(DIR *);
long times(struct tms *); long times(struct tms *);
sighandler_t signal(int, sighandler_t);
size_t GetFileSize(const char *); size_t GetFileSize(const char *);
size_t getfiledescriptorsize(int); size_t getfiledescriptorsize(int);
ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t); ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t);
@ -247,51 +245,6 @@ int vdprintf(int, const char *, va_list) paramsnonnull();
*/ */
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
void _init_onntconsoleevent(void);
void _init_wincrash(void);
#ifndef __SIGACTION_YOINK
#define __SIGACTION_YOINK(SIG) \
do { \
if (SupportsWindows()) { \
if (__builtin_constant_p(SIG)) { \
switch (SIG) { \
case SIGINT: \
case SIGQUIT: \
case SIGHUP: \
case SIGTERM: \
YOINK(_init_onntconsoleevent); \
break; \
case SIGTRAP: \
case SIGILL: \
case SIGSEGV: \
case SIGABRT: \
case SIGFPE: \
YOINK(_init_wincrash); \
break; \
default: \
break; \
} \
} else { \
YOINK(_init_onntconsoleevent); \
YOINK(_init_wincrash); \
} \
} \
} while (0)
#endif
#define sigaction(SIG, ACT, OLD) \
({ \
__SIGACTION_YOINK(SIG); \
sigaction(SIG, (ACT), OLD); \
})
#define signal(SIG, HAND) \
({ \
__SIGACTION_YOINK(SIG); \
signal(SIG, HAND); \
})
#define dprintf(FD, FMT, ...) (dprintf)(FD, PFLINK(FMT), ##__VA_ARGS__) #define dprintf(FD, FMT, ...) (dprintf)(FD, PFLINK(FMT), ##__VA_ARGS__)
#define vdprintf(FD, FMT, VA) (vdprintf)(FD, PFLINK(FMT), VA) #define vdprintf(FD, FMT, VA) (vdprintf)(FD, PFLINK(FMT), VA)

View file

@ -18,39 +18,55 @@
*/ */
#include "libc/bits/safemacros.internal.h" #include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static noasan bool AccessCommand(char path[hasatleast PATH_MAX], static noasan bool EndsWithIgnoreCase(const char *p, size_t n, const char *s) {
const char *name, size_t namelen, size_t i, m;
size_t pathlen) { m = __strlen(s);
if (pathlen + 1 + namelen + 1 + 4 + 1 > PATH_MAX) return -1; if (n >= m) {
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) { for (i = n - m; i < n; ++i) {
path[pathlen] = !IsWindows() ? '/' if (kToLower[p[i] & 255] != (*s++ & 255)) {
: memchr(path, '\\', pathlen) ? '\\' return false;
: '/'; }
pathlen++; }
return true;
} else {
return false;
} }
memcpy(path + pathlen, name, namelen + 1);
if (isexecutable(path)) return true;
memcpy(path + pathlen + namelen, ".com", 5);
if (isexecutable(path)) return true;
memcpy(path + pathlen + namelen, ".exe", 5);
if (isexecutable(path)) return true;
return false;
} }
static noasan bool SearchPath(char path[hasatleast PATH_MAX], const char *name, static noasan bool AccessCommand(const char *name,
size_t namelen) { char path[hasatleast PATH_MAX], size_t namelen,
const char *suffix, size_t pathlen) {
size_t suffixlen;
suffixlen = __strlen(suffix);
if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return -1;
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
path[pathlen] = !IsWindows() ? '/'
: __memchr(path, '\\', pathlen) ? '\\'
: '/';
pathlen++;
}
__repmovsb(path + pathlen, name, namelen);
__repmovsb(path + pathlen + namelen, suffix, suffixlen + 1);
return isexecutable(path);
}
static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
size_t namelen, const char *suffix) {
size_t i; size_t i;
const char *p; const char *p;
p = firstnonnull(emptytonull(getenv("PATH")), "/bin:/usr/local/bin:/usr/bin"); p = firstnonnull(emptytonull(getenv("PATH")), "/bin:/usr/local/bin:/usr/bin");
for (;;) { for (;;) {
for (i = 0; p[i] && p[i] != ':' && p[i] != ';'; ++i) { for (i = 0; p[i] && p[i] != ':' && p[i] != ';'; ++i) {
if (i < PATH_MAX) path[i] = p[i]; if (i < PATH_MAX) {
path[i] = p[i];
}
} }
if (AccessCommand(path, name, namelen, i)) { if (AccessCommand(name, path, namelen, suffix, i)) {
return true; return true;
} }
if (p[i] == ':' || p[i] == ';') { if (p[i] == ':' || p[i] == ';') {
@ -62,6 +78,23 @@ static noasan bool SearchPath(char path[hasatleast PATH_MAX], const char *name,
return false; return false;
} }
static noasan bool FindCommand(const char *name,
char pathbuf[hasatleast PATH_MAX],
size_t namelen, const char *suffix) {
if (memchr(name, '/', namelen) || memchr(name, '\\', namelen)) {
pathbuf[0] = 0;
return AccessCommand(name, pathbuf, namelen, suffix, 0);
}
return ((IsWindows() &&
(AccessCommand(name, pathbuf, namelen, suffix,
stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) ||
AccessCommand(name, pathbuf, namelen, suffix,
stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf) ||
AccessCommand(name, pathbuf, namelen, suffix,
stpcpy(pathbuf, ".") - pathbuf))) ||
SearchPath(name, pathbuf, namelen, suffix));
}
/** /**
* Resolves full pathname of executable. * Resolves full pathname of executable.
* *
@ -72,40 +105,28 @@ static noasan bool SearchPath(char path[hasatleast PATH_MAX], const char *name,
* @vforksafe * @vforksafe
*/ */
noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) { noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
char *p; int olderr;
size_t namelen; size_t namelen;
int rc, olderr;
if (!name) { if (!name) {
efault(); efault();
return NULL; return 0;
} }
if (!(namelen = strlen(name))) { if (!(namelen = __strlen(name))) {
enoent(); enoent();
return NULL; return 0;
} }
if (namelen + 1 > PATH_MAX) { if (namelen + 1 > PATH_MAX) {
enametoolong(); enametoolong();
return NULL; return 0;
} }
if (strchr(name, '/') || strchr(name, '\\')) { if (FindCommand(name, pathbuf, namelen, "") ||
if (AccessCommand(strcpy(pathbuf, ""), name, namelen, 0)) { (!EndsWithIgnoreCase(name, namelen, ".exe") &&
return pathbuf; !EndsWithIgnoreCase(name, namelen, ".com") &&
} else { !EndsWithIgnoreCase(name, namelen, ".com.dbg") &&
return NULL; (FindCommand(name, pathbuf, namelen, ".com") ||
} FindCommand(name, pathbuf, namelen, ".exe")))) {
}
olderr = errno;
if ((IsWindows() &&
(AccessCommand(pathbuf, name, namelen,
stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) ||
AccessCommand(pathbuf, name, namelen,
stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf) ||
AccessCommand(pathbuf, name, namelen,
stpcpy(pathbuf, ".") - pathbuf))) ||
SearchPath(pathbuf, name, namelen)) {
errno = olderr;
return pathbuf; return pathbuf;
} else { } else {
return NULL; return 0;
} }
} }

View file

@ -24,6 +24,10 @@
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static void __ensurefds_destroy(void) {
weaken(free)(g_fds.p);
}
int __ensurefds(int fd) { int __ensurefds(int fd) {
size_t n1, n2; size_t n1, n2;
struct Fd *p1, *p2; struct Fd *p1, *p2;
@ -36,9 +40,15 @@ int __ensurefds(int fd) {
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) { if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
memcpy(p2, p1, n1 * sizeof(*p1)); memcpy(p2, p1, n1 * sizeof(*p1));
bzero(p2 + n1, (n2 - n1) * sizeof(*p1)); bzero(p2 + n1, (n2 - n1) * sizeof(*p1));
if (p1 != g_fds.__init_p && weaken(free)) weaken(free)(p1);
if (cmpxchg(&g_fds.p, p1, p2)) { if (cmpxchg(&g_fds.p, p1, p2)) {
g_fds.n = n2; g_fds.n = n2;
if (weaken(free)) {
if (p1 == g_fds.__init_p) {
atexit(__ensurefds_destroy);
} else {
weaken(free)(p1);
}
}
return fd; return fd;
} else if (weaken(free)) { } else if (weaken(free)) {
weaken(free)(p2); weaken(free)(p2);

View file

@ -19,6 +19,7 @@
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -42,15 +43,18 @@ char *getcwd(char *buf, size_t size) {
if (buf) { if (buf) {
p = buf; p = buf;
if (!size) { if (!size) {
SYSDEBUG("getcwd(%p, %x) EINVAL", buf, size);
einval(); einval();
return 0; return 0;
} }
} else if (weaken(malloc)) { } else if (weaken(malloc)) {
if (!size) size = PATH_MAX + 1; if (!size) size = PATH_MAX + 1;
if (!(p = weaken(malloc)(size))) { if (!(p = weaken(malloc)(size))) {
SYSDEBUG("getcwd(%p, %x) ENOMEM", buf, size);
return 0; return 0;
} }
} else { } else {
SYSDEBUG("getcwd() EINVAL needs buf≠0 or STATIC_YOINK(\"malloc\")");
einval(); einval();
return 0; return 0;
} }
@ -81,5 +85,6 @@ char *getcwd(char *buf, size_t size) {
} }
} }
} }
SYSDEBUG("getcwd(%p, %x) -> %s", buf, size, r);
return r; return r;
} }

View file

@ -12,6 +12,7 @@
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h" #include "libc/calls/struct/timeval.h"
#include "libc/calls/ucontext.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
@ -115,6 +116,7 @@ i32 __sys_fcntl(i32, i32, ...) hidden;
i32 __sys_fstat(i32, void *) hidden; i32 __sys_fstat(i32, void *) hidden;
i32 __sys_fstatat(i32, const char *, void *, i32) hidden; i32 __sys_fstatat(i32, const char *, void *, i32) hidden;
i32 __sys_getrusage(i32, struct rusage *) hidden; i32 __sys_getrusage(i32, struct rusage *) hidden;
i32 __sys_munmap(void *, u64) hidden;
i32 __sys_openat(i32, const char *, i32, u32) hidden; i32 __sys_openat(i32, const char *, i32, u32) hidden;
i32 __sys_pipe2(i32[hasatleast 2], u32) hidden; i32 __sys_pipe2(i32[hasatleast 2], u32) hidden;
i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden; i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden;
@ -177,6 +179,7 @@ i32 sys_setresuid(uint32_t, uint32_t, uint32_t) hidden;
i32 sys_setrlimit(i32, const struct rlimit *) hidden; i32 sys_setrlimit(i32, const struct rlimit *) hidden;
i32 sys_setsid(void) hidden; i32 sys_setsid(void) hidden;
i32 sys_sigaction(i32, const void *, void *, i64, i64) hidden; i32 sys_sigaction(i32, const void *, void *, i64, i64) hidden;
i32 sys_sigaltstack(const void *, void *) hidden;
i32 sys_sigprocmask(i32, const sigset *, sigset *, u64) hidden; i32 sys_sigprocmask(i32, const sigset *, sigset *, u64) hidden;
i32 sys_sigqueue(i32, i32, const union sigval) hidden; i32 sys_sigqueue(i32, i32, const union sigval) hidden;
i32 sys_sigqueueinfo(i32, const siginfo_t *) hidden; i32 sys_sigqueueinfo(i32, const siginfo_t *) hidden;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
@ -25,6 +26,7 @@
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/struct/ipadapteraddresses.h" #include "libc/nt/struct/ipadapteraddresses.h"
#include "libc/nt/winsock.h" #include "libc/nt/winsock.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -239,6 +241,7 @@ struct HostAdapterInfoNode *appendHostInfo(
/* Returns -1 in case of failure */ /* Returns -1 in case of failure */
static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) { static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) {
static bool once;
struct NtIpAdapterAddresses *aa; struct NtIpAdapterAddresses *aa;
struct NtIpAdapterUnicastAddress *ua; struct NtIpAdapterUnicastAddress *ua;
struct NtIpAdapterPrefix *ap; struct NtIpAdapterPrefix *ap;
@ -270,7 +273,12 @@ static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) {
(ua != NULL) && (count < MAX_UNICAST_ADDR); ++count) { (ua != NULL) && (count < MAX_UNICAST_ADDR); ++count) {
node = appendHostInfo(node, baseName, aa, &ua, &ap, count); node = appendHostInfo(node, baseName, aa, &ua, &ap, count);
if (!node) goto err; if (!node) goto err;
if (!__hostInfo) __hostInfo = node; if (!__hostInfo) {
__hostInfo = node;
if (cmpxchg(&once, false, true)) {
atexit(freeHostInfo);
}
}
} }
/* Note: do we need to process the remaining adapter prefix? /* Note: do we need to process the remaining adapter prefix?

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/ntmagicpaths.internal.h" #include "libc/calls/ntmagicpaths.internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/nt/systeminfo.h" #include "libc/nt/systeminfo.h"
#include "libc/str/oldutf16.internal.h" #include "libc/str/oldutf16.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -94,7 +95,10 @@ textwindows int __mkntpath2(const char *path,
m = 0; m = 0;
} }
n = tprecode8to16(p, z, q).ax; n = tprecode8to16(p, z, q).ax;
if (n == z - 1) return enametoolong(); if (n == z - 1) {
SYSDEBUG("path too long for windows: %s", path);
return enametoolong();
}
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
if (p[i] == '/') { if (p[i] == '/') {
p[i] = '\\'; p[i] = '\\';

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -33,7 +34,10 @@ int __mkntpathat(int dirfd, const char *path, int flags,
dirlen = GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir), dirlen = GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
kNtFileNameNormalized | kNtVolumeNameDos); kNtFileNameNormalized | kNtVolumeNameDos);
if (!dirlen) return __winerr(); if (!dirlen) return __winerr();
if (dirlen + 1 + filelen + 1 > ARRAYLEN(dir)) return enametoolong(); if (dirlen + 1 + filelen + 1 > ARRAYLEN(dir)) {
SYSDEBUG("path too long: %.*hs\\%.*hs", dirlen, dir, filelen, file);
return enametoolong();
}
dir[dirlen] = u'\\'; dir[dirlen] = u'\\';
memcpy(dir + dirlen + 1, file, (filelen + 1) * sizeof(char16_t)); memcpy(dir + dirlen + 1, file, (filelen + 1) * sizeof(char16_t));
memcpy(file, dir, (dirlen + 1 + filelen + 1) * sizeof(char16_t)); memcpy(file, dir, (dirlen + 1 + filelen + 1) * sizeof(char16_t));

View file

@ -34,7 +34,7 @@ extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect;
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @see mmap() * @see mmap()
*/ */
privileged int mprotect(void *addr, uint64_t len, int prot) { noasan noubsan privileged int mprotect(void *addr, uint64_t len, int prot) {
bool cf; bool cf;
int64_t rc; int64_t rc;
uint32_t oldprot; uint32_t oldprot;

View file

@ -95,7 +95,7 @@ textwindows int ntspawn(
} else { } else {
__winerr(); __winerr();
} }
SYSDEBUG("CreateProcess(`%S`, `%S`) -> %d", prog16, block->cmdline, rc); SYSDEBUG("CreateProcess(`%hs`, `%hs`) -> %d", prog16, block->cmdline, rc);
} }
} else { } else {
__winerr(); __winerr();

View file

@ -20,6 +20,7 @@
#include "libc/calls/sysdebug.internal.h" #include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/f.h" #include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h" #include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
@ -59,9 +60,11 @@ int sys_openat(int dirfd, const char *file, int flags, unsigned mode) {
} }
} }
if (d != -1) { if (d != -1) {
SYSDEBUG("sys_openat(0x%x, %s, %d, %d) -> %d", dirfd, file, flags, mode, d); SYSDEBUG("sys_openat(%d, %s, %d, %d) -> %d", (long)dirfd, file, flags,
(flags & (O_CREAT | O_TMPFILE)) ? mode : 0, d);
} else { } else {
SYSDEBUG("sys_openat(0x%x, %s, %d, %d) -> %m", dirfd, file, flags, mode); SYSDEBUG("sys_openat(%d, %s, %d, %d) -> %s", (long)dirfd, file, flags,
(flags & (O_CREAT | O_TMPFILE)) ? mode : 0, strerror(errno));
} }
return d; return d;
} }

View file

@ -153,8 +153,17 @@ ssize_t readansi(int fd, char *p, size_t n) {
} }
break; break;
case kEsc: case kEsc:
if (0x20 <= c && c <= 0x2f) { if (0x20 <= c && c <= 0x2f) { /* Nf */
t = kNf; /*
* Almost no one uses ANSI Nf sequences
* They overlaps with alt+graphic keystrokes
* We care more about being able to type alt-/
*/
if (c == ' ' || c == '#') {
t = kNf;
} else {
t = kDone;
}
} else if (0x30 <= c && c <= 0x3f) { /* Fp */ } else if (0x30 <= c && c <= 0x3f) { /* Fp */
t = kDone; t = kDone;
} else if (0x20 <= c && c <= 0x5F) { /* Fe */ } else if (0x20 <= c && c <= 0x5F) { /* Fe */
@ -173,8 +182,6 @@ ssize_t readansi(int fd, char *p, size_t n) {
case '_': /* DCS (Application Program Command) */ case '_': /* DCS (Application Program Command) */
t = kStr; t = kStr;
break; break;
case '\\':
goto Whoopsie;
default: default:
t = kDone; t = kDone;
break; break;

View file

@ -20,6 +20,7 @@
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nexgen32e/bsr.h" #include "libc/nexgen32e/bsr.h"
#include "libc/nt/createfile.h" #include "libc/nt/createfile.h"
@ -37,7 +38,9 @@
static textwindows ssize_t sys_readlinkat_nt_error(void) { static textwindows ssize_t sys_readlinkat_nt_error(void) {
uint32_t e; uint32_t e;
switch ((e = GetLastError())) { e = GetLastError();
SYSDEBUG("sys_readlinkat_nt() error %d", e);
switch (e) {
case kNtErrorNotAReparsePoint: case kNtErrorNotAReparsePoint:
return einval(); return einval();
default: default:
@ -56,7 +59,10 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
uint32_t e, i, j, n, mem; uint32_t e, i, j, n, mem;
char16_t path16[PATH_MAX], *p; char16_t path16[PATH_MAX], *p;
struct NtReparseDataBuffer *rdb; struct NtReparseDataBuffer *rdb;
if (!buf) return efault(); if (__mkntpathat(dirfd, path, 0, path16) == -1) {
SYSDEBUG("sys_readlinkat_nt() failed b/c __mkntpathat() failed");
return -1;
}
if (weaken(malloc)) { if (weaken(malloc)) {
mem = 16384; mem = 16384;
rdb = weaken(malloc)(mem); rdb = weaken(malloc)(mem);
@ -66,9 +72,9 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
rdb = (struct NtReparseDataBuffer *)buf; rdb = (struct NtReparseDataBuffer *)buf;
freeme = 0; freeme = 0;
} else { } else {
SYSDEBUG("sys_readlinkat_nt() needs bigger buffer malloc() to be yoinked");
return enomem(); return enomem();
} }
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
if ((h = CreateFile(path16, 0, 0, 0, kNtOpenExisting, if ((h = CreateFile(path16, 0, 0, 0, kNtOpenExisting,
kNtFileFlagOpenReparsePoint | kNtFileFlagBackupSemantics, kNtFileFlagOpenReparsePoint | kNtFileFlagBackupSemantics,
0)) != -1) { 0)) != -1) {
@ -107,16 +113,20 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
if (freeme || (intptr_t)(buf + j) <= (intptr_t)(p + i)) { if (freeme || (intptr_t)(buf + j) <= (intptr_t)(p + i)) {
rc = j; rc = j;
} else { } else {
SYSDEBUG("sys_readlinkat_nt() too many astral codepoints");
rc = enametoolong(); rc = enametoolong();
} }
} else { } else {
SYSDEBUG("sys_readlinkat_nt() should have kNtIoReparseTagSymlink");
rc = einval(); rc = einval();
} }
} else { } else {
SYSDEBUG("DeviceIoControl(kNtFsctlGetReparsePoint) failed");
rc = sys_readlinkat_nt_error(); rc = sys_readlinkat_nt_error();
} }
CloseHandle(h); CloseHandle(h);
} else { } else {
SYSDEBUG("CreateFile(kNtFileFlagOpenReparsePoint) failed");
rc = sys_readlinkat_nt_error(); rc = sys_readlinkat_nt_error();
} }
if (freeme && weaken(free)) { if (freeme && weaken(free)) {

View file

@ -19,8 +19,11 @@
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h" #include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h" #include "libc/zipos/zipos.internal.h"
@ -46,14 +49,19 @@
* @asyncsignalsafe * @asyncsignalsafe
*/ */
ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) { ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
ssize_t bytes;
struct ZiposUri zipname; struct ZiposUri zipname;
if (IsAsan() && !__asan_is_valid(buf, bufsiz)) return efault(); if ((IsAsan() && !__asan_is_valid(buf, bufsiz)) || (bufsiz && !buf)) {
if (weaken(__zipos_notat) && __zipos_notat(dirfd, path) == -1) { bytes = efault();
return -1; /* TODO(jart): code me */ } else if (weaken(__zipos_notat) && __zipos_notat(dirfd, path) == -1) {
} SYSDEBUG("TOOD: zipos support for readlinkat");
if (!IsWindows()) { bytes = enosys(); /* TODO(jart): code me */
return sys_readlinkat(dirfd, path, buf, bufsiz); } else if (!IsWindows()) {
bytes = sys_readlinkat(dirfd, path, buf, bufsiz);
} else { } else {
return sys_readlinkat_nt(dirfd, path, buf, bufsiz); bytes = sys_readlinkat_nt(dirfd, path, buf, bufsiz);
} }
SYSDEBUG("readlinkat(%d, %s, 0x%p, 0x%x) -> %d %s", (long)dirfd, path, buf,
bufsiz, bytes, bytes != -1 ? "" : strerror(errno));
return bytes;
} }

View file

@ -29,6 +29,7 @@
#include "libc/bits/safemacros.internal.h" #include "libc/bits/safemacros.internal.h"
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
@ -160,6 +161,7 @@ restart:
if (!check_dir) goto skip_readlink; if (!check_dir) goto skip_readlink;
} }
k = readlink(output, stack, p); k = readlink(output, stack, p);
if (k<0) SYSDEBUG("realpath readlink failed %d", (long)errno);
if (k==p) goto toolong; if (k==p) goto toolong;
if (!k) { if (!k) {
errno = ENOENT; errno = ENOENT;

106
libc/calls/sigaltstack.c Normal file
View file

@ -0,0 +1,106 @@
/*-*- 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/calls/internal.h"
#include "libc/calls/struct/metasigaltstack.h"
#include "libc/calls/struct/sigaltstack.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
static noasan void sigaltstack2bsd(struct sigaltstack_bsd *bsd,
const struct sigaltstack *linux) {
void *sp;
int flags;
size_t size;
sp = linux->ss_sp;
flags = linux->ss_flags;
size = linux->ss_size;
bsd->ss_sp = sp;
bsd->ss_flags = flags;
bsd->ss_size = size;
}
static noasan void sigaltstack2linux(struct sigaltstack *linux,
const struct sigaltstack_bsd *bsd) {
void *sp;
int flags;
size_t size;
sp = bsd->ss_sp;
flags = bsd->ss_flags;
size = bsd->ss_size;
linux->ss_sp = sp;
linux->ss_flags = flags;
linux->ss_size = size;
}
/**
* Sets and/or gets alternate signal stack, e.g.
*
* struct sigaction sa;
* struct sigaltstack ss;
* ss.ss_flags = 0;
* ss.ss_size = SIGSTKSZ;
* ss.ss_sp = malloc(ss.ss_size);
* sa.sa_flags = SA_ONSTACK;
* sa.sa_handler = OnStackOverflow;
* __cxa_atexit(free, ss[0].ss_sp, 0);
* sigemptyset(&sa.ss_mask);
* sigaltstack(&ss, 0);
* sigaction(SIGSEGV, &sa, 0);
*
* @param neu if non-null will install new signal alt stack
* @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 rc;
void *a, *b;
struct sigaltstack_bsd bsd;
if (IsAsan() && ((old && __asan_check(old, sizeof(*old)).kind) ||
(neu && (__asan_check(neu, sizeof(*neu)).kind ||
__asan_check(neu->ss_sp, neu->ss_size).kind)))) {
return efault();
}
if (IsLinux()) {
a = neu;
b = old;
} else if (IsBsd()) {
if (neu) {
sigaltstack2bsd(&bsd, neu);
a = &bsd;
} else {
a = 0;
}
if (old) {
b = &bsd;
} else {
b = 0;
}
} else {
return enosys();
}
if ((rc = sys_sigaltstack(a, b)) != -1) {
if (old) {
sigaltstack2linux(old, &bsd);
}
return 0;
} else {
return -1;
}
}

View file

@ -18,10 +18,13 @@
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/metasigaltstack.h"
#include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/siginfo.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h" #include "libc/calls/ucontext.h"
#include "libc/intrin/repstosb.h" #include "libc/intrin/repstosb.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
/** /**
* @fileoverview XNU kernel callback normalization. * @fileoverview XNU kernel callback normalization.
@ -45,12 +48,6 @@ struct __darwin_siginfo {
uint64_t __pad[7]; uint64_t __pad[7];
}; };
struct __darwin_sigaltstack {
void *ss_sp;
uint64_t ss_size;
int32_t ss_flags;
};
struct __darwin_mmst_reg { struct __darwin_mmst_reg {
char __mmst_reg[10]; char __mmst_reg[10];
char __mmst_rsrv[6]; char __mmst_rsrv[6];
@ -368,7 +365,7 @@ struct __darwin_mcontext64 {
struct __darwin_ucontext { struct __darwin_ucontext {
int32_t uc_onstack; int32_t uc_onstack;
uint32_t uc_sigmask; uint32_t uc_sigmask;
struct __darwin_sigaltstack uc_stack; struct sigaltstack_bsd uc_stack;
struct __darwin_ucontext *uc_link; struct __darwin_ucontext *uc_link;
uint64_t uc_mcsize; uint64_t uc_mcsize;
struct __darwin_mcontext64 *uc_mcontext; struct __darwin_mcontext64 *uc_mcontext;
@ -387,7 +384,7 @@ noasan static void linuxexceptionstate2xnu(
} }
noasan static void xnuthreadstate2linux( noasan static void xnuthreadstate2linux(
ucontext_t *uc, mcontext_t *mc, struct __darwin_x86_thread_state64 *xnuss) { mcontext_t *mc, struct __darwin_x86_thread_state64 *xnuss) {
mc->rdi = xnuss->__rdi; mc->rdi = xnuss->__rdi;
mc->rsi = xnuss->__rsi; mc->rsi = xnuss->__rsi;
mc->rbp = xnuss->__rbp; mc->rbp = xnuss->__rbp;
@ -401,7 +398,6 @@ noasan static void xnuthreadstate2linux(
mc->gs = xnuss->__gs; mc->gs = xnuss->__gs;
mc->fs = xnuss->__fs; mc->fs = xnuss->__fs;
mc->eflags = xnuss->__rflags; mc->eflags = xnuss->__rflags;
uc->uc_flags = xnuss->__rflags;
mc->r8 = xnuss->__r8; mc->r8 = xnuss->__r8;
mc->r9 = xnuss->__r9; mc->r9 = xnuss->__r9;
mc->r10 = xnuss->__r10; mc->r10 = xnuss->__r10;
@ -427,7 +423,6 @@ noasan static void linuxthreadstate2xnu(
xnuss->__gs = mc->gs; xnuss->__gs = mc->gs;
xnuss->__fs = mc->fs; xnuss->__fs = mc->fs;
xnuss->__rflags = mc->eflags; xnuss->__rflags = mc->eflags;
xnuss->__rflags = uc->uc_flags;
xnuss->__r8 = mc->r8; xnuss->__r8 = mc->r8;
xnuss->__r9 = mc->r9; xnuss->__r9 = mc->r9;
xnuss->__r10 = mc->r10; xnuss->__r10 = mc->r10;
@ -484,6 +479,7 @@ noasan void __sigenter_xnu(void *fn, int infostyle, int sig,
if (rva >= kSigactionMinRva) { if (rva >= kSigactionMinRva) {
repstosb(&g, 0, sizeof(g)); repstosb(&g, 0, sizeof(g));
if (xnuctx) { if (xnuctx) {
g.uc.uc_flags = xnuctx->uc_onstack ? SA_ONSTACK : 0;
g.uc.uc_sigmask.__bits[0] = xnuctx->uc_sigmask; g.uc.uc_sigmask.__bits[0] = xnuctx->uc_sigmask;
g.uc.uc_stack.ss_sp = xnuctx->uc_stack.ss_sp; g.uc.uc_stack.ss_sp = xnuctx->uc_stack.ss_sp;
g.uc.uc_stack.ss_flags = xnuctx->uc_stack.ss_flags; g.uc.uc_stack.ss_flags = xnuctx->uc_stack.ss_flags;
@ -498,8 +494,7 @@ noasan void __sigenter_xnu(void *fn, int infostyle, int sig,
if (xnuctx->uc_mcsize >= if (xnuctx->uc_mcsize >=
(sizeof(struct __darwin_x86_exception_state64) + (sizeof(struct __darwin_x86_exception_state64) +
sizeof(struct __darwin_x86_thread_state64))) { sizeof(struct __darwin_x86_thread_state64))) {
xnuthreadstate2linux(&g.uc, &g.uc.uc_mcontext, xnuthreadstate2linux(&g.uc.uc_mcontext, &xnuctx->uc_mcontext->__ss);
&xnuctx->uc_mcontext->__ss);
} }
if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) { if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) {
xnussefpustate2linux(&g.uc.__fpustate, &xnuctx->uc_mcontext->__fs); xnussefpustate2linux(&g.uc.__fpustate, &xnuctx->uc_mcontext->__fs);

View file

@ -0,0 +1,15 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_METASIGALTSTACK_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_METASIGALTSTACK_H_
#include "libc/calls/struct/sigaltstack.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct sigaltstack_bsd {
void *ss_sp;
uint64_t ss_size;
int32_t ss_flags;
};
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_METASIGALTSTACK_H_ */

View file

@ -14,7 +14,60 @@ struct sigaction { /* cosmo abi */
void (*sa_restorer)(void); void (*sa_restorer)(void);
struct sigset sa_mask; struct sigset sa_mask;
int64_t __pad; int64_t __pad;
} forcealign(8); };
sighandler_t signal(int, sighandler_t);
int sigaction(int, const struct sigaction *, struct sigaction *);
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
COSMOPOLITAN_C_START_
void _init_onntconsoleevent(void);
void _init_wincrash(void);
#ifndef __SIGACTION_YOINK
#define __SIGACTION_YOINK(SIG) \
do { \
if (SupportsWindows()) { \
if (__builtin_constant_p(SIG)) { \
switch (SIG) { \
case SIGINT: \
case SIGQUIT: \
case SIGHUP: \
case SIGTERM: \
YOINK(_init_onntconsoleevent); \
break; \
case SIGTRAP: \
case SIGILL: \
case SIGSEGV: \
case SIGABRT: \
case SIGFPE: \
YOINK(_init_wincrash); \
break; \
default: \
break; \
} \
} else { \
YOINK(_init_onntconsoleevent); \
YOINK(_init_wincrash); \
} \
} \
} while (0)
#endif
#define sigaction(SIG, ACT, OLD) \
({ \
__SIGACTION_YOINK(SIG); \
sigaction(SIG, (ACT), OLD); \
})
#define signal(SIG, HAND) \
({ \
__SIGACTION_YOINK(SIG); \
signal(SIG, HAND); \
})
#endif /* GNU && !ANSI */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_H_ */ #endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_H_ */

View file

@ -1,6 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_ #ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_ #define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct sigaltstack { struct sigaltstack {
void *ss_sp; void *ss_sp;
@ -10,5 +11,8 @@ struct sigaltstack {
typedef struct sigaltstack stack_t; typedef struct sigaltstack stack_t;
int sigaltstack(const struct sigaltstack *, struct sigaltstack *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_ */ #endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_ */

View file

@ -16,6 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/weaken.h"
#include "libc/mem/internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
/** /**
@ -29,6 +31,9 @@ int unsetenv(const char *s) {
for (j = 0;; ++j) { for (j = 0;; ++j) {
if (!s[j]) { if (!s[j]) {
if (p[i][j] == '=') { if (p[i][j] == '=') {
if (weaken(__freeenv)) {
weaken(__freeenv)(p[i]);
}
k = i + 1; k = i + 1;
do { do {
p[k - 1] = p[k]; p[k - 1] = p[k];

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/siginfo.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h" #include "libc/calls/sysdebug.internal.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h" #include "libc/calls/ucontext.h"
#include "libc/nt/enum/exceptionhandleractions.h" #include "libc/nt/enum/exceptionhandleractions.h"
#include "libc/nt/enum/signal.h" #include "libc/nt/enum/signal.h"

View file

@ -16,10 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/weaken.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
/** /**
@ -29,8 +31,13 @@
* @note this is a code-size saving device * @note this is a code-size saving device
*/ */
privileged noasan int64_t __winerr(void) { privileged noasan int64_t __winerr(void) {
errno_t e;
if (IsWindows()) { if (IsWindows()) {
errno = GetLastError(); e = GetLastError();
if (weaken(__dos2errno)) {
e = weaken(__dos2errno)(e);
}
errno = e;
return -1; return -1;
} else { } else {
return enosys(); return enosys();

View file

@ -85,6 +85,7 @@ int LookupProtoByNumber(const int protonum, char *buf, size_t bufsize,
free(line); free(line);
if (ferror(f)) { if (ferror(f)) {
errno = ferror(f); errno = ferror(f);
fclose(f);
return -1; return -1;
} }
fclose(f); fclose(f);

View file

@ -17,7 +17,6 @@ COSMOPOLITAN_C_START_
int abs(int) libcesque pureconst; int abs(int) libcesque pureconst;
long labs(long) libcesque pureconst; long labs(long) libcesque pureconst;
long long llabs(long long) libcesque pureconst; long long llabs(long long) libcesque pureconst;
int llog10(unsigned long) libcesque pureconst;
int atoi(const char *) paramsnonnull() libcesque; int atoi(const char *) paramsnonnull() libcesque;
long atol(const char *) paramsnonnull() libcesque; long atol(const char *) paramsnonnull() libcesque;
long long atoll(const char *) paramsnonnull() libcesque; long long atoll(const char *) paramsnonnull() libcesque;

View file

@ -42,6 +42,15 @@
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}}; static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
static void __fmt_free_dtoa(char **mem) {
if (*mem) {
if (weaken(freedtoa)) {
weaken(freedtoa)(*mem);
}
*mem = 0;
}
}
static int __fmt_atoi(const char **str) { static int __fmt_atoi(const char **str) {
int i; int i;
for (i = 0; '0' <= **str && **str <= '9'; ++*str) { for (i = 0; '0' <= **str && **str <= '9'; ++*str) {
@ -135,11 +144,12 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
int (*out)(const char *, void *, size_t); int (*out)(const char *, void *, size_t);
unsigned char signbit, log2base; unsigned char signbit, log2base;
int c, d, k, w, n, i1, ui, bw, bex; int c, d, k, w, n, i1, ui, bw, bex;
char *s, *q, *se, qchar, special[8]; char *s, *q, *se, *mem, qchar, special[8];
int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr; int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr;
lasterr = errno; lasterr = errno;
out = fn ? fn : (void *)missingno; out = fn ? fn : (void *)missingno;
mem = 0;
while (*format) { while (*format) {
if (*format != '%') { if (*format != '%') {
@ -388,7 +398,8 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
p = "?"; p = "?";
goto FormatThatThing; goto FormatThatThing;
} }
s = weaken(__fmt_dtoa)(pun.d, 3, prec, &decpt, &sgn, &se); assert(!mem);
s = mem = weaken(__fmt_dtoa)(pun.d, 3, prec, &decpt, &sgn, &se);
if (decpt == 9999) { if (decpt == 9999) {
Format9999: Format9999:
bzero(special, sizeof(special)); bzero(special, sizeof(special));
@ -402,6 +413,8 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
} }
memcpy(q, kSpecialFloats[*s == 'N'][d >= 'a'], 4); memcpy(q, kSpecialFloats[*s == 'N'][d >= 'a'], 4);
FormatThatThing: FormatThatThing:
__fmt_free_dtoa(&mem);
mem = 0;
prec = alt = 0; prec = alt = 0;
flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_SPACE); flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_SPACE);
goto FormatString; goto FormatString;
@ -462,6 +475,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
while (--width >= 0) { while (--width >= 0) {
PUT(' '); PUT(' ');
} }
__fmt_free_dtoa(&mem);
continue; continue;
case 'G': case 'G':
@ -477,7 +491,9 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
p = "?"; p = "?";
goto FormatThatThing; goto FormatThatThing;
} }
s = weaken(__fmt_dtoa)(pun.d, prec ? 2 : 0, prec, &decpt, &sgn, &se); assert(!mem);
s = mem =
weaken(__fmt_dtoa)(pun.d, prec ? 2 : 0, prec, &decpt, &sgn, &se);
if (decpt == 9999) goto Format9999; if (decpt == 9999) goto Format9999;
c = se - s; c = se - s;
prec1 = prec; prec1 = prec;
@ -512,7 +528,8 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
p = "?"; p = "?";
goto FormatThatThing; goto FormatThatThing;
} }
s = weaken(__fmt_dtoa)(pun.d, 2, prec + 1, &decpt, &sgn, &se); assert(!mem);
s = mem = weaken(__fmt_dtoa)(pun.d, 2, prec + 1, &decpt, &sgn, &se);
if (decpt == 9999) goto Format9999; if (decpt == 9999) goto Format9999;
FormatExpo: FormatExpo:
if (sgn) sign = '-'; if (sgn) sign = '-';
@ -547,6 +564,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
} }
PUT(c); PUT(c);
} }
__fmt_free_dtoa(&mem);
PUT(d); PUT(d);
if (decpt < 0) { if (decpt < 0) {
PUT('-'); PUT('-');
@ -721,5 +739,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
break; break;
} }
} }
assert(!mem);
return 0; return 0;
} }

View file

@ -16,6 +16,10 @@ COSMOPOLITAN_C_START_
- uint128toarray_radix10(0x31337, a) l: 93 (27ns) m: 141 (41ns) - uint128toarray_radix10(0x31337, a) l: 93 (27ns) m: 141 (41ns)
- int128toarray_radix10(0x31337, a) l: 96 (28ns) m: 173 (51ns) */ - int128toarray_radix10(0x31337, a) l: 96 (28ns) m: 173 (51ns) */
unsigned LengthInt64(int64_t) pureconst;
unsigned LengthUint64(uint64_t) pureconst;
unsigned LengthInt64Thousands(int64_t) pureconst;
unsigned LengthUint64Thousands(uint64_t) pureconst;
char *FormatInt32(char[hasatleast 12], int32_t); char *FormatInt32(char[hasatleast 12], int32_t);
char *FormatUint32(char[hasatleast 12], uint32_t); char *FormatUint32(char[hasatleast 12], uint32_t);
char *FormatInt64(char[hasatleast 21], int64_t); char *FormatInt64(char[hasatleast 21], int64_t);

102
libc/fmt/kdos2errno.S Normal file
View file

@ -0,0 +1,102 @@
/*-*- 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 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/nt/errors.h"
#include "libc/macros.internal.h"
// @fileoverview data structure for __dos2errno()
.macro .e doscode systemv
.short \doscode
.long \systemv - kDos2Errno
.endm
.section .rodata
kDos2Errno:
.e kNtErrorModNotFound,ENOSYS
.e kNtErrorBadCommand,EACCES
.e kNtErrorBadLength,EACCES
.e kNtErrorBadNetpath,ENOENT
.e kNtErrorBadNetName,ENOENT
.e kNtErrorBadNetResp,ENETDOWN
.e kNtErrorBadPathname,ENOENT
.e kNtErrorCannotMake,EACCES
.e kNtErrorCommitmentLimit,ENOMEM
.e kNtErrorConnectionAborted,ECONNABORTED
.e kNtErrorConnectionActive,EISCONN
.e kNtErrorConnectionRefused,ECONNREFUSED
.e kNtErrorCrc,EACCES
.e kNtErrorDirNotEmpty,ENOTEMPTY
.e kNtErrorDupName,EADDRINUSE
.e kNtErrorFilenameExcedRange,ENOENT
.e kNtErrorGenFailure,EACCES
.e kNtErrorGracefulDisconnect,EPIPE
.e kNtErrorHostDown,EHOSTUNREACH
.e kNtErrorHostUnreachable,EHOSTUNREACH
.e kNtErrorInsufficientBuffer,EFAULT
.e kNtErrorInvalidAddress,EADDRNOTAVAIL
.e kNtErrorInvalidFunction,EINVAL
.e kNtErrorInvalidNetname,EADDRNOTAVAIL
.e kNtErrorInvalidUserBuffer,EMSGSIZE
.e kNtErrorIoPending,EINPROGRESS
.e kNtErrorLockViolation,EACCES
.e kNtErrorMoreData,EMSGSIZE
.e kNtErrorNetnameDeleted,ECONNABORTED
.e kNtErrorNetworkAccessDenied,EACCES
.e kNtErrorNetworkBusy,ENETDOWN
.e kNtErrorNetworkUnreachable,ENETUNREACH
.e kNtErrorNoaccess,EFAULT
.e kNtErrorNonpagedSystemResources,ENOMEM
.e kNtErrorNotEnoughMemory,ENOMEM
.e kNtErrorNotEnoughQuota,ENOMEM
.e kNtErrorNotFound,ENOENT
.e kNtErrorNotLocked,EACCES
.e kNtErrorNotReady,EACCES
.e kNtErrorNotSupported,ENOTSUP
.e kNtErrorNoMoreFiles,ENOENT
.e kNtErrorNoSystemResources,ENOMEM
.e kNtErrorOperationAborted,EINTR
.e kNtErrorOutOfPaper,EACCES
.e kNtErrorPagedSystemResources,ENOMEM
.e kNtErrorPagefileQuota,ENOMEM
.e kNtErrorPipeNotConnected,EPIPE
.e kNtErrorPortUnreachable,ECONNRESET
.e kNtErrorProtocolUnreachable,ENETUNREACH
.e kNtErrorRemNotList,ECONNREFUSED
.e kNtErrorRequestAborted,EINTR
.e kNtErrorReqNotAccep,EWOULDBLOCK
.e kNtErrorSectorNotFound,EACCES
.e kNtErrorSemTimeout,ETIMEDOUT
.e kNtErrorSharingViolation,EACCES
.e kNtErrorTooManyNames,ENOMEM
.e kNtErrorUnexpNetErr,ECONNABORTED
.e kNtErrorWorkingSetQuota,ENOMEM
.e kNtErrorWriteProtect,EACCES
.e kNtErrorWrongDisk,EACCES
.e WSAEACCES,EACCES
.e WSAEDISCON,EPIPE
.e WSAEFAULT,EFAULT
.e WSAEINPROGRESS,EBUSY
.e WSAEINVAL,EINVAL
.e WSAEPROCLIM,ENOMEM
.e WSAESHUTDOWN,EPIPE
.e WSANOTINITIALISED,ENETDOWN
.e WSASYSNOTREADY,ENETDOWN
.e WSAVERNOTSUPPORTED,ENOSYS
.short 0
.endobj kDos2Errno,globl,hidden

98
libc/fmt/lengthuint64.c Normal file
View file

@ -0,0 +1,98 @@
/*-*- 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/fmt/itoa.h"
static const uint64_t kTens[] = {
1ull,
10ull,
100ull,
1000ull,
10000ull,
100000ull,
1000000ull,
10000000ull,
100000000ull,
1000000000ull,
10000000000ull,
100000000000ull,
1000000000000ull,
10000000000000ull,
100000000000000ull,
1000000000000000ull,
10000000000000000ull,
100000000000000000ull,
1000000000000000000ull,
10000000000000000000ull,
};
static const unsigned char kTensIndex[] = {
0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, //
5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, //
10, 10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, //
15, 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 18, 19, 19, //
};
/**
* Returns `len(str(x))` where x is an unsigned 64-bit integer.
*/
unsigned LengthUint64(uint64_t x) {
unsigned w;
if (x) {
w = kTensIndex[63 ^ __builtin_clzll(x)];
w += x >= kTens[w];
return w;
} else {
return 1;
}
}
/**
* Returns `len(str(x))` where x is a signed 64-bit integer.
*/
unsigned LengthInt64(int64_t x) {
if (x >= 0) {
return LengthUint64(x);
} else {
return 1 + LengthUint64(-(uint64_t)x);
}
}
/**
* Returns decimal string length of uint64 w/ thousands separators.
*/
unsigned LengthUint64Thousands(uint64_t x) {
unsigned w;
w = LengthUint64(x);
w += (w - 1) / 3;
return w;
}
/**
* Returns decimal string length of int64 w/ thousands separators.
*/
unsigned LengthInt64Thousands(int64_t x) {
unsigned w;
if (x >= 0) {
w = LengthUint64(x);
return w + (w - 1) / 3;
} else {
w = LengthUint64(-(uint64_t)x);
return 1 + w + (w - 1) / 3;
}
}

View file

@ -0,0 +1,41 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/errno.h"
#include "libc/nt/errors.h"
#include "libc/sock/sock.h"
struct thatispacked Dos2Errno {
uint16_t doscode;
int32_t systemv;
};
extern const struct Dos2Errno kDos2Errno[];
/**
* Translates Windows error using superset of consts.sh.
*/
textwindows errno_t __dos2errno(uint32_t error) {
int i;
for (i = 0; kDos2Errno[i].doscode; ++i) {
if (error == kDos2Errno[i].doscode) {
return *(const int *)((intptr_t)kDos2Errno + kDos2Errno[i].systemv);
}
}
return error;
}

View file

@ -21,6 +21,7 @@
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/fmt/fmts.h" #include "libc/fmt/fmts.h"
#include "libc/fmt/internal.h" #include "libc/fmt/internal.h"
#include "libc/limits.h"
#define BUFFER_SIZE 144 #define BUFFER_SIZE 144
@ -31,7 +32,6 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
unsigned log2base, unsigned prec, unsigned width, unsigned log2base, unsigned prec, unsigned width,
unsigned char flags) { unsigned char flags) {
unsigned i; unsigned i;
/* pad leading zeros */ /* pad leading zeros */
if (!(flags & FLAGS_LEFT)) { if (!(flags & FLAGS_LEFT)) {
if (width && (flags & FLAGS_ZEROPAD) && if (width && (flags & FLAGS_ZEROPAD) &&
@ -45,7 +45,6 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
buf[len++] = '0'; buf[len++] = '0';
} }
} }
/* handle hash */ /* handle hash */
if (flags & FLAGS_HASH) { if (flags & FLAGS_HASH) {
if (!(flags & FLAGS_PRECISION) && len && if (!(flags & FLAGS_PRECISION) && len &&
@ -64,7 +63,6 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
buf[len++] = '0'; buf[len++] = '0';
} }
} }
if (len < BUFFER_SIZE) { if (len < BUFFER_SIZE) {
if (negative) { if (negative) {
buf[len++] = '-'; buf[len++] = '-';
@ -74,17 +72,14 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
buf[len++] = ' '; buf[len++] = ' ';
} }
} }
/* pad spaces up to given width */ /* pad spaces up to given width */
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
if (len < width) { if (len < width) {
if (__fmt_pad(out, arg, width - len) == -1) return -1; if (__fmt_pad(out, arg, width - len) == -1) return -1;
} }
} }
reverse(buf, len); reverse(buf, len);
if (out(buf, arg, len) == -1) return -1; if (out(buf, arg, len) == -1) return -1;
/* append pad spaces up to given width */ /* append pad spaces up to given width */
if (flags & FLAGS_LEFT) { if (flags & FLAGS_LEFT) {
if (len < width) { if (len < width) {
@ -97,6 +92,7 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg, int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
uintmax_t value, bool neg, unsigned log2base, unsigned prec, uintmax_t value, bool neg, unsigned log2base, unsigned prec,
unsigned width, unsigned flags, const char *alphabet) { unsigned width, unsigned flags, const char *alphabet) {
uint64_t u64;
uintmax_t remainder; uintmax_t remainder;
unsigned len, count, digit; unsigned len, count, digit;
char buf[BUFFER_SIZE]; char buf[BUFFER_SIZE];
@ -105,10 +101,15 @@ int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
if (value || !(flags & FLAGS_PRECISION)) { if (value || !(flags & FLAGS_PRECISION)) {
count = 0; count = 0;
do { do {
assert(len < BUFFER_SIZE);
if (!log2base) { if (!log2base) {
value = __udivmodti4(value, 10, &remainder); if (value <= UINT64_MAX) {
digit = remainder; u64 = value;
digit = u64 % 10;
value = u64 / 10;
} else {
value = __udivmodti4(value, 10, &remainder);
digit = remainder;
}
} else { } else {
digit = value; digit = value;
digit &= (1u << log2base) - 1; digit &= (1u << log2base) - 1;
@ -122,6 +123,7 @@ int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
} }
buf[len++] = alphabet[digit]; buf[len++] = alphabet[digit];
} while (value); } while (value);
assert(count <= BUFFER_SIZE);
} }
return __fmt_ntoa_format(out, arg, buf, len, neg, log2base, prec, width, return __fmt_ntoa_format(out, arg, buf, len, neg, log2base, prec, width,
flags); flags);

View file

@ -22,7 +22,7 @@
* Converts errno value to string non-reentrantly. * Converts errno value to string non-reentrantly.
* @see strerror_r() * @see strerror_r()
*/ */
char *strerror(int err) { noasan char *strerror(int err) {
_Alignas(1) static char buf[512]; _Alignas(1) static char buf[512];
strerror_r(err, buf, sizeof(buf)); strerror_r(err, buf, sizeof(buf));
return buf; return buf;

View file

@ -21,11 +21,20 @@
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nt/enum/formatmessageflags.h" #include "libc/nt/enum/formatmessageflags.h"
#include "libc/nt/enum/lang.h"
#include "libc/nt/memory.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/str/tpenc.h"
#if !IsTiny()
STATIC_YOINK("__dos2errno");
#endif
struct Error { struct Error {
int x; int x;
@ -35,7 +44,7 @@ struct Error {
extern const struct Error kErrorNames[]; extern const struct Error kErrorNames[];
extern const struct Error kErrorNamesLong[]; extern const struct Error kErrorNamesLong[];
static const char *GetErrorName(long x) { noasan static inline const char *GetErrorName(long x) {
int i; int i;
if (x) { if (x) {
for (i = 0; kErrorNames[i].x; ++i) { for (i = 0; kErrorNames[i].x; ++i) {
@ -47,7 +56,7 @@ static const char *GetErrorName(long x) {
return "EUNKNOWN"; return "EUNKNOWN";
} }
static const char *GetErrorNameLong(long x) { noasan static inline const char *GetErrorNameLong(long x) {
int i; int i;
if (x) { if (x) {
for (i = 0; kErrorNamesLong[i].x; ++i) { for (i = 0; kErrorNamesLong[i].x; ++i) {
@ -65,24 +74,51 @@ static const char *GetErrorNameLong(long x) {
* Converts errno value to string. * Converts errno value to string.
* @return 0 on success, or error code * @return 0 on success, or error code
*/ */
int strerror_r(int err, char *buf, size_t size) { noasan int strerror_r(int err, char *buf, size_t size) {
char *p; uint64_t w;
int c, i, n;
char *p, *e;
const char *s; const char *s;
err &= 0xFFFF; char16_t *ws = 0;
if (IsTiny()) {
s = GetErrorName(err);
} else {
s = GetErrorNameLong(err);
}
p = buf; p = buf;
if (strlen(s) + 1 + 5 + 1 + 1 <= size) { e = p + size;
p = stpcpy(p, s); err &= 0xFFFF;
*p++ = '['; s = IsTiny() ? GetErrorName(err) : GetErrorNameLong(err);
p += uint64toarray_radix10(err, p); while ((c = *s++)) {
*p++ = ']'; if (p + 1 + 1 <= e) *p++ = c;
} }
if (p - buf < size) { if (!IsTiny()) {
*p++ = '\0'; if (p + 1 + 5 + 1 + 1 <= e) {
*p++ = '[';
p = __intcpy(p, err);
*p++ = ']';
}
if (IsWindows()) {
err = GetLastError() & 0xffff;
if ((n = FormatMessage(
kNtFormatMessageAllocateBuffer | kNtFormatMessageFromSystem |
kNtFormatMessageIgnoreInserts,
0, err, MAKELANGID(kNtLangNeutral, kNtSublangDefault),
(char16_t *)&ws, 0, 0))) {
while (n && ws[n - 1] <= L' ' || ws[n - 1] == L'.') --n;
if (p + 1 + 1 <= e) *p++ = '[';
for (i = 0; i < n; ++i) {
w = tpenc(ws[i] & 0xffff);
if (p + (bsrll(w) >> 3) + 1 + 1 <= e) {
do *p++ = w;
while ((w >>= 8));
}
}
if (p + 1 + 1 <= e) *p++ = ']';
LocalFree(ws);
}
if (p + 1 + 5 + 1 + 1 <= e) {
*p++ = '[';
p = __intcpy(p, err);
*p++ = ']';
}
}
} }
if (p + 1 <= e) *p = 0;
return 0; return 0;
} }

View file

@ -157,7 +157,7 @@ typedef uint64_t uintmax_t;
#define strlenesque libcesque nosideeffect paramsnonnull() #define strlenesque libcesque nosideeffect paramsnonnull()
#define vallocesque \ #define vallocesque \
libcesque nodiscard returnsaligned((PAGESIZE)) returnspointerwithnoaliases libcesque nodiscard returnsaligned((PAGESIZE)) returnspointerwithnoaliases
#define reallocesque libcesque returnsaligned((__BIGGEST_ALIGNMENT__)) #define reallocesque libcesque returnsaligned((16))
#define mallocesque reallocesque returnspointerwithnoaliases #define mallocesque reallocesque returnspointerwithnoaliases
#define interruptfn nocallersavedregisters forcealignargpointer #define interruptfn nocallersavedregisters forcealignargpointer

View file

@ -64,7 +64,7 @@
#endif #endif
#define BIGPAGESIZE 0x200000 #define BIGPAGESIZE 0x200000
#define STACKSIZE 0x200000 #define STACKSIZE 0x20000
#define FRAMESIZE 0x10000 /* 8086 */ #define FRAMESIZE 0x10000 /* 8086 */
#define PAGESIZE 0x1000 /* i386+ */ #define PAGESIZE 0x1000 /* i386+ */
#define BUFSIZ 0x1000 /* best stdio default */ #define BUFSIZ 0x1000 /* best stdio default */

File diff suppressed because it is too large Load diff

View file

@ -1,53 +1,61 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ #ifndef COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
#define COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ #define COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/macros.internal.h"
#define kAsanScale 3 #define kAsanScale 3
#define kAsanMagic 0x7fff8000 #define kAsanMagic 0x7fff8000
#define kAsanHeapFree -1 /* F */ #define kAsanNullPage -1 /* ∅ 0xff */
#define kAsanStackFree -2 /* F */ #define kAsanProtected -2 /* P 0xfe */
#define kAsanRelocated -3 /* R */ #define kAsanHeapFree -3 /* F 0xfd */
#define kAsanHeapUnderrun -4 /* U */ #define kAsanHeapRelocated -4 /* R 0xfc */
#define kAsanHeapOverrun -5 /* O */ #define kAsanAllocaOverrun -5 /* 𝑂 0xfb */
#define kAsanGlobalOverrun -6 /* O */ #define kAsanHeapUnderrun -6 /* U 0xfa */
#define kAsanGlobalUnregistered -7 /* G */ #define kAsanHeapOverrun -7 /* O 0xf9 */
#define kAsanStackUnderrun -8 /* U */ #define kAsanStackUnscoped -8 /* s 0xf8 */
#define kAsanStackOverrun -9 /* O */ #define kAsanStackOverflow -9 /* ! 0xf7 */
#define kAsanAllocaUnderrun -10 /* U */ #define kAsanGlobalOrder -10 /* I 0xf6 */
#define kAsanAllocaOverrun -11 /* O */ #define kAsanStackFree -11 /* r 0xf5 */
#define kAsanUnscoped -12 /* S */ #define kAsanStackPartial -12 /* p 0xf4 */
#define kAsanUnmapped -13 /* M */ #define kAsanStackOverrun -13 /* o 0xf3 */
#define kAsanProtected -14 /* P */ #define kAsanStackMiddle -14 /* m 0xf2 */
#define kAsanStackGuard -15 /* _ */ #define kAsanStackUnderrun -15 /* u 0xf1 */
#define kAsanNullPage -16 #define kAsanAllocaUnderrun -16 /* 𝑈 0xf0 */
#define kAsanUnmapped -17 /* M 0xef */
#define kAsanGlobalRedzone -18 /* G 0xee */
#define kAsanGlobalGone -19 /* 𝐺 0xed */
#define SHADOW(x) ((signed char *)(((uintptr_t)(x) >> kAsanScale) + kAsanMagic)) #define SHADOW(x) ((signed char *)(((intptr_t)(x) >> kAsanScale) + kAsanMagic))
#define UNSHADOW(x) ((void *)(((uintptr_t)(x) + 0x7fff8000) << 3)) #define UNSHADOW(x) ((void *)(MAX(0, (intptr_t)(x)-kAsanMagic) << kAsanScale))
typedef void __asan_die_f(void);
struct AsanFault { struct AsanFault {
char kind; signed char kind;
signed char *shadow; signed char *shadow;
}; };
void __asan_unpoison(uintptr_t, size_t); extern bool __asan_noreentry;
void __asan_unpoison(long, long);
void __asan_poison(long, long, signed char);
void __asan_verify(const void *, size_t); void __asan_verify(const void *, size_t);
void __asan_map_shadow(uintptr_t, size_t); void __asan_map_shadow(uintptr_t, size_t);
void __asan_poison(uintptr_t, size_t, int); bool __asan_is_valid(const void *, long) nosideeffect;
bool __asan_is_valid(const void *, size_t); bool __asan_is_valid_strlist(char *const *) strlenesque;
bool __asan_is_valid_strlist(char *const *); bool __asan_is_valid_iov(const struct iovec *, int) nosideeffect;
bool __asan_is_valid_iov(const struct iovec *, int); wint_t __asan_symbolize_access_poison(signed char) pureconst;
struct AsanFault __asan_check(const void *, size_t); const char *__asan_describe_access_poison(signed char) pureconst;
void __asan_report_memory_fault(void *, int, const char *) wontreturn; struct AsanFault __asan_check(const void *, long) nosideeffect;
void __asan_report(void *, int, const char *, char) wontreturn;
void *__asan_memalign(size_t, size_t);
void __asan_free(void *); void __asan_free(void *);
void *__asan_malloc(size_t); void *__asan_malloc(size_t);
int __asan_malloc_trim(size_t);
int __asan_print_trace(void *);
void *__asan_calloc(size_t, size_t); void *__asan_calloc(size_t, size_t);
void *__asan_realloc(void *, size_t); void *__asan_realloc(void *, size_t);
void *__asan_memalign(size_t, size_t);
size_t __asan_get_heap_size(const void *);
void *__asan_realloc_in_place(void *, size_t); void *__asan_realloc_in_place(void *, size_t);
void *__asan_valloc(size_t);
void *__asan_pvalloc(size_t);
int __asan_malloc_trim(size_t);
void __asan_die(const char *) wontreturn;
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ */ #endif /* COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ */

View file

@ -28,7 +28,7 @@ typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
noasan static noinline antiquity void bzero_sse(char *p, size_t n) { noasan static noinline antiquity void bzero_sse(char *p, size_t n) {
xmm_t v = {0}; xmm_t v = {0};
if (IsAsan()) __asan_check(p, n); if (IsAsan()) __asan_verify(p, n);
if (n <= 32) { if (n <= 32) {
*(xmm_t *)(p + n - 16) = v; *(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v; *(xmm_t *)p = v;
@ -45,7 +45,7 @@ noasan static noinline antiquity void bzero_sse(char *p, size_t n) {
noasan microarchitecture("avx") static void bzero_avx(char *p, size_t n) { noasan microarchitecture("avx") static void bzero_avx(char *p, size_t n) {
xmm_t v = {0}; xmm_t v = {0};
if (IsAsan()) __asan_check(p, n); if (IsAsan()) __asan_verify(p, n);
if (n <= 32) { if (n <= 32) {
*(xmm_t *)(p + n - 16) = v; *(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v; *(xmm_t *)p = v;
@ -134,11 +134,6 @@ void(bzero)(void *p, size_t n) {
char *b; char *b;
uint64_t x; uint64_t x;
b = p; b = p;
if (IsTiny()) {
if (IsAsan()) __asan_check(p, n);
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(0));
return;
}
asm("xorl\t%k0,%k0" : "=r"(x)); asm("xorl\t%k0,%k0" : "=r"(x));
if (n <= 16) { if (n <= 16) {
if (n >= 8) { if (n >= 8) {
@ -153,6 +148,9 @@ void(bzero)(void *p, size_t n) {
b[--n] = x; b[--n] = x;
} while (n); } while (n);
} }
} else if (IsTiny()) {
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(0));
return;
} else if (X86_HAVE(AVX)) { } else if (X86_HAVE(AVX)) {
bzero_avx(b, n); bzero_avx(b, n);
} else { } else {

View file

@ -20,22 +20,12 @@
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/nexgen32e/bsr.h" #include "libc/nexgen32e/bsr.h"
#include "libc/runtime/cxaatexit.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static struct CxaAtexitBlocks { STATIC_YOINK("__cxa_finalize");
struct CxaAtexitBlock {
unsigned mask;
struct CxaAtexitBlock *next;
struct CxaAtexit {
void *fp;
void *arg;
void *pred;
} p[ATEXIT_MAX];
} * p, root;
} __cxa_blocks;
/** /**
* Adds global destructor. * Adds global destructor.
@ -52,6 +42,7 @@ static struct CxaAtexitBlocks {
* @note folks have forked libc in past just to unbloat atexit() * @note folks have forked libc in past just to unbloat atexit()
*/ */
noasan int __cxa_atexit(void *fp, void *arg, void *pred) { noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
/* asan runtime depends on this function */
unsigned i; unsigned i;
struct CxaAtexitBlock *b, *b2; struct CxaAtexitBlock *b, *b2;
_Static_assert(ATEXIT_MAX == CHAR_BIT * sizeof(b->mask), ""); _Static_assert(ATEXIT_MAX == CHAR_BIT * sizeof(b->mask), "");
@ -74,51 +65,3 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
b->p[i].pred = pred; b->p[i].pred = pred;
return 0; return 0;
} }
/**
* Triggers global destructors.
*
* They're called in LIFO order. If a destructor adds more destructors,
* then those destructors will be called immediately following, before
* iteration continues.
*
* @param pred can be null to match all
*/
void __cxa_finalize(void *pred) {
unsigned i, mask;
struct CxaAtexitBlock *b, *b2;
StartOver:
if ((b = __cxa_blocks.p)) {
for (;;) {
mask = b->mask;
while (mask) {
i = bsf(mask);
mask &= ~(1u << i);
if (!pred || pred == b->p[i].pred) {
b->mask &= ~(1u << i);
if (b->p[i].fp) {
((void (*)(void *))b->p[i].fp)(b->p[i].arg);
goto StartOver;
}
}
}
if (!pred) {
b2 = b->next;
if (b2) {
assert(b != &__cxa_blocks.root);
if (weaken(free)) {
weaken(free)(b);
}
}
__cxa_blocks.p = b2;
goto StartOver;
} else {
if (b->next) {
b = b->next;
} else {
break;
}
}
}
}
}

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,18 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h" #include "libc/runtime/cxaatexit.internal.h"
.source __FILE__
.initbss 202,_init_pvalloc struct CxaAtexitBlocks __cxa_blocks;
hook_pvalloc:
.quad 0
.endobj hook_pvalloc,globl,hidden
.previous
.init.start 202,_init_pvalloc
.hidden dlpvalloc
ezlea dlpvalloc,ax
stosq
yoink free
.init.end 202,_init_pvalloc

72
libc/intrin/cxafinalize.c Normal file
View file

@ -0,0 +1,72 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/runtime/cxaatexit.internal.h"
#include "libc/runtime/runtime.h"
/**
* Triggers global destructors.
*
* They're called in LIFO order. If a destructor adds more destructors,
* then those destructors will be called immediately following, before
* iteration continues.
*
* @param pred can be null to match all
*/
void __cxa_finalize(void *pred) {
unsigned i, mask;
struct CxaAtexitBlock *b, *b2;
StartOver:
if ((b = __cxa_blocks.p)) {
for (;;) {
mask = b->mask;
while (mask) {
i = bsf(mask);
mask &= ~(1u << i);
if (!pred || pred == b->p[i].pred) {
b->mask &= ~(1u << i);
if (b->p[i].fp) {
((void (*)(void *))b->p[i].fp)(b->p[i].arg);
goto StartOver;
}
}
}
if (!pred) {
b2 = b->next;
if (b2) {
assert(b != &__cxa_blocks.root);
if (weaken(free)) {
weaken(free)(b);
}
}
__cxa_blocks.p = b2;
goto StartOver;
} else {
if (b->next) {
b = b->next;
} else {
break;
}
}
}
}
}

View file

@ -36,7 +36,7 @@ extern void(__msabi* __imp_ExitProcess)(uint32_t);
* @vforksafe * @vforksafe
* @noreturn * @noreturn
*/ */
privileged wontreturn void _Exit(int exitcode) { privileged noinstrument noasan noubsan wontreturn void _Exit(int exitcode) {
if ((!IsWindows() && !IsMetal()) || (IsMetal() && IsGenuineCosmo())) { if ((!IsWindows() && !IsMetal()) || (IsMetal() && IsGenuineCosmo())) {
asm volatile("syscall" asm volatile("syscall"
: /* no outputs */ : /* no outputs */

View file

@ -41,12 +41,27 @@ $(LIBC_INTRIN_A).pkg: \
$(LIBC_INTRIN_A_OBJS) \ $(LIBC_INTRIN_A_OBJS) \
$(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x)_A).pkg) $(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x)_A).pkg)
$(LIBC_INTRIN_A_OBJS): \
OVERRIDE_CFLAGS += \
-foptimize-sibling-calls
o/$(MODE)/libc/intrin/asan.o \ o/$(MODE)/libc/intrin/asan.o \
o/$(MODE)/libc/intrin/ubsan.o: \ o/$(MODE)/libc/intrin/ubsan.o: \
OVERRIDE_CFLAGS += \ OVERRIDE_CFLAGS += \
-fno-sanitize=all \ -fno-sanitize=all \
-fno-stack-protector \ -fno-stack-protector
-O3
o/$(MODE)/libc/intrin/asan.o: \
OVERRIDE_CFLAGS += \
-O2 \
-finline \
-finline-functions
o/$(MODE)/libc/intrin/asan.o \
o/$(MODE)/libc/intrin/ubsan.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all \
-fno-stack-protector
o/$(MODE)/libc/intrin/memcmp.o: \ o/$(MODE)/libc/intrin/memcmp.o: \
OVERRIDE_CFLAGS += \ OVERRIDE_CFLAGS += \
@ -63,12 +78,18 @@ o//libc/intrin/memmove.o: \
OVERRIDE_CFLAGS += \ OVERRIDE_CFLAGS += \
-O3 -O3
o/tiny/libc/intrin/memcmp.o \ o/$(MODE)/libc/intrin/bzero.o \
o/tiny/libc/intrin/memmove.o \ o/$(MODE)/libc/intrin/memcmp.o \
o/tiny/libc/intrin/memmove-gcc.asm: \ o/$(MODE)/libc/intrin/memmove.o: \
OVERRIDE_CFLAGS += \ OVERRIDE_CFLAGS += \
-fpie -fpie
o/$(MODE)/libc/intrin/printf.o: \
OVERRIDE_CFLAGS += \
-Os \
-fpie \
-mgeneral-regs-only
LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x))) LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)))
LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS)) LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS))
LIBC_INTRIN_SRCS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_SRCS)) LIBC_INTRIN_SRCS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_SRCS))

View file

@ -16,51 +16,43 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/alg/alg.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/fmt/conv.h" #include "libc/log/libfatal.internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/nexgen32e/vendor.internal.h" #include "libc/nexgen32e/vendor.internal.h"
#include "libc/nt/struct/teb.h" #include "libc/nt/struct/teb.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#define kBufSize 1024 #define kBufSize 1024
#define kProcStatus "/proc/self/status" #define kPid "TracerPid:\t"
#define kPid "TracerPid:\t"
static noasan int NtBeingDebugged(void) {
return NtGetPeb()->BeingDebugged;
}
/** /**
* Determines if gdb, strace, windbg, etc. is controlling process. * Determines if gdb, strace, windbg, etc. is controlling process.
* @return non-zero if attached, otherwise 0 * @return non-zero if attached, otherwise 0
*/ */
int IsDebuggerPresent(bool force) { noasan noubsan int IsDebuggerPresent(bool force) {
/* asan runtime depends on this function */
int fd, res; int fd, res;
ssize_t got; ssize_t got;
char buf[1024]; char *p, buf[1024];
res = false;
if (!force) { if (!force) {
if (getenv("HEISENDEBUG")) return false; if (IsGenuineCosmo()) return 0;
if (IsGenuineCosmo()) return false; if (__getenv(__envp, "HEISENDEBUG")) return 0;
} }
if (IsWindows()) { if (IsWindows()) {
res = NtBeingDebugged(); return NtGetPeb()->BeingDebugged; /* needs noasan */
} else if (IsLinux()) { } else {
if ((fd = sys_openat(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) { res = 0;
if ((got = sys_read(fd, buf, sizeof(buf) - sizeof(kPid))) != -1) { if ((fd = __sysv_open("/proc/self/status", O_RDONLY, 0)) >= 0) {
if ((got = __sysv_read(fd, buf, sizeof(buf) - 1)) > 0) {
buf[got] = '\0'; buf[got] = '\0';
res = atoi(firstnonnull(strstr(buf, kPid), kPid) + strlen(kPid)); if ((p = __strstr(buf, kPid))) {
p += sizeof(kPid) - 1;
res = __atoul(p);
}
} }
sys_close(fd); __sysv_close(fd);
} }
return res;
} }
return res;
} }

View file

@ -16,6 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
@ -28,8 +30,9 @@ bool IsRunningUnderMake(void) {
return g_isrunningundermake; return g_isrunningundermake;
} }
textstartup void g_isrunningundermake_init(void) { textstartup void g_isrunningundermake_init(int argc, char **argv, char **envp,
g_isrunningundermake = !!getenv("MAKEFLAGS"); intptr_t *auxv) {
g_isrunningundermake = !!__getenv(envp, "MAKEFLAGS");
} }
const void *const g_isrunningundermake_ctor[] initarray = { const void *const g_isrunningundermake_ctor[] initarray = {

View file

@ -0,0 +1,46 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/safemacros.internal.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/nt/enum/version.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
bool g_isterminalinarticulate;
bool IsTerminalInarticulate(void) {
return g_isterminalinarticulate;
}
textstartup noasan void g_isterminalinarticulate_init(int argc, char **argv,
char **envp,
intptr_t *auxv) {
char *s;
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
g_isterminalinarticulate = true;
} else if ((s = __getenv(envp, "TERM"))) {
g_isterminalinarticulate = !__strcmp(s, "dumb");
}
}
const void *const g_isterminalinarticulate_ctor[] initarray = {
g_isterminalinarticulate_init,
};

View file

@ -21,6 +21,8 @@
#include "libc/nexgen32e/x86feature.h" #include "libc/nexgen32e/x86feature.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#define PMOVMSKB(x) __builtin_ia32_pmovmskb128(x)
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1))); typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
static noinline antiquity int memcmp_sse(const unsigned char *p, static noinline antiquity int memcmp_sse(const unsigned char *p,
@ -29,9 +31,7 @@ static noinline antiquity int memcmp_sse(const unsigned char *p,
unsigned u, u0, u1, u2, u3; unsigned u, u0, u1, u2, u3;
if (n > 32) { if (n > 32) {
while (n > 16 + 16) { while (n > 16 + 16) {
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p == if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
*(const xmm_t *)q) -
0xffff)) {
n -= 16; n -= 16;
p += 16; p += 16;
q += 16; q += 16;
@ -41,10 +41,8 @@ static noinline antiquity int memcmp_sse(const unsigned char *p,
} }
} }
} }
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p == *(const xmm_t *)q) - if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
0xffff)) { if (!(u = PMOVMSKB(*(xmm_t *)(p + n - 16) == *(xmm_t *)(q + n - 16)) ^
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)(p + n - 16) ==
*(const xmm_t *)(q + n - 16)) -
0xffff)) { 0xffff)) {
return 0; return 0;
} else { } else {
@ -61,19 +59,13 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
const unsigned char *q, const unsigned char *q,
size_t n) { size_t n) {
uint64_t w; uint64_t w;
unsigned u, u0, u1, u2, u3; unsigned u;
if (n > 32) { if (n > 32) {
while (n >= 16 + 64) { while (n >= 16 + 64) {
u0 = __builtin_ia32_pmovmskb128( w = (uint64_t)PMOVMSKB(((xmm_t *)p)[0] == ((xmm_t *)q)[0]) << 000 |
(((const xmm_t *)p)[0] == ((const xmm_t *)q)[0])); (uint64_t)PMOVMSKB(((xmm_t *)p)[1] == ((xmm_t *)q)[1]) << 020 |
u1 = __builtin_ia32_pmovmskb128( (uint64_t)PMOVMSKB(((xmm_t *)p)[2] == ((xmm_t *)q)[2]) << 040 |
(((const xmm_t *)p)[1] == ((const xmm_t *)q)[1])); (uint64_t)PMOVMSKB(((xmm_t *)p)[3] == ((xmm_t *)q)[3]) << 060;
u2 = __builtin_ia32_pmovmskb128(
(((const xmm_t *)p)[2] == ((const xmm_t *)q)[2]));
u3 = __builtin_ia32_pmovmskb128(
(((const xmm_t *)p)[3] == ((const xmm_t *)q)[3]));
w = (uint64_t)u0 | (uint64_t)u1 << 16 | (uint64_t)u2 << 32 |
(uint64_t)u3 << 48;
if (w == -1) { if (w == -1) {
n -= 64; n -= 64;
p += 64; p += 64;
@ -84,9 +76,7 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
} }
} }
while (n > 16 + 16) { while (n > 16 + 16) {
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p == if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
*(const xmm_t *)q) -
0xffff)) {
n -= 16; n -= 16;
p += 16; p += 16;
q += 16; q += 16;
@ -96,10 +86,8 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
} }
} }
} }
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p == *(const xmm_t *)q) - if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
0xffff)) { if (!(u = PMOVMSKB(*(xmm_t *)(p + n - 16) == *(xmm_t *)(q + n - 16)) ^
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)(p + n - 16) ==
*(const xmm_t *)(q + n - 16)) -
0xffff)) { 0xffff)) {
return 0; return 0;
} else { } else {

View file

@ -26,9 +26,6 @@
typedef long long xmm_t __attribute__((__vector_size__(16), __aligned__(1))); typedef long long xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16))); typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
asm("memcpy = memmove\n\t"
".globl\tmemcpy");
/** /**
* Copies memory. * Copies memory.
* *
@ -120,8 +117,6 @@ void *memmove(void *dst, const void *src, size_t n) {
*d = *s; *d = *s;
} }
} else { } else {
if (IsAsan()) __asan_check(d, n);
if (IsAsan()) __asan_check(s, n);
if (d <= s) { if (d <= s) {
asm("rep movsb" asm("rep movsb"
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])dst) : "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])dst)
@ -224,8 +219,8 @@ void *memmove(void *dst, const void *src, size_t n) {
*(xmm_t *)(d + n + 16) = w; *(xmm_t *)(d + n + 16) = w;
} while (n >= 32); } while (n >= 32);
} else { } else {
if (IsAsan()) __asan_check(d, n); if (IsAsan()) __asan_verify(d, n);
if (IsAsan()) __asan_check(s, n); if (IsAsan()) __asan_verify(s, n);
asm("std\n\t" asm("std\n\t"
"rep movsb\n\t" "rep movsb\n\t"
"cld" "cld"
@ -246,8 +241,8 @@ void *memmove(void *dst, const void *src, size_t n) {
s += i; s += i;
n -= i; n -= i;
} else { } else {
if (IsAsan()) __asan_check(d, n); if (IsAsan()) __asan_verify(d, n);
if (IsAsan()) __asan_check(s, n); if (IsAsan()) __asan_verify(s, n);
asm("rep movsb" asm("rep movsb"
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])d) : "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])d)
: "m"(*(char(*)[n])s)); : "m"(*(char(*)[n])s));
@ -313,3 +308,6 @@ void *memmove(void *dst, const void *src, size_t n) {
return dst; return dst;
} }
} }
asm("memcpy = memmove\n\t"
".globl\tmemcpy");

View file

@ -28,7 +28,7 @@ typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
noasan static noinline antiquity void *memset_sse(char *p, char c, size_t n) { noasan static noinline antiquity void *memset_sse(char *p, char c, size_t n) {
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c}; xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
if (IsAsan()) __asan_check(p, n); if (IsAsan()) __asan_verify(p, n);
if (n <= 32) { if (n <= 32) {
*(xmm_t *)(p + n - 16) = v; *(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v; *(xmm_t *)p = v;
@ -48,7 +48,7 @@ noasan microarchitecture("avx") static void *memset_avx(char *p, char c,
size_t n) { size_t n) {
char *t; char *t;
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c}; xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
if (IsAsan()) __asan_check(p, n); if (IsAsan()) __asan_verify(p, n);
if (n <= 32) { if (n <= 32) {
*(xmm_t *)(p + n - 16) = v; *(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v; *(xmm_t *)p = v;
@ -140,11 +140,6 @@ void *memset(void *p, int c, size_t n) {
uint32_t u; uint32_t u;
uint64_t x; uint64_t x;
b = p; b = p;
if (IsTiny()) {
if (IsAsan()) __asan_check(p, n);
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(c));
return p;
}
if (n <= 16) { if (n <= 16) {
if (n >= 8) { if (n >= 8) {
x = 0x0101010101010101ul * (c & 255); x = 0x0101010101010101ul * (c & 255);
@ -161,6 +156,9 @@ void *memset(void *p, int c, size_t n) {
} while (n); } while (n);
} }
return b; return b;
} else if (IsTiny()) {
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(c));
return p;
} else if (X86_HAVE(AVX)) { } else if (X86_HAVE(AVX)) {
return memset_avx(b, c, n); return memset_avx(b, c, n);
} else { } else {

View file

@ -18,7 +18,6 @@
*/ */
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nexgen32e/uart.internal.h" #include "libc/nexgen32e/uart.internal.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
@ -26,23 +25,25 @@
#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/nr.h"
/** /**
* Low-level printf. * Privileged printf.
* *
* This will work without any cosmopolitan runtime support once the * This will work without any cosmopolitan runtime support once the
* executable has been loaded into memory. * executable has been loaded into memory.
*/ */
privileged noasan noinstrument void __printf(const char *fmt, ...) { privileged noasan noubsan noinstrument void __printf(const char *fmt, ...) {
long d, ax; /* system call support runtime depends on this function */
/* function tracing runtime depends on this function */
/* asan runtime depends on this function */
short w[2];
va_list va; va_list va;
uint16_t dx; uint16_t dx;
const char *s; const void *s;
uint32_t wrote; uint32_t wrote;
unsigned long x; unsigned long x;
unsigned char al; unsigned char al;
const char16_t *S; int i, j, t, cstr;
int i, n, t, w, plus; long d, rax, rdi, rsi, rdx, dot;
char c, f, *p, *e, b[2048]; char c, *p, *e, pad, bits, base, sign, thou, z[28], b[2048];
w = 0;
p = b; p = b;
e = p + sizeof(b); e = p + sizeof(b);
va_start(va, fmt); va_start(va, fmt);
@ -56,98 +57,132 @@ privileged noasan noinstrument void __printf(const char *fmt, ...) {
case '\0': case '\0':
break; break;
case '%': case '%':
w = 0; dot = 0;
f = ' '; pad = ' ';
plus = 0; sign = 0;
n = INT_MAX; bits = 0;
thou = 0;
w[0] = 0;
w[1] = SHRT_MAX;
NeedMoar: NeedMoar:
switch ((c = *fmt++)) { switch ((c = *fmt++)) {
case '\0': case '\0':
break; break;
case '0': case 'l':
f = c; case 'z':
goto NeedMoar; goto NeedMoar;
case ' ':
case '+': case '+':
plus = c; sign = c;
goto NeedMoar;
case 'e':
dot = 1;
goto NeedMoar;
case ',':
thou = c;
goto NeedMoar;
case 'h':
bits = 16;
goto NeedMoar;
case '0':
pad = c;
/* fallthrough */
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
w[dot] *= 10;
w[dot] += c - '0';
goto NeedMoar; goto NeedMoar;
case '*': case '*':
w = va_arg(va, int); w[dot] = va_arg(va, int);
goto NeedMoar; goto NeedMoar;
case 'd': case 'd':
d = va_arg(va, long); d = va_arg(va, long);
ApiAbuse: ApiAbuse:
if (p + 22 <= e) { x = d;
if (d || !plus) { if (d < 0) {
if (d > 0 && plus) { x = -x;
*p++ = plus; sign = '-';
} }
p = __intcpy(p, d); for (i = j = 0;;) {
z[i++] = x % 10 + '0';
if (!(x /= 10)) break;
if (thou && !(++j % 3)) {
z[i++] = thou;
} }
} }
if (sign) {
z[i++] = sign;
}
EmitNumber:
while (w[0]-- > i) {
if (p < e) *p++ = pad;
}
do {
if (p < e) *p++ = z[--i];
} while (i);
break; break;
case 'b':
base = 1;
BinaryNumber:
i = 0;
x = va_arg(va, unsigned long);
do z[i++] = "0123456789abcdef"[x & ((1 << base) - 1)];
while ((x >>= base) && i < w[1]);
goto EmitNumber;
case 'p': case 'p':
w = 12; pad = '0';
f = '0'; w[0] = 12;
w[1] = 12;
/* fallthrough */ /* fallthrough */
case 'x': case 'x':
x = va_arg(va, unsigned long); base = 4;
if (x) { goto BinaryNumber;
n = __builtin_clzl(x) ^ (sizeof(long) * 8 - 1); case 'o':
n >>= 2; base = 3;
n += 1; goto BinaryNumber;
} else { case 'c':
n = 1; cstr = va_arg(va, int);
} s = &cstr;
while (w-- > n) { goto EmitString;
if (p < e) {
*p++ = f;
}
}
while (n--) {
if (p < e) {
*p++ = "0123456789abcdef"[(x >> (n << 2)) & 15];
}
}
break;
case 'S':
n = va_arg(va, int);
/* fallthrough */
case 's': case 's':
s = va_arg(va, const char *); s = va_arg(va, const void *);
EmitString:
if (!s) { if (!s) {
EmitNullString:
s = "NULL"; s = "NULL";
} bits = 0;
if ((uintptr_t)s < PAGESIZE) { } else if ((uintptr_t)s < PAGESIZE) {
d = (intptr_t)s; d = (intptr_t)s;
goto ApiAbuse; goto ApiAbuse;
} }
for (i = 0; i < n; ++i) { for (i = 0; i < w[1]; ++i) {
if (!s[i]) { if (!bits) {
n = i; t = ((const char *)s)[i];
break; EmitByte:
} if (t) {
} if (p < e) {
while (w-- > n) { *p++ = t;
if (p < e) { }
*p++ = f;
}
}
for (i = 0; i < n && p < e; ++i) {
*p++ = s[i];
}
break;
case 'u':
S = va_arg(va, const char16_t *);
if (!S) goto EmitNullString;
while ((t = *S++)) {
if (p + 3 <= e && (t & 0xfc00) != 0xdc00) {
if (t <= 0x7ff) {
p[0] = 0300 | t >> 6;
p[1] = 0200 | x << 8 | t & 077;
p += 2;
} else { } else {
if (t > 0xffff) t = 0xfffd; break;
}
} else {
t = ((const char16_t *)s)[i];
if (t <= 0x7f) {
goto EmitByte;
} else if (t <= 0x7ff) {
if (p + 1 < e) {
p[0] = 0300 | t >> 6;
p[1] = 0200 | x << 8 | t & 077;
p += 2;
}
} else if (p + 2 < e) {
p[0] = 0340 | t >> 12; p[0] = 0340 | t >> 12;
p[1] = 0200 | x << 8 | (t >> 6) & 077; p[1] = 0200 | x << 8 | (t >> 6) & 077;
p[2] = 0200 | x << 8 | t & 077; p[2] = 0200 | x << 8 | t & 077;
@ -155,6 +190,9 @@ privileged noasan noinstrument void __printf(const char *fmt, ...) {
} }
} }
} }
while (w[0]-- > i) {
if (p < e) *p++ = pad;
}
break; break;
default: default:
break; break;
@ -186,8 +224,8 @@ privileged noasan noinstrument void __printf(const char *fmt, ...) {
} }
} else { } else {
asm volatile("syscall" asm volatile("syscall"
: "=a"(ax) : "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
: "0"(__NR_write), "D"(2), "S"(b), "d"(p - b) : "0"(__NR_write), "1"(2L), "2"(b), "3"(p - b)
: "rcx", "r11", "memory"); : "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
} }
} }

View file

@ -0,0 +1,37 @@
/*-*- 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/dce.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/sysv/consts/o.h"
privileged void PrintSystemMappings(int outfd) {
int infd;
ssize_t rc;
char buf[64];
if (!IsWindows()) {
if ((infd = __sysv_open("/proc/self/maps", O_RDONLY, 0)) >= 0) {
__sysv_write(outfd, "\n", 1);
while ((rc = __sysv_read(infd, buf, sizeof(buf))) > 0) {
__sysv_write(outfd, buf, rc);
}
}
__sysv_close(infd);
}
}

View file

@ -19,384 +19,165 @@
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
.source __FILE__ .source __FILE__
.macro .acall fn:req
xor %eax,%eax
mov $1,%r10b
cmpxchg %r10b,__asan_noreentry(%rip)
jnz 2f
call \fn
decb __asan_noreentry(%rip)
2: nop
.endm
.rodata.cst4 .rodata.cst4
__asan_option_detect_stack_use_after_return: __asan_option_detect_stack_use_after_return:
.long 0 .long 0
.endobj __asan_option_detect_stack_use_after_return,globl .endobj __asan_option_detect_stack_use_after_return,globl
.previous .previous
.bss
__asan_noreentry:
.byte 0
.endobj __asan_noreentry
.previous
__asan_report_load1: __asan_report_load1:
push %rbp push $1
mov %rsp,%rbp jmp 1f
.profilable
mov $1,%esi
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load1,globl .endfn __asan_report_load1,globl
__asan_report_load2: __asan_report_load2:
push %rbp push $2
mov %rsp,%rbp jmp 1f
.profilable
mov $2,%esi
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load2,globl .endfn __asan_report_load2,globl
__asan_report_load4: __asan_report_load4:
push %rbp push $4
mov %rsp,%rbp jmp 1f
.profilable
mov $4,%esi
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load4,globl .endfn __asan_report_load4,globl
__asan_report_load8: __asan_report_load8:
push %rbp push $8
mov %rsp,%rbp jmp 1f
.profilable
mov $8,%esi
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load8,globl .endfn __asan_report_load8,globl
__asan_report_load16: __asan_report_load16:
push %rbp push $16
mov %rsp,%rbp jmp 1f
.profilable
mov $16,%esi
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load16,globl .endfn __asan_report_load16,globl
__asan_report_load32: __asan_report_load32:
push %rbp push $32
mov %rsp,%rbp 1: pop %rsi
.profilable 0: jmp __asan_report_load
mov $32,%esi
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load32,globl .endfn __asan_report_load32,globl
__asan_report_load_n: __asan_report_load_n:
push %rbp jmp 0b
mov %rsp,%rbp
.profilable
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load_n,globl .endfn __asan_report_load_n,globl
__asan_report_store1: __asan_report_store1:
push %rbp push $1
mov %rsp,%rbp jmp 1f
.profilable
mov $1,%esi
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_store1,globl .endfn __asan_report_store1,globl
__asan_report_store2: __asan_report_store2:
push %rbp push $2
mov %rsp,%rbp jmp 1f
.profilable
mov $2,%esi
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_store2,globl .endfn __asan_report_store2,globl
__asan_report_store4: __asan_report_store4:
push %rbp push $4
mov %rsp,%rbp jmp 1f
.profilable
mov $4,%esi
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_store4,globl .endfn __asan_report_store4,globl
__asan_report_store8: __asan_report_store8:
push %rbp push $8
mov %rsp,%rbp jmp 1f
.profilable
mov $8,%esi
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_store8,globl .endfn __asan_report_store8,globl
__asan_report_store16: __asan_report_store16:
push %rbp push $16
mov %rsp,%rbp jmp 1f
.profilable
mov $16,%esi
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_store16,globl .endfn __asan_report_store16,globl
__asan_report_store32: __asan_report_store32:
push %rbp push $32
mov %rsp,%rbp 1: pop %rsi
.profilable 0: jmp __asan_report_store
mov $32,%esi
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_store32,globl .endfn __asan_report_store32,globl
__asan_report_store_n: __asan_report_store_n:
push %rbp jmp 0b
mov %rsp,%rbp
.profilable
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_store_n,globl .endfn __asan_report_store_n,globl
__asan_stack_free_0: __asan_stack_free_0:
push %rbp push $0
mov %rsp,%rbp jmp 1f
.profilable
mov $0,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_0,globl .endfn __asan_stack_free_0,globl
__asan_stack_free_1: __asan_stack_free_1:
push %rbp push $1
mov %rsp,%rbp jmp 1f
.profilable
mov $1,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_1,globl .endfn __asan_stack_free_1,globl
__asan_stack_free_2: __asan_stack_free_2:
push %rbp push $2
mov %rsp,%rbp jmp 1f
.profilable
mov $2,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_2,globl .endfn __asan_stack_free_2,globl
__asan_stack_free_3: __asan_stack_free_3:
push %rbp push $3
mov %rsp,%rbp jmp 1f
.profilable
mov $3,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_3,globl .endfn __asan_stack_free_3,globl
__asan_stack_free_4: __asan_stack_free_4:
push %rbp push $4
mov %rsp,%rbp jmp 1f
.profilable
mov $4,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_4,globl .endfn __asan_stack_free_4,globl
__asan_stack_free_5: __asan_stack_free_5:
push %rbp push $5
mov %rsp,%rbp
.profilable
mov $5,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_5,globl .endfn __asan_stack_free_5,globl
__asan_stack_free_hop:
1: pop %rdx
jmp __asan_stack_free
.endfn __asan_report_store_n,globl
__asan_stack_free_6: __asan_stack_free_6:
push %rbp push $6
mov %rsp,%rbp jmp 1b
.profilable
mov $6,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_6,globl .endfn __asan_stack_free_6,globl
__asan_stack_free_7: __asan_stack_free_7:
push %rbp push $7
mov %rsp,%rbp jmp 1b
.profilable
mov $7,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_7,globl .endfn __asan_stack_free_7,globl
__asan_stack_free_8: __asan_stack_free_8:
push %rbp push $8
mov %rsp,%rbp jmp 1b
.profilable
mov $8,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_8,globl .endfn __asan_stack_free_8,globl
__asan_stack_free_9: __asan_stack_free_9:
push %rbp push $9
mov %rsp,%rbp jmp 1b
.profilable
mov $9,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_9,globl .endfn __asan_stack_free_9,globl
__asan_stack_free_10: __asan_stack_free_10:
push %rbp push $10
mov %rsp,%rbp jmp 1b
.profilable
mov $10,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_10,globl .endfn __asan_stack_free_10,globl
__asan_stack_malloc_0: __asan_stack_malloc_0:
push %rbp push $0
mov %rsp,%rbp jmp 1f
.profilable
mov $0,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_0,globl .endfn __asan_stack_malloc_0,globl
__asan_stack_malloc_1: __asan_stack_malloc_1:
push %rbp push $1
mov %rsp,%rbp jmp 1f
.profilable
mov $1,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_1,globl .endfn __asan_stack_malloc_1,globl
__asan_stack_malloc_2: __asan_stack_malloc_2:
push %rbp push $2
mov %rsp,%rbp jmp 1f
.profilable
mov $2,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_2,globl .endfn __asan_stack_malloc_2,globl
__asan_stack_malloc_3: __asan_stack_malloc_3:
push %rbp push $3
mov %rsp,%rbp jmp 1f
.profilable
mov $3,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_3,globl .endfn __asan_stack_malloc_3,globl
__asan_stack_malloc_4: __asan_stack_malloc_4:
push %rbp push $4
mov %rsp,%rbp jmp 1f
.profilable
mov $4,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_4,globl .endfn __asan_stack_malloc_4,globl
__asan_stack_malloc_5: __asan_stack_malloc_5:
push %rbp push $5
mov %rsp,%rbp jmp 1f
.profilable
mov $5,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_5,globl .endfn __asan_stack_malloc_5,globl
__asan_stack_malloc_hop:
1: pop %rsi
jmp __asan_stack_malloc
.endfn __asan_report_store_n,globl
__asan_stack_malloc_6: __asan_stack_malloc_6:
push %rbp push $6
mov %rsp,%rbp jmp 1b
.profilable
mov $6,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_6,globl .endfn __asan_stack_malloc_6,globl
__asan_stack_malloc_7: __asan_stack_malloc_7:
push %rbp push $7
mov %rsp,%rbp jmp 1b
.profilable
mov $7,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_7,globl .endfn __asan_stack_malloc_7,globl
__asan_stack_malloc_8: __asan_stack_malloc_8:
push %rbp push $8
mov %rsp,%rbp jmp 1b
.profilable
mov $8,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_8,globl .endfn __asan_stack_malloc_8,globl
__asan_stack_malloc_9: __asan_stack_malloc_9:
push %rbp push $9
mov %rsp,%rbp jmp 1b
.profilable
mov $9,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_9,globl .endfn __asan_stack_malloc_9,globl
__asan_stack_malloc_10: __asan_stack_malloc_10:
push %rbp push $10
mov %rsp,%rbp jmp 1b
.profilable
mov $10,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_10,globl .endfn __asan_stack_malloc_10,globl
__asan_version_mismatch_check_v8: __asan_version_mismatch_check_v8:

View file

@ -17,8 +17,49 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
.privileged
// Invokes SYSCALL for libfatal forceinline asm() routines.
//
// @param rax is ordinal
// @param rdi is arg1
// @param rsi is arg2
// @param rdx is arg3
// @param rcx is arg4
// @param r8 is arg5
// @param r9 is arg6
// @param rsp may contain more args
// @return rdx:rax where rax holds -errno on error
// @clob rax,rdx,memory,cc
__syscall__: __syscall__:
mov %rcx,.Lrcx(%rip)
mov %rdi,.Lrdi(%rip)
mov %rsi,.Lrsi(%rip)
mov %r8,.Lr8(%rip)
mov %r9,.Lr9(%rip)
mov %r10,.Lr10(%rip)
mov %r11,.Lr11(%rip)
mov %rcx,%r10
clc
syscall syscall
jnc 1f
neg %rax
1: mov .Lrcx(%rip),%rcx
mov .Lrdi(%rip),%rdi
mov .Lrsi(%rip),%rsi
mov .Lr8(%rip),%r8
mov .Lr9(%rip),%r9
mov .Lr10(%rip),%r10
mov .Lr11(%rip),%r11
ret ret
.endfn __syscall__,globl,hidden .endfn __syscall__,globl,hidden
.bss
.align 8
.Lrcx: .quad 0 # clobbered by syscall
.Lrdi: .quad 0 # just in case
.Lrsi: .quad 0 # just in case
.Lr8: .quad 0 # freebsd bug?
.Lr9: .quad 0 # just in case
.Lr10: .quad 0 # just in case
.Lr11: .quad 0 # clobbered by syscall

View file

@ -22,6 +22,7 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
@ -151,55 +152,19 @@ static bool __ubsan_negative(struct UbsanTypeDescriptor *t, uintptr_t x) {
return __ubsan_signed(t) && (intptr_t)x < 0; return __ubsan_signed(t) && (intptr_t)x < 0;
} }
static size_t __ubsan_strlen(const char *s) {
size_t n = 0;
while (*s++) ++n;
return n;
}
static char *__ubsan_stpcpy(char *d, const char *s) {
size_t i;
for (i = 0;; ++i) {
if (!(d[i] = s[i])) {
return d + i;
}
}
}
static char *__ubsan_poscpy(char *p, uintptr_t i) {
int j = 0;
do {
p[j++] = i % 10 + '0';
i /= 10;
} while (i > 0);
reverse(p, j);
return p + j;
}
static char *__ubsan_intcpy(char *p, intptr_t i) {
if (i >= 0) return __ubsan_poscpy(p, i);
*p++ = '-';
return __ubsan_poscpy(p, -i);
}
static char *__ubsan_hexcpy(char *p, uintptr_t x, int k) {
while (k) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
return p;
}
static char *__ubsan_itpcpy(char *p, struct UbsanTypeDescriptor *t, static char *__ubsan_itpcpy(char *p, struct UbsanTypeDescriptor *t,
uintptr_t x) { uintptr_t x) {
if (__ubsan_signed(t)) { if (__ubsan_signed(t)) {
return __ubsan_intcpy(p, x); return __intcpy(p, x);
} else { } else {
return __ubsan_poscpy(p, x); return __uintcpy(p, x);
} }
} }
static const char *__ubsan_dubnul(const char *s, unsigned i) { static const char *__ubsan_dubnul(const char *s, unsigned i) {
size_t n; size_t n;
while (i--) { while (i--) {
if ((n = __ubsan_strlen(s))) { if ((n = __strlen(s))) {
s += n + 1; s += n + 1;
} else { } else {
return NULL; return NULL;
@ -222,53 +187,11 @@ static uintptr_t __ubsan_extend(struct UbsanTypeDescriptor *t, uintptr_t x) {
return x; return x;
} }
static privileged noinline wontreturn void __ubsan_exit(int rc) {
if (!IsWindows()) {
asm volatile("syscall"
: /* no outputs */
: "a"(__NR_exit_group), "D"(rc)
: "memory");
unreachable;
} else {
ExitProcess(rc);
}
}
static privileged noinline ssize_t __ubsan_write(const void *data,
size_t size) {
ssize_t rc;
uint32_t wrote;
if (!IsWindows()) {
asm volatile("syscall"
: "=a"(rc)
: "0"(__NR_write), "D"(2), "S"(data), "d"(size)
: "rcx", "r11", "memory");
return rc;
} else {
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
return wrote;
} else {
return -1;
}
}
}
static ssize_t __ubsan_write_string(const char *s) {
return __ubsan_write(s, __ubsan_strlen(s));
}
void __ubsan_abort(const struct UbsanSourceLocation *loc, void __ubsan_abort(const struct UbsanSourceLocation *loc,
const char *description) { const char *description) {
char buf[1024], *p = buf; __printf("\r\n%s:%d: ubsan error: %s\r\n", loc->file, loc->line, description);
p = __ubsan_stpcpy(p, "error: ");
p = __ubsan_stpcpy(p, loc->file), *p++ = ':';
p = __ubsan_intcpy(p, loc->line);
p = __ubsan_stpcpy(p, ": ");
p = __ubsan_stpcpy(p, description);
p = __ubsan_stpcpy(p, "\r\n");
__ubsan_write_string(buf);
if (weaken(__die)) weaken(__die)(); if (weaken(__die)) weaken(__die)();
__ubsan_exit(134); _Exit(134);
} }
static const char *__ubsan_describe_shift( static const char *__ubsan_describe_shift(
@ -291,11 +214,11 @@ void __ubsan_handle_shift_out_of_bounds(struct UbsanShiftOutOfBoundsInfo *info,
char buf[512], *p = buf; char buf[512], *p = buf;
lhs = __ubsan_extend(info->lhs_type, lhs); lhs = __ubsan_extend(info->lhs_type, lhs);
rhs = __ubsan_extend(info->rhs_type, rhs); rhs = __ubsan_extend(info->rhs_type, rhs);
p = __ubsan_stpcpy(p, __ubsan_describe_shift(info, lhs, rhs)), *p++ = ' '; p = __stpcpy(p, __ubsan_describe_shift(info, lhs, rhs)), *p++ = ' ';
p = __ubsan_itpcpy(p, info->lhs_type, lhs), *p++ = ' '; p = __ubsan_itpcpy(p, info->lhs_type, lhs), *p++ = ' ';
p = __ubsan_stpcpy(p, info->lhs_type->name), *p++ = ' '; p = __stpcpy(p, info->lhs_type->name), *p++ = ' ';
p = __ubsan_itpcpy(p, info->rhs_type, rhs), *p++ = ' '; p = __ubsan_itpcpy(p, info->rhs_type, rhs), *p++ = ' ';
p = __ubsan_stpcpy(p, info->rhs_type->name); p = __stpcpy(p, info->rhs_type->name);
__ubsan_abort(&info->location, buf); __ubsan_abort(&info->location, buf);
} }
@ -307,12 +230,12 @@ void __ubsan_handle_shift_out_of_bounds_abort(
void __ubsan_handle_out_of_bounds(struct UbsanOutOfBoundsInfo *info, void __ubsan_handle_out_of_bounds(struct UbsanOutOfBoundsInfo *info,
uintptr_t index) { uintptr_t index) {
char buf[512], *p = buf; char buf[512], *p = buf;
p = __ubsan_stpcpy(p, info->index_type->name); p = __stpcpy(p, info->index_type->name);
p = __ubsan_stpcpy(p, " index "); p = __stpcpy(p, " index ");
p = __ubsan_itpcpy(p, info->index_type, index); p = __ubsan_itpcpy(p, info->index_type, index);
p = __ubsan_stpcpy(p, " into "); p = __stpcpy(p, " into ");
p = __ubsan_stpcpy(p, info->array_type->name); p = __stpcpy(p, info->array_type->name);
p = __ubsan_stpcpy(p, " out of bounds"); p = __stpcpy(p, " out of bounds");
__ubsan_abort(&info->location, buf); __ubsan_abort(&info->location, buf);
} }
@ -328,19 +251,19 @@ void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *info,
if (!pointer) __ubsan_abort(&info->location, "null pointer access"); if (!pointer) __ubsan_abort(&info->location, "null pointer access");
kind = __ubsan_dubnul(kUbsanTypeCheckKinds, info->type_check_kind); kind = __ubsan_dubnul(kUbsanTypeCheckKinds, info->type_check_kind);
if (info->alignment && (pointer & (info->alignment - 1))) { if (info->alignment && (pointer & (info->alignment - 1))) {
p = __ubsan_stpcpy(p, "unaligned "); p = __stpcpy(p, "unaligned ");
p = __ubsan_stpcpy(p, kind), *p++ = ' '; p = __stpcpy(p, kind), *p++ = ' ';
p = __ubsan_stpcpy(p, info->type->name), *p++ = ' ', *p++ = '@'; p = __stpcpy(p, info->type->name), *p++ = ' ', *p++ = '@';
p = __ubsan_itpcpy(p, info->type, pointer); p = __ubsan_itpcpy(p, info->type, pointer);
p = __ubsan_stpcpy(p, " align "); p = __stpcpy(p, " align ");
p = __ubsan_intcpy(p, info->alignment); p = __intcpy(p, info->alignment);
} else { } else {
p = __ubsan_stpcpy(p, "insufficient size\r\n\t"); p = __stpcpy(p, "insufficient size\r\n\t");
p = __ubsan_stpcpy(p, kind); p = __stpcpy(p, kind);
p = __ubsan_stpcpy(p, " address 0x"); p = __stpcpy(p, " address 0x");
p = __ubsan_hexcpy(p, pointer, sizeof(pointer) * CHAR_BIT); p = __fixcpy(p, pointer, sizeof(pointer) * CHAR_BIT);
p = __ubsan_stpcpy(p, " with insufficient space for object of type "); p = __stpcpy(p, " with insufficient space for object of type ");
p = __ubsan_stpcpy(p, info->type->name); p = __stpcpy(p, info->type->name);
} }
__ubsan_abort(&info->location, buf); __ubsan_abort(&info->location, buf);
} }

View file

@ -31,13 +31,17 @@
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/nexgen32e/gc.internal.h" #include "libc/nexgen32e/gc.internal.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/symbols.internal.h" #include "libc/runtime/symbols.internal.h"
#include "libc/stdio/append.internal.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/x/x.h"
#define kBacktraceMaxFrames 128 #define kBacktraceMaxFrames 128
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1)) #define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1))
@ -168,13 +172,14 @@ static noasan int PrintBacktrace(int fd, const struct StackFrame *bp) {
} }
noasan void ShowBacktrace(int fd, const struct StackFrame *bp) { noasan void ShowBacktrace(int fd, const struct StackFrame *bp) {
/* asan runtime depends on this function */
static bool noreentry; static bool noreentry;
++ftrace; ++g_ftrace;
if (!bp) bp = __builtin_frame_address(0); if (!bp) bp = __builtin_frame_address(0);
if (!noreentry) { if (!noreentry) {
noreentry = true; noreentry = true;
PrintBacktrace(fd, bp); PrintBacktrace(fd, bp);
noreentry = false; noreentry = false;
} }
--ftrace; --g_ftrace;
} }

View file

@ -31,6 +31,8 @@
#include "libc/runtime/symbols.internal.h" #include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#define LIMIT 100
/** /**
* Prints stack frames with symbols. * Prints stack frames with symbols.
* *
@ -46,14 +48,18 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
struct SymbolTable *st) { struct SymbolTable *st) {
size_t gi; size_t gi;
intptr_t addr; intptr_t addr;
int symbol, addend; int i, symbol, addend;
struct Garbages *garbage; struct Garbages *garbage;
const struct StackFrame *frame; const struct StackFrame *frame;
++ftrace; ++g_ftrace;
if (!bp) bp = __builtin_frame_address(0); if (!bp) bp = __builtin_frame_address(0);
garbage = weaken(__garbage); garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0; gi = garbage ? garbage->i : 0;
for (frame = bp; frame; frame = frame->next) { for (i = 0, frame = bp; frame; frame = frame->next) {
if (++i == LIMIT) {
__printf("<truncated backtrace>\n");
break;
}
addr = frame->addr; addr = frame->addr;
if (addr == weakaddr("__gc")) { if (addr == weakaddr("__gc")) {
do { do {
@ -68,15 +74,16 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
* __restore_rt where the kernel creates a stack frame that points * __restore_rt where the kernel creates a stack frame that points
* to the beginning of the function. * to the beginning of the function.
*/ */
if ((symbol = GetSymbol(st, addr - 1)) != -1 || if ((symbol = __get_symbol(st, addr - 1)) != -1 ||
(symbol = GetSymbol(st, addr - 0)) != -1) { (symbol = __get_symbol(st, addr - 0)) != -1) {
addend = addr - st->addr_base; addend = addr - st->addr_base;
addend -= st->symbols[symbol].x; addend -= st->symbols[symbol].x;
} else { } else {
addend = 0; addend = 0;
} }
__printf("%p %p %s%+d\r\n", frame, addr, GetSymbolName(st, symbol), addend); __printf("%p %p %s%+d\r\n", frame, addr, __get_symbol_name(st, symbol),
addend);
} }
--ftrace; --g_ftrace;
return 0; return 0;
} }

60
libc/log/cxaprintexits.c Normal file
View file

@ -0,0 +1,60 @@
/*-*- 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/fmt/fmt.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/runtime/cxaatexit.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
/**
* Prints global destructors.
*
* @param pred can be null to match all
*/
void __cxa_printexits(FILE *f, void *pred) {
char name[23];
unsigned i, mask;
const char *symbol;
struct CxaAtexitBlock *b;
fprintf(f, "\n");
fprintf(f, " GLOBAL DESTRUCTORS \n");
fprintf(f, " callback arg pred \n");
fprintf(f, "---------------------- ------------------ ------------------\n");
if ((b = __cxa_blocks.p)) {
do {
mask = b->mask;
while (mask) {
i = bsf(mask);
mask &= ~(1u << i);
if (!pred || pred == b->p[i].pred) {
symbol = __get_symbol_by_addr((intptr_t)b->p[i].fp);
if (symbol) {
snprintf(name, sizeof(name), "%s", symbol);
} else {
snprintf(name, sizeof(name), "0x%016lx", b->p[i].fp);
}
fprintf(f, "%-22s 0x%016lx 0x%016lx\n", name, b->p[i].arg,
b->p[i].pred);
}
}
} while ((b = b->next));
}
fprintf(f, "\n");
}

View file

@ -29,6 +29,7 @@
* If a debugger is present then this will trigger a breakpoint. * If a debugger is present then this will trigger a breakpoint.
*/ */
relegated wontreturn void __die(void) { relegated wontreturn void __die(void) {
/* asan runtime depends on this function */
static bool once; static bool once;
if (cmpxchg(&once, false, true)) { if (cmpxchg(&once, false, true)) {
__restore_tty(1); __restore_tty(1);

View file

@ -26,6 +26,6 @@
const char *GetCallerName(const struct StackFrame *bp) { const char *GetCallerName(const struct StackFrame *bp) {
struct SymbolTable *st; struct SymbolTable *st;
if (!bp && (bp = __builtin_frame_address(0))) bp = bp->next; if (!bp && (bp = __builtin_frame_address(0))) bp = bp->next;
if (bp) return GetSymbolByAddr(bp->addr - 1); if (bp) return __get_symbol_by_addr(bp->addr);
return 0; return 0;
} }

View file

@ -0,0 +1,34 @@
/*-*- 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/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
/**
* Returns name of symbol at address.
*/
noasan char *__get_symbol_by_addr(int64_t addr) {
/* asan runtime depends on this function */
int i;
struct SymbolTable *st;
st = GetSymbolTable();
i = __get_symbol(st, addr);
if (i == -1) i = __get_symbol(st, addr - 1);
return __get_symbol_name(st, i);
}

View file

@ -24,18 +24,16 @@
* Returns debug binary symbol table, as global singleton. * Returns debug binary symbol table, as global singleton.
* @return symbol table, or NULL w/ errno on first call * @return symbol table, or NULL w/ errno on first call
*/ */
struct SymbolTable *GetSymbolTable(void) { noasan struct SymbolTable *GetSymbolTable(void) {
/* asan runtime depends on this function */
static bool once; static bool once;
static struct SymbolTable *singleton; static struct SymbolTable *singleton;
const char *debugbin; const char *debugbin;
if (!once) { if (!once) {
once = true; once = true;
++ftrace; ++g_ftrace;
if ((debugbin = FindDebugBinary()) && singleton = OpenSymbolTable(FindDebugBinary());
(singleton = OpenSymbolTable(debugbin))) { --g_ftrace;
__cxa_atexit(CloseSymbolTable, &singleton, NULL);
}
--ftrace;
} }
return singleton; return singleton;
} }

View file

@ -7,9 +7,11 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
extern int kCrashSigs[8] hidden; extern hidden int kCrashSigs[8];
extern struct termios g_oldtermios hidden; extern hidden bool g_isrunningundermake;
extern struct sigaction g_oldcrashacts[8] hidden; extern hidden bool g_isterminalinarticulate;
extern hidden struct termios g_oldtermios;
extern hidden struct sigaction g_oldcrashacts[8];
void __start_fatal(const char *, int) hidden; void __start_fatal(const char *, int) hidden;
void __start_fatal_ndebug(void) hidden; void __start_fatal_ndebug(void) hidden;

View file

@ -5,42 +5,94 @@
#include "libc/nexgen32e/bsr.h" #include "libc/nexgen32e/bsr.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/nr.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
extern char __fatalbuf[]; extern char __fatalbuf[];
void __printf(const char *, ...);
forceinline void __sysv_exit(long rc) {
asm volatile("call\t__syscall__"
: /* no outputs */
: "a"(__NR_exit_group), "D"(rc)
: "memory", "cc");
}
forceinline int __sysv_close(long fd) {
long ax;
asm volatile("call\t__syscall__"
: "=a"(ax)
: "0"(__NR_close), "D"(fd)
: "rdx", "memory", "cc");
return ax;
}
forceinline int __sysv_open(const char *path, long flags, long mode) {
long ax, dx;
asm volatile("call\t__syscall__"
: "=a"(ax), "=d"(dx)
: "0"(__NR_open), "D"(path), "S"(flags), "1"(mode)
: "memory", "cc");
return ax;
}
forceinline long __sysv_read(long fd, void *data, unsigned long size) {
long ax, dx;
asm volatile("call\t__syscall__"
: "=a"(ax), "=d"(dx)
: "0"(__NR_read), "D"(fd), "S"(data), "1"(size)
: "memory", "cc");
return ax;
}
forceinline long __sysv_write(long fd, const void *data, unsigned long size) {
long ax, dx;
asm volatile("call\t__syscall__"
: "=a"(ax), "=d"(dx)
: "0"(__NR_write), "D"(fd), "S"(data), "1"(size)
: "memory", "cc");
return ax;
}
forceinline long __sysv_mprotect(void *addr, size_t size, long prot) {
long ax, dx;
asm volatile("call\t__syscall__"
: "=a"(ax), "=d"(dx)
: "0"(__NR_mprotect), "D"(addr), "S"(size), "1"(prot)
: "memory", "cc");
return ax;
}
forceinline int __sysv_getpid(void) {
long ax;
asm volatile("call\t__syscall__"
: "=a"(ax)
: "0"(__NR_getpid)
: "rdx", "memory", "cc");
return ax;
}
forceinline int __getpid(void) { forceinline int __getpid(void) {
int rc;
if (!IsWindows()) { if (!IsWindows()) {
asm volatile("call\t__syscall__" return __sysv_getpid();
: "=a"(rc)
: "0"(__NR_getpid)
: "rcx", "r11", "memory");
return rc;
} else { } else {
return GetCurrentProcessId(); return GetCurrentProcessId();
} }
} }
forceinline ssize_t __write(const void *data, size_t size) { forceinline ssize_t __write(const void *p, size_t n) {
char cf; char cf;
ssize_t rc; ssize_t rc;
uint32_t wrote; uint32_t wrote;
if (!IsWindows()) { if (!IsWindows()) {
asm volatile("call\t__syscall__" return __sysv_write(2, p, n);
: "=@ccc"(cf), "=a"(rc) } else if (WriteFile(GetStdHandle(kNtStdErrorHandle), p, n, &wrote, 0)) {
: "1"(__NR_write), "D"(2), "S"(data), "d"(size) return wrote;
: "rcx", "r11", "memory");
if (cf && IsBsd()) rc = -rc;
return rc;
} else { } else {
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) { return -GetLastError();
return wrote;
} else {
return -1;
}
} }
} }
@ -54,6 +106,12 @@ forceinline ssize_t __write_str(const char *s) {
return __write(s, __strlen(s)); return __write(s, __strlen(s));
} }
forceinline int __strcmp(const char *l, const char *r) {
size_t i = 0;
while (l[i] == r[i] && r[i]) ++i;
return (l[i] & 255) - (r[i] & 255);
}
forceinline char *__stpcpy(char *d, const char *s) { forceinline char *__stpcpy(char *d, const char *s) {
size_t i; size_t i;
for (i = 0;; ++i) { for (i = 0;; ++i) {
@ -63,6 +121,13 @@ forceinline char *__stpcpy(char *d, const char *s) {
} }
} }
forceinline void *__repstosb(void *di, char al, size_t cx) {
asm("rep stosb"
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
: "0"(di), "1"(cx), "a"(al));
return di;
}
forceinline void *__repmovsb(void *di, void *si, size_t cx) { forceinline void *__repmovsb(void *di, void *si, size_t cx) {
asm("rep movsb" asm("rep movsb"
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di) : "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
@ -112,7 +177,64 @@ forceinline char *__hexcpy(char p[hasatleast 17], uint64_t x) {
return __fixcpy(p, x, ROUNDUP(x ? bsrl(x) + 1 : 1, 4)); return __fixcpy(p, x, ROUNDUP(x ? bsrl(x) + 1 : 1, 4));
} }
void __printf(const char *, ...); forceinline const void *__memchr(const void *s, unsigned char c, size_t n) {
size_t i;
for (i = 0; i < n; ++i) {
if (((const unsigned char *)s)[i] == c) {
return (const unsigned char *)s + i;
}
}
return 0;
}
forceinline char *__strstr(const char *haystack, const char *needle) {
size_t i;
for (;;) {
for (i = 0;; ++i) {
if (!needle[i]) return (/*unconst*/ char *)haystack;
if (!haystack[i]) break;
if (needle[i] != haystack[i]) break;
}
if (!*haystack++) break;
}
return 0;
}
forceinline char *__getenv(char **p, const char *s) {
size_t i, j;
if (p) {
for (i = 0; p[i]; ++i) {
for (j = 0;; ++j) {
if (!s[j]) {
if (p[i][j] == '=') {
return p[i] + j + 1;
}
break;
}
if (s[j] != p[i][j]) {
break;
}
}
}
}
return 0;
}
forceinline unsigned long __atoul(const char *p) {
int c;
unsigned long x = 0;
while ('0' <= (c = *p++) && c <= '9') x *= 10, x += c - '0';
return x;
}
forceinline long __atol(const char *p) {
int s = *p;
unsigned long x;
if (s == '-' || s == '+') ++p;
x = __atoul(p);
if (s == '-') x = -x;
return x;
}
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -55,8 +55,8 @@ bool32 IsDebuggerPresent(bool);
bool IsRunningUnderMake(void); bool IsRunningUnderMake(void);
const char *GetSiCodeName(int, int); const char *GetSiCodeName(int, int);
void AppendResourceReport(char **, struct rusage *, const char *); void AppendResourceReport(char **, struct rusage *, const char *);
char *GetSymbolByAddr(int64_t); char *__get_symbol_by_addr(int64_t);
void PrintGarbage(FILE *); void PrintGarbage(void);
void PrintGarbageNumeric(FILE *); void PrintGarbageNumeric(FILE *);
#define showcrashreports() ShowCrashReports() #define showcrashreports() ShowCrashReports()
@ -75,15 +75,15 @@ extern unsigned __log_level; /* log level for runtime check */
// log a message with the specified log level (not checking if LOGGABLE) // log a message with the specified log level (not checking if LOGGABLE)
#define LOGF(LEVEL, FMT, ...) \ #define LOGF(LEVEL, FMT, ...) \
do { \ do { \
++ftrace; \ ++g_ftrace; \
flogf(LEVEL, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ flogf(LEVEL, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \ --g_ftrace; \
} while (0) } while (0)
// die with an error message without backtrace and debugger invocation // die with an error message without backtrace and debugger invocation
#define DIEF(FMT, ...) \ #define DIEF(FMT, ...) \
do { \ do { \
++ftrace; \ ++g_ftrace; \
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
exit(1); \ exit(1); \
unreachable; \ unreachable; \
@ -91,7 +91,7 @@ extern unsigned __log_level; /* log level for runtime check */
#define FATALF(FMT, ...) \ #define FATALF(FMT, ...) \
do { \ do { \
++ftrace; \ ++g_ftrace; \
ffatalf(kLogFatal, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ ffatalf(kLogFatal, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
unreachable; \ unreachable; \
} while (0) } while (0)
@ -99,78 +99,78 @@ extern unsigned __log_level; /* log level for runtime check */
#define ERRORF(FMT, ...) \ #define ERRORF(FMT, ...) \
do { \ do { \
if (LOGGABLE(kLogError)) { \ if (LOGGABLE(kLogError)) { \
++ftrace; \ ++g_ftrace; \
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \ --g_ftrace; \
} \ } \
} while (0) } while (0)
#define WARNF(FMT, ...) \ #define WARNF(FMT, ...) \
do { \ do { \
if (LOGGABLE(kLogWarn)) { \ if (LOGGABLE(kLogWarn)) { \
++ftrace; \ ++g_ftrace; \
flogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ flogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \ --g_ftrace; \
} \ } \
} while (0) } while (0)
#define INFOF(FMT, ...) \ #define INFOF(FMT, ...) \
do { \ do { \
if (LOGGABLE(kLogInfo)) { \ if (LOGGABLE(kLogInfo)) { \
++ftrace; \ ++g_ftrace; \
flogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ flogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \ --g_ftrace; \
} \ } \
} while (0) } while (0)
#define VERBOSEF(FMT, ...) \ #define VERBOSEF(FMT, ...) \
do { \ do { \
if (LOGGABLE(kLogVerbose)) { \ if (LOGGABLE(kLogVerbose)) { \
++ftrace; \ ++g_ftrace; \
fverbosef(kLogVerbose, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ fverbosef(kLogVerbose, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \ --g_ftrace; \
} \ } \
} while (0) } while (0)
#define DEBUGF(FMT, ...) \ #define DEBUGF(FMT, ...) \
do { \ do { \
if (UNLIKELY(LOGGABLE(kLogDebug))) { \ if (UNLIKELY(LOGGABLE(kLogDebug))) { \
++ftrace; \ ++g_ftrace; \
fdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ fdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \ --g_ftrace; \
} \ } \
} while (0) } while (0)
#define NOISEF(FMT, ...) \ #define NOISEF(FMT, ...) \
do { \ do { \
if (UNLIKELY(LOGGABLE(kLogNoise))) { \ if (UNLIKELY(LOGGABLE(kLogNoise))) { \
++ftrace; \ ++g_ftrace; \
fnoisef(kLogNoise, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ fnoisef(kLogNoise, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--ftrace; \ --g_ftrace; \
} \ } \
} while (0) } while (0)
#define FLOGF(F, FMT, ...) \ #define FLOGF(F, FMT, ...) \
do { \ do { \
if (LOGGABLE(kLogInfo)) { \ if (LOGGABLE(kLogInfo)) { \
++ftrace; \ ++g_ftrace; \
flogf(kLogInfo, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ flogf(kLogInfo, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
--ftrace; \ --g_ftrace; \
} \ } \
} while (0) } while (0)
#define FWARNF(F, FMT, ...) \ #define FWARNF(F, FMT, ...) \
do { \ do { \
if (LOGGABLE(kLogWarn)) { \ if (LOGGABLE(kLogWarn)) { \
++ftrace; \ ++g_ftrace; \
flogf(kLogWarn, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ flogf(kLogWarn, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
--ftrace; \ --g_ftrace; \
} \ } \
} while (0) } while (0)
#define FFATALF(F, FMT, ...) \ #define FFATALF(F, FMT, ...) \
do { \ do { \
++ftrace; \ ++g_ftrace; \
ffatalf(kLogFatal, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ ffatalf(kLogFatal, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
unreachable; \ unreachable; \
} while (0) } while (0)
@ -178,18 +178,18 @@ extern unsigned __log_level; /* log level for runtime check */
#define FDEBUGF(F, FMT, ...) \ #define FDEBUGF(F, FMT, ...) \
do { \ do { \
if (UNLIKELY(LOGGABLE(kLogDebug))) { \ if (UNLIKELY(LOGGABLE(kLogDebug))) { \
++ftrace; \ ++g_ftrace; \
fdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ fdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
--ftrace; \ --g_ftrace; \
} \ } \
} while (0) } while (0)
#define FNOISEF(F, FMT, ...) \ #define FNOISEF(F, FMT, ...) \
do { \ do { \
if (UNLIKELY(LOGGABLE(kLogNoise))) { \ if (UNLIKELY(LOGGABLE(kLogNoise))) { \
++ftrace; \ ++g_ftrace; \
fnoisef(kLogNoise, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ fnoisef(kLogNoise, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
--ftrace; \ --g_ftrace; \
} \ } \
} while (0) } while (0)
@ -201,9 +201,9 @@ extern unsigned __log_level; /* log level for runtime check */
({ \ ({ \
autotype(FORM) Ax = (FORM); \ autotype(FORM) Ax = (FORM); \
if (UNLIKELY(Ax == (typeof(Ax))(-1)) && LOGGABLE(kLogWarn)) { \ if (UNLIKELY(Ax == (typeof(Ax))(-1)) && LOGGABLE(kLogWarn)) { \
++ftrace; \ ++g_ftrace; \
__logerrno(__FILE__, __LINE__, #FORM); \ __logerrno(__FILE__, __LINE__, #FORM); \
--ftrace; \ --g_ftrace; \
} \ } \
Ax; \ Ax; \
}) })
@ -212,9 +212,9 @@ extern unsigned __log_level; /* log level for runtime check */
({ \ ({ \
autotype(FORM) Ax = (FORM); \ autotype(FORM) Ax = (FORM); \
if (Ax == NULL && LOGGABLE(kLogWarn)) { \ if (Ax == NULL && LOGGABLE(kLogWarn)) { \
++ftrace; \ ++g_ftrace; \
__logerrno(__FILE__, __LINE__, #FORM); \ __logerrno(__FILE__, __LINE__, #FORM); \
--ftrace; \ --g_ftrace; \
} \ } \
Ax; \ Ax; \
}) })

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/sigbits.h" #include "libc/calls/sigbits.h"
@ -44,6 +45,7 @@
#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/pc.internal.h" #include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/fileno.h"
@ -94,20 +96,23 @@ relegated static const char *TinyStrSignal(int sig) {
return "???"; return "???";
} }
relegated static void ShowFunctionCalls(int fd, ucontext_t *ctx) { relegated static void ShowFunctionCalls(ucontext_t *ctx) {
struct StackFrame *bp; struct StackFrame *bp;
struct StackFrame goodframe; struct StackFrame goodframe;
write(fd, "\n", 1); if (ctx->uc_mcontext.rip && ctx->uc_mcontext.rbp) {
if (ctx && ctx->uc_mcontext.rip && ctx->uc_mcontext.rbp) {
goodframe.next = (struct StackFrame *)ctx->uc_mcontext.rbp; goodframe.next = (struct StackFrame *)ctx->uc_mcontext.rbp;
goodframe.addr = ctx->uc_mcontext.rip; goodframe.addr = ctx->uc_mcontext.rip;
bp = &goodframe; bp = &goodframe;
ShowBacktrace(fd, bp); ShowBacktrace(2, bp);
} }
} }
relegated static char *AddFlag(char *p, int b, const char *s) { relegated static char *AddFlag(char *p, int b, const char *s) {
if (b) p = stpcpy(p, s); if (b) {
p = __stpcpy(p, s);
} else {
*p = 0;
}
return p; return p;
} }
@ -137,11 +142,13 @@ relegated static char *DescribeCpuFlags(char *p, int flags, int x87sw,
return p; return p;
} }
relegated static char *ShowGeneralRegisters(char *p, ucontext_t *ctx) { relegated static void ShowGeneralRegisters(ucontext_t *ctx) {
int64_t x; int64_t x;
const char *s; const char *s;
size_t i, j, k; size_t i, j, k;
long double st; long double st;
char *p, buf[128];
p = buf;
*p++ = '\n'; *p++ = '\n';
for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) { for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) {
if (j > 0) *p++ = ' '; if (j > 0) *p++ = ' ';
@ -162,20 +169,25 @@ relegated static char *ShowGeneralRegisters(char *p, ucontext_t *ctx) {
if (x < 0) x = -x, *p++ = '-'; if (x < 0) x = -x, *p++ = '-';
p = __uintcpy(p, x / 1000), *p++ = '.'; p = __uintcpy(p, x / 1000), *p++ = '.';
p = __uintcpy(p, x % 1000), *p++ = '\n'; p = __uintcpy(p, x % 1000), *p++ = '\n';
*p = 0;
__printf("%s", buf);
p = buf;
} }
} }
return DescribeCpuFlags( DescribeCpuFlags(
p, ctx->uc_mcontext.gregs[REG_EFL], p, ctx->uc_mcontext.gregs[REG_EFL],
ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->swd : 0, ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->swd : 0,
ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->mxcsr : 0); ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->mxcsr : 0);
__printf("%s\n", buf);
} }
relegated static char *ShowSseRegisters(char *p, ucontext_t *ctx) { relegated static void ShowSseRegisters(ucontext_t *ctx) {
size_t i; size_t i;
char *p, buf[128];
if (ctx->uc_mcontext.fpregs) { if (ctx->uc_mcontext.fpregs) {
p = __stpcpy(p, "\n\n"); __printf("\n");
for (i = 0; i < 8; ++i) { for (i = 0; i < 8; ++i) {
p = __stpcpy(p, "XMM"); p = buf;
if (i >= 10) { if (i >= 10) {
*p++ = i / 10 + '0'; *p++ = i / 10 + '0';
*p++ = i % 10 + '0'; *p++ = i % 10 + '0';
@ -197,93 +209,61 @@ relegated static char *ShowSseRegisters(char *p, ucontext_t *ctx) {
*p++ = ' '; *p++ = ' ';
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[1], 64); p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[1], 64);
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[0], 64); p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[0], 64);
*p++ = '\n'; *p = 0;
__printf("XMM%s\n", buf);
} }
} }
return p;
}
relegated static void ShowMemoryMappings(int outfd) {
ssize_t rc;
int c, infd;
char buf[64];
if (!IsTiny()) {
PrintMemoryIntervals(outfd, &_mmi);
if ((infd = open("/proc/self/maps", O_RDONLY)) != -1) {
while ((rc = read(infd, buf, sizeof(buf))) > 0) {
__write(buf, rc);
}
}
close(infd);
}
} }
void ShowCrashReportHook(int, int, int, struct siginfo *, ucontext_t *); void ShowCrashReportHook(int, int, int, struct siginfo *, ucontext_t *);
relegated void ShowCrashReport(int err, int fd, int sig, struct siginfo *si, relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
ucontext_t *ctx) { ucontext_t *ctx) {
int i; int i;
char *p; char *p;
bool colorful; char host[64];
char hostname[64]; intptr_t stackaddr;
struct utsname names; struct utsname names;
static char buf[4096]; static char buf[4096];
if (weaken(ShowCrashReportHook)) { if (weaken(ShowCrashReportHook)) {
ShowCrashReportHook(err, fd, sig, si, ctx); ShowCrashReportHook(2, err, sig, si, ctx);
} }
colorful = cancolor(); __stpcpy(host, "unknown");
__stpcpy(hostname, "unknown"); gethostname(host, sizeof(host));
gethostname(hostname, sizeof(hostname));
p = buf; p = buf;
p = __stpcpy(p, "\n"); __printf("\n%serror%s: Uncaught SIG%s",
if (colorful) p = __stpcpy(p, "\e[30;101m"); !g_isterminalinarticulate ? "\e[30;101m" : "",
p = __stpcpy(p, "error"); !g_isterminalinarticulate ? "\e[0m" : "", TinyStrSignal(sig));
if (colorful) p = __stpcpy(p, "\e[0m"); stackaddr = GetStackAddr(0);
p = __stpcpy(p, ": Uncaught SIG"); if (ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) &&
p = __stpcpy(p, TinyStrSignal(sig)); ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE)) {
if (si) { __printf(" (Stack Overflow)");
p = __stpcpy(p, " ("); } else if (si) {
p = __stpcpy(p, GetSiCodeName(sig, si->si_code)); __printf(" (%s)", GetSiCodeName(sig, si->si_code));
p = __stpcpy(p, ")");
} }
p = __stpcpy(p, " on "); __printf(" on %s pid %d\n %s\n %s\n", host, __getpid(),
p = __stpcpy(p, hostname); program_invocation_name, strerror(err));
p = __stpcpy(p, " pid ");
p = __intcpy(p, __getpid());
p = __stpcpy(p, "\n ");
p = __stpcpy(p, program_invocation_name);
p = __stpcpy(p, "\n ");
p = __stpcpy(p, strerror(err));
*p++ = '\n';
if (uname(&names) != -1) { if (uname(&names) != -1) {
p = __stpcpy(p, " "); __printf(" %s %s %s %s\n", names.sysname, names.nodename, names.release,
p = __stpcpy(p, names.sysname), *p++ = ' '; names.version);
p = __stpcpy(p, names.nodename), *p++ = ' ';
p = __stpcpy(p, names.release), *p++ = ' ';
p = __stpcpy(p, names.version), *p++ = '\n';
} }
__write(buf, p - buf);
ShowFunctionCalls(fd, ctx);
if (ctx) { if (ctx) {
p = buf; __printf("\n");
p = ShowGeneralRegisters(p, ctx); ShowFunctionCalls(ctx);
p = ShowSseRegisters(p, ctx); ShowGeneralRegisters(ctx);
*p++ = '\n'; ShowSseRegisters(ctx);
__write(buf, p - buf);
} }
p = buf; __printf("\n");
*p++ = '\n'; PrintMemoryIntervals(2, &_mmi);
ShowMemoryMappings(fd); /* PrintSystemMappings(2); */
__write(buf, p - buf);
if (__argv) { if (__argv) {
for (i = 0; i < __argc; ++i) { for (i = 0; i < __argc; ++i) {
if (!__argv[i]) continue; if (!__argv[i]) continue;
if (IsAsan() && !__asan_is_valid(__argv[i], 1)) continue; if (IsAsan() && !__asan_is_valid(__argv[i], 1)) continue;
__write(__argv[i], strlen(__argv[i])); __printf("%s ", __argv[i]);
__write(" ", 1);
} }
} }
__write("\n", 1); __printf("\n");
} }
relegated static void RestoreDefaultCrashSignalHandlers(void) { relegated static void RestoreDefaultCrashSignalHandlers(void) {
@ -309,29 +289,48 @@ relegated static void RestoreDefaultCrashSignalHandlers(void) {
* *
* This function never returns, except for traps w/ human supervision. * This function never returns, except for traps w/ human supervision.
*/ */
relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) { noasan relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
intptr_t rip; intptr_t rip;
int gdbpid, err; int gdbpid, err;
static bool once; static bool noreentry, notpossible;
err = errno; ++g_ftrace;
if (once) _exit(119);
once = true;
rip = ctx ? ctx->uc_mcontext.rip : 0; rip = ctx ? ctx->uc_mcontext.rip : 0;
if ((gdbpid = IsDebuggerPresent(true))) { if (cmpxchg(&noreentry, false, true)) {
DebugBreak(); err = errno;
} else if (IsTerminalInarticulate() || IsRunningUnderMake()) { if ((gdbpid = IsDebuggerPresent(true))) {
gdbpid = -1; DebugBreak();
} else if (FindDebugBinary()) { } else if (g_isterminalinarticulate || g_isrunningundermake) {
RestoreDefaultCrashSignalHandlers(); gdbpid = -1;
gdbpid = } else if (FindDebugBinary()) {
attachdebugger(((sig == SIGTRAP || sig == SIGQUIT) && RestoreDefaultCrashSignalHandlers();
(rip >= (intptr_t)&_base && rip < (intptr_t)&_etext)) gdbpid =
? rip attachdebugger(((sig == SIGTRAP || sig == SIGQUIT) &&
: 0); (rip >= (intptr_t)&_base && rip < (intptr_t)&_etext))
? rip
: 0);
}
if (!(gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT))) {
__restore_tty(1);
ShowCrashReport(err, sig, si, ctx);
_Exit(128 + sig);
}
} else if (cmpxchg(&notpossible, false, true)) {
__printf("\n"
"\n"
"CRASHED WHILE CRASHING WITH SIG%s\n"
"%s\n"
"RIP %x\n"
"RSP %x\n"
"RBP %x\n"
"\n",
TinyStrSignal(sig), __argv[0], rip, ctx ? ctx->uc_mcontext.rsp : 0,
ctx ? ctx->uc_mcontext.rbp : 0);
_Exit(119);
} else {
for (;;) {
asm("ud2");
}
} }
if (gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT)) return; noreentry = false;
__restore_tty(1); --g_ftrace;
ShowCrashReport(err, STDERR_FILENO, sig, si, ctx);
exit(128 + sig);
unreachable;
} }

View file

@ -16,6 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/fmt.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/nexgen32e/gc.internal.h" #include "libc/nexgen32e/gc.internal.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
@ -24,19 +26,31 @@
/** /**
* Prints list of deferred operations on shadow stack. * Prints list of deferred operations on shadow stack.
*/ */
void PrintGarbage(FILE *f) { void PrintGarbage(void) {
size_t i; size_t i;
f = stderr; char name[19];
fprintf(f, "\n"); const char *symbol;
fprintf(f, " SHADOW STACK @ 0x%016lx\n", __builtin_frame_address(0)); __printf("\n");
fprintf(f, " garbage entry parent frame original ret callback arg \n"); __printf(" SHADOW STACK @ 0x%p\n", __builtin_frame_address(0));
fprintf(f, "-------------- -------------- ------------------ ------------------ ------------------\n"); __printf("garbage entry parent frame original ret callback arg \n");
for (i = __garbage.i; i--;) { __printf("-------------- -------------- ------------------ ------------------ ------------------\n");
fprintf(f, "0x%012lx 0x%012lx %-18s %-18s 0x%016lx\n", if (__garbage.i) {
__garbage.p + i, for (i = __garbage.i; i--;) {
__garbage.p[i].frame, symbol = __get_symbol_by_addr(__garbage.p[i].ret);
GetSymbolByAddr(__garbage.p[i].ret-1), if (symbol) {
GetSymbolByAddr(__garbage.p[i].fn), snprintf(name, sizeof(name), "%s", symbol);
__garbage.p[i].arg); } else {
snprintf(name, sizeof(name), "0x%012lx", __garbage.p[i].ret);
}
__printf("0x%p 0x%p %18s %18s 0x%016lx\n",
__garbage.p + i,
__garbage.p[i].frame,
name,
__get_symbol_by_addr(__garbage.p[i].fn),
__garbage.p[i].arg);
}
} else {
__printf("%14s %14s %18s %18s %18s\n","empty","-","-","-","-");
} }
__printf("\n");
} }

View file

@ -16,22 +16,15 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h" #include "libc/calls/sigbits.h"
#include "libc/calls/termios.h" #include "libc/calls/struct/sigaction.h"
#include "libc/calls/typedef/sigaction_f.h" #include "libc/calls/struct/sigaltstack.h"
#include "libc/dce.h"
#include "libc/log/check.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nt/signals.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/ss.h"
STATIC_YOINK("__die"); STATIC_YOINK("__die");
@ -57,6 +50,7 @@ extern const unsigned char __oncrash_thunks[8][11];
void ShowCrashReports(void) { void ShowCrashReports(void) {
size_t i; size_t i;
struct sigaction sa; struct sigaction sa;
struct sigaltstack ss;
/* <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */ /* <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
kCrashSigs[0] = SIGQUIT; /* ctrl+\ aka ctrl+break */ kCrashSigs[0] = SIGQUIT; /* ctrl+\ aka ctrl+break */
kCrashSigs[1] = SIGFPE; /* 1 / 0 */ kCrashSigs[1] = SIGFPE; /* 1 / 0 */
@ -68,11 +62,16 @@ void ShowCrashReports(void) {
kCrashSigs[7] = SIGPIPE; /* write to closed thing */ kCrashSigs[7] = SIGPIPE; /* write to closed thing */
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */ /* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
bzero(&sa, sizeof(sa)); bzero(&sa, sizeof(sa));
sa.sa_flags = SA_RESETHAND | SA_SIGINFO; ss.ss_flags = 0;
ss.ss_size = SIGSTKSZ;
ss.ss_sp = malloc(SIGSTKSZ);
__cxa_atexit(free, ss.ss_sp, 0);
sa.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
sigfillset(&sa.sa_mask); sigfillset(&sa.sa_mask);
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) { for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
sigdelset(&sa.sa_mask, kCrashSigs[i]); sigdelset(&sa.sa_mask, kCrashSigs[i]);
} }
sigaltstack(&ss, 0);
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) { for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
if (kCrashSigs[i]) { if (kCrashSigs[i]) {
sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i]; sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i];

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,18 +16,23 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/errno.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
.source __FILE__ #include "libc/mem/mem.h"
.initbss 202,_init_posix_memalign /**
hook_posix_memalign: * Same as memalign(a, n) but requires IS2POW(a).
.quad 0 *
.endobj hook_posix_memalign,globl,hidden * @param n number of bytes needed
.previous * @return memory address, or NULL w/ errno
* @throw EINVAL if !IS2POW(a)
.init.start 202,_init_posix_memalign * @see pvalloc()
.hidden dlposix_memalign */
ezlea dlposix_memalign,ax void *aligned_alloc(size_t a, size_t n) {
stosq if (IS2POW(a)) {
yoink free return memalign(a, n);
.init.end 202,_init_posix_memalign } else {
errno = EINVAL;
return 0;
}
}

View file

@ -22,37 +22,39 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/arena.h" #include "libc/mem/arena.h"
#include "libc/mem/hook/hook.internal.h" #include "libc/mem/hook/hook.internal.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
#define BASE ((char *)0x30000000) #define BASE 0x50000000
#define LIMIT ((char *)0x50000000) #define SIZE 0x2ffe0000
#define P(i) ((void *)(intptr_t)(i))
#define EXCHANGE(HOOK, SLOT) \ #define EXCHANGE(HOOK, SLOT) \
__arena_hook((intptr_t *)weaken(HOOK), (intptr_t *)(&(SLOT))) __arena_hook((intptr_t *)weaken(HOOK), (intptr_t *)(&(SLOT)))
static struct Arena { static struct Arena {
bool once; bool once;
uint8_t depth; size_t size;
unsigned size; size_t depth;
unsigned offset[16]; size_t offset[16];
void (*free)(void *); void (*free)(void *);
void *(*malloc)(size_t); void *(*malloc)(size_t);
void *(*calloc)(size_t, size_t); void *(*calloc)(size_t, size_t);
void *(*memalign)(size_t, size_t); void *(*memalign)(size_t, size_t);
void *(*realloc)(void *, size_t); void *(*realloc)(void *, size_t);
void *(*realloc_in_place)(void *, size_t); void *(*realloc_in_place)(void *, size_t);
void *(*valloc)(size_t);
void *(*pvalloc)(size_t);
int (*malloc_trim)(size_t);
size_t (*malloc_usable_size)(const void *); size_t (*malloc_usable_size)(const void *);
size_t (*bulk_free)(void *[], size_t); size_t (*bulk_free)(void *[], size_t);
int (*malloc_trim)(size_t);
} __arena; } __arena;
static wontreturn void __arena_die(void) { static wontreturn void __arena_die(void) {
@ -61,103 +63,202 @@ static wontreturn void __arena_die(void) {
} }
static wontreturn void __arena_not_implemented(void) { static wontreturn void __arena_not_implemented(void) {
__printf("not implemented"); assert(!"not implemented");
__arena_die(); __arena_die();
} }
static void __arena_free(void *p) { forceinline void __arena_check(void) {
if (!p) return;
assert(__arena.depth); assert(__arena.depth);
assert((intptr_t)BASE + __arena.offset[__arena.depth - 1] <= (intptr_t)p && }
(intptr_t)p < (intptr_t)BASE + __arena.offset[__arena.depth]);
forceinline void __arena_check_pointer(void *p) {
assert(BASE + __arena.offset[__arena.depth - 1] <= (uintptr_t)p &&
(uintptr_t)p < BASE + __arena.offset[__arena.depth]);
}
forceinline bool __arena_is_arena_pointer(void *p) {
return BASE <= (uintptr_t)p && (uintptr_t)p < BASE + SIZE;
}
forceinline size_t __arena_get_size(void *p) {
return *(const size_t *)((const char *)p - sizeof(size_t));
}
static void __arena_free(void *p) {
__arena_check();
if (p) {
__arena_check_pointer(p);
if (!(BASE <= (uintptr_t)p && (uintptr_t)p < BASE + SIZE)) {
__arena.free(p);
}
}
} }
static size_t __arena_bulk_free(void *p[], size_t n) { static size_t __arena_bulk_free(void *p[], size_t n) {
size_t i; size_t i;
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
if (p[i]) __arena_free(p[i]); __arena_free(p[i]);
p[i] = 0;
} }
bzero(p, n * sizeof(void *)); return 0;
}
static noinline bool __arena_grow(size_t offset, size_t request) {
size_t greed;
greed = __arena.size + 1;
do {
greed += greed >> 1;
greed = ROUNDUP(greed, FRAMESIZE);
} while (greed < offset + request);
if (greed <= SIZE) {
if (mmap(P(BASE + __arena.size), greed - __arena.size,
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
-1, 0) != MAP_FAILED) {
__arena.size = greed;
return true;
}
} else {
enomem();
}
if (weaken(__oom_hook)) {
weaken(__oom_hook)(request);
}
return false;
}
static void *__arena_alloc(size_t a, size_t n) {
size_t o;
if (!n) n = 1;
o = ROUNDUP(__arena.offset[__arena.depth] + sizeof(size_t), a);
if (o + n >= n) {
if (n <= sizeof(size_t)) {
n = sizeof(size_t);
} else {
n = ROUNDUP(n, sizeof(size_t));
}
if (o + n <= SIZE) {
if (UNLIKELY(o + n > __arena.size)) {
if (!__arena_grow(o, n)) return 0;
}
__arena.offset[__arena.depth] = o + n;
*(size_t *)(BASE + o - sizeof(size_t)) = n;
return (void *)(BASE + o);
}
}
enomem();
return 0; return 0;
} }
static void *__arena_malloc(size_t n) { static void *__arena_malloc(size_t n) {
char *ptr; __arena_check();
size_t need, greed; return __arena_alloc(16, n);
assert(__arena.depth); }
if (!n) n = 1;
if (n < LIMIT - BASE) { static void *__arena_calloc(size_t n, size_t z) {
need = __arena.offset[__arena.depth] + n; __arena_check();
need = ROUNDUP(need, __BIGGEST_ALIGNMENT__); if (__builtin_mul_overflow(n, z, &n)) n = -1;
if (UNLIKELY(need > __arena.size)) { return __arena_alloc(16, n);
greed = __arena.size + 1; }
do {
greed += greed >> 1; static void *__arena_memalign(size_t a, size_t n) {
greed = ROUNDUP(greed, FRAMESIZE); __arena_check();
} while (need > greed); if (a <= sizeof(size_t)) {
if (greed < LIMIT - BASE && return __arena_alloc(8, n);
mmap(BASE + __arena.size, greed - __arena.size, } else {
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, return __arena_alloc(2ul << bsrl(a - 1), n);
-1, 0) != MAP_FAILED) { }
__arena.size = greed; }
static size_t __arena_malloc_usable_size(const void *p) {
__arena_check();
__arena_check_pointer(p);
if (__arena_is_arena_pointer(p)) {
return __arena_get_size(p);
} else {
return __arena.malloc_usable_size(p);
}
}
static void *__arena_realloc(void *p, size_t n) {
char *q;
size_t m, o, z;
__arena_check();
if (p) {
__arena_check_pointer(p);
if (__arena_is_arena_pointer(p)) {
if (n) {
if ((m = __arena_get_size(p)) >= n) {
return p;
} else if (n <= SIZE) {
z = 2ul << bsrl(n - 1);
if (__arena.offset[__arena.depth] - m == (o = (intptr_t)p - BASE)) {
if (UNLIKELY(o + z > __arena.size)) {
if (o + z <= SIZE) {
if (!__arena_grow(o, z)) {
return 0;
}
} else {
enomem();
return 0;
}
}
__arena.offset[__arena.depth] = o + z;
*(size_t *)((char *)p - sizeof(size_t)) = z;
return p;
} else if ((q = __arena_alloc(1ul << bsfl((intptr_t)p), z))) {
memmove(q, p, m);
return q;
} else {
return 0;
}
} else {
enomem();
return 0;
}
} else { } else {
return 0; return 0;
} }
} else {
return __arena.realloc(p, n);
}
} else {
if (n <= 16) {
n = 16;
} else {
n = 2ul << bsrl(n - 1);
}
return __arena_alloc(16, n);
}
}
static void *__arena_realloc_in_place(void *p, size_t n) {
char *q;
size_t m, z;
__arena_check();
if (p) {
__arena_check_pointer(p);
if (__arena_is_arena_pointer(p)) {
if (n) {
if ((m = __arena_get_size(p)) >= n) {
return p;
} else {
return 0;
}
} else {
return 0;
}
} else {
return __arena.realloc_in_place(p, n);
} }
ptr = BASE + __arena.offset[__arena.depth];
__arena.offset[__arena.depth] = need;
return ptr;
} else { } else {
return 0; return 0;
} }
} }
static void *__arena_calloc(size_t n, size_t z) {
if (__builtin_mul_overflow(n, z, &n)) n = -1;
return __arena_malloc(n);
}
static void *__arena_memalign(size_t a, size_t n) {
if (a <= __BIGGEST_ALIGNMENT__) {
return __arena_malloc(n);
} else {
__arena_not_implemented();
}
}
static void *__arena_realloc(void *p, size_t n) {
if (p) {
if (n) {
__arena_not_implemented();
} else {
__arena_free(p);
return 0;
}
} else {
return __arena_malloc(n);
}
}
static int __arena_malloc_trim(size_t n) { static int __arena_malloc_trim(size_t n) {
return 0; return 0;
} }
static void *__arena_realloc_in_place(void *p, size_t n) {
__arena_not_implemented();
}
static void *__arena_valloc(size_t n) {
__arena_not_implemented();
}
static void *__arena_pvalloc(size_t n) {
__arena_not_implemented();
}
static size_t __arena_malloc_usable_size(const void *p) {
__arena_not_implemented();
}
static void __arena_hook(intptr_t *h, intptr_t *f) { static void __arena_hook(intptr_t *h, intptr_t *f) {
intptr_t t; intptr_t t;
if (h) { if (h) {
@ -169,42 +270,32 @@ static void __arena_hook(intptr_t *h, intptr_t *f) {
static void __arena_install(void) { static void __arena_install(void) {
EXCHANGE(hook_free, __arena.free); EXCHANGE(hook_free, __arena.free);
EXCHANGE(hook_realloc, __arena.realloc);
EXCHANGE(hook_realloc, __arena.realloc);
EXCHANGE(hook_malloc, __arena.malloc); EXCHANGE(hook_malloc, __arena.malloc);
EXCHANGE(hook_calloc, __arena.calloc); EXCHANGE(hook_calloc, __arena.calloc);
EXCHANGE(hook_realloc, __arena.realloc);
EXCHANGE(hook_memalign, __arena.memalign); EXCHANGE(hook_memalign, __arena.memalign);
EXCHANGE(hook_realloc_in_place, __arena.realloc_in_place);
EXCHANGE(hook_valloc, __arena.valloc);
EXCHANGE(hook_pvalloc, __arena.pvalloc);
EXCHANGE(hook_malloc_trim, __arena.malloc_trim);
EXCHANGE(hook_malloc_usable_size, __arena.malloc_usable_size);
EXCHANGE(hook_bulk_free, __arena.bulk_free); EXCHANGE(hook_bulk_free, __arena.bulk_free);
EXCHANGE(hook_malloc_trim, __arena.malloc_trim);
EXCHANGE(hook_realloc_in_place, __arena.realloc_in_place);
EXCHANGE(hook_malloc_usable_size, __arena.malloc_usable_size);
} }
static void __arena_destroy(void) { static void __arena_destroy(void) {
if (__arena.depth) { if (__arena.depth) __arena_install();
__arena_install(); if (__arena.size) munmap(P(BASE), __arena.size);
}
if (__arena.size) {
munmap(BASE, __arena.size);
}
bzero(&__arena, sizeof(__arena)); bzero(&__arena, sizeof(__arena));
} }
static void __arena_init(void) { static void __arena_init(void) {
__arena.free = __arena_free; __arena.free = __arena_free;
__arena.realloc = __arena_realloc;
__arena.realloc = __arena_realloc;
__arena.malloc = __arena_malloc; __arena.malloc = __arena_malloc;
__arena.calloc = __arena_calloc; __arena.calloc = __arena_calloc;
__arena.realloc = __arena_realloc;
__arena.memalign = __arena_memalign; __arena.memalign = __arena_memalign;
__arena.realloc_in_place = __arena_realloc_in_place;
__arena.valloc = __arena_valloc;
__arena.pvalloc = __arena_pvalloc;
__arena.malloc_trim = __arena_malloc_trim;
__arena.malloc_usable_size = __arena_malloc_usable_size;
__arena.bulk_free = __arena_bulk_free; __arena.bulk_free = __arena_bulk_free;
__arena.malloc_trim = __arena_malloc_trim;
__arena.realloc_in_place = __arena_realloc_in_place;
__arena.malloc_usable_size = __arena_malloc_usable_size;
atexit(__arena_destroy); atexit(__arena_destroy);
} }
@ -215,24 +306,27 @@ void __arena_push(void) {
} }
if (!__arena.depth) { if (!__arena.depth) {
__arena_install(); __arena_install();
} else if (__arena.depth == ARRAYLEN(__arena.offset) - 1) { } else {
__printf("too many arenas"); assert(__arena.depth < ARRAYLEN(__arena.offset) - 1);
__arena_die();
} }
__arena.offset[__arena.depth + 1] = __arena.offset[__arena.depth]; __arena.offset[__arena.depth + 1] = __arena.offset[__arena.depth];
++__arena.depth; ++__arena.depth;
} }
void __arena_pop(void) { void __arena_pop(void) {
unsigned greed; size_t a, b, greed;
assert(__arena.depth); __arena_check();
bzero(BASE + __arena.offset[__arena.depth - 1],
__arena.offset[__arena.depth] - __arena.offset[__arena.depth - 1]);
if (!--__arena.depth) __arena_install(); if (!--__arena.depth) __arena_install();
greed = __arena.offset[__arena.depth]; a = __arena.offset[__arena.depth];
b = __arena.offset[__arena.depth + 1];
greed = a;
greed += FRAMESIZE; greed += FRAMESIZE;
greed <<= 1; greed <<= 1;
if (__arena.size > greed) { if (__arena.size > greed) {
munmap(BASE + greed, __arena.size - greed); munmap(P(BASE + greed), __arena.size - greed);
__arena.size = greed;
b = MIN(b, greed);
a = MIN(b, a);
} }
bzero(P(BASE + a), b - a);
} }

View file

@ -19,6 +19,8 @@
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/buffer.h" #include "libc/runtime/buffer.h"
/* TODO(jart): delete */
#define kGuard PAGESIZE #define kGuard PAGESIZE
#define kGrain FRAMESIZE #define kGrain FRAMESIZE

View file

@ -18,11 +18,13 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/bits/likely.h" #include "libc/bits/likely.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nexgen32e/gc.internal.h" #include "libc/nexgen32e/gc.internal.h"
#include "libc/runtime/gc.internal.h" #include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h"
forceinline bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame, forceinline bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame,
struct StackFrame *parent, struct StackFrame *parent,
@ -31,14 +33,28 @@ forceinline bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame,
((intptr_t)ptr < (intptr_t)parent)); ((intptr_t)ptr < (intptr_t)parent));
} }
static void __garbage_destroy(void) {
if (weaken(free)) {
weaken(free)(__garbage.p);
}
bzero(&__garbage, sizeof(__garbage));
}
void __deferer(struct StackFrame *frame, void *fn, void *arg) { void __deferer(struct StackFrame *frame, void *fn, void *arg) {
size_t n2; size_t n2;
struct Garbage *p2; struct Garbage *p2;
if (UNLIKELY(__garbage.i == __garbage.n)) { if (UNLIKELY(__garbage.i == __garbage.n)) {
p2 = __garbage.p;
n2 = __garbage.n + (__garbage.n >> 1); n2 = __garbage.n + (__garbage.n >> 1);
p2 = malloc(n2 * sizeof(*__garbage.p)); if (__garbage.p != __garbage.initmem) {
memcpy(p2, __garbage.p, __garbage.n * sizeof(*__garbage.p)); if (!weaken(realloc)) return;
if (__garbage.p != __garbage.initmem) free(__garbage.p); if (!(p2 = weaken(realloc)(p2, n2 * sizeof(*p2)))) return;
} else {
if (!weaken(malloc)) return;
if (!(p2 = weaken(malloc)(n2 * sizeof(*p2)))) return;
memcpy(p2, __garbage.p, __garbage.n * sizeof(*p2));
atexit(__garbage_destroy);
}
__garbage.p = p2; __garbage.p = p2;
__garbage.n = n2; __garbage.n = n2;
} }
@ -59,11 +75,11 @@ void __deferer(struct StackFrame *frame, void *fn, void *arg) {
* @return arg * @return arg
*/ */
void __defer(struct StackFrame *frame, void *fn, void *arg) { void __defer(struct StackFrame *frame, void *fn, void *arg) {
struct StackFrame *f2; struct StackFrame *f;
if (!arg) return; if (!arg) return;
f2 = __builtin_frame_address(0); f = __builtin_frame_address(0);
assert(__garbage.n); assert(__garbage.n);
assert(f2->next == frame); assert(f->next == frame);
assert(PointerNotOwnedByParentStackFrame(f2, frame, arg)); assert(PointerNotOwnedByParentStackFrame(f, frame, arg));
__deferer(frame, fn, arg); __deferer(frame, fn, arg);
} }

View file

@ -9,8 +9,6 @@ extern void *(*hook_calloc)(size_t, size_t);
extern void *(*hook_memalign)(size_t, size_t); extern void *(*hook_memalign)(size_t, size_t);
extern void *(*hook_realloc)(void *, size_t); extern void *(*hook_realloc)(void *, size_t);
extern void *(*hook_realloc_in_place)(void *, size_t); extern void *(*hook_realloc_in_place)(void *, size_t);
extern void *(*hook_valloc)(size_t);
extern void *(*hook_pvalloc)(size_t);
extern int (*hook_malloc_trim)(size_t); extern int (*hook_malloc_trim)(size_t);
extern size_t (*hook_malloc_usable_size)(const void *); extern size_t (*hook_malloc_usable_size)(const void *);
extern size_t (*hook_bulk_free)(void *[], size_t); extern size_t (*hook_bulk_free)(void *[], size_t);

View file

@ -4,6 +4,7 @@
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
int PutEnvImpl(char *, bool) hidden; int PutEnvImpl(char *, bool) hidden;
void __freeenv(void *) hidden;
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
.source __FILE__
// Allocates uninitialized memory. // Allocates uninitialized memory.
// //
@ -32,9 +31,7 @@
// fail. The maximum supported value of n differs across systems, but is // fail. The maximum supported value of n differs across systems, but is
// in all cases less than the maximum representable value of a size_t. // in all cases less than the maximum representable value of a size_t.
// //
// @param rdi is number of bytes needed // @param rdi is number of bytes needed, coerced to 1+
// @return new memory, or NULL w/ errno // @return new memory, or NULL w/ errno
// @note malloc(0) → malloc(32)
// @see dlmalloc()
malloc: jmp *hook_malloc(%rip) malloc: jmp *hook_malloc(%rip)
.endfn malloc,globl .endfn malloc,globl

View file

@ -15,15 +15,17 @@ void free(void *) libcesque;
void *malloc(size_t) attributeallocsize((1)) mallocesque; void *malloc(size_t) attributeallocsize((1)) mallocesque;
void *calloc(size_t, size_t) attributeallocsize((1, 2)) mallocesque; void *calloc(size_t, size_t) attributeallocsize((1, 2)) mallocesque;
void *memalign(size_t, size_t) attributeallocalign((1)) void *memalign(size_t, size_t) attributeallocalign((1))
attributeallocsize((2)) mallocesque; attributeallocsize((2)) returnspointerwithnoaliases libcesque nodiscard;
void *realloc(void *, size_t) reallocesque; void *realloc(void *, size_t) reallocesque;
void *realloc_in_place(void *, size_t); void *realloc_in_place(void *, size_t) reallocesque;
void *reallocarray(void *, size_t, size_t) nodiscard; void *reallocarray(void *, size_t, size_t) nodiscard;
void *valloc(size_t) attributeallocsize((1)) vallocesque; void *valloc(size_t) attributeallocsize((1)) vallocesque;
void *pvalloc(size_t) attributeallocsize((1)) mallocesque; void *pvalloc(size_t) vallocesque;
char *strdup(const char *) paramsnonnull() mallocesque; char *strdup(const char *) paramsnonnull() mallocesque;
char *strndup(const char *, size_t) paramsnonnull() mallocesque; char *strndup(const char *, size_t) paramsnonnull() mallocesque;
int posix_memalign(void **, size_t, size_t); /* wut */ void *aligned_alloc(size_t, size_t) attributeallocsize((1))
attributeallocsize((2)) returnspointerwithnoaliases libcesque nodiscard;
int posix_memalign(void **, size_t, size_t);
bool __grow(void *, size_t *, size_t, size_t) paramsnonnull((1, 2)) libcesque; bool __grow(void *, size_t *, size_t, size_t) paramsnonnull((1, 2)) libcesque;
int malloc_trim(size_t); int malloc_trim(size_t);

View file

@ -18,22 +18,18 @@
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/notice.inc" #include "libc/notice.inc"
.source __FILE__
// Allocates aligned memory. // Allocates aligned memory.
// //
// Returns a pointer to a newly allocated chunk of n bytes, aligned in // Returns a pointer to a newly allocated chunk of n bytes, aligned in
// accord with the alignment argument. The alignment argument should be // accord with the alignment argument. The alignment argument shall be
// a power of two. If the argument is not a power of two, the nearest // rounded up to the nearest two power and higher 2 powers may be used
// greater power is used. 8-byte alignment is guaranteed by normal // if the allocator imposes a minimum alignment requirement.
// malloc calls, so don't bother calling memalign with an argument of 8
// or less.
// //
// @param rdi is alignment in bytes // @param rdi is alignment in bytes, coerced to 1+ w/ 2-power roundup
// @param rsi (newsize) is number of bytes needed // @param rsi is number of bytes needed, coerced to 1+
// @return rax is memory address, or NULL w/ errno // @return rax is memory address, or NULL w/ errno
// @note overreliance on memalign is a sure way to fragment space // @see valloc(), pvalloc()
// @see dlmemalign()
memalign: memalign:
jmp *hook_memalign(%rip) jmp *hook_memalign(%rip)
.endfn memalign,globl .endfn memalign,globl

View file

@ -1,36 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.source __FILE__
// Allocates aligned memory the POSIX way.
//
// Allocates a chunk of n bytes, aligned in accord with the alignment
// argument. Differs from memalign only in that it (1) assigns the
// allocated memory to *pp rather than returning it, (2) fails and
// returns EINVAL if the alignment is not a power of two (3) fails and
// returns ENOMEM if memory cannot be allocated.
//
// @param rdi is void **pp
// @param rsi is size_t align
// @param rdx is size_t size
// @return eax
posix_memalign:
jmp *hook_posix_memalign(%rip)
.endfn posix_memalign,globl

58
libc/mem/posix_memalign.c Normal file
View file

@ -0,0 +1,58 @@
/*-*- 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/errno.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
/**
* Allocates aligned memory, the POSIX way.
*
* Allocates a chunk of n bytes, aligned in accord with the alignment
* argument. Differs from memalign() only in that it:
*
* 1. Assigns the allocated memory to *pp rather than returning it
* 2. Fails and returns EINVAL if the alignment is not a power of two
* 3. Fails and returns ENOMEM if memory cannot be allocated
*
* @param pp receives pointer, only on success
* @param alignment must be 2-power multiple of sizeof(void *)
* @param bytes is number of bytes to allocate
* @return return 0 or EINVAL or ENOMEM w/o setting errno
* @see memalign()
*/
int posix_memalign(void **pp, size_t alignment, size_t bytes) {
int e;
void *m;
size_t q, r;
q = alignment / sizeof(void *);
r = alignment % sizeof(void *);
if (!r && q && IS2POW(q)) {
e = errno;
m = memalign(alignment, bytes);
errno = e;
if (m) {
*pp = m;
return 0;
} else {
return ENOMEM;
}
} else {
return EINVAL;
}
}

View file

@ -43,6 +43,12 @@ static void PutEnvInit(void) {
atexit(PutEnvDestroy); atexit(PutEnvDestroy);
} }
void __freeenv(void *p) {
if (once) {
free(p);
}
}
int PutEnvImpl(char *s, bool overwrite) { int PutEnvImpl(char *s, bool overwrite) {
char *p; char *p;
unsigned i, namelen; unsigned i, namelen;
@ -62,7 +68,10 @@ int PutEnvImpl(char *s, bool overwrite) {
goto replace; goto replace;
} }
} }
if (i + 1 >= MAX_VARS) goto fail; if (i + 1 >= MAX_VARS) {
free(s);
return enomem();
}
environ[i + 1] = NULL; environ[i + 1] = NULL;
replace: replace:
free(environ[i]); free(environ[i]);

View file

@ -1,30 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/notice.inc"
.source __FILE__
// Equivalent to valloc(minimum-page-that-holds(n)), that is,
// round up n to nearest pagesize.
//
// @param rdi is number of bytes needed
// @return rax is memory address, or NULL w/ errno
// @see dlpvalloc()
pvalloc:jmp *hook_pvalloc(%rip)
.endfn pvalloc,globl

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -17,13 +17,15 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/notice.inc" #include "libc/mem/mem.h"
.source __FILE__
// Equivalent to memalign(4096, n). /**
// * Equivalent to memalign(PAGESIZE, ROUNDUP(n, PAGESIZE)).
// @param rdi is number of bytes needed *
// @return rax is memory address, or NULL w/ errno * @param n number of bytes needed
// @see dlvalloc() * @return memory address, or NULL w/ errno
valloc: jmp *hook_valloc(%rip) * @see valloc()
.endfn valloc,globl */
void *pvalloc(size_t n) {
return memalign(PAGESIZE, ROUNDUP(n, PAGESIZE));
}

View file

@ -23,6 +23,5 @@
nodiscard void *unhexstr(const char *hexdigs) { nodiscard void *unhexstr(const char *hexdigs) {
assert(strlen(hexdigs) % 2 == 0); assert(strlen(hexdigs) % 2 == 0);
return unhexbuf(memalign(__BIGGEST_ALIGNMENT__, strlen(hexdigs) / 2), return unhexbuf(malloc(strlen(hexdigs) / 2), strlen(hexdigs) / 2, hexdigs);
strlen(hexdigs) / 2, hexdigs);
} }

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