Make improvements

- Fix build flakes
- Polyfill SIGWINCH on Windows
- Fix an execve issue on Windows
- Make strerror show more information
- Improve cmd.exe setup/teardown on Windows
- Support bracketed paste mode in Blinkenlights
- Show keyboard shortcuts in Blinkenlights status bar
- Fixed copy_file_range() and copyfile() w/ zip filesystem
- Size optimize GetDosArgv() to keep life.com 12kb in size
- Improve Blinkenlights ability to load weird ELF executables
- Fix program_executable_name and add GetInterpreterExecutableName
- Make Python in tiny mode fail better if docstrings are requested
- Update Python test exclusions in tiny* modes such as tinylinux
- Add bulletproof unbreakable kprintf() troubleshooting function
- Remove "oldskool" keyword from ape.S for virus scanners
- Fix issue that caused backtraces to not print sometimes
- Improve Blinkenlights serial uart character i/o
- Make clock_gettime() not clobber errno on xnu
- Improve sha256 cpuid check for old computers
- Integrate some bestline linenoise fixes
- Show runit process names better in htop
- Remove SIGPIPE from ShowCrashReports()
- Make realpath() not clobber errno
- Avoid attaching GDB on non-Linux
- Improve img.com example
This commit is contained in:
Justine Tunney 2022-03-16 13:33:13 -07:00
parent 2a938b3eaa
commit b45d50b690
194 changed files with 4881 additions and 2966 deletions

View file

