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:
@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))))
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
$(file >$@,$(SRCS))
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))))
$(file >$@) $(foreach x,$(INCS) $(INCS),$(file >>$@,$(x)))
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
$(file >$@,$(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 $@
@$(COMPILE) -ATAGS -T$@ $(TAGS) $(TAGSFLAGS) -L $< -o $@
HTAGS: o/$(MODE)/hdrs.txt $(HDRS)
HTAGS: o/$(MODE)/hdrs-old.txt $(HDRS)
@rm -f $@
@$(COMPILE) -ATAGS -T$@ build/htags -L $< -o $@
@ -326,14 +321,15 @@ COSMOPOLITAN_HEADERS = \
THIRD_PARTY_ZLIB \
THIRD_PARTY_REGEX
o/$(MODE)/cosmopolitan.a.txt:
printf "%s\n" $(call reverse,$(call uniq,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)))))
o/$(MODE)/cosmopolitan.a: $(filter-out o/libc/stubs/exit11.o,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_A_OBJS)))
o/$(MODE)/cosmopolitan.a: \
$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_A_OBJS))
o/cosmopolitan.h: \
o/$(MODE)/tool/build/rollup.com \
libc/integral/normalize.inc \
$(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/$(MODE)/third_party/chibicc/chibicc.com.dbg \

View file

@ -92,4 +92,4 @@ find o -name \*.com | xargs ls -rShal | less
| FreeBSD | 12 | 2018 |
| OpenBSD | 6.4 | 2018 |
| 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_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_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_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) {
long ax;
long ax, di;
asm volatile("syscall"
: "=a"(ax)
: "0"(__NR_close), "D"(fd)
: "=a"(ax), "=D"(di)
: "0"(__NR_close), "1"(fd)
: "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc");
}
static long Read(int os, long fd, void *data, unsigned long size) {
bool cf;
long ax;
long ax, di, si, dx;
asm volatile("clc\n\t"
"syscall"
: "=@ccc"(cf), "=a"(ax)
: "1"(__NR_read), "D"(fd), "S"(data), "d"(size)
: "=@ccc"(cf), "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
: "1"(__NR_read), "2"(fd), "3"(data), "4"(size)
: "rcx", "r8", "r9", "r10", "r11", "memory");
if (cf) ax = -ax;
return ax;
}
static void Write(int os, long fd, const void *data, unsigned long size) {
long ax;
long ax, di, si, dx;
asm volatile("syscall"
: "=a"(ax)
: "0"(__NR_write), "D"(fd), "S"(data), "d"(size)
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
: "0"(__NR_write), "1"(fd), "2"(data), "3"(size)
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
}
static long Fstat(int os, long fd, union metastat *st) {
long ax;
long ax, di, si;
asm volatile("syscall"
: "=a"(ax)
: "0"(__NR_fstat), "D"(fd), "S"(st)
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory");
: "=a"(ax), "=D"(di), "=S"(si)
: "0"(__NR_fstat), "1"(fd), "2"(st)
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc");
return ax;
}
static void Msyscall(int os, long p, long n) {
long ax;
long ax, di, si;
if (os == OPENBSD) {
asm volatile("syscall"
: "=a"(ax)
: "0"(37), "D"(p), "S"(n)
: "=a"(ax), "=D"(di), "=S"(si)
: "0"(37), "1"(p), "2"(n)
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc");
}
}
static long Open(int os, const char *path, long flags, long mode) {
bool cf;
long ax;
long ax, di, si, dx;
asm volatile("clc\n\t"
"syscall"
: "=@ccc"(cf), "=a"(ax)
: "1"(__NR_open), "D"(path), "S"(flags), "d"(mode)
: "=@ccc"(cf), "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
: "1"(__NR_open), "2"(path), "3"(flags), "4"(mode)
: "rcx", "r8", "r9", "r10", "r11", "memory");
if (cf) ax = -ax;
return ax;

Binary file not shown.

Binary file not shown.

View file

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

View file

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

View file

@ -16,7 +16,6 @@
MAKEFLAGS += --no-builtin-rules
o/%.a: ; @$(COMPILE) -AARCHIVE -T$@ $(AR) $(ARFLAGS) $@ $^
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) $<
@ -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/%.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: %.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: CC = $(CLANG)
o/%.a:
$(file >$@.args,$^)
@$(COMPILE) -AARCHIVE -T$@ $(AR) $(ARFLAGS) $@ @$@.args
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj.com
@$(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) {
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;
ir = r < 48 ? 0 : r < 115 ? 1 : (r - 35) / 40;
ig = g < 48 ? 0 : g < 115 ? 1 : (g - 35) / 40;

View file

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

View file

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

View file

@ -10,6 +10,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/rusage.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/errno.h"
#include "libc/log/check.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
* routines to ash routines using defines.
*/
/* #undef stdout /\* TODO(jart): XXX *\/ */
/* #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 Printf out1fmt
#define INITARGS(argv)
#define setprogname(s)
#define getprogname() commandname
#define setlocate(l, s) 0
#define equal(s1, s2) (strcmp(s1, s2) == 0)
/* #define getenv(p) bltinlookup((p), 0) */
#define isodigit(c) ((c) >= '0' && (c) <= '7')
#define octtobin(c) ((c) - '0')
#define scopy(s1, s2) ((void)strcpy(s2, s1))
#define equal(s1, s2) (!strcmp(s1, s2))
#define isodigit(c) ((c) >= '0' && (c) <= '7')
#define octtobin(c) ((c) - '0')
#define scopy(s1, s2) ((void)strcpy(s2, s1))
#define TRACE(param)
/* #define TRACE(param) \ */
@ -9483,13 +9469,13 @@ static void sigblockall(sigset_t *oldmask) {
{ \
switch ((char *)param - (char *)array) { \
default: \
(void)printf(f, array[0], array[1], func); \
(void)Printf(f, array[0], array[1], func); \
break; \
case sizeof(*param): \
(void)printf(f, array[0], func); \
(void)Printf(f, array[0], func); \
break; \
case 0: \
(void)printf(f, func); \
(void)Printf(f, func); \
break; \
} \
}
@ -10118,7 +10104,7 @@ static int timescmd() {
struct tms buf;
long int clk_tck = sysconf(_SC_CLK_TCK);
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_stime) / clk_tck, (int)(buf.tms_cutime / 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/rusage.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigval.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/sysinfo.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/tms.h"
#include "libc/calls/struct/utsname.h"
#include "libc/calls/typedef/sighandler_t.h"
#include "libc/dce.h"
#include "libc/fmt/pflink.h"
#include "libc/sysv/consts/s.h"
@ -178,7 +178,6 @@ int setreuid(uint32_t, uint32_t);
int setrlimit(int, const struct rlimit *);
int setsid(void);
int setuid(uint32_t);
int sigaction(int, const struct sigaction *, struct sigaction *);
int sigignore(int);
int siginterrupt(int, int);
int sigprocmask(int, const struct sigset *, struct sigset *);
@ -206,7 +205,6 @@ intptr_t syscall(int, ...);
long ptrace(int, int, void *, void *);
long telldir(DIR *);
long times(struct tms *);
sighandler_t signal(int, sighandler_t);
size_t GetFileSize(const char *);
size_t getfiledescriptorsize(int);
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__)
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 vdprintf(FD, FMT, VA) (vdprintf)(FD, PFLINK(FMT), VA)

View file

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

View file

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

View file

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

View file

@ -12,6 +12,7 @@
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/ucontext.h"
#include "libc/dce.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
@ -115,6 +116,7 @@ i32 __sys_fcntl(i32, i32, ...) hidden;
i32 __sys_fstat(i32, void *) hidden;
i32 __sys_fstatat(i32, const char *, void *, i32) 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_pipe2(i32[hasatleast 2], u32) 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_setsid(void) 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_sigqueue(i32, i32, const union sigval) hidden;
i32 sys_sigqueueinfo(i32, const siginfo_t *) hidden;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
@ -25,6 +26,7 @@
#include "libc/nt/runtime.h"
#include "libc/nt/struct/ipadapteraddresses.h"
#include "libc/nt/winsock.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
@ -239,6 +241,7 @@ struct HostAdapterInfoNode *appendHostInfo(
/* Returns -1 in case of failure */
static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) {
static bool once;
struct NtIpAdapterAddresses *aa;
struct NtIpAdapterUnicastAddress *ua;
struct NtIpAdapterPrefix *ap;
@ -270,7 +273,12 @@ static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) {
(ua != NULL) && (count < MAX_UNICAST_ADDR); ++count) {
node = appendHostInfo(node, baseName, aa, &ua, &ap, count);
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?

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/internal.h"
#include "libc/calls/ntmagicpaths.internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/nt/systeminfo.h"
#include "libc/str/oldutf16.internal.h"
#include "libc/str/str.h"
@ -94,7 +95,10 @@ textwindows int __mkntpath2(const char *path,
m = 0;
}
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) {
if (p[i] == '/') {
p[i] = '\\';

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/files.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),
kNtFileNameNormalized | kNtVolumeNameDos);
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'\\';
memcpy(dir + dirlen + 1, file, (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
* @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;
int64_t rc;
uint32_t oldprot;

View file

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

View file

@ -20,6 +20,7 @@
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.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) {
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 {
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;
}

View file

@ -153,8 +153,17 @@ ssize_t readansi(int fd, char *p, size_t n) {
}
break;
case kEsc:
if (0x20 <= c && c <= 0x2f) {
t = kNf;
if (0x20 <= c && c <= 0x2f) { /* Nf */
/*
* 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 */
t = kDone;
} 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) */
t = kStr;
break;
case '\\':
goto Whoopsie;
default:
t = kDone;
break;

View file

@ -20,6 +20,7 @@
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nt/createfile.h"
@ -37,7 +38,9 @@
static textwindows ssize_t sys_readlinkat_nt_error(void) {
uint32_t e;
switch ((e = GetLastError())) {
e = GetLastError();
SYSDEBUG("sys_readlinkat_nt() error %d", e);
switch (e) {
case kNtErrorNotAReparsePoint:
return einval();
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;
char16_t path16[PATH_MAX], *p;
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)) {
mem = 16384;
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;
freeme = 0;
} else {
SYSDEBUG("sys_readlinkat_nt() needs bigger buffer malloc() to be yoinked");
return enomem();
}
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
if ((h = CreateFile(path16, 0, 0, 0, kNtOpenExisting,
kNtFileFlagOpenReparsePoint | kNtFileFlagBackupSemantics,
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)) {
rc = j;
} else {
SYSDEBUG("sys_readlinkat_nt() too many astral codepoints");
rc = enametoolong();
}
} else {
SYSDEBUG("sys_readlinkat_nt() should have kNtIoReparseTagSymlink");
rc = einval();
}
} else {
SYSDEBUG("DeviceIoControl(kNtFsctlGetReparsePoint) failed");
rc = sys_readlinkat_nt_error();
}
CloseHandle(h);
} else {
SYSDEBUG("CreateFile(kNtFileFlagOpenReparsePoint) failed");
rc = sys_readlinkat_nt_error();
}
if (freeme && weaken(free)) {

View file

@ -19,8 +19,11 @@
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -46,14 +49,19 @@
* @asyncsignalsafe
*/
ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
ssize_t bytes;
struct ZiposUri zipname;
if (IsAsan() && !__asan_is_valid(buf, bufsiz)) return efault();
if (weaken(__zipos_notat) && __zipos_notat(dirfd, path) == -1) {
return -1; /* TODO(jart): code me */
}
if (!IsWindows()) {
return sys_readlinkat(dirfd, path, buf, bufsiz);
if ((IsAsan() && !__asan_is_valid(buf, bufsiz)) || (bufsiz && !buf)) {
bytes = efault();
} else if (weaken(__zipos_notat) && __zipos_notat(dirfd, path) == -1) {
SYSDEBUG("TOOD: zipos support for readlinkat");
bytes = enosys(); /* TODO(jart): code me */
} else if (!IsWindows()) {
bytes = sys_readlinkat(dirfd, path, buf, bufsiz);
} 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/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/mem/mem.h"
@ -160,6 +161,7 @@ restart:
if (!check_dir) goto skip_readlink;
}
k = readlink(output, stack, p);
if (k<0) SYSDEBUG("realpath readlink failed %d", (long)errno);
if (k==p) goto toolong;
if (!k) {
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/internal.h"
#include "libc/calls/struct/metasigaltstack.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h"
#include "libc/intrin/repstosb.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
/**
* @fileoverview XNU kernel callback normalization.
@ -45,12 +48,6 @@ struct __darwin_siginfo {
uint64_t __pad[7];
};
struct __darwin_sigaltstack {
void *ss_sp;
uint64_t ss_size;
int32_t ss_flags;
};
struct __darwin_mmst_reg {
char __mmst_reg[10];
char __mmst_rsrv[6];
@ -368,7 +365,7 @@ struct __darwin_mcontext64 {
struct __darwin_ucontext {
int32_t uc_onstack;
uint32_t uc_sigmask;
struct __darwin_sigaltstack uc_stack;
struct sigaltstack_bsd uc_stack;
struct __darwin_ucontext *uc_link;
uint64_t uc_mcsize;
struct __darwin_mcontext64 *uc_mcontext;
@ -387,7 +384,7 @@ noasan static void linuxexceptionstate2xnu(
}
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->rsi = xnuss->__rsi;
mc->rbp = xnuss->__rbp;
@ -401,7 +398,6 @@ noasan static void xnuthreadstate2linux(
mc->gs = xnuss->__gs;
mc->fs = xnuss->__fs;
mc->eflags = xnuss->__rflags;
uc->uc_flags = xnuss->__rflags;
mc->r8 = xnuss->__r8;
mc->r9 = xnuss->__r9;
mc->r10 = xnuss->__r10;
@ -427,7 +423,6 @@ noasan static void linuxthreadstate2xnu(
xnuss->__gs = mc->gs;
xnuss->__fs = mc->fs;
xnuss->__rflags = mc->eflags;
xnuss->__rflags = uc->uc_flags;
xnuss->__r8 = mc->r8;
xnuss->__r9 = mc->r9;
xnuss->__r10 = mc->r10;
@ -484,6 +479,7 @@ noasan void __sigenter_xnu(void *fn, int infostyle, int sig,
if (rva >= kSigactionMinRva) {
repstosb(&g, 0, sizeof(g));
if (xnuctx) {
g.uc.uc_flags = xnuctx->uc_onstack ? SA_ONSTACK : 0;
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_flags = xnuctx->uc_stack.ss_flags;
@ -498,8 +494,7 @@ noasan void __sigenter_xnu(void *fn, int infostyle, int sig,
if (xnuctx->uc_mcsize >=
(sizeof(struct __darwin_x86_exception_state64) +
sizeof(struct __darwin_x86_thread_state64))) {
xnuthreadstate2linux(&g.uc, &g.uc.uc_mcontext,
&xnuctx->uc_mcontext->__ss);
xnuthreadstate2linux(&g.uc.uc_mcontext, &xnuctx->uc_mcontext->__ss);
}
if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) {
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);
struct sigset sa_mask;
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 /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_H_ */

View file

@ -1,6 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct sigaltstack {
void *ss_sp;
@ -10,5 +11,8 @@ struct sigaltstack {
typedef struct sigaltstack stack_t;
int sigaltstack(const struct sigaltstack *, struct sigaltstack *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#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
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/mem/internal.h"
#include "libc/runtime/runtime.h"
/**
@ -29,6 +31,9 @@ int unsetenv(const char *s) {
for (j = 0;; ++j) {
if (!s[j]) {
if (p[i][j] == '=') {
if (weaken(__freeenv)) {
weaken(__freeenv)(p[i]);
}
k = i + 1;
do {
p[k - 1] = p[k];

View file

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

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h"
#include "libc/nt/enum/exceptionhandleractions.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
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/nt/errors.h"
#include "libc/nt/runtime.h"
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h"
/**
@ -29,8 +31,13 @@
* @note this is a code-size saving device
*/
privileged noasan int64_t __winerr(void) {
errno_t e;
if (IsWindows()) {
errno = GetLastError();
e = GetLastError();
if (weaken(__dos2errno)) {
e = weaken(__dos2errno)(e);
}
errno = e;
return -1;
} else {
return enosys();

View file

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

View file

@ -17,7 +17,6 @@ COSMOPOLITAN_C_START_
int abs(int) libcesque pureconst;
long labs(long) libcesque pureconst;
long long llabs(long long) libcesque pureconst;
int llog10(unsigned long) libcesque pureconst;
int atoi(const char *) paramsnonnull() libcesque;
long atol(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 void __fmt_free_dtoa(char **mem) {
if (*mem) {
if (weaken(freedtoa)) {
weaken(freedtoa)(*mem);
}
*mem = 0;
}
}
static int __fmt_atoi(const char **str) {
int i;
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);
unsigned char signbit, log2base;
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;
lasterr = errno;
out = fn ? fn : (void *)missingno;
mem = 0;
while (*format) {
if (*format != '%') {
@ -388,7 +398,8 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
p = "?";
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) {
Format9999:
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);
FormatThatThing:
__fmt_free_dtoa(&mem);
mem = 0;
prec = alt = 0;
flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_SPACE);
goto FormatString;
@ -462,6 +475,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
while (--width >= 0) {
PUT(' ');
}
__fmt_free_dtoa(&mem);
continue;
case 'G':
@ -477,7 +491,9 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
p = "?";
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;
c = se - s;
prec1 = prec;
@ -512,7 +528,8 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
p = "?";
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;
FormatExpo:
if (sgn) sign = '-';
@ -547,6 +564,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
}
PUT(c);
}
__fmt_free_dtoa(&mem);
PUT(d);
if (decpt < 0) {
PUT('-');
@ -721,5 +739,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
break;
}
}
assert(!mem);
return 0;
}

View file

@ -16,6 +16,10 @@ COSMOPOLITAN_C_START_
- uint128toarray_radix10(0x31337, a) l: 93 (27ns) m: 141 (41ns)
- 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 *FormatUint32(char[hasatleast 12], uint32_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/fmts.h"
#include "libc/fmt/internal.h"
#include "libc/limits.h"
#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 char flags) {
unsigned i;
/* pad leading zeros */
if (!(flags & FLAGS_LEFT)) {
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';
}
}
/* handle hash */
if (flags & FLAGS_HASH) {
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';
}
}
if (len < BUFFER_SIZE) {
if (negative) {
buf[len++] = '-';
@ -74,17 +72,14 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
buf[len++] = ' ';
}
}
/* pad spaces up to given width */
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
if (len < width) {
if (__fmt_pad(out, arg, width - len) == -1) return -1;
}
}
reverse(buf, len);
if (out(buf, arg, len) == -1) return -1;
/* append pad spaces up to given width */
if (flags & FLAGS_LEFT) {
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,
uintmax_t value, bool neg, unsigned log2base, unsigned prec,
unsigned width, unsigned flags, const char *alphabet) {
uint64_t u64;
uintmax_t remainder;
unsigned len, count, digit;
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)) {
count = 0;
do {
assert(len < BUFFER_SIZE);
if (!log2base) {
value = __udivmodti4(value, 10, &remainder);
digit = remainder;
if (value <= UINT64_MAX) {
u64 = value;
digit = u64 % 10;
value = u64 / 10;
} else {
value = __udivmodti4(value, 10, &remainder);
digit = remainder;
}
} else {
digit = value;
digit &= (1u << log2base) - 1;
@ -122,6 +123,7 @@ int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
}
buf[len++] = alphabet[digit];
} while (value);
assert(count <= BUFFER_SIZE);
}
return __fmt_ntoa_format(out, arg, buf, len, neg, log2base, prec, width,
flags);

View file

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

View file

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

View file

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

View file

@ -64,7 +64,7 @@
#endif
#define BIGPAGESIZE 0x200000
#define STACKSIZE 0x200000
#define STACKSIZE 0x20000
#define FRAMESIZE 0x10000 /* 8086 */
#define PAGESIZE 0x1000 /* i386+ */
#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_
#define COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
#include "libc/calls/struct/iovec.h"
#include "libc/macros.internal.h"
#define kAsanScale 3
#define kAsanMagic 0x7fff8000
#define kAsanHeapFree -1 /* F */
#define kAsanStackFree -2 /* F */
#define kAsanRelocated -3 /* R */
#define kAsanHeapUnderrun -4 /* U */
#define kAsanHeapOverrun -5 /* O */
#define kAsanGlobalOverrun -6 /* O */
#define kAsanGlobalUnregistered -7 /* G */
#define kAsanStackUnderrun -8 /* U */
#define kAsanStackOverrun -9 /* O */
#define kAsanAllocaUnderrun -10 /* U */
#define kAsanAllocaOverrun -11 /* O */
#define kAsanUnscoped -12 /* S */
#define kAsanUnmapped -13 /* M */
#define kAsanProtected -14 /* P */
#define kAsanStackGuard -15 /* _ */
#define kAsanNullPage -16
#define kAsanScale 3
#define kAsanMagic 0x7fff8000
#define kAsanNullPage -1 /* ∅ 0xff */
#define kAsanProtected -2 /* P 0xfe */
#define kAsanHeapFree -3 /* F 0xfd */
#define kAsanHeapRelocated -4 /* R 0xfc */
#define kAsanAllocaOverrun -5 /* 𝑂 0xfb */
#define kAsanHeapUnderrun -6 /* U 0xfa */
#define kAsanHeapOverrun -7 /* O 0xf9 */
#define kAsanStackUnscoped -8 /* s 0xf8 */
#define kAsanStackOverflow -9 /* ! 0xf7 */
#define kAsanGlobalOrder -10 /* I 0xf6 */
#define kAsanStackFree -11 /* r 0xf5 */
#define kAsanStackPartial -12 /* p 0xf4 */
#define kAsanStackOverrun -13 /* o 0xf3 */
#define kAsanStackMiddle -14 /* m 0xf2 */
#define kAsanStackUnderrun -15 /* u 0xf1 */
#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 UNSHADOW(x) ((void *)(((uintptr_t)(x) + 0x7fff8000) << 3))
#define SHADOW(x) ((signed char *)(((intptr_t)(x) >> kAsanScale) + kAsanMagic))
#define UNSHADOW(x) ((void *)(MAX(0, (intptr_t)(x)-kAsanMagic) << kAsanScale))
typedef void __asan_die_f(void);
struct AsanFault {
char kind;
signed char kind;
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_map_shadow(uintptr_t, size_t);
void __asan_poison(uintptr_t, size_t, int);
bool __asan_is_valid(const void *, size_t);
bool __asan_is_valid_strlist(char *const *);
bool __asan_is_valid_iov(const struct iovec *, int);
struct AsanFault __asan_check(const void *, size_t);
void __asan_report_memory_fault(void *, int, const char *) wontreturn;
void __asan_report(void *, int, const char *, char) wontreturn;
void *__asan_memalign(size_t, size_t);
bool __asan_is_valid(const void *, long) nosideeffect;
bool __asan_is_valid_strlist(char *const *) strlenesque;
bool __asan_is_valid_iov(const struct iovec *, int) nosideeffect;
wint_t __asan_symbolize_access_poison(signed char) pureconst;
const char *__asan_describe_access_poison(signed char) pureconst;
struct AsanFault __asan_check(const void *, long) nosideeffect;
void __asan_free(void *);
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_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_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_ */

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) {
xmm_t v = {0};
if (IsAsan()) __asan_check(p, n);
if (IsAsan()) __asan_verify(p, n);
if (n <= 32) {
*(xmm_t *)(p + n - 16) = 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) {
xmm_t v = {0};
if (IsAsan()) __asan_check(p, n);
if (IsAsan()) __asan_verify(p, n);
if (n <= 32) {
*(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v;
@ -134,11 +134,6 @@ void(bzero)(void *p, size_t n) {
char *b;
uint64_t x;
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));
if (n <= 16) {
if (n >= 8) {
@ -153,6 +148,9 @@ void(bzero)(void *p, size_t n) {
b[--n] = x;
} 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)) {
bzero_avx(b, n);
} else {

View file

@ -20,22 +20,12 @@
#include "libc/bits/weaken.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/runtime/cxaatexit.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
static struct CxaAtexitBlocks {
struct CxaAtexitBlock {
unsigned mask;
struct CxaAtexitBlock *next;
struct CxaAtexit {
void *fp;
void *arg;
void *pred;
} p[ATEXIT_MAX];
} * p, root;
} __cxa_blocks;
STATIC_YOINK("__cxa_finalize");
/**
* Adds global destructor.
@ -52,6 +42,7 @@ static struct CxaAtexitBlocks {
* @note folks have forked libc in past just to unbloat atexit()
*/
noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
/* asan runtime depends on this function */
unsigned i;
struct CxaAtexitBlock *b, *b2;
_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;
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 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,18 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.source __FILE__
#include "libc/runtime/cxaatexit.internal.h"
.initbss 202,_init_pvalloc
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
struct CxaAtexitBlocks __cxa_blocks;

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
* @noreturn
*/
privileged wontreturn void _Exit(int exitcode) {
privileged noinstrument noasan noubsan wontreturn void _Exit(int exitcode) {
if ((!IsWindows() && !IsMetal()) || (IsMetal() && IsGenuineCosmo())) {
asm volatile("syscall"
: /* no outputs */

View file

@ -41,12 +41,27 @@ $(LIBC_INTRIN_A).pkg: \
$(LIBC_INTRIN_A_OBJS) \
$(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/ubsan.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all \
-fno-stack-protector \
-O3
-fno-stack-protector
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: \
OVERRIDE_CFLAGS += \
@ -63,12 +78,18 @@ o//libc/intrin/memmove.o: \
OVERRIDE_CFLAGS += \
-O3
o/tiny/libc/intrin/memcmp.o \
o/tiny/libc/intrin/memmove.o \
o/tiny/libc/intrin/memmove-gcc.asm: \
o/$(MODE)/libc/intrin/bzero.o \
o/$(MODE)/libc/intrin/memcmp.o \
o/$(MODE)/libc/intrin/memmove.o: \
OVERRIDE_CFLAGS += \
-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_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS))
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
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/fmt/conv.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/vendor.internal.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"
#define kBufSize 1024
#define kProcStatus "/proc/self/status"
#define kPid "TracerPid:\t"
static noasan int NtBeingDebugged(void) {
return NtGetPeb()->BeingDebugged;
}
#define kBufSize 1024
#define kPid "TracerPid:\t"
/**
* Determines if gdb, strace, windbg, etc. is controlling process.
* @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;
ssize_t got;
char buf[1024];
res = false;
char *p, buf[1024];
if (!force) {
if (getenv("HEISENDEBUG")) return false;
if (IsGenuineCosmo()) return false;
if (IsGenuineCosmo()) return 0;
if (__getenv(__envp, "HEISENDEBUG")) return 0;
}
if (IsWindows()) {
res = NtBeingDebugged();
} else if (IsLinux()) {
if ((fd = sys_openat(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
if ((got = sys_read(fd, buf, sizeof(buf) - sizeof(kPid))) != -1) {
return NtGetPeb()->BeingDebugged; /* needs noasan */
} else {
res = 0;
if ((fd = __sysv_open("/proc/self/status", O_RDONLY, 0)) >= 0) {
if ((got = __sysv_read(fd, buf, sizeof(buf) - 1)) > 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
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
@ -28,8 +30,9 @@ bool IsRunningUnderMake(void) {
return g_isrunningundermake;
}
textstartup void g_isrunningundermake_init(void) {
g_isrunningundermake = !!getenv("MAKEFLAGS");
textstartup void g_isrunningundermake_init(int argc, char **argv, char **envp,
intptr_t *auxv) {
g_isrunningundermake = !!__getenv(envp, "MAKEFLAGS");
}
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/str/str.h"
#define PMOVMSKB(x) __builtin_ia32_pmovmskb128(x)
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
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;
if (n > 32) {
while (n > 16 + 16) {
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p ==
*(const xmm_t *)q) -
0xffff)) {
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
n -= 16;
p += 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) -
0xffff)) {
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)(p + n - 16) ==
*(const xmm_t *)(q + n - 16)) -
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
if (!(u = PMOVMSKB(*(xmm_t *)(p + n - 16) == *(xmm_t *)(q + n - 16)) ^
0xffff)) {
return 0;
} else {
@ -61,19 +59,13 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
const unsigned char *q,
size_t n) {
uint64_t w;
unsigned u, u0, u1, u2, u3;
unsigned u;
if (n > 32) {
while (n >= 16 + 64) {
u0 = __builtin_ia32_pmovmskb128(
(((const xmm_t *)p)[0] == ((const xmm_t *)q)[0]));
u1 = __builtin_ia32_pmovmskb128(
(((const xmm_t *)p)[1] == ((const xmm_t *)q)[1]));
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;
w = (uint64_t)PMOVMSKB(((xmm_t *)p)[0] == ((xmm_t *)q)[0]) << 000 |
(uint64_t)PMOVMSKB(((xmm_t *)p)[1] == ((xmm_t *)q)[1]) << 020 |
(uint64_t)PMOVMSKB(((xmm_t *)p)[2] == ((xmm_t *)q)[2]) << 040 |
(uint64_t)PMOVMSKB(((xmm_t *)p)[3] == ((xmm_t *)q)[3]) << 060;
if (w == -1) {
n -= 64;
p += 64;
@ -84,9 +76,7 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
}
}
while (n > 16 + 16) {
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p ==
*(const xmm_t *)q) -
0xffff)) {
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
n -= 16;
p += 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) -
0xffff)) {
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)(p + n - 16) ==
*(const xmm_t *)(q + n - 16)) -
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
if (!(u = PMOVMSKB(*(xmm_t *)(p + n - 16) == *(xmm_t *)(q + n - 16)) ^
0xffff)) {
return 0;
} else {

View file

@ -26,9 +26,6 @@
typedef long long xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
asm("memcpy = memmove\n\t"
".globl\tmemcpy");
/**
* Copies memory.
*
@ -120,8 +117,6 @@ void *memmove(void *dst, const void *src, size_t n) {
*d = *s;
}
} else {
if (IsAsan()) __asan_check(d, n);
if (IsAsan()) __asan_check(s, n);
if (d <= s) {
asm("rep movsb"
: "+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;
} while (n >= 32);
} else {
if (IsAsan()) __asan_check(d, n);
if (IsAsan()) __asan_check(s, n);
if (IsAsan()) __asan_verify(d, n);
if (IsAsan()) __asan_verify(s, n);
asm("std\n\t"
"rep movsb\n\t"
"cld"
@ -246,8 +241,8 @@ void *memmove(void *dst, const void *src, size_t n) {
s += i;
n -= i;
} else {
if (IsAsan()) __asan_check(d, n);
if (IsAsan()) __asan_check(s, n);
if (IsAsan()) __asan_verify(d, n);
if (IsAsan()) __asan_verify(s, n);
asm("rep movsb"
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])d)
: "m"(*(char(*)[n])s));
@ -313,3 +308,6 @@ void *memmove(void *dst, const void *src, size_t n) {
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) {
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) {
*(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v;
@ -48,7 +48,7 @@ noasan microarchitecture("avx") static void *memset_avx(char *p, char c,
size_t n) {
char *t;
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) {
*(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v;
@ -140,11 +140,6 @@ void *memset(void *p, int c, size_t n) {
uint32_t u;
uint64_t x;
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 >= 8) {
x = 0x0101010101010101ul * (c & 255);
@ -161,6 +156,9 @@ void *memset(void *p, int c, size_t n) {
} while (n);
}
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)) {
return memset_avx(b, c, n);
} else {

View file

@ -18,7 +18,6 @@
*/
#include "libc/limits.h"
#include "libc/log/libfatal.internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
@ -26,23 +25,25 @@
#include "libc/sysv/consts/nr.h"
/**
* Low-level printf.
* Privileged printf.
*
* This will work without any cosmopolitan runtime support once the
* executable has been loaded into memory.
*/
privileged noasan noinstrument void __printf(const char *fmt, ...) {
long d, ax;
privileged noasan noubsan noinstrument void __printf(const char *fmt, ...) {
/* 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;
uint16_t dx;
const char *s;
const void *s;
uint32_t wrote;
unsigned long x;
unsigned char al;
const char16_t *S;
int i, n, t, w, plus;
char c, f, *p, *e, b[2048];
w = 0;
int i, j, t, cstr;
long d, rax, rdi, rsi, rdx, dot;
char c, *p, *e, pad, bits, base, sign, thou, z[28], b[2048];
p = b;
e = p + sizeof(b);
va_start(va, fmt);
@ -56,98 +57,132 @@ privileged noasan noinstrument void __printf(const char *fmt, ...) {
case '\0':
break;
case '%':
w = 0;
f = ' ';
plus = 0;
n = INT_MAX;
dot = 0;
pad = ' ';
sign = 0;
bits = 0;
thou = 0;
w[0] = 0;
w[1] = SHRT_MAX;
NeedMoar:
switch ((c = *fmt++)) {
case '\0':
break;
case '0':
f = c;
case 'l':
case 'z':
goto NeedMoar;
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;
case '*':
w = va_arg(va, int);
w[dot] = va_arg(va, int);
goto NeedMoar;
case 'd':
d = va_arg(va, long);
ApiAbuse:
if (p + 22 <= e) {
if (d || !plus) {
if (d > 0 && plus) {
*p++ = plus;
}
p = __intcpy(p, d);
x = d;
if (d < 0) {
x = -x;
sign = '-';
}
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;
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':
w = 12;
f = '0';
pad = '0';
w[0] = 12;
w[1] = 12;
/* fallthrough */
case 'x':
x = va_arg(va, unsigned long);
if (x) {
n = __builtin_clzl(x) ^ (sizeof(long) * 8 - 1);
n >>= 2;
n += 1;
} else {
n = 1;
}
while (w-- > n) {
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 */
base = 4;
goto BinaryNumber;
case 'o':
base = 3;
goto BinaryNumber;
case 'c':
cstr = va_arg(va, int);
s = &cstr;
goto EmitString;
case 's':
s = va_arg(va, const char *);
s = va_arg(va, const void *);
EmitString:
if (!s) {
EmitNullString:
s = "NULL";
}
if ((uintptr_t)s < PAGESIZE) {
bits = 0;
} else if ((uintptr_t)s < PAGESIZE) {
d = (intptr_t)s;
goto ApiAbuse;
}
for (i = 0; i < n; ++i) {
if (!s[i]) {
n = i;
break;
}
}
while (w-- > n) {
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;
for (i = 0; i < w[1]; ++i) {
if (!bits) {
t = ((const char *)s)[i];
EmitByte:
if (t) {
if (p < e) {
*p++ = t;
}
} 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[1] = 0200 | x << 8 | (t >> 6) & 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;
default:
break;
@ -186,8 +224,8 @@ privileged noasan noinstrument void __printf(const char *fmt, ...) {
}
} else {
asm volatile("syscall"
: "=a"(ax)
: "0"(__NR_write), "D"(2), "S"(b), "d"(p - b)
: "rcx", "r11", "memory");
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
: "0"(__NR_write), "1"(2L), "2"(b), "3"(p - b)
: "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"
.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
__asan_option_detect_stack_use_after_return:
.long 0
.endobj __asan_option_detect_stack_use_after_return,globl
.previous
.bss
__asan_noreentry:
.byte 0
.endobj __asan_noreentry
.previous
__asan_report_load1:
push %rbp
mov %rsp,%rbp
.profilable
mov $1,%esi
.acall __asan_report_load
pop %rbp
ret
push $1
jmp 1f
.endfn __asan_report_load1,globl
__asan_report_load2:
push %rbp
mov %rsp,%rbp
.profilable
mov $2,%esi
.acall __asan_report_load
pop %rbp
ret
push $2
jmp 1f
.endfn __asan_report_load2,globl
__asan_report_load4:
push %rbp
mov %rsp,%rbp
.profilable
mov $4,%esi
.acall __asan_report_load
pop %rbp
ret
push $4
jmp 1f
.endfn __asan_report_load4,globl
__asan_report_load8:
push %rbp
mov %rsp,%rbp
.profilable
mov $8,%esi
.acall __asan_report_load
pop %rbp
ret
push $8
jmp 1f
.endfn __asan_report_load8,globl
__asan_report_load16:
push %rbp
mov %rsp,%rbp
.profilable
mov $16,%esi
.acall __asan_report_load
pop %rbp
ret
push $16
jmp 1f
.endfn __asan_report_load16,globl
__asan_report_load32:
push %rbp
mov %rsp,%rbp
.profilable
mov $32,%esi
.acall __asan_report_load
pop %rbp
ret
push $32
1: pop %rsi
0: jmp __asan_report_load
.endfn __asan_report_load32,globl
__asan_report_load_n:
push %rbp
mov %rsp,%rbp
.profilable
.acall __asan_report_load
pop %rbp
ret
jmp 0b
.endfn __asan_report_load_n,globl
__asan_report_store1:
push %rbp
mov %rsp,%rbp
.profilable
mov $1,%esi
.acall __asan_report_store
pop %rbp
ret
push $1
jmp 1f
.endfn __asan_report_store1,globl
__asan_report_store2:
push %rbp
mov %rsp,%rbp
.profilable
mov $2,%esi
.acall __asan_report_store
pop %rbp
ret
push $2
jmp 1f
.endfn __asan_report_store2,globl
__asan_report_store4:
push %rbp
mov %rsp,%rbp
.profilable
mov $4,%esi
.acall __asan_report_store
pop %rbp
ret
push $4
jmp 1f
.endfn __asan_report_store4,globl
__asan_report_store8:
push %rbp
mov %rsp,%rbp
.profilable
mov $8,%esi
.acall __asan_report_store
pop %rbp
ret
push $8
jmp 1f
.endfn __asan_report_store8,globl
__asan_report_store16:
push %rbp
mov %rsp,%rbp
.profilable
mov $16,%esi
.acall __asan_report_store
pop %rbp
ret
push $16
jmp 1f
.endfn __asan_report_store16,globl
__asan_report_store32:
push %rbp
mov %rsp,%rbp
.profilable
mov $32,%esi
.acall __asan_report_store
pop %rbp
ret
push $32
1: pop %rsi
0: jmp __asan_report_store
.endfn __asan_report_store32,globl
__asan_report_store_n:
push %rbp
mov %rsp,%rbp
.profilable
.acall __asan_report_store
pop %rbp
ret
jmp 0b
.endfn __asan_report_store_n,globl
__asan_stack_free_0:
push %rbp
mov %rsp,%rbp
.profilable
mov $0,%edx
call __asan_stack_free
pop %rbp
ret
push $0
jmp 1f
.endfn __asan_stack_free_0,globl
__asan_stack_free_1:
push %rbp
mov %rsp,%rbp
.profilable
mov $1,%edx
call __asan_stack_free
pop %rbp
ret
push $1
jmp 1f
.endfn __asan_stack_free_1,globl
__asan_stack_free_2:
push %rbp
mov %rsp,%rbp
.profilable
mov $2,%edx
call __asan_stack_free
pop %rbp
ret
push $2
jmp 1f
.endfn __asan_stack_free_2,globl
__asan_stack_free_3:
push %rbp
mov %rsp,%rbp
.profilable
mov $3,%edx
call __asan_stack_free
pop %rbp
ret
push $3
jmp 1f
.endfn __asan_stack_free_3,globl
__asan_stack_free_4:
push %rbp
mov %rsp,%rbp
.profilable
mov $4,%edx
call __asan_stack_free
pop %rbp
ret
push $4
jmp 1f
.endfn __asan_stack_free_4,globl
__asan_stack_free_5:
push %rbp
mov %rsp,%rbp
.profilable
mov $5,%edx
call __asan_stack_free
pop %rbp
ret
push $5
.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:
push %rbp
mov %rsp,%rbp
.profilable
mov $6,%edx
call __asan_stack_free
pop %rbp
ret
push $6
jmp 1b
.endfn __asan_stack_free_6,globl
__asan_stack_free_7:
push %rbp
mov %rsp,%rbp
.profilable
mov $7,%edx
call __asan_stack_free
pop %rbp
ret
push $7
jmp 1b
.endfn __asan_stack_free_7,globl
__asan_stack_free_8:
push %rbp
mov %rsp,%rbp
.profilable
mov $8,%edx
call __asan_stack_free
pop %rbp
ret
push $8
jmp 1b
.endfn __asan_stack_free_8,globl
__asan_stack_free_9:
push %rbp
mov %rsp,%rbp
.profilable
mov $9,%edx
call __asan_stack_free
pop %rbp
ret
push $9
jmp 1b
.endfn __asan_stack_free_9,globl
__asan_stack_free_10:
push %rbp
mov %rsp,%rbp
.profilable
mov $10,%edx
call __asan_stack_free
pop %rbp
ret
push $10
jmp 1b
.endfn __asan_stack_free_10,globl
__asan_stack_malloc_0:
push %rbp
mov %rsp,%rbp
.profilable
mov $0,%esi
call __asan_stack_malloc
pop %rbp
ret
push $0
jmp 1f
.endfn __asan_stack_malloc_0,globl
__asan_stack_malloc_1:
push %rbp
mov %rsp,%rbp
.profilable
mov $1,%esi
call __asan_stack_malloc
pop %rbp
ret
push $1
jmp 1f
.endfn __asan_stack_malloc_1,globl
__asan_stack_malloc_2:
push %rbp
mov %rsp,%rbp
.profilable
mov $2,%esi
call __asan_stack_malloc
pop %rbp
ret
push $2
jmp 1f
.endfn __asan_stack_malloc_2,globl
__asan_stack_malloc_3:
push %rbp
mov %rsp,%rbp
.profilable
mov $3,%esi
call __asan_stack_malloc
pop %rbp
ret
push $3
jmp 1f
.endfn __asan_stack_malloc_3,globl
__asan_stack_malloc_4:
push %rbp
mov %rsp,%rbp
.profilable
mov $4,%esi
call __asan_stack_malloc
pop %rbp
ret
push $4
jmp 1f
.endfn __asan_stack_malloc_4,globl
__asan_stack_malloc_5:
push %rbp
mov %rsp,%rbp
.profilable
mov $5,%esi
call __asan_stack_malloc
pop %rbp
ret
push $5
jmp 1f
.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:
push %rbp
mov %rsp,%rbp
.profilable
mov $6,%esi
call __asan_stack_malloc
pop %rbp
ret
push $6
jmp 1b
.endfn __asan_stack_malloc_6,globl
__asan_stack_malloc_7:
push %rbp
mov %rsp,%rbp
.profilable
mov $7,%esi
call __asan_stack_malloc
pop %rbp
ret
push $7
jmp 1b
.endfn __asan_stack_malloc_7,globl
__asan_stack_malloc_8:
push %rbp
mov %rsp,%rbp
.profilable
mov $8,%esi
call __asan_stack_malloc
pop %rbp
ret
push $8
jmp 1b
.endfn __asan_stack_malloc_8,globl
__asan_stack_malloc_9:
push %rbp
mov %rsp,%rbp
.profilable
mov $9,%esi
call __asan_stack_malloc
pop %rbp
ret
push $9
jmp 1b
.endfn __asan_stack_malloc_9,globl
__asan_stack_malloc_10:
push %rbp
mov %rsp,%rbp
.profilable
mov $10,%esi
call __asan_stack_malloc
pop %rbp
ret
push $10
jmp 1b
.endfn __asan_stack_malloc_10,globl
__asan_version_mismatch_check_v8:

View file

@ -17,8 +17,49 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#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__:
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
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
.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/fmt/fmt.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/nt/runtime.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;
}
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,
uintptr_t x) {
if (__ubsan_signed(t)) {
return __ubsan_intcpy(p, x);
return __intcpy(p, x);
} else {
return __ubsan_poscpy(p, x);
return __uintcpy(p, x);
}
}
static const char *__ubsan_dubnul(const char *s, unsigned i) {
size_t n;
while (i--) {
if ((n = __ubsan_strlen(s))) {
if ((n = __strlen(s))) {
s += n + 1;
} else {
return NULL;
@ -222,53 +187,11 @@ static uintptr_t __ubsan_extend(struct UbsanTypeDescriptor *t, uintptr_t 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,
const char *description) {
char buf[1024], *p = buf;
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);
__printf("\r\n%s:%d: ubsan error: %s\r\n", loc->file, loc->line, description);
if (weaken(__die)) weaken(__die)();
__ubsan_exit(134);
_Exit(134);
}
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;
lhs = __ubsan_extend(info->lhs_type, lhs);
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_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_stpcpy(p, info->rhs_type->name);
p = __stpcpy(p, info->rhs_type->name);
__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,
uintptr_t index) {
char buf[512], *p = buf;
p = __ubsan_stpcpy(p, info->index_type->name);
p = __ubsan_stpcpy(p, " index ");
p = __stpcpy(p, info->index_type->name);
p = __stpcpy(p, " index ");
p = __ubsan_itpcpy(p, info->index_type, index);
p = __ubsan_stpcpy(p, " into ");
p = __ubsan_stpcpy(p, info->array_type->name);
p = __ubsan_stpcpy(p, " out of bounds");
p = __stpcpy(p, " into ");
p = __stpcpy(p, info->array_type->name);
p = __stpcpy(p, " out of bounds");
__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");
kind = __ubsan_dubnul(kUbsanTypeCheckKinds, info->type_check_kind);
if (info->alignment && (pointer & (info->alignment - 1))) {
p = __ubsan_stpcpy(p, "unaligned ");
p = __ubsan_stpcpy(p, kind), *p++ = ' ';
p = __ubsan_stpcpy(p, info->type->name), *p++ = ' ', *p++ = '@';
p = __stpcpy(p, "unaligned ");
p = __stpcpy(p, kind), *p++ = ' ';
p = __stpcpy(p, info->type->name), *p++ = ' ', *p++ = '@';
p = __ubsan_itpcpy(p, info->type, pointer);
p = __ubsan_stpcpy(p, " align ");
p = __ubsan_intcpy(p, info->alignment);
p = __stpcpy(p, " align ");
p = __intcpy(p, info->alignment);
} else {
p = __ubsan_stpcpy(p, "insufficient size\r\n\t");
p = __ubsan_stpcpy(p, kind);
p = __ubsan_stpcpy(p, " address 0x");
p = __ubsan_hexcpy(p, pointer, sizeof(pointer) * CHAR_BIT);
p = __ubsan_stpcpy(p, " with insufficient space for object of type ");
p = __ubsan_stpcpy(p, info->type->name);
p = __stpcpy(p, "insufficient size\r\n\t");
p = __stpcpy(p, kind);
p = __stpcpy(p, " address 0x");
p = __fixcpy(p, pointer, sizeof(pointer) * CHAR_BIT);
p = __stpcpy(p, " with insufficient space for object of type ");
p = __stpcpy(p, info->type->name);
}
__ubsan_abort(&info->location, buf);
}

View file

@ -31,13 +31,17 @@
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/stdio/append.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sig.h"
#include "libc/x/x.h"
#define kBacktraceMaxFrames 128
#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) {
/* asan runtime depends on this function */
static bool noreentry;
++ftrace;
++g_ftrace;
if (!bp) bp = __builtin_frame_address(0);
if (!noreentry) {
noreentry = true;
PrintBacktrace(fd, bp);
noreentry = false;
}
--ftrace;
--g_ftrace;
}

View file

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

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.
*/
relegated wontreturn void __die(void) {
/* asan runtime depends on this function */
static bool once;
if (cmpxchg(&once, false, true)) {
__restore_tty(1);

View file

@ -26,6 +26,6 @@
const char *GetCallerName(const struct StackFrame *bp) {
struct SymbolTable *st;
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;
}

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.
* @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 struct SymbolTable *singleton;
const char *debugbin;
if (!once) {
once = true;
++ftrace;
if ((debugbin = FindDebugBinary()) &&
(singleton = OpenSymbolTable(debugbin))) {
__cxa_atexit(CloseSymbolTable, &singleton, NULL);
}
--ftrace;
++g_ftrace;
singleton = OpenSymbolTable(FindDebugBinary());
--g_ftrace;
}
return singleton;
}

View file

@ -7,9 +7,11 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern int kCrashSigs[8] hidden;
extern struct termios g_oldtermios hidden;
extern struct sigaction g_oldcrashacts[8] hidden;
extern hidden int kCrashSigs[8];
extern hidden bool g_isrunningundermake;
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_ndebug(void) hidden;

View file

@ -5,42 +5,94 @@
#include "libc/nexgen32e/bsr.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/nr.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
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) {
int rc;
if (!IsWindows()) {
asm volatile("call\t__syscall__"
: "=a"(rc)
: "0"(__NR_getpid)
: "rcx", "r11", "memory");
return rc;
return __sysv_getpid();
} else {
return GetCurrentProcessId();
}
}
forceinline ssize_t __write(const void *data, size_t size) {
forceinline ssize_t __write(const void *p, size_t n) {
char cf;
ssize_t rc;
uint32_t wrote;
if (!IsWindows()) {
asm volatile("call\t__syscall__"
: "=@ccc"(cf), "=a"(rc)
: "1"(__NR_write), "D"(2), "S"(data), "d"(size)
: "rcx", "r11", "memory");
if (cf && IsBsd()) rc = -rc;
return rc;
return __sysv_write(2, p, n);
} else if (WriteFile(GetStdHandle(kNtStdErrorHandle), p, n, &wrote, 0)) {
return wrote;
} else {
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
return wrote;
} else {
return -1;
}
return -GetLastError();
}
}
@ -54,6 +106,12 @@ forceinline ssize_t __write_str(const char *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) {
size_t 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) {
asm("rep movsb"
: "=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));
}
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_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

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

View file

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

View file

@ -16,6 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/stdio/stdio.h"
@ -24,19 +26,31 @@
/**
* Prints list of deferred operations on shadow stack.
*/
void PrintGarbage(FILE *f) {
void PrintGarbage(void) {
size_t i;
f = stderr;
fprintf(f, "\n");
fprintf(f, " SHADOW STACK @ 0x%016lx\n", __builtin_frame_address(0));
fprintf(f, " garbage entry parent frame original ret callback arg \n");
fprintf(f, "-------------- -------------- ------------------ ------------------ ------------------\n");
for (i = __garbage.i; i--;) {
fprintf(f, "0x%012lx 0x%012lx %-18s %-18s 0x%016lx\n",
__garbage.p + i,
__garbage.p[i].frame,
GetSymbolByAddr(__garbage.p[i].ret-1),
GetSymbolByAddr(__garbage.p[i].fn),
__garbage.p[i].arg);
char name[19];
const char *symbol;
__printf("\n");
__printf(" SHADOW STACK @ 0x%p\n", __builtin_frame_address(0));
__printf("garbage entry parent frame original ret callback arg \n");
__printf("-------------- -------------- ------------------ ------------------ ------------------\n");
if (__garbage.i) {
for (i = __garbage.i; i--;) {
symbol = __get_symbol_by_addr(__garbage.p[i].ret);
if (symbol) {
snprintf(name, sizeof(name), "%s", symbol);
} 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
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/termios.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/dce.h"
#include "libc/log/check.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigaltstack.h"
#include "libc/log/internal.h"
#include "libc/log/log.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/sig.h"
#include "libc/sysv/consts/ss.h"
STATIC_YOINK("__die");
@ -57,6 +50,7 @@ extern const unsigned char __oncrash_thunks[8][11];
void ShowCrashReports(void) {
size_t i;
struct sigaction sa;
struct sigaltstack ss;
/* <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
kCrashSigs[0] = SIGQUIT; /* ctrl+\ aka ctrl+break */
kCrashSigs[1] = SIGFPE; /* 1 / 0 */
@ -68,11 +62,16 @@ void ShowCrashReports(void) {
kCrashSigs[7] = SIGPIPE; /* write to closed thing */
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
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);
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
sigdelset(&sa.sa_mask, kCrashSigs[i]);
}
sigaltstack(&ss, 0);
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
if (kCrashSigs[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 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,18 +16,23 @@
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"
.source __FILE__
#include "libc/mem/mem.h"
.initbss 202,_init_posix_memalign
hook_posix_memalign:
.quad 0
.endobj hook_posix_memalign,globl,hidden
.previous
.init.start 202,_init_posix_memalign
.hidden dlposix_memalign
ezlea dlposix_memalign,ax
stosq
yoink free
.init.end 202,_init_posix_memalign
/**
* Same as memalign(a, n) but requires IS2POW(a).
*
* @param n number of bytes needed
* @return memory address, or NULL w/ errno
* @throw EINVAL if !IS2POW(a)
* @see pvalloc()
*/
void *aligned_alloc(size_t a, size_t n) {
if (IS2POW(a)) {
return memalign(a, n);
} else {
errno = EINVAL;
return 0;
}
}

View file

@ -22,37 +22,39 @@
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/limits.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/arena.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/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
#define BASE ((char *)0x30000000)
#define LIMIT ((char *)0x50000000)
#define BASE 0x50000000
#define SIZE 0x2ffe0000
#define P(i) ((void *)(intptr_t)(i))
#define EXCHANGE(HOOK, SLOT) \
__arena_hook((intptr_t *)weaken(HOOK), (intptr_t *)(&(SLOT)))
static struct Arena {
bool once;
uint8_t depth;
unsigned size;
unsigned offset[16];
size_t size;
size_t depth;
size_t offset[16];
void (*free)(void *);
void *(*malloc)(size_t);
void *(*calloc)(size_t, size_t);
void *(*memalign)(size_t, size_t);
void *(*realloc)(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 (*bulk_free)(void *[], size_t);
int (*malloc_trim)(size_t);
} __arena;
static wontreturn void __arena_die(void) {
@ -61,103 +63,202 @@ static wontreturn void __arena_die(void) {
}
static wontreturn void __arena_not_implemented(void) {
__printf("not implemented");
assert(!"not implemented");
__arena_die();
}
static void __arena_free(void *p) {
if (!p) return;
forceinline void __arena_check(void) {
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) {
size_t 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;
}
static void *__arena_malloc(size_t n) {
char *ptr;
size_t need, greed;
assert(__arena.depth);
if (!n) n = 1;
if (n < LIMIT - BASE) {
need = __arena.offset[__arena.depth] + n;
need = ROUNDUP(need, __BIGGEST_ALIGNMENT__);
if (UNLIKELY(need > __arena.size)) {
greed = __arena.size + 1;
do {
greed += greed >> 1;
greed = ROUNDUP(greed, FRAMESIZE);
} while (need > greed);
if (greed < LIMIT - BASE &&
mmap(BASE + __arena.size, greed - __arena.size,
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
-1, 0) != MAP_FAILED) {
__arena.size = greed;
__arena_check();
return __arena_alloc(16, n);
}
static void *__arena_calloc(size_t n, size_t z) {
__arena_check();
if (__builtin_mul_overflow(n, z, &n)) n = -1;
return __arena_alloc(16, n);
}
static void *__arena_memalign(size_t a, size_t n) {
__arena_check();
if (a <= sizeof(size_t)) {
return __arena_alloc(8, n);
} else {
return __arena_alloc(2ul << bsrl(a - 1), n);
}
}
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 {
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 {
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) {
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) {
intptr_t t;
if (h) {
@ -169,42 +270,32 @@ static void __arena_hook(intptr_t *h, intptr_t *f) {
static void __arena_install(void) {
EXCHANGE(hook_free, __arena.free);
EXCHANGE(hook_realloc, __arena.realloc);
EXCHANGE(hook_realloc, __arena.realloc);
EXCHANGE(hook_malloc, __arena.malloc);
EXCHANGE(hook_calloc, __arena.calloc);
EXCHANGE(hook_realloc, __arena.realloc);
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_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) {
if (__arena.depth) {
__arena_install();
}
if (__arena.size) {
munmap(BASE, __arena.size);
}
if (__arena.depth) __arena_install();
if (__arena.size) munmap(P(BASE), __arena.size);
bzero(&__arena, sizeof(__arena));
}
static void __arena_init(void) {
__arena.free = __arena_free;
__arena.realloc = __arena_realloc;
__arena.realloc = __arena_realloc;
__arena.malloc = __arena_malloc;
__arena.calloc = __arena_calloc;
__arena.realloc = __arena_realloc;
__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.malloc_trim = __arena_malloc_trim;
__arena.realloc_in_place = __arena_realloc_in_place;
__arena.malloc_usable_size = __arena_malloc_usable_size;
atexit(__arena_destroy);
}
@ -215,24 +306,27 @@ void __arena_push(void) {
}
if (!__arena.depth) {
__arena_install();
} else if (__arena.depth == ARRAYLEN(__arena.offset) - 1) {
__printf("too many arenas");
__arena_die();
} else {
assert(__arena.depth < ARRAYLEN(__arena.offset) - 1);
}
__arena.offset[__arena.depth + 1] = __arena.offset[__arena.depth];
++__arena.depth;
}
void __arena_pop(void) {
unsigned greed;
assert(__arena.depth);
bzero(BASE + __arena.offset[__arena.depth - 1],
__arena.offset[__arena.depth] - __arena.offset[__arena.depth - 1]);
size_t a, b, greed;
__arena_check();
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 <<= 1;
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/runtime/buffer.h"
/* TODO(jart): delete */
#define kGuard PAGESIZE
#define kGrain FRAMESIZE

View file

@ -18,11 +18,13 @@
*/
#include "libc/assert.h"
#include "libc/bits/likely.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
forceinline bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame,
struct StackFrame *parent,
@ -31,14 +33,28 @@ forceinline bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame,
((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) {
size_t n2;
struct Garbage *p2;
if (UNLIKELY(__garbage.i == __garbage.n)) {
p2 = __garbage.p;
n2 = __garbage.n + (__garbage.n >> 1);
p2 = malloc(n2 * sizeof(*__garbage.p));
memcpy(p2, __garbage.p, __garbage.n * sizeof(*__garbage.p));
if (__garbage.p != __garbage.initmem) free(__garbage.p);
if (__garbage.p != __garbage.initmem) {
if (!weaken(realloc)) return;
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.n = n2;
}
@ -59,11 +75,11 @@ void __deferer(struct StackFrame *frame, void *fn, void *arg) {
* @return arg
*/
void __defer(struct StackFrame *frame, void *fn, void *arg) {
struct StackFrame *f2;
struct StackFrame *f;
if (!arg) return;
f2 = __builtin_frame_address(0);
f = __builtin_frame_address(0);
assert(__garbage.n);
assert(f2->next == frame);
assert(PointerNotOwnedByParentStackFrame(f2, frame, arg));
assert(f->next == frame);
assert(PointerNotOwnedByParentStackFrame(f, frame, 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_realloc)(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 size_t (*hook_malloc_usable_size)(const void *);
extern size_t (*hook_bulk_free)(void *[], size_t);

View file

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

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.source __FILE__
// Allocates uninitialized memory.
//
@ -32,9 +31,7 @@
// 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.
//
// @param rdi is number of bytes needed
// @param rdi is number of bytes needed, coerced to 1+
// @return new memory, or NULL w/ errno
// @note malloc(0) → malloc(32)
// @see dlmalloc()
malloc: jmp *hook_malloc(%rip)
.endfn malloc,globl

View file

@ -15,15 +15,17 @@ void free(void *) libcesque;
void *malloc(size_t) attributeallocsize((1)) mallocesque;
void *calloc(size_t, size_t) attributeallocsize((1, 2)) mallocesque;
void *memalign(size_t, size_t) attributeallocalign((1))
attributeallocsize((2)) mallocesque;
attributeallocsize((2)) returnspointerwithnoaliases libcesque nodiscard;
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 *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 *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;
int malloc_trim(size_t);

View file

@ -18,22 +18,18 @@
*/
#include "libc/macros.internal.h"
#include "libc/notice.inc"
.source __FILE__
// Allocates aligned memory.
//
// Returns a pointer to a newly allocated chunk of n bytes, aligned in
// accord with the alignment argument. The alignment argument should be
// a power of two. If the argument is not a power of two, the nearest
// greater power is used. 8-byte alignment is guaranteed by normal
// malloc calls, so don't bother calling memalign with an argument of 8
// or less.
// accord with the alignment argument. The alignment argument shall be
// rounded up to the nearest two power and higher 2 powers may be used
// if the allocator imposes a minimum alignment requirement.
//
// @param rdi is alignment in bytes
// @param rsi (newsize) is number of bytes needed
// @param rdi is alignment in bytes, coerced to 1+ w/ 2-power roundup
// @param rsi is number of bytes needed, coerced to 1+
// @return rax is memory address, or NULL w/ errno
// @note overreliance on memalign is a sure way to fragment space
// @see dlmemalign()
// @see valloc(), pvalloc()
memalign:
jmp *hook_memalign(%rip)
.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);
}
void __freeenv(void *p) {
if (once) {
free(p);
}
}
int PutEnvImpl(char *s, bool overwrite) {
char *p;
unsigned i, namelen;
@ -62,7 +68,10 @@ int PutEnvImpl(char *s, bool overwrite) {
goto replace;
}
}
if (i + 1 >= MAX_VARS) goto fail;
if (i + 1 >= MAX_VARS) {
free(s);
return enomem();
}
environ[i + 1] = NULL;
replace:
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 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -17,13 +17,15 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/notice.inc"
.source __FILE__
#include "libc/mem/mem.h"
// Equivalent to memalign(4096, n).
//
// @param rdi is number of bytes needed
// @return rax is memory address, or NULL w/ errno
// @see dlvalloc()
valloc: jmp *hook_valloc(%rip)
.endfn valloc,globl
/**
* Equivalent to memalign(PAGESIZE, ROUNDUP(n, PAGESIZE)).
*
* @param n number of bytes needed
* @return memory address, or NULL w/ errno
* @see valloc()
*/
void *pvalloc(size_t n) {
return memalign(PAGESIZE, ROUNDUP(n, PAGESIZE));
}

View file

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

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