@ -22,10 +22,11 @@
#include "libc/bits/likely.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
@ -89,12 +90,13 @@ STATIC_YOINK("_init_asan");
} \
} while (0)
#define REQUIRE(FUNC) \
do { \
if (!weaken(FUNC)) { \
__asan_die("error: asan needs " #FUNC "\n")(); \
__asan_unreachable(); \
} \
#define REQUIRE(FUNC) \
do { \
if (!weaken(FUNC)) { \
kprintf("error: asan needs %s%n", #FUNC); \
__asan_die()(); \
__asan_unreachable(); \
} \
} while (0)
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
@ -139,6 +141,7 @@ struct AsanMorgue {
};
bool __asan_noreentry;
extern bool __nomultics;
static struct AsanMorgue __asan_morgue;
static wontreturn void __asan_unreachable(void) {
@ -227,7 +230,8 @@ static void *__asan_memset(void *p, char c, size_t n) {
static void *__asan_mempcpy(void *dst, const void *src, size_t n) {
size_t i;
char *d, *s;
char *d;
const char *s;
uint64_t a, b;
d = dst;
s = src;
@ -303,14 +307,13 @@ static char *__asan_hexcpy(char *p, uint64_t x, uint8_t k) {
}
static void __asan_exit(void) {
__printf("your asan runtime needs\n"
"\tSTATIC_YOINK(\"__die\");\n"
"in order to show you backtraces\n");
kprintf("your asan runtime needs%n"
"\tSTATIC_YOINK(\"__die\");%n"
"in order to show you backtraces%n");
_Exit(99);
}
nodiscard static __asan_die_f *__asan_die(const char *msg) {
__printf("%s", msg);
nodiscard static __asan_die_f *__asan_die(void) {
if (weaken(__die)) {
return weaken(__die);
} else {
@ -358,7 +361,7 @@ static bool __asan_is_mapped(int x) {
struct MemoryIntervals *m;
m = weaken(_mmi);
i = FindMemoryInterval(m, x);
return i < m->i && m->p[i].x <= x && x <= m->p[i].y;
return i < m->i && x >= m->p[i].x;
}
static bool __asan_is_image(const unsigned char *p) {
@ -366,7 +369,7 @@ static bool __asan_is_image(const unsigned char *p) {
}
static bool __asan_exists(const void *x) {
return __asan_is_image(x) || __asan_is_mapped((intptr_t)x >> 16);
return !kisdangerous(x);
}
static struct AsanFault __asan_fault(const signed char *s, signed char dflt) {
@ -385,13 +388,13 @@ static struct AsanFault __asan_fault(const signed char *s, signed char dflt) {
static struct AsanFault __asan_checka(const signed char *s, long ndiv8) {
intptr_t a;
uint64_t w;
signed char c, *e = s + ndiv8;
const signed char *e = s + ndiv8;
for (; ((intptr_t)s & 7) && s < e; ++s) {
if (*s) return __asan_fault(s - 1, kAsanHeapOverrun);
}
for (; s + 8 <= e; s += 8) {
if (UNLIKELY(!((a = (intptr_t)s) & 0xffff))) {
if (!__asan_is_mapped(a >> 16)) {
if (kisdangerous((void *)a)) {
return (struct AsanFault){kAsanUnmapped, s};
}
}
@ -422,7 +425,6 @@ static struct AsanFault __asan_checka(const signed char *s, long ndiv8) {
*/
struct AsanFault __asan_check(const void *p, long n) {
intptr_t a;
uint64_t w;
struct AsanFault f;
signed char c, k, *s;
if (n > 0) {
@ -431,7 +433,7 @@ struct AsanFault __asan_check(const void *p, long n) {
s = (signed char *)a;
if (OverlapsShadowSpace(p, n)) {
return (struct AsanFault){kAsanProtected, s};
} else if (IsLegalPointer(a) && !__asan_is_mapped(a >> 16)) {
} else if (kisdangerous((void *)a)) {
return (struct AsanFault){kAsanUnmapped, s};
}
if (UNLIKELY(k)) {
@ -491,19 +493,6 @@ bool __asan_is_valid_strlist(char *const *p) {
}
}
static const char *__asan_dscribe_heap_poison(signed char c) {
switch (c) {
case kAsanHeapFree:
return "heap double free";
case kAsanStackFree:
return "free stack after return";
case kAsanHeapRelocated:
return "free after relocate";
default:
return "this corruption";
}
}
wint_t __asan_symbolize_access_poison(signed char kind) {
switch (kind) {
case kAsanNullPage:
@ -544,6 +533,10 @@ wint_t __asan_symbolize_access_poison(signed char kind) {
return L'G';
case kAsanGlobalGone:
return L'𝐺';
case kAsanGlobalUnderrun:
return L'μ';
case kAsanGlobalOverrun:
return L'Ω';
default:
return L'?';
}
@ -589,16 +582,19 @@ const char *__asan_describe_access_poison(signed char kind) {
return "global redzone";
case kAsanGlobalGone:
return "global gone";
case kAsanGlobalUnderrun:
return "global underrun";
case kAsanGlobalOverrun:
return "global overrun";
default:
return "poisoned";
}
}
nodiscard static __asan_die_f *__asan_report_invalid_pointer(void *addr) {
__printf("\r\n%sasan error%s: this corruption at 0x%p shadow 0x%p\r\n",
!g_isterminalinarticulate ? "\e[J\e[1;91m" : "",
!g_isterminalinarticulate ? "\e[0m" : "", addr, SHADOW(addr));
return __asan_die("");
nodiscard static __asan_die_f *__asan_report_invalid_pointer(const void *addr) {
kprintf("%n\e[J\e[1;31masan error\e[0m: this corruption at %p shadow %p%n",
addr, SHADOW(addr));
return __asan_die();
}
static char *__asan_format_interval(char *p, intptr_t a, intptr_t b) {
@ -607,8 +603,8 @@ static char *__asan_format_interval(char *p, intptr_t a, intptr_t b) {
return p;
}
static char *__asan_format_section(char *p, void *p1, void *p2,
const char *name, void *addr) {
static char *__asan_format_section(char *p, const void *p1, const void *p2,
const char *name, const void *addr) {
intptr_t a, b;
if ((a = (intptr_t)p1) < (b = (intptr_t)p2)) {
p = __asan_format_interval(p, a, b), *p++ = ' ';
@ -616,26 +612,25 @@ static char *__asan_format_section(char *p, void *p1, void *p2,
if (a <= (intptr_t)addr && (intptr_t)addr <= b) {
p = __stpcpy(p, " ←address");
}
*p++ = '\r', *p++ = '\n';
if (__nomultics) *p++ = '\r';
*p++ = '\n';
}
return p;
}
nodiscard static __asan_die_f *__asan_report(void *addr, int size,
nodiscard static __asan_die_f *__asan_report(const void *addr, int size,
const char *message,
signed char kind) {
int i;
wint_t c;
int i, cc;
signed char t;
uint64_t x, y, z;
char *p, *q, *base;
struct MemoryIntervals *m;
p = __fatalbuf;
__printf("\r\n%sasan error%s: %s %d-byte %s at 0x%p shadow 0x%p\r\n",
!g_isterminalinarticulate ? "\e[J\e[1;91m" : "",
!g_isterminalinarticulate ? "\e[0m" : "",
__asan_describe_access_poison(kind), size, message, addr,
SHADOW(addr));
kprintf("%n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p%n%s%n",
__asan_describe_access_poison(kind), size, message, addr,
SHADOW(addr), __argv[0]);
if (0 < size && size < 80) {
base = (char *)addr - ((80 >> 1) - (size >> 1));
for (i = 0; i < 80; ++i) {
@ -649,30 +644,32 @@ nodiscard static __asan_die_f *__asan_report(void *addr, int size,
*p++ = ' ';
}
}
*p++ = '\r', *p++ = '\n';
if (__nomultics) *p++ = '\r';
*p++ = '\n';
for (c = i = 0; i < 80; ++i) {
if (!(t = __asan_check(base + i, 1).kind)) {
if (!g_isterminalinarticulate && c != 32) {
if (c != 32) {
p = __stpcpy(p, "\e[32m");
c = 32;
}
*p++ = '.';
} else {
if (!g_isterminalinarticulate && c != 31) {
if (c != 31) {
p = __stpcpy(p, "\e[31m");
c = 31;
}
p = __asan_utf8cpy(p, __asan_symbolize_access_poison(t));
}
}
if (!g_isterminalinarticulate) p = __stpcpy(p, "\e[39m");
*p++ = '\r', *p++ = '\n';
p = __stpcpy(p, "\e[39m");
if (__nomultics) *p++ = '\r';
*p++ = '\n';
for (i = 0; (intptr_t)(base + i) & 7; ++i) *p++ = ' ';
for (; i + 8 <= 80; i += 8) {
q = p + 8;
*p++ = '|';
z = ((intptr_t)(base + i) >> 3) + 0x7fff8000;
if (__asan_is_mapped(z >> 16)) {
if (!kisdangerous((void *)z)) {
p = __intcpy(p, *(signed char *)z);
} else {
*p++ = '!';
@ -682,13 +679,15 @@ nodiscard static __asan_die_f *__asan_report(void *addr, int size,
}
}
for (; i < 80; ++i) *p++ = ' ';
*p++ = '\r', *p++ = '\n';
if (__nomultics) *p++ = '\r';
*p++ = '\n';
for (i = 0; i < 80; ++i) {
p = __asan_utf8cpy(p, __asan_exists(base + i)
? kCp437[((unsigned char *)base)[i]]
: L'');
}
*p++ = '\r', *p++ = '\n';
if (__nomultics) *p++ = '\r';
*p++ = '\n';
}
p = __asan_format_section(p, _base, _etext, ".text", addr);
p = __asan_format_section(p, _etext, _edata, ".data", addr);
@ -701,10 +700,12 @@ nodiscard static __asan_die_f *__asan_report(void *addr, int size,
if (x <= z && z <= y) p = __stpcpy(p, " ←address");
z = (((intptr_t)addr >> 3) + 0x7fff8000) >> 16;
if (x <= z && z <= y) p = __stpcpy(p, " ←shadow");
*p++ = '\r', *p++ = '\n';
if (__nomultics) *p++ = '\r';
*p++ = '\n';
}
*p = 0;
return __asan_die(__fatalbuf);
kprintf("%s", __fatalbuf);
return __asan_die();
}
void __asan_verify(const void *p, size_t n) {
@ -726,7 +727,7 @@ nodiscard __asan_die_f *__asan_report_memory_fault(void *addr, int size,
__asan_fault(SHADOW(addr), -128).kind);
}
const void *__asan_morgue_add(void *p) {
void *__asan_morgue_add(void *p) {
void *r;
int i, j;
for (;;) {
@ -785,6 +786,17 @@ static bool __asan_read48(uint64_t value, uint64_t *x) {
return cookie == ('J' | 'T' << 8);
}
static void __asan_rawtrace(struct AsanTrace *bt, const struct StackFrame *bp) {
size_t i;
for (i = 0; bp && i < ARRAYLEN(bt->p); ++i, bp = bp->next) {
if (kisdangerous(bp)) break;
bt->p[i] = bp->addr;
}
for (; i < ARRAYLEN(bt->p); ++i) {
bt->p[i] = 0;
}
}
static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
int f1, f2;
size_t i, gi;
@ -792,10 +804,9 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
struct Garbages *garbage;
garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0;
__asan_memset(bt, 0, sizeof(*bt));
for (f1 = -1, i = 0; bp && i < ARRAYLEN(bt->p); ++i, bp = bp->next) {
if (f1 != (f2 = ((intptr_t)bp >> 16))) {
if (!__asan_is_mapped(f2)) break;
if (kisdangerous(bp)) break;
f1 = f2;
}
if (!__asan_checka(SHADOW(bp), sizeof(*bp) >> 3).kind) {
@ -809,8 +820,13 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
break;
}
}
for (; i < ARRAYLEN(bt->p); ++i) {
bt->p[i] = 0;
}
}
#define __asan_trace __asan_rawtrace
static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
struct AsanTrace *bt) {
char *p;
@ -830,17 +846,14 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
return p;
}
static struct AsanExtra *__asan_get_extra(void *p, size_t *c) {
static struct AsanExtra *__asan_get_extra(const void *p, size_t *c) {
int f;
long x, n;
struct AsanExtra *e;
if ((0 < (intptr_t)p && (intptr_t)p < 0x800000000000) &&
__asan_is_mapped((f = (intptr_t)p >> 16)) &&
(LIKELY(f == (int)(((intptr_t)p - 16) >> 16)) ||
__asan_is_mapped(((intptr_t)p - 16) >> 16)) &&
(n = weaken(dlmalloc_usable_size)(p)) > sizeof(*e) &&
f = (intptr_t)p >> 16;
if (!kisdangerous(p) && (n = weaken(dlmalloc_usable_size)(p)) > sizeof(*e) &&
!__builtin_add_overflow((intptr_t)p, n, &x) && x <= 0x800000000000 &&
(LIKELY(f == (int)((x - 1) >> 16)) || __asan_is_mapped((x - 1) >> 16)) &&
(LIKELY(f == (int)((x - 1) >> 16)) || !kisdangerous((void *)(x - 1))) &&
(LIKELY(f == (int)((x = x - sizeof(*e)) >> 16)) ||
__asan_is_mapped(x >> 16)) &&
!(x & (alignof(struct AsanExtra) - 1))) {
@ -882,27 +895,25 @@ static size_t __asan_malloc_usable_size(const void *p) {
}
int __asan_print_trace(void *p) {
intptr_t x;
size_t c, i, n;
const char *name;
struct AsanExtra *e;
if (!(e = __asan_get_extra(p, &c))) {
__printf(" bad pointer");
kprintf(" bad pointer");
return einval();
}
if (!__asan_read48(e->size, &n)) {
__printf(" bad cookie");
kprintf(" bad cookie");
return -1;
}
__printf(" %,d used", n);
kprintf(" %'zu used", n);
if (!__asan_is_mapped((((intptr_t)p >> 3) + 0x7fff8000) >> 16)) {
__printf(" (shadow not mapped?!)");
kprintf(" (shadow not mapped?!)");
}
for (i = 0; i < ARRAYLEN(e->bt.p) && e->bt.p[i]; ++i) {
__printf("\n%*x %s", 12, e->bt.p[i],
weaken(__get_symbol_by_addr)
? weaken(__get_symbol_by_addr)(e->bt.p[i])
: "please STATIC_YOINK(\"__get_symbol_by_addr\")");
kprintf("%n%*lx %s", 12, e->bt.p[i],
weaken(__get_symbol_by_addr)
? weaken(__get_symbol_by_addr)(e->bt.p[i])
: "please STATIC_YOINK(\"__get_symbol_by_addr\")");
}
return 0;
}
@ -1078,21 +1089,36 @@ void __asan_unregister_globals(struct AsanGlobal g[], int n) {
}
}
void __asan_evil(uint8_t *addr, int size, const char *s1, const char *s2) {
struct AsanTrace tr;
__asan_rawtrace(&tr, __builtin_frame_address(0));
kprintf("WARNING: ASAN error during %s bad %d byte %s at %p bt %p %p %p %p%n",
s1, size, s2, addr, tr.p[0], tr.p[1], tr.p[2], tr.p[3]);
}
void __asan_report_load(uint8_t *addr, int size) {
if (cmpxchg(&__asan_noreentry, false, true)) {
__asan_report_memory_fault(addr, size, "load")();
__asan_unreachable();
if (!__vforked) {
__asan_report_memory_fault(addr, size, "load")();
__asan_unreachable();
} else {
__asan_evil(addr, size, "vfork()", "load");
}
} else {
__printf("WARNING: ASAN error reporting had an ASAN error\r\n");
__asan_evil(addr, size, "ASAN Reporting", "load");
}
}
void __asan_report_store(uint8_t *addr, int size) {
if (cmpxchg(&__asan_noreentry, false, true)) {
__asan_report_memory_fault(addr, size, "store")();
__asan_unreachable();
if (!__vforked) {
__asan_report_memory_fault(addr, size, "store")();
__asan_unreachable();
} else {
__asan_evil(addr, size, "vfork()", "store");
}
} else {
__printf("WARNING: ASAN error reporting had an ASAN error\r\n");
__asan_evil(addr, size, "ASAN reporting", "store");
}
}
@ -1138,12 +1164,11 @@ void __asan_install_malloc_hooks(void) {
void __asan_map_shadow(uintptr_t p, size_t n) {
void *addr;
int i, a, b;
size_t size;
int prot, flag;
int i, x, a, b;
struct DirectMap sm;
struct MemoryIntervals *m;
SYSDEBUG("__asan_map_shadow(0x%p, 0x%x)", p, n);
assert(!OverlapsShadowSpace((void *)p, n));
m = weaken(_mmi);
a = (0x7fff8000 + (p >> 3)) >> 16;
@ -1167,7 +1192,8 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
weaken(TrackMemoryInterval)(
m, a, a + i - 1, sm.maphandle, PROT_READ | PROT_WRITE,
MAP_PRIVATE | *weaken(MAP_ANONYMOUS) | MAP_FIXED) == -1) {
__asan_die("error: could not map asan shadow memory\n")();
kprintf("error: could not map asan shadow memory%n");
__asan_die()();
__asan_unreachable();
}
__repstosb((void *)(intptr_t)((int64_t)((uint64_t)a << 32) >> 16),
@ -1202,20 +1228,21 @@ static textstartup void __asan_shadow_string_list(char **list) {
__asan_map_shadow((uintptr_t)list, (i + 1) * sizeof(char *));
}
static textstartup void __asan_shadow_existing_mappings(void) {
size_t i;
struct MemoryIntervals m;
__asan_memcpy(&m, weaken(_mmi), sizeof(m));
for (i = 0; i < m.i; ++i) {
__asan_map_shadow((uintptr_t)m.p[i].x << 16,
(uintptr_t)(m.p[i].y - m.p[i].x + 1) << 16);
static textstartup void __asan_shadow_mapping(struct MemoryIntervals *m,
size_t i) {
uintptr_t x, y;
if (i < m->i) {
x = m->p[i].x;
y = m->p[i].y;
__asan_shadow_mapping(m, i + 1);
__asan_map_shadow(x << 16, (y - x + 1) << 16);
}
__asan_poison(GetStackAddr(0), PAGESIZE, kAsanStackOverflow);
}
static textstartup bool IsMemoryManagementRuntimeLinked(void) {
return weaken(_mmi) && weaken(sys_mmap) && weaken(MAP_ANONYMOUS) &&
weaken(TrackMemoryInterval);
static textstartup void __asan_shadow_existing_mappings(void) {
__asan_shadow_mapping(&_mmi, 0);
__asan_map_shadow(GetStackAddr(0), GetStackSize());
__asan_poison(GetStackAddr(0), PAGESIZE, kAsanStackOverflow);
}
textstartup void __asan_init(int argc, char **argv, char **envp,
@ -1223,7 +1250,7 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
static bool once;
if (!cmpxchg(&once, false, true)) return;
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
__write_str("error: asan binaries require windows10\n");
__write_str("error: asan binaries require windows10\r\n");
_Exit(0); /* So `make MODE=dbg test` passes w/ Windows7 */
}
REQUIRE(_mmi);
@ -1241,7 +1268,7 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
__asan_map_shadow(0, 4096);
__asan_poison(0, PAGESIZE, kAsanNullPage);
if (!IsWindows()) {
__sysv_mprotect((void *)0x00007fff8000, 0x10000, PROT_READ);
__sysv_mprotect((void *)0x7fff8000, 0x10000, PROT_READ);
}
__asan_shadow_string_list(argv);
__asan_shadow_string_list(envp);

View file

@ -1,29 +1,10 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
#define COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
#include "libc/calls/struct/iovec.h"
#include "libc/intrin/asancodes.h"
#include "libc/macros.internal.h"
#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 */
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define SHADOW(x) ((signed char *)(((intptr_t)(x) >> kAsanScale) + kAsanMagic))
#define UNSHADOW(x) ((void *)(MAX(0, (intptr_t)(x)-kAsanMagic) << kAsanScale))
@ -32,7 +13,7 @@ typedef void __asan_die_f(void);
struct AsanFault {
signed char kind;
signed char *shadow;
const signed char *shadow;
};
extern bool __asan_noreentry;
@ -58,4 +39,6 @@ void *__asan_memalign(size_t, size_t);
size_t __asan_get_heap_size(const void *);
void *__asan_realloc_in_place(void *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ */

28
libc/intrin/asancodes.h Normal file
View file

@ -0,0 +1,28 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_ASANCODES_H_
#define COSMOPOLITAN_LIBC_INTRIN_ASANCODES_H_
#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 kAsanGlobalUnderrun -20 /* μ 0xec */
#define kAsanGlobalOverrun -21 /* Ω 0xeb */
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASANCODES_H_ */

42
libc/intrin/assertfail.c Normal file
View file

@ -0,0 +1,42 @@
/*-*- 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/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
/**
* Handles failure of assert() macro.
*/
relegated wontreturn void __assert_fail(const char *expr, const char *file,
int line) {
static bool noreentry;
kprintf("%s:%d: assert(%s) failed%n", file, line, expr);
if (cmpxchg(&noreentry, false, true)) {
if (weaken(__die)) {
weaken(__die)();
} else {
kprintf("can't backtrace b/c `__die` not linked%n");
}
quick_exit(23);
}
_Exit(24);
}

View file

@ -16,15 +16,15 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#define ShouldUseMsabiAttribute() 1
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/nexgen32e/vendor.internal.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/sysv/consts/nr.h"
extern void(__msabi* __imp_ExitProcess)(uint32_t);
/**
* Terminates process, ignoring destructors and atexit() handlers.
*

View file

@ -57,6 +57,12 @@ o/$(MODE)/libc/intrin/asan.o: \
-finline \
-finline-functions
o/$(MODE)/libc/intrin/kstarttsc.o \
o/$(MODE)/libc/intrin/nomultics.o \
o/$(MODE)/libc/intrin/ntconsolemode.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all
o/$(MODE)/libc/intrin/asan.o \
o/$(MODE)/libc/intrin/ubsan.o: \
OVERRIDE_CFLAGS += \

798
libc/intrin/kprintf.greg.c Normal file
View file

@ -0,0 +1,798 @@
/*-*- 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.
*/
#define ShouldUseMsabiAttribute() 1
#include "libc/bits/bits.h"
#include "libc/bits/likely.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/divmod10.internal.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
#include "libc/str/utf16.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/prot.h"
#define MAXT (24 * 60 * 60 * 1000000000ull)
#define WRAP ((MAXT + 1) / 10 * 33)
struct Timestamps {
unsigned long long birth;
unsigned long long start;
};
extern int __pid;
extern bool __replmode;
extern bool __nomultics;
static volatile unsigned long long kbirth;
privileged static struct Timestamps kenter(void) {
struct Timestamps ts;
ts.start = rdtsc();
ts.birth = kbirth;
if (!ts.birth) {
ts.birth = kStartTsc;
if (!ts.birth) ts.birth = 1;
cmpxchg(&kbirth, 0, ts.birth);
}
return ts;
}
privileged static void kleave(struct Timestamps ts) {
uint64_t finish, elapse, adjust;
finish = rdtsc();
elapse = unsignedsubtract(finish, ts.start);
adjust = ts.birth + elapse;
if (!adjust) adjust = 1;
cmpxchg(&kbirth, ts.birth, adjust); /* ignore overlapping time intervals */
}
privileged static inline char *kadvance(char *p, char *e, long n) {
intptr_t t = (intptr_t)p;
if (__builtin_add_overflow(t, n, &t)) t = (intptr_t)e;
return (char *)t;
}
privileged static char *kemitquote(char *p, char *e, signed char t,
unsigned c) {
if (t) {
if (p < e) {
*p = t < 0 ? 'u' : 'L';
}
++p;
}
if (p < e) {
*p = c;
}
++p;
return p;
}
privileged static unsigned long long kgetint(va_list va, signed char t,
bool s) {
#ifdef __LP64__
int bits;
unsigned long long x;
x = va_arg(va, unsigned long);
if (t <= 0) {
bits = 64 - (32 >> MIN(5, -t));
x <<= bits;
if (s) {
x = (signed long)x >> bits;
} else {
x >>= bits;
}
}
return x;
#else
if (s) {
switch (t) {
case -2:
return (signed char)va_arg(va, int);
case -1:
return (signed short)va_arg(va, int);
default:
return va_arg(va, signed int);
case 1:
return va_arg(va, signed long);
case 2:
return va_arg(va, signed long long);
}
} else {
switch (t) {
case -2:
return (unsigned char)va_arg(va, int);
case -1:
return (unsigned short)va_arg(va, int);
default:
return va_arg(va, unsigned int);
case 1:
return va_arg(va, unsigned long);
case 2:
return va_arg(va, unsigned long long);
}
}
#endif
}
privileged static inline bool kiskernelpointer(const void *p) {
return 0x7f0000000000 <= (intptr_t)p && (intptr_t)p < 0x800000000000;
}
privileged static inline bool kistextpointer(const void *p) {
return _base <= (const unsigned char *)p && (const unsigned char *)p < _etext;
}
privileged static inline bool kisimagepointer(const void *p) {
return _base <= (const unsigned char *)p && (const unsigned char *)p < _end;
}
privileged static inline bool kischarmisaligned(const char *p, signed char t) {
if (t == -1) return (intptr_t)p & 1;
if (t >= 1) return !!((intptr_t)p & 3);
return false;
}
privileged static inline bool kismemtrackhosed(void) {
return !((weaken(_mmi)->i <= weaken(_mmi)->n) &&
(weaken(_mmi)->p == weaken(_mmi)->s ||
weaken(_mmi)->p == (struct MemoryInterval *)kMemtrackStart));
}
privileged static bool kismapped(int x) {
size_t m, r, l = 0;
if (!weaken(_mmi)) return true;
if (kismemtrackhosed()) return false;
r = weaken(_mmi)->i;
while (l < r) {
m = (l + r) >> 1;
if (weaken(_mmi)->p[m].y < x) {
l = m + 1;
} else {
r = m;
}
}
if (l < weaken(_mmi)->i && x >= weaken(_mmi)->p[l].x) {
return !!(weaken(_mmi)->p[l].prot & PROT_READ);
} else {
return false;
}
}
privileged bool kisdangerous(const void *p) {
int frame;
if (kisimagepointer(p)) return false;
if (kiskernelpointer(p)) return false;
if (IsLegalPointer(p)) {
frame = (intptr_t)p >> 16;
if (IsStackFrame(frame)) return false;
if (IsOldStackFrame(frame)) return false;
if (kismapped(frame)) return false;
}
return true;
}
privileged static void klog(const char *b, size_t n) {
int e;
size_t i;
uint16_t dx;
uint32_t wrote;
unsigned char al;
long rax, rdi, rsi, rdx;
if (IsWindows()) {
e = __imp_GetLastError();
__imp_WriteFile(__imp_GetStdHandle(kNtStdErrorHandle), b, n, &wrote, 0);
__imp_SetLastError(e);
} else if (IsMetal()) {
for (i = 0; i < n; ++i) {
for (;;) {
dx = 0x3F8 + UART_LSR;
asm("inb\t%1,%0" : "=a"(al) : "dN"(dx));
if (al & UART_TTYTXR) break;
asm("pause");
}
dx = 0x3F8;
asm volatile("outb\t%0,%1"
: /* no inputs */
: "a"(b[i]), "dN"(dx));
}
} else {
asm volatile("syscall"
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
: "0"(__NR_write), "1"(2), "2"(b), "3"(n)
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
}
}
privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
struct Timestamps ts) {
int si;
wint_t t, u;
const char *abet;
signed char type;
const char *s, *f;
unsigned long long x;
unsigned i, j, m, rem, sign, hash, cols, prec;
char c, *p, *e, pdot, zero, flip, dang, base, quot, z[128];
if (kistextpointer(b) || kisdangerous(b)) n = 0;
if (!kistextpointer(fmt)) fmt = "!!WONTFMT";
p = b;
f = fmt;
e = p + n;
for (;;) {
for (;;) {
if (!(c = *f++) || c == '%') break;
EmitFormatByte:
if (p < e) *p = c;
++p;
}
if (!c) break;
pdot = 0;
flip = 0;
dang = 0;
hash = 0;
sign = 0;
prec = 0;
quot = 0;
type = 0;
cols = 0;
zero = 0;
abet = "0123456789abcdef";
for (;;) {
switch ((c = *f++)) {
default:
goto EmitFormatByte;
case '\0':
break;
case '.':
pdot = 1;
continue;
case '-':
flip = 1;
continue;
case '#':
hash = '0';
continue;
case '_':
case ',':
case '\'':
quot = c;
continue;
case ' ':
case '+':
sign = c;
continue;
case 'h':
--type;
continue;
case 'j':
case 'l':
case 'z':
++type;
continue;
case '!':
dang = 1;
continue;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
si = pdot ? prec : cols;
si *= 10;
si += c - '0';
goto UpdateCols;
case '*':
si = va_arg(va, int);
UpdateCols:
if (pdot) {
if (si >= 0) {
prec = si;
}
} else {
if (si < 0) {
flip = 1;
si = -si;
}
cols = si;
if (!cols) {
zero = 1;
}
}
continue;
case 'T':
x = unsignedsubtract(ts.start, ts.birth) % WRAP * 10 / 33;
goto FormatUnsigned;
case 'P':
if (!__vforked) {
x = __pid;
} else {
asm volatile("syscall"
: "=a"(x)
: "0"(__NR_getpid)
: "rcx", "rdx", "r11", "memory", "cc");
}
goto FormatUnsigned;
case 'u':
case 'd':
if (UNLIKELY(type <= -3)) {
s = va_arg(va, int) ? "true" : "false";
goto FormatString;
}
x = kgetint(va, type, c == 'd');
FormatDecimal:
if ((long long)x < 0 && c != 'u') {
x = -x;
sign = '-';
}
FormatUnsigned:
if (x && hash) sign = hash;
for (i = j = 0;;) {
x = DivMod10(x, &rem);
z[i++ & 127] = '0' + rem;
if (pdot ? i >= prec : !x) break;
if (quot && ++j == 3) {
z[i++ & 127] = quot;
j = 0;
}
}
EmitNumber:
if (flip || pdot) zero = 0;
while (zero && sign) {
if (p < e) *p = sign;
if (cols) --cols;
sign >>= 8;
++p;
}
t = !!sign + !!(sign >> 8);
if (!flip && cols >= t) {
for (j = i; j < cols - t; ++j) {
if (p < e) {
*p++ = zero ? '0' : ' ';
} else {
p = kadvance(p, e, cols - t - j);
break;
}
}
}
while (sign) {
if (p < e) *p = sign;
sign >>= 8;
++p;
}
for (j = i; j; ++p) {
--j;
if (p < e) {
*p = z[j & 127];
}
}
if (flip && cols >= t) {
for (j = i; j < cols - t; ++j) {
if (p < e) {
*p++ = ' ';
} else {
p = kadvance(p, e, cols - t - j);
break;
}
}
}
break;
case 'b':
base = 1;
if (hash) hash = '0' | 'b' << 8;
BinaryNumber:
x = kgetint(va, type, false);
FormatNumber:
i = 0;
m = (1 << base) - 1;
if (hash && x) sign = hash;
do z[i++ & 127] = abet[x & m];
while ((x >>= base) || (pdot && i < prec));
goto EmitNumber;
case 'X':
abet = "0123456789ABCDEF";
/* fallthrough */
case 'x':
base = 4;
if (hash) hash = '0' | 'x' << 8;
goto BinaryNumber;
case 'o':
base = 3;
goto BinaryNumber;
case 'p':
x = va_arg(va, intptr_t);
if (!x && pdot) pdot = 0;
if ((long)x == -1) {
pdot = 0;
goto FormatDecimal;
}
hash = '0' | 'x' << 8;
base = 4;
goto FormatNumber;
case 'C':
c = 'c';
type = 1;
/* fallthrough */
case 'c':
i = 1;
j = 0;
x = 0;
s = (const char *)&x;
t = va_arg(va, int);
if (!type) t &= 255;
if (hash) {
quot = 1;
hash = '\'';
p = kemitquote(p, e, type, hash);
if (cols && type) --cols; /* u/L */
if (cols) --cols; /* start quote */
if (cols) --cols; /* end quote */
}
goto EmitChar;
case 'm':
if (!(x = errno) && sign == ' ') {
break;
} else if (weaken(strerror_r) &&
!weaken(strerror_r)(x, z, sizeof(z))) {
s = z;
goto FormatString;
} else {
goto FormatDecimal;
}
case 'n':
if (__nomultics) {
if (p < e) *p = '\r';
++p;
}
if (p < e) *p = '\n';
++p;
break;
case 'r':
if (!__replmode) {
break;
} else {
s = "\r\033[K";
goto FormatString;
}
case 'S':
c = 's';
type = 1;
/* fallthrough */
case 's':
if (!(s = va_arg(va, const void *))) {
s = sign != ' ' ? "NULL" : "";
FormatString:
type = 0;
hash = 0;
} else if (!dang && (kisdangerous(s) || kischarmisaligned(s, type))) {
if (sign == ' ') {
if (p < e) *p = ' ';
++p;
}
x = (intptr_t)s;
base = 4;
hash = '!' | '!' << 8;
goto FormatNumber;
} else if (hash) {
quot = 1;
hash = '"';
if (cols && type) --cols; /* u/L */
if (cols) --cols; /* start quote */
if (cols) --cols; /* end quote */
p = kemitquote(p, e, type, hash);
}
if (sign == ' ' && (!pdot || prec) && *s) {
if (p < e) *p = ' ';
++p;
}
for (i = j = 0; !pdot || j < prec; ++j) {
if (UNLIKELY(!((intptr_t)s & (PAGESIZE - 1)))) {
if (!dang && kisdangerous(s)) break;
}
if (!type) {
if (!(t = *s++ & 255)) break;
if ((t & 0300) == 0200) goto ActuallyEmitByte;
++i;
EmitByte:
if (UNLIKELY(quot) && (t == '\\' || ((t == '"' && c == 's') ||
(t == '\'' && c == 'c')))) {
if (p + 2 <= e) {
p[0] = '\\';
p[1] = t;
}
p += 2;
i += 1;
continue;
}
if (pdot ||
(t != 0x7F && (t >= 0x20 || (t == '\n' || t == '\t' ||
t == '\r' || t == '\e')))) {
ActuallyEmitByte:
if (p < e) *p = t;
p += 1;
continue;
} else if (quot) {
if (p + 4 <= e) {
p[0] = '\\';
p[1] = '0' + ((t & 0300) >> 6);
p[2] = '0' + ((t & 0070) >> 3);
p[3] = '0' + ((t & 0007) >> 0);
}
p += 4;
i += 3;
continue;
} else {
/* Control Pictures
2400 0 1 2 3 4 5 6 7 8 9 a b c d e f
2400
2410
2420 */
if (t != 0x7F) {
t += 0x2400;
} else {
t = 0x2421;
}
goto EmitChar;
}
} else if (type < -1) {
if ((t = *s++ & 255)) {
t = kCp437[t];
}
} else if (type < 0) {
t = *(const char16_t *)s;
s += sizeof(char16_t);
if (IsHighSurrogate(t)) {
if (!pdot || j + 1 < prec) {
if (UNLIKELY(!((intptr_t)s & (PAGESIZE - 1)))) {
if (!dang && kisdangerous(s)) break;
}
u = *(const char16_t *)s;
if (IsLowSurrogate(u)) {
t = MergeUtf16(t, u);
s += sizeof(char16_t);
j += 1;
}
} else {
break;
}
} else if (!t) {
break;
}
} else {
t = *(const wchar_t *)s;
s += sizeof(wchar_t);
}
if (!t) break;
++i;
EmitChar:
if (t <= 0x7f) {
goto EmitByte;
} else if (t <= 0x7ff) {
if (p + 2 <= e) {
p[0] = 0300 | (t >> 6);
p[1] = 0200 | (t & 077);
}
p += 2;
} else if (t <= 0xffff) {
if (UNLIKELY(IsSurrogate(t))) {
EncodeReplacementCharacter:
t = 0xfffd;
}
if (p + 3 <= e) {
p[0] = 0340 | (t >> 12);
p[1] = 0200 | ((t >> 6) & 077);
p[2] = 0200 | (t & 077);
}
p += 3;
} else if (~(t >> 18) & 007) {
if (p + 4 <= e) {
p[0] = 0360 | (t >> 18);
p[1] = 0200 | ((t >> 12) & 077);
p[2] = 0200 | ((t >> 6) & 077);
p[3] = 0200 | (t & 077);
}
p += 4;
} else {
goto EncodeReplacementCharacter;
}
}
if (hash) {
if (p < e) *p = hash;
++p;
}
for (; cols > i; --cols) {
if (p < e) {
*p++ = ' ';
} else {
p = kadvance(p, e, cols - i);
break;
}
}
break;
}
break;
}
}
if (p < e) {
*p = 0;
} else if (e > b) {
u = 0;
*--e = 0;
s = "\n...";
if (!(((f - fmt) >= 2 && f[-2] == '\n') ||
((f - fmt) >= 3 && f[-3] == '%' && f[-2] == 'n'))) {
++s;
}
while ((t = *s++) && e > b) {
u = *--e;
*e = t;
}
if ((u & 0300) == 0200) {
while (e > b) {
u = *--e;
*e = '.';
if ((u & 0300) != 0200) {
break;
}
}
}
}
return p - b;
}
/**
* Privileged snprintf().
*
* @param b is buffer, and guaranteed a NUL-terminator if `n>0`
* @param n is number of bytes available in buffer
* @return length of output excluding NUL, which may exceed `n`
* @see kprintf() for documentation
* @asyncsignalsafe
* @vforksafe
*/
privileged size_t ksnprintf(char *b, size_t n, const char *fmt, ...) {
size_t m;
va_list v;
struct Timestamps t = {0};
va_start(v, fmt);
m = kformat(b, n, fmt, v, t);
va_end(v);
return m;
}
/**
* Privileged vsnprintf().
*
* @param b is buffer, and guaranteed a NUL-terminator if `n>0`
* @param n is number of bytes available in buffer
* @return length of output excluding NUL, which may exceed `n`
* @see kprintf() for documentation
* @asyncsignalsafe
* @vforksafe
*/
privileged size_t kvsnprintf(char *b, size_t n, const char *fmt, va_list v) {
struct Timestamps t = {0};
return kformat(b, n, fmt, v, t);
}
/**
* Privileged vprintf.
*
* @see kprintf() for documentation
* @asyncsignalsafe
* @vforksafe
*/
privileged void kvprintf(const char *fmt, va_list v) {
size_t n;
char b[2048];
struct Timestamps t;
if (!v) return;
t = kenter();
n = kformat(b, sizeof(b), fmt, v, t);
klog(b, MIN(n, sizeof(b)));
kleave(t);
}
/**
* Privileged printf().
*
* This function is intended for crash reporting. It's designed to be as
* unbreakable as possible, so that error messages can always be printed
* even when the rest of the runtime is broken. As such, it has continue
* on error semantics, doesn't support buffering between invocations and
* floating point is not supported. Output is also truncated if the line
* gets too long, but care is taken to preserve your newline characters.
* Your errno and GetLastError() state will not be clobbered, and ftrace
* and other runtime magic won't be invoked, since all the runtime magic
* depends on this function.
*
* Directives:
*
* %[FLAGS][WIDTH|*][.[PRECISION|*]][TYPE]SPECIFIER
*
* Specifiers:
*
* - `P` pid
* - `c` char
* - `o` octal
* - `b` binary
* - `s` string
* - `p` pointer
* - `d` decimal
* - `n` newline
* - `u` unsigned
* - `r` carriage
* - `m` strerror
* - `X` uppercase
* - `T` timestamp
* - `x` hexadecimal
*
* Types:
*
* - `hhh` bool
* - `hh` char or cp437
* - `h` short or char16_t
* - `l` long or wchar_t
* - `ll` long long
*
* Flags:
*
* - `0` zero padding
* - `-` flip alignment
* - `!` bypass memory safety
* - `,` thousands grouping w/ comma
* - `'` thousands grouping w/ apostrophe
* - `_` thousands grouping w/ underscore
* - `+` plus leftpad if positive (aligns w/ negatives)
* - ` ` space leftpad if positive (aligns w/ negatives)
* - `#` represent value with literal syntax, e.g. 0x, 0b, quotes
*
* @asyncsignalsafe
* @vforksafe
*/
privileged void kprintf(const char *fmt, ...) {
/* system call support runtime depends on this function */
/* function tracing runtime depends on this function */
/* asan runtime depends on this function */
va_list v;
va_start(v, fmt);
kvprintf(fmt, v);
va_end(v);
}

14
libc/intrin/kprintf.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_KPRINTF_H_
#define COSMOPOLITAN_LIBC_INTRIN_KPRINTF_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void kprintf(const char *, ...);
size_t ksnprintf(char *, size_t, const char *, ...);
void kvprintf(const char *, va_list);
size_t kvsnprintf(char *, size_t, const char *, va_list);
bool kisdangerous(const void *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_KPRINTF_H_ */

26
libc/intrin/kstarttsc.c Normal file
View file

@ -0,0 +1,26 @@
/*-*- 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.
*/
/**
* Timestamp of process start.
*
* @see libc/runtime/winmain.greg.h
* @see libc/crt/crt.S
*/
uint64_t kStartTsc;

30
libc/intrin/nomultics.c Normal file
View file

@ -0,0 +1,30 @@
/*-*- 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.
*/
/**
* Controls disablement of MULTICS newlines.
*
* Normally we use `\n` for newlines. If this is `true` then we'll try
* our best to use `\r\n`. This is toggled automatically on Windows or
* when `ioctl(TCSETS)` disables `OPOST`.
*
* @see kprintf()
*/
bool __nomultics;
bool __replmode;

View file

@ -0,0 +1,21 @@
/*-*- 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/runtime/internal.h"
uint32_t __ntconsolemode[2];

View file

@ -1,242 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/limits.h"
#include "libc/log/libfatal.internal.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/str/tpenc.h"
#include "libc/sysv/consts/nr.h"
/**
* Privileged vprintf.
*
* This will work without any cosmopolitan runtime support once the
* executable has been loaded into memory.
*/
privileged noasan noubsan noinstrument void __vprintf(const char *fmt,
va_list va) {
short w[2];
uint16_t dx;
const void *s;
uint32_t wrote;
unsigned long x;
unsigned char al;
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);
do {
switch ((c = *fmt++)) {
default:
if (p < e) {
*p++ = c;
}
break;
case '\0':
break;
case '%':
dot = 0;
pad = ' ';
sign = 0;
bits = 0;
thou = 0;
w[0] = 0;
w[1] = SHRT_MAX;
NeedMoar:
switch ((c = *fmt++)) {
case '\0':
break;
case 'l':
case 'z':
goto NeedMoar;
case ' ':
case '+':
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[dot] = va_arg(va, int);
goto NeedMoar;
case 'd':
d = va_arg(va, long);
ApiAbuse:
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':
pad = '0';
w[0] = 12;
w[1] = 12;
/* fallthrough */
case 'x':
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 void *);
EmitString:
if (!s) {
s = "NULL";
bits = 0;
} else if ((uintptr_t)s < PAGESIZE) {
d = (intptr_t)s;
goto ApiAbuse;
}
for (i = 0; i < w[1]; ++i) {
if (!bits) {
t = ((const char *)s)[i];
EmitByte:
if (t) {
if (p < e) {
*p++ = t;
}
} else {
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;
p += 3;
}
}
}
while (w[0]-- > i) {
if (p < e) *p++ = pad;
}
break;
default:
break;
}
break;
}
} while (c);
if (p == e) {
e[-4] = '.';
e[-3] = '.';
e[-2] = '.';
e[-1] = '\n';
}
if (IsWindows()) {
WriteFile(GetStdHandle(kNtStdErrorHandle), b, p - b, &wrote, 0);
} else if (IsMetal()) {
for (e = p, p = b; p < e; ++p) {
for (;;) {
dx = 0x3F8 + UART_LSR;
asm("inb\t%1,%0" : "=a"(al) : "dN"(dx));
if (al & UART_TTYTXR) break;
asm("pause");
}
dx = 0x3F8;
asm volatile("outb\t%0,%1"
: /* no inputs */
: "a"(*p), "dN"(dx));
}
} else {
asm volatile("syscall"
: "=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");
}
}
/**
* Privileged printf.
*
* This will work without any cosmopolitan runtime support once the
* executable has been loaded into memory.
*/
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 */
va_list va;
va_start(va, fmt);
__vprintf(fmt, va);
va_end(va);
}

50
libc/intrin/quick_exit.c Normal file
View file

@ -0,0 +1,50 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/dce.h"
#include "libc/nt/console.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
const char kConsoleHandles[2] = {kNtStdInputHandle, kNtStdOutputHandle};
/**
* Exits process faster.
*
* @param exitcode is masked with 255
* @noreturn
*/
wontreturn void quick_exit(int exitcode) {
int i;
const uintptr_t *p;
if (weaken(fflush)) {
weaken(fflush)(0);
}
if (SupportsWindows() && __ntconsolemode[0]) {
for (i = 0; i < 2; ++i) {
SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]);
}
}
for (p = __fini_array_end; p > __fini_array_start;) {
((void (*)(void))(*--p))();
}
_Exit(exitcode);
}

View file

@ -21,6 +21,7 @@
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
@ -189,7 +190,7 @@ static uintptr_t __ubsan_extend(struct UbsanTypeDescriptor *t, uintptr_t x) {
void __ubsan_abort(const struct UbsanSourceLocation *loc,
const char *description) {
__printf("\r\n%s:%d: ubsan error: %s\r\n", loc->file, loc->line, description);
kprintf("%n%s:%d: ubsan error: %s%n", loc->file, loc->line, description);
if (weaken(__die)) weaken(__die)();
_Exit(134);
}
@ -258,7 +259,7 @@ void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *info,
p = __stpcpy(p, " align ");
p = __intcpy(p, info->alignment);
} else {
p = __stpcpy(p, "insufficient size\r\n\t");
p = __stpcpy(p, "insufficient size%n\t");
p = __stpcpy(p, kind);
p = __stpcpy(p, " address 0x");
p = __fixcpy(p, pointer, sizeof(pointer) * CHAR_BIT);

21
libc/intrin/vforked.c Normal file
View file

@ -0,0 +1,21 @@
/*-*- 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"
int __vforked;