Add MODE=optlinux build mode (#141)

This commit is contained in:
Justine Tunney 2021-10-14 19:36:49 -07:00
parent 226aaf3547
commit 67b5200a0b
111 changed files with 934 additions and 854 deletions

Binary file not shown.

View file

@ -9,17 +9,13 @@
# - Reasonably small
# - Reasonably optimized
# - Reasonably debuggable
ifeq ($(MODE),)
CONFIG_CCFLAGS += \
$(BACKTRACES) \
$(FTRACE) \
-Og
TARGET_ARCH ?= \
-msse3
endif
# Optimized Mode
@ -31,22 +27,39 @@ endif
# - No memory corruption detection
# - assert() / CHECK_xx() may leak code into binary for debuggability
# - GCC 8+ hoists check fails into .text.cold, thus minimizing impact
ifeq ($(MODE), opt)
CONFIG_CPPFLAGS += \
-DNDEBUG \
-msse2avx \
-Wa,-msse2avx
CONFIG_CCFLAGS += \
$(BACKTRACES) \
$(FTRACE) \
-O3
TARGET_ARCH ?= \
-march=native
endif
# Optimized Linux Mode
#
# - `make MODE=optlinux`
# - Turns on red zone
# - Turns off backtraces
# - Turns off function tracing
# - Turns off support for older cpu models
# - Turns off support for other operating systems
ifeq ($(MODE), optlinux)
CONFIG_CPPFLAGS += \
-DNDEBUG \
-msse2avx \
-Wa,-msse2avx \
-DSUPPORT_VECTOR=1
CONFIG_CCFLAGS += \
-O3
DEFAULT_COPTS += \
-mred-zone
TARGET_ARCH ?= \
-march=native
endif
# Release Mode
@ -62,22 +75,16 @@ endif
# - DCHECK_xx() statements removed
# - No memory corruption detection
# - CHECK_xx() won't leak strings into binary
ifeq ($(MODE), rel)
CONFIG_CPPFLAGS += \
-DNDEBUG
CONFIG_CCFLAGS += \
$(BACKTRACES) \
-O2
TARGET_ARCH ?= \
-msse3
PYFLAGS += \
-O1
endif
# Asan Mode
@ -90,19 +97,14 @@ endif
# - Backtraces
# - Debuggability
# - Larger binaries
ifeq ($(MODE), asan)
CONFIG_CCFLAGS += \
$(BACKTRACES) \
-O2
CONFIG_COPTS += \
-fsanitize=address
TARGET_ARCH ?= \
-msse3
endif
# Debug Mode
@ -114,27 +116,20 @@ endif
# - Stack canaries
# - No optimization (TODO)
# - Enormous binaries
ifeq ($(MODE), dbg)
CONFIG_CPPFLAGS += \
-DMODE_DBG
CONFIG_CCFLAGS += \
$(BACKTRACES) \
$(FTRACE) \
-O2 \
-fno-inline
CONFIG_COPTS += \
-fsanitize=address
TARGET_ARCH ?= \
-msse3
OVERRIDE_CCFLAGS += \
-fno-pie
endif
# Tiny Mode
@ -148,7 +143,6 @@ endif
# - No backtraces
# - No algorithmics
# - YOLO
ifeq ($(MODE), tiny)
CONFIG_CPPFLAGS += \
-DTINY \
@ -161,6 +155,7 @@ CONFIG_CCFLAGS += \
-fno-align-labels \
-fno-align-loops \
-fschedule-insns2 \
-fomit-frame-pointer \
-momit-leaf-frame-pointer \
-foptimize-sibling-calls
TARGET_ARCH ?= \
@ -182,20 +177,21 @@ endif
# - No portability
# - No algorithmics
# - YOLO
ifeq ($(MODE), tinylinux)
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=1
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
-fno-align-jumps \
-fno-align-labels \
DEFAULT_COPTS += \
-mred-zone
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
-fno-align-jumps \
-fno-align-labels \
-fno-align-loops
TARGET_ARCH ?= \
TARGET_ARCH ?= \
-msse3
endif
@ -212,13 +208,14 @@ endif
# - No backtraces
# - No algorithmics
# - YOLO
ifeq ($(MODE), tinylinuxbsd)
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=113
DEFAULT_COPTS += \
-mred-zone
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
@ -241,13 +238,14 @@ endif
# - No backtraces
# - No algorithmics
# - YOLO
ifeq ($(MODE), tinysysv)
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=121
DEFAULT_COPTS += \
-mred-zone
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
@ -270,7 +268,6 @@ endif
# - No backtraces
# - No algorithmics
# - YOLO
ifeq ($(MODE), tinynowin)
CONFIG_CPPFLAGS += \
-DTINY \

View file

@ -89,6 +89,8 @@ FTRACE = \
-pg
BACKTRACES = \
-fno-schedule-insns2 \
-fno-omit-frame-pointer \
-fno-optimize-sibling-calls \
-mno-omit-leaf-frame-pointer
@ -129,7 +131,6 @@ DEFAULT_COPTS = \
-fno-gnu-unique \
-fstrict-aliasing \
-fstrict-overflow \
-fno-omit-frame-pointer \
-fno-semantic-interposition
MATHEMATICAL = \

View file

@ -132,6 +132,14 @@ o/$(MODE)/examples/nesemu1.com.dbg: \
$(APE)
@$(APELINK)
o/$(MODE)/examples/hello.com.dbg: \
$(EXAMPLES_DEPS) \
o/$(MODE)/examples/hello.o \
o/$(MODE)/examples/examples.pkg \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/examples/nesemu1.o: QUOTA += -M512m
$(EXAMPLES_OBJS): examples/examples.mk

View file

@ -19,9 +19,12 @@
#include "libc/calls/math.h"
#include "libc/macros.internal.h"
/**
* Adds resource usages.
*/
void AddRusage(struct rusage *x, const struct rusage *y) {
AddTimeval(&x->ru_utime, &y->ru_utime);
AddTimeval(&x->ru_stime, &y->ru_stime);
x->ru_utime = AddTimeval(x->ru_utime, y->ru_utime);
x->ru_stime = AddTimeval(x->ru_stime, y->ru_stime);
x->ru_maxrss = MAX(x->ru_maxrss, y->ru_maxrss);
x->ru_ixrss += y->ru_ixrss;
x->ru_idrss += y->ru_idrss;

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,21 +16,17 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/calls/math.h"
// 8-bit strlen that's tiny and near optimal if data's tiny.
//
// @param RDI is char *s
// @param EAX is unsigned length
// @see libc/nexgen32e/strsak.S
tinystrlen:
.leafprologue
.profilable
xor %eax,%eax
1: cmpb $0,(%rdi,%rax)
jz 2f
inc %eax
jmp 1b
2: .leafepilogue
.endfn tinystrlen,globl
.source __FILE__
/**
* Adds two microsecond timestamps.
*/
struct timespec AddTimespec(struct timespec x, struct timespec y) {
x.tv_sec += y.tv_sec;
x.tv_nsec += y.tv_nsec;
if (x.tv_nsec >= 10000000000) {
x.tv_nsec -= 10000000000;
x.tv_sec += 1;
}
return x;
}

View file

@ -18,11 +18,15 @@
*/
#include "libc/calls/math.h"
void AddTimeval(struct timeval *x, const struct timeval *y) {
x->tv_sec += y->tv_sec;
x->tv_usec += y->tv_usec;
if (x->tv_usec >= 1000000) {
x->tv_usec -= 1000000;
x->tv_sec += 1;
/**
* Adds two microsecond timestamps.
*/
struct timeval AddTimeval(struct timeval x, struct timeval y) {
x.tv_sec += y.tv_sec;
x.tv_usec += y.tv_usec;
if (x.tv_usec >= 1000000) {
x.tv_usec -= 1000000;
x.tv_sec += 1;
}
return x;
}

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/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
@ -39,9 +40,16 @@
* @see fchmod()
*/
int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) {
int rc;
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (weaken(__zipos_notat) && weaken(__zipos_notat)(dirfd, path) == -1) {
return -1; /* TODO(jart): implement me */
rc = -1; /* TODO(jart): implement me */
} else if (!IsWindows()) {
rc = sys_fchmodat(dirfd, path, mode, flags);
} else {
rc = sys_fchmodat_nt(dirfd, path, mode, flags);
}
return sys_fchmodat(dirfd, path, mode, flags);
SYSDEBUG("fchmodat(%d, %s, %o, %d) -> %d %s", (long)dirfd, path, mode, flags,
rc != -1 ? "" : strerror(errno));
return rc;
}

View file

@ -44,30 +44,35 @@
*/
bool fileexists(const char *path) {
int e;
bool res;
union metastat st;
struct ZiposUri zipname;
uint16_t path16[PATH_MAX];
e = errno;
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(path, &zipname) != -1) {
e = errno;
if (weaken(__zipos_stat)(&zipname, &st.cosmo) != -1) {
return true;
res = true;
} else {
errno = e;
return false;
res = false;
}
} else if (IsMetal()) {
return false;
res = false;
} else if (!IsWindows()) {
e = errno;
if (__sys_fstatat(AT_FDCWD, path, &st, 0) != -1) {
return true;
res = true;
} else {
errno = e;
return false;
res = false;
}
} else if (__mkntpath(path, path16) != -1) {
res = GetFileAttributes(path16) != -1u;
} else {
if (__mkntpath(path, path16) == -1) return -1;
return GetFileAttributes(path16) != -1u;
res = false;
}
SYSDEBUG("fileexists(%s) -> %s %s", path, res ? "true" : "false",
res ? "" : strerror(errno));
if (!res && (errno == ENOENT || errno == ENOTDIR)) {
errno = e;
}
return res;
}

View file

@ -21,6 +21,9 @@
#include "libc/calls/weirdtypes.h"
#include "libc/str/str.h"
/**
* Convert pathname and a project ID to System V IPC key.
*/
int ftok(const char *path, int id) {
struct stat st;
if (stat(path, &st) == -1) return -1;

View file

@ -16,8 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/runtime/runtime.h"
#define ToUpper(c) \
(IsWindows() && (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
/**
* Returns value of environment variable, or NULL if not found.
*
@ -35,11 +39,11 @@ char *getenv(const char *s) {
}
break;
}
if (s[j] != p[i][j]) {
if (ToUpper(s[j]) != ToUpper(p[i][j])) {
break;
}
}
}
}
return NULL;
return 0;
}

View file

@ -21,6 +21,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/metastat.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
@ -43,29 +44,34 @@
* @see isregularfile(), issymlink(), ischardev()
*/
bool isdirectory(const char *path) {
int rc, e;
int e;
bool res;
union metastat st;
struct ZiposUri zipname;
e = errno;
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(path, &zipname) != -1) {
e = errno;
if (weaken(__zipos_stat)(&zipname, &st.cosmo) != -1) {
return S_ISDIR(st.cosmo.st_mode);
res = S_ISDIR(st.cosmo.st_mode);
} else {
errno = e;
return false;
res = false;
}
} else if (IsMetal()) {
return false;
res = false;
} else if (!IsWindows()) {
e = errno;
if (__sys_fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW) != -1) {
return S_ISDIR(METASTAT(st, st_mode));
res = S_ISDIR(METASTAT(st, st_mode));
} else {
errno = e;
return false;
res = false;
}
} else {
return isdirectory_nt(path);
res = isdirectory_nt(path);
}
SYSDEBUG("isdirectory(%s) -> %s %s", path, res ? "true" : "false",
res ? "" : strerror(errno));
if (!res && (errno == ENOENT || errno == ENOTDIR)) {
errno = e;
}
return res;
}

View file

@ -1,11 +1,13 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_MATH_H_
#define COSMOPOLITAN_LIBC_CALLS_MATH_H_
#include "libc/calls/struct/rusage.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void AddTimeval(struct timeval *, const struct timeval *);
struct timeval AddTimeval(struct timeval, struct timeval);
struct timespec AddTimespec(struct timespec, struct timespec);
void AddRusage(struct rusage *, const struct rusage *);
COSMOPOLITAN_C_END_

View file

@ -29,10 +29,13 @@
#include "libc/str/utf16.h"
#include "libc/sysv/errfuns.h"
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
static noasan int CompareStrings(const char *l, const char *r) {
int a, b;
size_t i = 0;
while (l[i] == r[i] && r[i]) ++i;
return (l[i] & 0xff) - (r[i] & 0xff);
while ((a = ToUpper(l[i] & 255)) == (b = ToUpper(r[i] & 255)) && r[i]) ++i;
return a - b;
}
static noasan void InsertString(char **a, size_t i, char *s) {
@ -56,6 +59,7 @@ static noasan void InsertString(char **a, size_t i, char *s) {
*/
textwindows noasan int mkntenvblock(char16_t envvars[ARG_MAX],
char *const envp[], const char *extravar) {
bool v;
char *t;
axdx_t rc;
uint64_t w;
@ -68,6 +72,7 @@ textwindows noasan int mkntenvblock(char16_t envvars[ARG_MAX],
if (extravar) InsertString(vars, n++, extravar);
for (k = i = 0; i < n; ++i) {
j = 0;
v = false;
do {
x = vars[i][j++] & 0xff;
if (x >= 0200) {
@ -83,6 +88,13 @@ textwindows noasan int mkntenvblock(char16_t envvars[ARG_MAX],
}
}
}
if (!v) {
if (x != '=') {
x = ToUpper(x);
} else {
v = true;
}
}
w = EncodeUtf16(x);
do {
envvars[k++] = w & 0xffff;

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/str/str.h"
@ -59,12 +58,5 @@ int sys_openat(int dirfd, const char *file, int flags, unsigned mode) {
d = sys_openat(dirfd, file, flags, mode);
}
}
if (d != -1) {
SYSDEBUG("sys_openat(%d, %s, %d, %d) -> %d", (long)dirfd, file, flags,
(flags & (O_CREAT | O_TMPFILE)) ? mode : 0, d);
} else {
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

@ -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/intrin/asan.internal.h"
#include "libc/log/log.h"
@ -43,24 +44,37 @@
* @vforksafe
*/
int openat(int dirfd, const char *file, int flags, ...) {
int rc;
va_list va;
unsigned mode;
struct ZiposUri zipname;
va_start(va, flags);
mode = va_arg(va, unsigned);
va_end(va);
if (!file) return efault();
if (IsAsan() && !__asan_is_valid(file, 1)) return efault();
if (__isfdkind(dirfd, kFdZip)) return einval(); /* TODO(jart): implement me */
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(file, &zipname) != -1) {
if (__vforked) return eopnotsupp();
if (dirfd != AT_FDCWD) return eopnotsupp();
return weaken(__zipos_open)(&zipname, flags, mode);
} else if (!IsWindows() && !IsMetal()) {
return sys_openat(dirfd, file, flags, mode);
} else if (IsMetal()) {
return sys_openat_metal(dirfd, file, flags, mode);
if (file && (!IsAsan() || __asan_is_valid(file, 1))) {
if (!__isfdkind(dirfd, kFdZip)) {
if (weaken(__zipos_open) &&
weaken(__zipos_parseuri)(file, &zipname) != -1) {
if (!__vforked && dirfd == AT_FDCWD) {
rc = weaken(__zipos_open)(&zipname, flags, mode);
} else {
rc = eopnotsupp(); /* TODO */
}
} else if (!IsWindows() && !IsMetal()) {
rc = sys_openat(dirfd, file, flags, mode);
} else if (IsMetal()) {
rc = sys_openat_metal(dirfd, file, flags, mode);
} else {
rc = sys_open_nt(dirfd, file, flags, mode);
}
} else {
rc = eopnotsupp(); /* TODO */
}
} else {
return sys_open_nt(dirfd, file, flags, mode);
rc = efault();
}
SYSDEBUG("openat(%d, %s, %d, %d) -> %d %s", (long)dirfd, file, flags,
(flags & (O_CREAT | O_TMPFILE)) ? mode : 0, (long)rc,
rc == -1 ? strerror(errno) : "");
return rc;
}

View file

@ -16,9 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Reads data from file descriptor.
@ -32,5 +39,22 @@
* @asyncsignalsafe
*/
ssize_t read(int fd, void *buf, size_t size) {
return readv(fd, &(struct iovec){buf, size}, 1);
if (fd >= 0) {
if (IsAsan() && !__asan_is_valid(buf, size)) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_read)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle,
&(struct iovec){buf, size}, 1, -1);
} else if (!IsWindows() && !IsMetal()) {
return sys_read(fd, buf, size);
} else if (fd >= g_fds.n) {
return ebadf();
} else if (IsMetal()) {
return sys_readv_metal(g_fds.p + fd, &(struct iovec){buf, size}, 1);
} else {
return sys_readv_nt(g_fds.p + fd, &(struct iovec){buf, size}, 1);
}
} else {
return einval();
}
}

View file

@ -96,7 +96,7 @@ noasan int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) {
return enosys();
}
if ((rc = sys_sigaltstack(a, b)) != -1) {
if (old) {
if (IsBsd() && old) {
sigaltstack2linux(old, &bsd);
}
return 0;

View file

@ -17,9 +17,13 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/dce.h"
#include "libc/mem/internal.h"
#include "libc/runtime/runtime.h"
#define ToUpper(c) \
(IsWindows() && (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
/**
* Removes environment variable.
*/
@ -42,7 +46,7 @@ int unsetenv(const char *s) {
}
break;
}
if (s[j] != p[i][j]) {
if (ToUpper(s[j]) != ToUpper(p[i][j])) {
break;
}
}

View file

@ -16,8 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/sock.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Writes data to file descriptor.
@ -31,5 +37,22 @@
* @asyncsignalsafe
*/
ssize_t write(int fd, const void *buf, size_t size) {
return writev(fd, &(struct iovec){buf, size}, 1);
if (fd >= 0) {
if (IsAsan() && !__asan_is_valid(buf, size)) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_write)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle,
&(struct iovec){buf, size}, 1, -1);
} else if (!IsWindows() && !IsMetal()) {
return sys_write(fd, buf, size);
} else if (fd >= g_fds.n) {
return ebadf();
} else if (IsMetal()) {
return sys_writev_metal(g_fds.p + fd, &(struct iovec){buf, size}, 1);
} else {
return sys_writev_nt(g_fds.p + fd, &(struct iovec){buf, size}, 1);
}
} else {
return einval();
}
}

View file

@ -37,6 +37,7 @@ _start:
0: mov (%rsp),%ebx # argc
lea 8(%rsp),%rsi # argv
lea 16(%rsp,%rbx,8),%rdx # envp
mov %rsp,__oldstack(%rip)
.frame0
// bofram 9f
.weak ape_idata_iat

View file

@ -16,13 +16,13 @@
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/safemacros.internal.h"
#include "libc/bits/weaken.h"
#include "libc/fmt/fmts.h"
#include "libc/fmt/internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nexgen32e/tinystrlen.internal.h"
#include "libc/str/str.h"
#include "libc/str/thompike.h"
#include "libc/str/tpenc.h"
@ -131,9 +131,9 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
if (!(flags & FLAGS_PRECISION)) precision = -1;
if (!(flags & FLAGS_PRECISION) || !ignorenul) {
if (signbit == 63) {
precision = tinywcsnlen((const wchar_t *)p, precision);
precision = wcsnlen((const wchar_t *)p, precision);
} else if (signbit == 15) {
precision = tinystrnlen16((const char16_t *)p, precision);
precision = strnlen16((const char16_t *)p, precision);
} else {
precision = strnlen(p, precision);
}

View file

@ -431,7 +431,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 (!(0 <= a && a <= 0x7fffffffffff) && !__asan_is_mapped(a >> 16)) {
} else if (IsLegalPointer(a) && !__asan_is_mapped(a >> 16)) {
return (struct AsanFault){kAsanUnmapped, s};
}
if (UNLIKELY(k)) {

View file

@ -13,7 +13,7 @@ typedef char __intrin_xmm_t _Vector_size(16) forcealign(16) mayalias;
#define INTRIN_SSEVEX_X_X_X_(PURE, ISA, OP, FLAGS, A, B, C) \
do { \
if (!IsModeDbg() && X86_HAVE(ISA)) { \
if (X86_HAVE(ISA)) { \
__intrin_xmm_t *Xmm0 = (void *)(A); \
const __intrin_xmm_t *Xmm1 = (const __intrin_xmm_t *)(B); \
const __intrin_xmm_t *Xmm2 = (const __intrin_xmm_t *)(C); \
@ -29,7 +29,7 @@ typedef char __intrin_xmm_t _Vector_size(16) forcealign(16) mayalias;
#define INTRIN_SSEVEX_X_X_I_(PURE, ISA, OP, A, B, I) \
do { \
if (!IsModeDbg() && X86_HAVE(ISA)) { \
if (X86_HAVE(ISA)) { \
__intrin_xmm_t *Xmm0 = (void *)(A); \
const __intrin_xmm_t *Xmm1 = (const __intrin_xmm_t *)(B); \
if (!X86_NEED(AVX)) { \
@ -44,7 +44,7 @@ typedef char __intrin_xmm_t _Vector_size(16) forcealign(16) mayalias;
#define INTRIN_SSEVEX_X_X_(PURE, ISA, OP, A, B) \
do { \
if (!IsModeDbg() && X86_HAVE(ISA)) { \
if (X86_HAVE(ISA)) { \
__intrin_xmm_t *Xmm0 = (void *)(A); \
const __intrin_xmm_t *Xmm1 = (const __intrin_xmm_t *)(B); \
if (!X86_NEED(AVX)) { \

View file

@ -22,7 +22,7 @@
/**
* Returns New Technology version, e.g.
*
* if (IsWindows() && NtGetVersion() >= kNtVersionWindows10) {...}
* if (IsWindows() && NtGetVersion() >=k NtVersionWindows10) {...}
*
* This can only be called on Windows.
*/

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,21 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
// 16-bit strlen that's tiny and near optimal if data's tiny.
//
// @param RDI is char16_t *s
// @param EAX is unsigned length
// @see libc/nexgen32e/strsak16.S
tinystrlen16:
.leafprologue
.profilable
xor %eax,%eax
1: cmpw $0,(%rdi,%rax,2)
jz 2f
inc %eax
jmp 1b
2: .leafepilogue
.endfn tinystrlen16,globl
.source __FILE__
intptr_t __oldstack;

View file

@ -25,17 +25,14 @@
#include "libc/sysv/consts/nr.h"
/**
* Privileged printf.
* Privileged vprintf.
*
* 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 */
privileged noasan noubsan noinstrument void __vprintf(const char *fmt,
va_list va) {
short w[2];
va_list va;
uint16_t dx;
const void *s;
uint32_t wrote;
@ -46,7 +43,6 @@ privileged noasan noubsan noinstrument void __printf(const char *fmt, ...) {
char c, *p, *e, pad, bits, base, sign, thou, z[28], b[2048];
p = b;
e = p + sizeof(b);
va_start(va, fmt);
do {
switch ((c = *fmt++)) {
default:
@ -200,7 +196,6 @@ privileged noasan noubsan noinstrument void __printf(const char *fmt, ...) {
break;
}
} while (c);
va_end(va);
if (p == e) {
e[-4] = '.';
e[-3] = '.';
@ -229,3 +224,19 @@ privileged noasan noubsan noinstrument void __printf(const char *fmt, ...) {
: "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);
}

View file

@ -1,10 +1,18 @@
#ifndef COSMOPOLITAN_LIBC_LOG_BACKTRACE_H_
#define COSMOPOLITAN_LIBC_LOG_BACKTRACE_H_
#include "libc/nexgen32e/stackframe.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/symbols.internal.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
forceinline pureconst bool IsValidStackFramePointer(struct StackFrame *x) {
return IsLegalPointer(x) && !((uintptr_t)x & 15) &&
(IsStaticStackFrame((uintptr_t)x >> 16) ||
IsSigAltStackFrame((uintptr_t)x >> 16) ||
IsOldStackFrame((uintptr_t)x >> 16));
}
void ShowBacktrace(int, const struct StackFrame *);
int PrintBacktraceUsingSymbols(int, const struct StackFrame *,
struct SymbolTable *);

View file

@ -70,6 +70,9 @@ static noasan int PrintBacktraceUsingAddr2line(int fd,
garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0;
for (frame = bp; frame && i < kBacktraceMaxFrames - 1; frame = frame->next) {
if (!IsValidStackFramePointer(frame)) {
return -1;
}
addr = frame->addr;
if (addr == weakaddr("__gc")) {
do {
@ -172,6 +175,7 @@ static noasan int PrintBacktrace(int fd, const struct StackFrame *bp) {
}
noasan void ShowBacktrace(int fd, const struct StackFrame *bp) {
#ifdef __FNO_OMIT_FRAME_POINTER__
/* asan runtime depends on this function */
static bool noreentry;
++g_ftrace;
@ -182,4 +186,9 @@ noasan void ShowBacktrace(int fd, const struct StackFrame *bp) {
noreentry = false;
}
--g_ftrace;
#else
__printf("ShowBacktrace() needs these flags to show C backtrace:\n"
"\t-D__FNO_OMIT_FRAME_POINTER__\n"
"\t-fno-omit-frame-pointer\n");
#endif
}

View file

@ -56,6 +56,10 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0;
for (i = 0, frame = bp; frame; frame = frame->next) {
if (!IsValidStackFramePointer(frame)) {
__printf("%p corrupt frame pointer\n", frame);
break;
}
if (++i == LIMIT) {
__printf("<truncated backtrace>\n");
break;

View file

@ -17,10 +17,10 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
/**
* Handles failure of CHECK_xx() macros in -DNDEBUG mode.
@ -34,17 +34,9 @@
*/
relegated void ___check_fail_ndebug(uint64_t want, uint64_t got,
const char *opchar) {
char bx[21];
int lasterr;
lasterr = errno;
__start_fatal_ndebug();
__print_string("check failed: 0x");
__print(bx, uint64toarray_radix16(want, bx));
__print_string(" ");
__print_string(opchar);
__print_string(" 0x");
__print(bx, uint64toarray_radix16(got, bx));
__print_string(" (");
__print(bx, int64toarray_radix10(lasterr, bx));
__print_string(")\n");
__restore_tty(1);
__printf("\n%serror: %s: check failed: 0x%x %s 0x%x (%s)\n",
!g_isterminalinarticulate ? "\e[J" : "", program_invocation_name,
want, opchar, got, strerror(errno));
exit(1);
}

View file

@ -22,6 +22,7 @@
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
/**
* Aborts process after printing a backtrace.
@ -33,11 +34,12 @@ relegated wontreturn void __die(void) {
static bool once;
if (cmpxchg(&once, false, true)) {
__restore_tty(1);
if (IsDebuggerPresent(false)) DebugBreak();
if (IsDebuggerPresent(false)) {
DebugBreak();
}
ShowBacktrace(2, NULL);
exit(77);
} else {
__write_str("PANIC: __DIE() DIED\r\n");
_exit(78);
quick_exit(77);
}
__write_str("PANIC: __DIE() DIED\r\n");
_Exit(78);
}

View file

@ -14,7 +14,6 @@ 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;
void __oncrash(int, struct siginfo *, struct ucontext *) relegated;
void __restore_tty(int);

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_LOG_LIBFATAL_INTERNAL_H_
#define COSMOPOLITAN_LIBC_LOG_LIBFATAL_INTERNAL_H_
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h"
@ -13,65 +14,96 @@ COSMOPOLITAN_C_START_
extern char __fatalbuf[];
void __printf(const char *, ...);
void __vprintf(const char *, va_list);
forceinline void __sysv_exit(long rc) {
forceinline long __sysv_exit(long rc) {
long ax;
#if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
asm volatile("call\t__syscall__"
: /* no outputs */
: "a"(__NR_exit_group), "D"(rc)
: "=a"(ax)
: "0"(__NR_exit_group), "D"(rc)
: "memory", "cc");
#else
ax = syscall(__NR_exit_group, rc);
#endif
return ax;
}
forceinline int __sysv_close(long fd) {
long ax;
#if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
asm volatile("call\t__syscall__"
: "=a"(ax)
: "0"(__NR_close), "D"(fd)
: "rdx", "memory", "cc");
#else
ax = syscall(__NR_close, fd);
#endif
return ax;
}
forceinline int __sysv_open(const char *path, long flags, long mode) {
long ax, dx;
#if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
asm volatile("call\t__syscall__"
: "=a"(ax), "=d"(dx)
: "0"(__NR_open), "D"(path), "S"(flags), "1"(mode)
: "memory", "cc");
#else
ax = syscall(__NR_open, path, flags, mode);
#endif
return ax;
}
forceinline long __sysv_read(long fd, void *data, unsigned long size) {
long ax, dx;
#if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
asm volatile("call\t__syscall__"
: "=a"(ax), "=d"(dx)
: "0"(__NR_read), "D"(fd), "S"(data), "1"(size)
: "memory", "cc");
#else
ax = syscall(__NR_read, fd, data, size);
#endif
return ax;
}
forceinline long __sysv_write(long fd, const void *data, unsigned long size) {
long ax, dx;
#if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
asm volatile("call\t__syscall__"
: "=a"(ax), "=d"(dx)
: "0"(__NR_write), "D"(fd), "S"(data), "1"(size)
: "memory", "cc");
#else
ax = syscall(__NR_write, fd, data, size);
#endif
return ax;
}
forceinline long __sysv_mprotect(void *addr, size_t size, long prot) {
long ax, dx;
#if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
asm volatile("call\t__syscall__"
: "=a"(ax), "=d"(dx)
: "0"(__NR_mprotect), "D"(addr), "S"(size), "1"(prot)
: "memory", "cc");
#else
ax = syscall(__NR_mprotect, addr, size, prot);
#endif
return ax;
}
forceinline int __sysv_getpid(void) {
long ax;
#if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
asm volatile("call\t__syscall__"
: "=a"(ax)
: "0"(__NR_getpid)
: "rdx", "memory", "cc");
#else
ax = syscall(__NR_getpid);
#endif
return ax;
}
@ -122,17 +154,32 @@ forceinline char *__stpcpy(char *d, const char *s) {
}
forceinline void *__repstosb(void *di, char al, size_t cx) {
#if defined(__x86__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
asm("rep stosb"
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
: "0"(di), "1"(cx), "a"(al));
return di;
#else
size_t i;
volatile char *volatile d = di;
while (cx--) *d++ = al;
return d;
#endif
}
forceinline void *__repmovsb(void *di, void *si, size_t cx) {
#if defined(__x86__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
asm("rep movsb"
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
: "0"(di), "1"(si), "2"(cx), "m"(*(char(*)[cx])si));
return di;
#else
size_t i;
volatile char *volatile d = di;
volatile char *volatile s = si;
while (cx--) *d++ = *s++;
return d;
#endif
}
forceinline void *__mempcpy(void *d, const void *s, size_t n) {

View file

@ -99,7 +99,11 @@ relegated static const char *TinyStrSignal(int sig) {
relegated static void ShowFunctionCalls(ucontext_t *ctx) {
struct StackFrame *bp;
struct StackFrame goodframe;
if (ctx->uc_mcontext.rip && ctx->uc_mcontext.rbp) {
if (!ctx->uc_mcontext.rip) {
__printf("%s is NULL can't show backtrace\n", "RIP");
} else if (!ctx->uc_mcontext.rbp) {
__printf("%s is NULL can't show backtrace\n", "RBP");
} else {
goodframe.next = (struct StackFrame *)ctx->uc_mcontext.rbp;
goodframe.addr = ctx->uc_mcontext.rip;
bp = &goodframe;

View file

@ -25,7 +25,6 @@
* Prints initial part of fatal message.
*
* @note this is support code for __check_fail(), __assert_fail(), etc.
* @see __start_fatal_ndebug()
*/
relegated void __start_fatal(const char *file, int line) {
bool colorful;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/alg.h"
#include "libc/dce.h"
#include "libc/mem/internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
@ -25,6 +26,8 @@
#define MAX_VARS 512
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
static bool once;
static void PutEnvDestroy(void) {
@ -56,8 +59,12 @@ int PutEnvImpl(char *s, bool overwrite) {
PutEnvInit();
once = true;
}
p = strchr(s, '=');
if (!p) goto fail;
for (p = s; *p && *p != '='; ++p) {
if (IsWindows()) {
*p = ToUpper(*p);
}
}
if (*p != '=') goto fail;
namelen = p + 1 - s;
for (i = 0; environ[i]; ++i) {
if (!strncmp(environ[i], s, namelen)) {

View file

@ -42,11 +42,6 @@ $(LIBC_NEXGEN32E_A).pkg: \
$(LIBC_NEXGEN32E_A_OBJS) \
$(foreach x,$(LIBC_NEXGEN32E_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/nexgen32e/tinystrlen.ncabi.o \
o/$(MODE)/libc/nexgen32e/tinystrncmp.ncabi.o: \
OVERRIDE_CFLAGS += \
-Os
o/$(MODE)/libc/nexgen32e/errno.o: \
OVERRIDE_CFLAGS += \
$(NO_MAGIC) \

View file

@ -95,32 +95,6 @@ strnlen16_s:
.leafepilogue
.endfn strnlen16_s,globl
// Returns length of NUL-terminated char16_t string.
//
// @param rdi is non-null NUL-terminated char16_t string pointer
// @return rax is the number of shorts, excluding the NUL
// @asyncsignalsafe
strlen16:
or $-1,%rsi
// fallthrough
.endfn strlen16,globl
// Returns length of NUL-terminated memory, with limit.
//
// @param rdi is non-null memory
// @param rsi is the maximum number of shorts to consider
// @return rax is the number of shorts, excluding the NUL
// @asyncsignalsafe
strnlen16:
.leafprologue
.profilable
or $-1,%r10
0: xor %edx,%edx
xor %r11d,%r11d
mov %rdi,%r8
// fallthrough
.endfn strnlen16,globl
// Swiss Army Knife of string char16_t scanning.
// Sixteen fast functions in one.
//

View file

@ -79,7 +79,8 @@ wcslen: or $-1,%rsi
// @param rsi is the maximum number of chars to consider
// @return rax is the number of chars, excluding the NUL
// @asyncsignalsafe
wcsnlen:.leafprologue
wcsnlen:
.leafprologue
.profilable
or $-1,%r10
0: xor %edx,%edx

View file

@ -1,55 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_NEXGEN32E_TINYSTRLEN_H_
#define COSMOPOLITAN_LIBC_NEXGEN32E_TINYSTRLEN_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#if !defined(__GNUC__) || defined(__STRICT_ANSI__)
int tinystrlen(const char *);
int tinystrnlen(const char *, size_t);
int tinystrlen16(const char16_t *);
int tinystrnlen16(const char16_t *, size_t);
int tinywcslen(const wchar_t *);
int tinywcsnlen(const wchar_t *, size_t);
#else
forceinline int tinystrlen(const char *s) {
unsigned ax;
asm("call\ttinystrlen" : "=a"(ax) : "D"(s), "m"(*(char(*)[PAGESIZE])s));
return ax;
}
forceinline int tinystrnlen(const char *s, size_t n) {
unsigned ax;
asm("call\ttinystrnlen" : "=a"(ax) : "D"(s), "S"(n), "m"(*(char(*)[n])s));
return ax;
}
forceinline int tinystrlen16(const char16_t *s) {
unsigned ax;
asm("call\ttinystrlen16" : "=a"(ax) : "D"(s), "m"(*(char16_t(*)[PAGESIZE])s));
return ax;
}
forceinline int tinystrnlen16(const char16_t *s, size_t n) {
unsigned ax;
asm("call\ttinystrnlen16"
: "=a"(ax)
: "D"(s), "S"(n), "m"(*(char16_t(*)[n])s));
return ax;
}
forceinline int tinywcslen(const wchar_t *s) {
unsigned ax;
asm("call\ttinywcslen" : "=a"(ax) : "D"(s), "m"(*(wchar_t(*)[PAGESIZE])s));
return ax;
}
forceinline int tinywcsnlen(const wchar_t *s, size_t n) {
unsigned ax;
asm("call\ttinywcsnlen" : "=a"(ax) : "D"(s), "S"(n), "m"(*(wchar_t(*)[n])s));
return ax;
}
#endif
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NEXGEN32E_TINYSTRLEN_H_ */

View file

@ -1,39 +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"
// 8-bit strnlen that's tiny and near optimal if data's tiny.
//
// @param RDI is char *s
// @param RSI is size_t n
// @param EAX is unsigned length
// @see libc/nexgen32e/strsak.S
tinystrnlen:
.leafprologue
.profilable
xor %eax,%eax
1: cmp %esi,%eax
jae 2f
cmpb $0,(%rdi,%rax)
jz 2f
inc %eax
jmp 1b
2: .leafepilogue
.endfn tinystrnlen,globl
.source __FILE__

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/sysdebug.internal.h"
#include "libc/runtime/memtrack.internal.h"
noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
@ -23,6 +24,7 @@ noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
int i;
for (i = 0; i < mm->i; ++i) {
if (mm->p[i].y < mm->p[i].x) {
SYSDEBUG("AreMemoryIntervalsOk() y should be >= x!");
return false;
}
if (i) {
@ -32,6 +34,7 @@ noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
}
} else {
if (!(mm->p[i - 1].y + 1 <= mm->p[i].x)) {
SYSDEBUG("AreMemoryIntervalsOk() out of order or overlap!");
return false;
}
}

View file

@ -21,6 +21,7 @@
#include "libc/bits/weaken.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
/**
* Handles failure of assert() macro.
@ -28,14 +29,14 @@
relegated wontreturn void __assert_fail(const char *expr, const char *file,
int line) {
static bool noreentry;
__printf("\r\n%s:%d: assert(%s) failed\r\n", file, line, expr);
__printf("%s:%d: assert(%s) failed\r\n", file, line, expr);
if (cmpxchg(&noreentry, false, true)) {
if (weaken(__die)) {
weaken(__die)();
} else {
__printf("can't backtrace b/c `__die` not linked\r\n");
}
exit(23);
quick_exit(23);
}
_exit(24);
_Exit(24);
}

View file

@ -41,7 +41,7 @@ noasan const char *DescribeFrame(int x) {
return " fixed ";
} else if (IsArenaFrame(x)) {
return " arena ";
} else if (IsStackFrame(x)) {
} else if (IsStaticStackFrame(x)) {
return " stack ";
} else {
return "";

View file

@ -91,7 +91,7 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size,
SYSDEBUG(
"MapViewOfFileExNuma(prot:%s, off:0x%x, size:0x%x, addr:0x%x) -> "
"addr:0x%x",
(prot & PROT_WRITE) ? "WX" : "RX", off, size, addr);
(prot & PROT_WRITE) ? "WX" : "RX", off, size, addr, dm.addr);
if (dm.addr) {
return dm;
} else {

View file

@ -19,6 +19,7 @@
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/errno.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"

View file

@ -21,19 +21,29 @@
#include "libc/str/tpenc.h"
#include "libc/str/utf16.h"
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
static textwindows noasan noinstrument axdx_t Recode16to8(char *dst,
size_t dstsize,
const char16_t *src) {
bool v;
axdx_t r;
uint64_t w;
wint_t x, y;
for (r.ax = 0, r.dx = 0;;) {
for (v = r.ax = 0, r.dx = 0;;) {
if (!(x = src[r.dx++])) break;
if (IsUtf16Cont(x)) continue;
if (!IsUcs2(x)) {
y = src[r.dx++];
x = MergeUtf16(x, y);
}
if (!v) {
if (x == '=') {
v = true;
} else {
x = ToUpper(x);
}
}
w = tpenc(x);
do {
if (r.ax + 1 >= dstsize) break;

View file

@ -18,6 +18,7 @@
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/likely.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/sysdebug.internal.h"
@ -61,71 +62,52 @@ static noasan void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i,
mm->i -= n;
}
static noasan void MapNewMappingArray(struct MemoryIntervals *mm) {
/* asan runtime depends on this function */
void *a;
int i, x, y, g;
size_t n, m, f;
static noasan bool ExtendMemoryIntervals(struct MemoryIntervals *mm) {
int prot, flags;
char *base, *shad;
size_t gran, size;
struct DirectMap dm;
struct MemoryInterval *p, *q;
assert(mm->i);
assert(AreMemoryIntervalsOk(mm));
n = mm->n;
n = n * sizeof(*mm->p);
n = ROUNDUP(n, FRAMESIZE);
gran = kMemtrackGran;
base = (char *)kMemtrackStart;
prot = PROT_READ | PROT_WRITE;
flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED;
if (mm->p == mm->s) {
m = n;
q = 0;
} else {
q = mm->p;
m = n + (n >> 1);
m = ROUNDUP(m, FRAMESIZE);
}
/*
* find a hole in the automap range
* we pad the sides for easier insertion logic
* only time this fails is MODE=tiny which makes no stack
*/
i = 0;
f = m >> 16;
for (;;) {
if (++i == mm->i || mm->p[i].x - mm->p[i - 1].y >= 1 + f + 1) {
x = mm->p[i - 1].y + 1;
y = x + f - 1;
a = (void *)((intptr_t)((uint64_t)x << 32) >> 16);
if (i == mm->i || (kAutomapStart <= (intptr_t)a &&
(intptr_t)a + m < kAutomapStart + kAutomapSize)) {
break;
if (IsAsan()) {
shad = (char *)(((intptr_t)base >> 3) + 0x7fff8000);
dm = sys_mmap(shad, gran >> 3, prot, flags, -1, 0);
if (!dm.addr) {
SYSDEBUG("ExtendMemoryIntervals() fail #1");
return false;
}
}
}
flags = MAP_ANONYMOUS | MAP_PRIVATE;
prot = PROT_READ | PROT_WRITE;
SYSDEBUG("MapNewMappingArray(0x%x, 0x%x) %d/%d/%d", a, m, i, mm->i, mm->n);
dm = sys_mmap(a, m, prot, flags | MAP_FIXED, -1, 0);
if ((p = dm.addr) != MAP_FAILED) {
MoveMemoryIntervals(p, mm->p, i);
MoveMemoryIntervals(p + i + 1, mm->p + i, mm->i - i);
mm->i += 1;
mm->n = m / sizeof(*mm->p);
mm->p = p;
mm->p[i].x = x;
mm->p[i].y = y;
mm->p[i].h = dm.maphandle;
mm->p[i].prot = prot;
mm->p[i].flags = flags;
if (q) {
munmap(q, n);
dm = sys_mmap(base, gran, prot, flags, -1, 0);
if (!dm.addr) {
SYSDEBUG("ExtendMemoryIntervals() fail #2");
return false;
}
if (IsAsan()) {
__asan_map_shadow((uintptr_t)a, m);
}
SYSDEBUG("MapNewMappingArray() succeeded");
MoveMemoryIntervals(dm.addr, mm->p, mm->i);
mm->p = dm.addr;
mm->n = gran / sizeof(*mm->p);
} else {
SYSDEBUG("MapNewMappingArray() failed: %s", strerror(errno));
size = ROUNDUP(mm->n * sizeof(*mm->p), gran);
base += size;
if (IsAsan()) {
shad = (char *)(((intptr_t)base >> 3) + 0x7fff8000);
dm = sys_mmap(shad, gran >> 3, prot, flags, -1, 0);
if (!dm.addr) {
SYSDEBUG("ExtendMemoryIntervals() fail #3");
return false;
}
}
dm = sys_mmap(base, gran, prot, flags, -1, 0);
if (!dm.addr) {
SYSDEBUG("ExtendMemoryIntervals() fail #4");
return false;
}
mm->n = (size + gran) / sizeof(*mm->p);
}
assert(AreMemoryIntervalsOk(mm));
return true;
}
noasan int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
@ -135,16 +117,12 @@ noasan int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
assert(i >= 0);
assert(i <= mm->i);
assert(mm->n >= 0);
if (mm->i == mm->n) {
SYSDEBUG("CreateMemoryInterval() failed");
return enomem();
}
if (UNLIKELY(mm->i == mm->n) && !ExtendMemoryIntervals(mm)) return enomem();
MoveMemoryIntervals(mm->p + i + 1, mm->p + i, mm->i++ - i);
return 0;
}
static noasan int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
if (mm->i == mm->n) return enomem();
if (CreateMemoryInterval(mm, i) == -1) return -1;
mm->p[i].y = x - 1;
mm->p[i + 1].x = y + 1;
@ -210,16 +188,12 @@ noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
prot == mm->p[i].prot && flags == mm->p[i].flags) {
mm->p[i].x = x;
} else {
if (mm->i == mm->n) return enomem();
if (CreateMemoryInterval(mm, i) == -1) return -1;
mm->p[i].x = x;
mm->p[i].y = y;
mm->p[i].h = h;
mm->p[i].prot = prot;
mm->p[i].flags = flags;
if (mm->i >= mm->n / 2) {
MapNewMappingArray(mm);
}
}
return 0;
}

View file

@ -5,24 +5,26 @@
#include "libc/nt/enum/version.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/sysv/consts/ss.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define _kAutomapStart 0x0000100080000000
#define _kAutomapSize 0x00000fff80000000
#define _kFixedmapStart 0x0000300000000000
#define _kFixedmapSize 0x00000fff80000000
/*
* TODO: Why can't we allocate addresses above 4GB on Windows 7 x64?
* https://github.com/jart/cosmopolitan/issues/19
*/
#define MEMTRACK_ADDRESS(NORMAL, WIN7) \
#define kAutomapStart _kMem(0x100080000000, 0x000010000000)
#define kAutomapSize \
_kMem(0x200000000000 - 0x100080000000 - _kMmi(0x800000000000), \
0x000040000000 - 0x000010000000 - _kMmi(0x000080000000))
#define kMemtrackStart \
_kMem(0x200000000000 - _kMmi(0x800000000000), \
0x000040000000 - _kMmi(0x000080000000))
#define kMemtrackSize _kMem(_kMmi(0x800000000000), _kMmi(0x000080000000))
#define kMemtrackGran (!IsAsan() ? FRAMESIZE : FRAMESIZE * 8)
#define kFixedmapStart _kMem(0x300000000000, 0x000040000000)
#define kFixedmapSize \
_kMem(0x400000000000 - 0x300000000000, 0x000070000000 - 0x000040000000)
#define _kMmi(VSPACE) \
ROUNDUP(VSPACE / FRAMESIZE * sizeof(struct MemoryInterval), FRAMESIZE)
#define _kMem(NORMAL, WIN7) \
(!(IsWindows() && NtGetVersion() < kNtVersionWindows10) ? NORMAL : WIN7)
#define kAutomapStart MEMTRACK_ADDRESS(_kAutomapStart, 0x10000000)
#define kAutomapSize MEMTRACK_ADDRESS(_kAutomapSize, 0x30000000)
#define kFixedmapStart MEMTRACK_ADDRESS(_kFixedmapStart, 0x40000000)
#define kFixedmapSize MEMTRACK_ADDRESS(_kFixedmapSize, 0x30000000)
struct MemoryInterval {
int x;
@ -52,11 +54,19 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *, int, int,
void ReleaseMemoryNt(struct MemoryIntervals *, int, int) hidden;
int UntrackMemoryIntervals(void *, size_t) hidden;
#define IsLegalPointer(p) \
(-0x800000000000 <= (intptr_t)(p) && (intptr_t)(p) <= 0x7fffffffffff)
forceinline pureconst bool IsAutoFrame(int x) {
return (kAutomapStart >> 16) <= x &&
x <= ((kAutomapStart + (kAutomapSize - 1)) >> 16);
}
forceinline pureconst bool IsMemtrackFrame(int x) {
return (kAutomapStart >> 16) <= x &&
x <= ((kAutomapStart + (kAutomapSize - 1)) >> 16);
}
forceinline pureconst bool IsArenaFrame(int x) {
return 0x5000 <= x && x < 0x7ffe;
}
@ -65,11 +75,21 @@ forceinline pureconst bool IsShadowFrame(int x) {
return 0x7fff <= x && x < 0x10008000;
}
forceinline pureconst bool IsStackFrame(int x) {
forceinline pureconst bool IsStaticStackFrame(int x) {
return (GetStaticStackAddr(0) >> 16) <= x &&
x <= ((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >> 16);
}
forceinline pureconst bool IsSigAltStackFrame(int x) {
return (GetStackAddr(0) >> 16) <= x &&
x <= ((GetStackAddr(0) + (SIGSTKSZ - FRAMESIZE)) >> 16);
}
forceinline pureconst bool IsOldStackFrame(int x) {
intptr_t old = ROUNDDOWN(__oldstack, STACKSIZE);
return (old >> 16) <= x && x <= ((old + (STACKSIZE - FRAMESIZE)) >> 16);
}
forceinline pureconst bool IsFixedFrame(int x) {
return (kFixedmapStart >> 16) <= x &&
x <= ((kFixedmapStart + (kFixedmapSize - 1)) >> 16);

View file

@ -23,8 +23,10 @@
#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/log/backtrace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/rand/rand.h"
@ -40,7 +42,6 @@
#define VIP(X) (void *)IP(X)
#define SMALL(n) ((n) <= 0xffffffffffff)
#define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1)))
#define LEGAL(p) (-0x800000000000 <= IP(p) && IP(p) <= 0x7fffffffffff)
#define ADDR(x) ((int64_t)((uint64_t)(x) << 32) >> 16)
#define SHADE(x) (((intptr_t)(x) >> 3) + 0x7fff8000)
#define FRAME(x) ((int)((intptr_t)(x) >> 16))
@ -104,6 +105,87 @@ noasan static bool Automap(int n, int *res) {
}
}
static noasan void *MapMemory(void *addr, size_t size, int prot, int flags,
int fd, int64_t off, int f, int x, int n) {
struct DirectMap dm;
dm = sys_mmap(addr, size, prot, f, fd, off);
if (UNLIKELY(dm.addr == MAP_FAILED)) {
if (IsWindows() && (flags & MAP_FIXED)) {
SYSDEBUG("mmap(0x%p, 0x%x) -> %s (%s)", addr, size, strerror(errno),
"can't recover from MAP_FIXED errors on Windows");
assert(!"MapMemory() failed");
Die();
}
return MAP_FAILED;
}
if (UNLIKELY(dm.addr != addr)) {
SYSDEBUG("KERNEL DIDN'T RESPECT MAP_FIXED");
assert(!"MapMemory() failed");
Die();
}
if (!IsWindows() && (flags & MAP_FIXED)) {
if (UntrackMemoryIntervals(addr, size)) {
SYSDEBUG("FIXED UNTRACK FAILED %s", strerror(errno));
assert(!"MapMemory() failed");
Die();
}
}
if (TrackMemoryInterval(&_mmi, x, x + (n - 1), dm.maphandle, prot, flags)) {
if (sys_munmap(addr, n) == -1) {
SYSDEBUG("TRACK MUNMAP FAILED %s", strerror(errno));
assert(!"MapMemory() failed");
Die();
}
return MAP_FAILED;
}
if (weaken(__asan_map_shadow) && !OverlapsShadowSpace(addr, size)) {
weaken(__asan_map_shadow)((intptr_t)addr, size);
}
return addr;
}
/**
* Maps memory from system, one frame at a time.
*
* This is useful on Windows since it allows us to partially unmap or
* punch holes into existing mappings.
*/
static textwindows noinline noasan void *MapMemories(char *addr, size_t size,
int prot, int flags,
int fd, int64_t off, int f,
int x, size_t n) {
struct DirectMap dm;
size_t i, m = (n - 1) * FRAMESIZE;
assert(m < size && m + FRAMESIZE >= size);
dm = sys_mmap(addr + m, size - m, prot, f, fd, fd == -1 ? 0 : off + m);
if (dm.addr == MAP_FAILED) {
SYSDEBUG("MapMemories(%p+%x/%x) %s", addr, m, size, strerror(errno));
return MAP_FAILED;
}
if (TrackMemoryInterval(&_mmi, x + (n - 1), x + (n - 1), dm.maphandle, prot,
flags) == -1) {
SYSDEBUG("MapMemories(%p+%x/%x) unrecoverable failure #1 %s", addr, m, size,
strerror(errno));
assert(!"MapMemories() failed");
Die();
}
for (i = 0; i < m; i += FRAMESIZE) {
dm = sys_mmap(addr + i, FRAMESIZE, prot, f, fd, fd == -1 ? 0 : off + i);
if (dm.addr == MAP_FAILED ||
TrackMemoryInterval(&_mmi, x + i / FRAMESIZE, x + i / FRAMESIZE,
dm.maphandle, prot, flags) == -1) {
SYSDEBUG("MapMemories(%p+%x/%x) unrecoverable failure #2 %s", addr, i,
size, strerror(errno));
assert(!"MapMemories() failed");
Die();
}
}
if (weaken(__asan_map_shadow) && !OverlapsShadowSpace(addr, size)) {
weaken(__asan_map_shadow)((intptr_t)addr, size);
}
return addr;
}
/**
* Beseeches system for page-table entries, e.g.
*
@ -146,7 +228,7 @@ noasan void *mmap(void *addr, size_t size, int prot, int flags, int fd,
SYSDEBUG("mmap(0x%p, 0x%x) EINVAL (size isn't 48-bit)", p, size);
return VIP(einval());
}
if (UNLIKELY(!LEGAL(p))) {
if (UNLIKELY(!IsLegalPointer(p))) {
SYSDEBUG("mmap(0x%p, 0x%x) EINVAL (p isn't 48-bit)", p, size);
return VIP(einval());
}
@ -202,6 +284,7 @@ noasan void *mmap(void *addr, size_t size, int prot, int flags, int fd,
if (IsWindows()) {
if (UntrackMemoryIntervals(p, size)) {
SYSDEBUG("FIXED UNTRACK FAILED %s", strerror(errno));
assert(!"mmap() failed");
Die();
}
}
@ -215,34 +298,9 @@ noasan void *mmap(void *addr, size_t size, int prot, int flags, int fd,
dm = sys_mmap(p, size, prot, f & ~MAP_GROWSDOWN, fd, off);
if (dm.addr == MAP_FAILED) return MAP_FAILED;
}
dm = sys_mmap(p, size, prot, f, fd, off);
if (UNLIKELY(dm.addr == MAP_FAILED)) {
if (IsWindows() && (flags & MAP_FIXED)) {
SYSDEBUG("mmap(0x%p, 0x%x) -> %s (%s)", p, size, strerror(errno),
"can't recover from MAP_FIXED errors on Windows");
Die();
}
return MAP_FAILED;
if (!IsWindows()) {
return MapMemory(p, size, prot, flags, fd, off, f, x, n);
} else {
return MapMemories(p, size, prot, flags, fd, off, f, x, n);
}
if (UNLIKELY(dm.addr != p)) {
SYSDEBUG("KERNEL DIDN'T RESPECT MAP_FIXED");
Die();
}
if (!IsWindows() && (flags & MAP_FIXED)) {
if (UntrackMemoryIntervals(p, size)) {
SYSDEBUG("FIXED UNTRACK FAILED %s", strerror(errno));
Die();
}
}
if (TrackMemoryInterval(&_mmi, x, x + (n - 1), dm.maphandle, prot, flags)) {
if (sys_munmap(p, n) == -1) {
SYSDEBUG("TRACK MUNMAP FAILED %s", strerror(errno));
Die();
}
return MAP_FAILED;
}
if (weaken(__asan_map_shadow) && !OverlapsShadowSpace(p, size)) {
weaken(__asan_map_shadow)((intptr_t)p, size);
}
return p;
}

View file

@ -38,7 +38,6 @@
#define VIP(X) (void *)IP(X)
#define SMALL(n) ((n) <= 0xffffffffffff)
#define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1)))
#define LEGAL(p) (-0x800000000000 <= IP(p) && IP(p) <= 0x7fffffffffff)
#define ADDR(x) ((int64_t)((uint64_t)(x) << 32) >> 16)
#define SHADE(x) (((intptr_t)(x) >> 3) + 0x7fff8000)
#define FRAME(x) ((int)((intptr_t)(x) >> 16))

View file

@ -20,6 +20,7 @@
#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/log/libfatal.internal.h"
#include "libc/macros.internal.h"
@ -32,7 +33,6 @@
#define IP(X) (intptr_t)(X)
#define SMALL(n) ((n) <= 0xffffffffffff)
#define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1)))
#define LEGAL(p) (-0x800000000000 <= IP(p) && IP(p) <= 0x7fffffffffff)
#define ADDR(x) ((int64_t)((uint64_t)(x) << 32) >> 16)
#define SHADE(x) (((intptr_t)(x) >> 3) + 0x7fff8000)
#define FRAME(x) ((int)((intptr_t)(x) >> 16))
@ -64,11 +64,11 @@ noasan int munmap(void *v, size_t n) {
SYSDEBUG("munmap(0x%p, 0x%x) EINVAL (n isn't 48-bit)", p, n);
return einval();
}
if (UNLIKELY(!LEGAL(p))) {
if (UNLIKELY(!IsLegalPointer(p))) {
SYSDEBUG("munmap(0x%p, 0x%x) EINVAL (p isn't 48-bit)", p, n);
return einval();
}
if (UNLIKELY(!LEGAL(p + (n - 1)))) {
if (UNLIKELY(!IsLegalPointer(p + (n - 1)))) {
SYSDEBUG("munmap(0x%p, 0x%x) EINVAL (p+(n-1) isn't 48-bit)", p, n);
return einval();
}
@ -80,7 +80,6 @@ noasan int munmap(void *v, size_t n) {
SYSDEBUG("munmap(0x%p, 0x%x) EFAULT (interval not tracked)", p, n);
return efault();
}
SYSDEBUG("munmap(0x%p, 0x%x)", p, n);
if (UntrackMemoryIntervals(p, n) != -1) {
if (!IsWindows()) {
rc = sys_munmap(p, n);
@ -105,11 +104,13 @@ noasan int munmap(void *v, size_t n) {
}
}
}
return rc;
} else {
return 0; /* UntrackMemoryIntervals does it for NT */
rc = 0; /* UntrackMemoryIntervals does it for NT */
}
} else {
return -1;
rc = -1;
}
SYSDEBUG("munmap(0x%p, 0x%x) -> %d %s", p, n, (long)rc,
rc == -1 ? strerror(errno) : "");
return rc;
}

View file

@ -23,9 +23,17 @@
_peekall:
.leafprologue
ezlea _base,si
ezlea _etext,cx
add $0x1000,%rsi
0: xor (%rsi),%eax
add $PAGESIZE,%rsi
cmp %rcx,%rsi
jb 0b
ezlea _etext,si
ezlea _end,cx
add $0x1000,%rsi
0: mov (%rsi),%eax
0: incq (%rsi)
decq (%rsi)
add $PAGESIZE,%rsi
cmp %rcx,%rsi
jb 0b

View file

@ -1,76 +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 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.
*/
#define ShouldUseMsabiAttribute() 1
#include "libc/dce.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/nr.h"
/* TODO(jart): DELETE */
#define WasImported(SLOT) \
((void *)*SLOT && *SLOT != (void *)&missingno /* see libc/crt/crt.S */)
static void __sys_print_nt(const void *data, size_t len) {
int64_t hand;
char xmm[256];
uint32_t wrote;
_savexmm(xmm + 128);
hand = __imp_GetStdHandle(kNtStdErrorHandle);
__imp_WriteFile(hand, data, len, &wrote, NULL);
_loadxmm(xmm + 128);
}
/**
* Prints string, by any means necessary.
*
* This function offers a subset of write(STDERR_FILENO) functionality.
* It's designed to work even when the runtime hasn't initialized, e.g.
* before _init() gets called.
*
* @param len can be computed w/ tinystrlen()
* @clob nothing except flags
*/
privileged noinline void __print(const void *data, size_t len) {
int64_t ax, ordinal;
if (WasImported(__imp_WriteFile)) {
__sys_print_nt(data, len);
} else {
ordinal = __NR_write > 0 ? __NR_write : IsXnu() ? 0x2000004 : 4;
asm volatile("syscall"
: "=a"(ax)
: "0"(ordinal), "D"(STDERR_FILENO), "S"(data), "d"(len)
: "rcx", "r11", "memory", "cc");
if (ax == -1 && !__hostos && !__NR_write) {
asm volatile("syscall"
: "=a"(ax)
: "0"(ordinal), "D"(STDERR_FILENO), "S"(data), "d"(len)
: "rcx", "r11", "memory", "cc");
}
}
}
void __print_string(const char *s) {
size_t n = 0;
while (s[n]) ++n;
__print(s, n);
}

View file

@ -26,9 +26,10 @@
static bool IsNoteworthyHole(unsigned i, const struct MemoryIntervals *mm) {
// gaps between shadow frames aren't interesting
// the chasm from heap to stack ruins statistics
return !((IsArenaFrame(mm->p[i].y) && !IsArenaFrame(mm->p[i + 1].x)) ||
(IsShadowFrame(mm->p[i].y) || IsShadowFrame(mm->p[i + 1].x)) ||
(!IsStackFrame(mm->p[i].y) && IsStackFrame(mm->p[i + 1].x)));
return !(
(IsArenaFrame(mm->p[i].y) && !IsArenaFrame(mm->p[i + 1].x)) ||
(IsShadowFrame(mm->p[i].y) || IsShadowFrame(mm->p[i + 1].x)) ||
(!IsStaticStackFrame(mm->p[i].y) && IsStaticStackFrame(mm->p[i + 1].x)));
}
void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) {
@ -40,8 +41,7 @@ void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) {
for (i = 0; i < mm->i; ++i) {
frames = mm->p[i].y + 1 - mm->p[i].x;
maptally += frames;
__printf("%0*x-%0*x %s %,*dx%s", 12, ADDR(mm->p[i].x), 12,
ADDR(mm->p[i].y + 1),
__printf("%012x-%012x %s %,*dx%s", ADDR(mm->p[i].x), ADDR(mm->p[i].y + 1),
DescribeMapping(mm->p[i].prot, mm->p[i].flags, mode), w, frames,
DescribeFrame(mm->p[i].x));
if (i + 1 < _mmi.i) {

View file

@ -33,6 +33,7 @@
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/consts/prot.h"
#define SIZE 1024
#define CTL_KERN 1

View file

@ -13,6 +13,7 @@ extern const int __argc; /* CRT */
extern char **const __argv; /* CRT */
extern char **const __envp; /* CRT */
extern unsigned long *const __auxv; /* CRT */
extern intptr_t __oldstack; /* CRT */
extern char program_executable_name[]; /* RII */
extern char *program_invocation_name; /* RII */
extern char *program_invocation_short_name; /* RII */
@ -86,8 +87,6 @@ bool _isheap(void *);
int NtGetVersion(void) pureconst;
long missingno();
void __oom_hook(size_t);
void __print(const void *, size_t);
void __print_string(const char *);
void _loadxmm(void *);
void _peekall(void);
void _savexmm(void *);

View file

@ -2,6 +2,7 @@
#define COSMOPOLITAN_LIBC_RUNTIME_STACK_H_
#include "ape/config.h"
#include "libc/dce.h"
#include "libc/runtime/runtime.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/**
@ -63,14 +64,18 @@ extern char ape_stack_memsz[] __attribute__((__weak__));
/**
* Returns preferred bottom address of stack.
*/
#define GetStaticStackAddr(ADDEND) \
({ \
intptr_t vAddr = 0; \
asm(".weak\tape_stack_vaddr\n\t" \
"movabs\t%1+ape_stack_vaddr,%0" \
: "=r"(vAddr) \
: "i"(ADDEND)); \
vAddr; \
#define GetStaticStackAddr(ADDEND) \
({ \
intptr_t vAddr; \
if (!IsWindows() || NtGetVersion() >= kNtVersionWindows10) { \
asm(".weak\tape_stack_vaddr\n\t" \
"movabs\t%1+ape_stack_vaddr,%0" \
: "=r"(vAddr) \
: "i"(ADDEND)); \
} else { \
vAddr = 0x10000000; \
} \
vAddr; \
})
COSMOPOLITAN_C_END_

View file

@ -98,6 +98,7 @@ static noasan textwindows wontreturn noinstrument void WinMainNew(void) {
extern char os asm("__hostos");
os = WINDOWS; /* madness https://news.ycombinator.com/item?id=21019722 */
version = NtGetPeb()->OSMajorVersion;
__oldstack = (intptr_t)__builtin_frame_address(0);
if ((intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui && version >= 10) {
SetConsoleCP(kNtCpUtf8);
SetConsoleOutputCP(kNtCpUtf8);
@ -114,9 +115,9 @@ static noasan textwindows wontreturn noinstrument void WinMainNew(void) {
kNtEnableVirtualTerminalProcessing);
}
_mmi.p = _mmi.s;
_mmi.n = OPEN_MAX;
_mmi.n = ARRAYLEN(_mmi.s);
argsize = ROUNDUP(sizeof(struct WinArgs), FRAMESIZE);
stackaddr = version < 10 ? 0x10000000 : GetStaticStackAddr(0);
stackaddr = GetStaticStackAddr(0);
stacksize = GetStackSize();
allocsize = argsize + stacksize;
allocaddr = stackaddr - argsize;

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,40 +16,35 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/str/str.h"
// Compares strings w/ limit & no-clobber greg abi.
//
// @param %rdi is first string
// @param %rsi is second string
// @param %rdx is max length
// @return <0, 0, or >0 depending on comparison
// @clob flags only
// @asyncsignalsafe
tinystrncmp:
.leafprologue
push %rbx
push %rcx
xor %eax,%eax
xor %ebx,%ebx
xor %ecx,%ecx
test %edx,%edx
jz 2f
cmp %rdi,%rsi
je 2f
0: cmp %edx,%ecx
jae 1f
movzbl (%rdi,%rcx,1),%eax
movzbl (%rsi,%rcx,1),%ebx
test %al,%al
jz 1f
cmp %bl,%al
jne 1f
inc %ecx
jmp 0b
1: sub %ebx,%eax
2: pop %rcx
pop %rbx
.leafepilogue
.endfn tinystrncmp,globl
.source __FILE__
#define TRIES 8
/**
* Returns offset of binary embedded inside binary.
*
* This can be used to load zip assets from an executable that hasn't
* gone through the `objcopy -S -O binary` step. We make the assumption
* that an x86_64-pc-linux-gnu toolchain is being used. This routine
* would need to be changed to accommodate binaries built locally on
* Apple, FreeBSD, etc.
*
* @param p needs to be page aligned
* @param n is byte length of p
* @return base address of image or NULL if not found
*/
uint8_t *FindEmbeddedApe(const uint8_t *p, size_t n) {
size_t i;
uint64_t w;
n = MIN(n, TRIES * PAGESIZE);
for (i = 0; i + 8 <= n; i += PAGESIZE) {
w = READ64LE(p + i);
if (w == READ64LE("MZqFpD='") || w == READ64LE("\177ELF\2\1\1\11")) {
return (/*unconst*/ uint8_t *)(p + i);
}
}
return 0;
}

View file

@ -6,6 +6,8 @@ COSMOPOLITAN_C_START_
unsigned getutf16(const char16_t *, wint_t *);
int pututf16(char16_t *, size_t, wint_t, bool);
#if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define pututf16(BUF, SIZE, CH, AWESOME) __pututf16(BUF, SIZE, CH, AWESOME)
#define getutf16(BUF, CHPTR) __getutf16(BUF, CHPTR)
@ -42,6 +44,8 @@ forceinline unsigned __getutf16(const char16_t *s, wint_t *wc) {
return ax;
}
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_STR_OLDUTF16_H_ */

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 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,29 +16,28 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/log/color.internal.h"
#include "libc/log/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/str/str.h"
asm(".section .privileged,\"ax\",@progbits\n__syscall:\n\t"
"syscall\n\t"
"ret\n\t"
".previous");
typedef char16_t xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
/**
* Prints initial part of fatal message.
* Returns length of NUL-terminated utf-16 string.
*
* @note this is support code for __check_fail(), __assert_fail(), etc.
* @see __start_fatal()
* @param s is non-null NUL-terminated string pointer
* @return number of shorts (excluding NUL)
* @asyncsignalsafe
*/
relegated void __start_fatal_ndebug(void) {
char s[16 + 16 + 16 + 16 + PATH_MAX + 16], *p = s;
__restore_tty(1);
*p++ = '\r';
if (cancolor()) p = stpcpy(p, "\e[J");
p = stpcpy(p, "error:");
p = stpcpy(p, program_invocation_name);
p = stpcpy(p, ": ");
write(2, s, p - s);
noasan size_t strlen16(const char16_t *s) {
size_t n;
xmm_t v, z = {0};
unsigned m, k = (uintptr_t)s & 15;
const xmm_t *p = (const xmm_t *)((uintptr_t)s & -16);
if (IsAsan()) __asan_verify(s, 2);
m = __builtin_ia32_pmovmskb128(*p == z) >> k << k;
while (!m) m = __builtin_ia32_pmovmskb128(*++p == z);
n = (const char16_t *)p + (__builtin_ctzl(m) >> 1) - s;
if (IsAsan()) __asan_verify(s, n * 2);
return n;
}

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,24 +16,22 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/assert.h"
#include "libc/str/str.h"
// 16-bit strnlen that's tiny and near optimal if data's tiny.
//
// @param RDI is char16_t *s
// @param RSI is size_t n
// @param EAX is unsigned length
// @see libc/nexgen32e/strsak16.S
tinystrnlen16:
.leafprologue
.profilable
xor %eax,%eax
1: cmp %esi,%eax
jae 2f
cmpw $0,(%rdi,%rax,2)
jz 2f
inc %eax
jmp 1b
2: .leafepilogue
.endfn tinystrnlen16,globl
.source __FILE__
/**
* Returns length of NUL-terminated 16-bit string w/ limit.
*
* @param s is utf16 string pointer
* @param n is max length in shorts
* @return number of shorts
* @asyncsignalsafe
*/
noasan size_t strnlen16(const char16_t *s, size_t n) {
size_t i;
for (i = 0;; ++i) {
if (i == n || !s[i]) break;
}
assert(i == n || (i < n && !s[i]));
return i;
}

View file

@ -5,7 +5,7 @@ COSMOPOLITAN_C_START_
int tpdecode(const char *, wint_t *) paramsnonnull((1)) libcesque;
#ifndef __STRICT_ANSI__
#if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define tpdecode(S, OUT) __tpdecode(S, OUT)
forceinline int __tpdecode(const char *s, wint_t *out) {
int ax;

View file

@ -5,7 +5,7 @@ COSMOPOLITAN_C_START_
uint64_t tpenc(int32_t) pureconst;
#ifndef __STRICT_ANSI__
#if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define tpenc(CODE) \
({ \
long Edi, Buf; \

View file

@ -153,7 +153,7 @@ intptr_t enotrecoverable(void) relegated;
intptr_t erfkill(void) relegated;
intptr_t ehwpoison(void) relegated;
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define __ERRFUN(FUNC) \
({ \
intptr_t NegOne; \

View file

@ -17,7 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.source __FILE__
.privileged
// Performs raw System Five system call.
//

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/kntprioritycombos.internal.h"
#include "libc/errno.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/runtime.h"
@ -51,9 +52,12 @@ void testlib_benchwarmup(void) {
* @see BENCH()
*/
void testlib_runallbenchmarks(void) {
int e;
e = errno;
_peekall();
mlockall(MCL_CURRENT);
nice(-1);
errno = e;
__log_level = kLogWarn;
testlib_runtestcases(__bench_start, __bench_end, testlib_benchwarmup);
}

View file

@ -71,7 +71,7 @@ noasan void testlib_checkformemoryleaks(void) {
struct mallinfo mi;
if (!cmpxchg(&once, false, true)) {
__printf("testlib_checkformemoryleaks() may only be called once\n");
_Exit(1);
exit(1);
}
__cxa_finalize(0);
if (!IsAsan()) {

View file

@ -47,7 +47,7 @@ static relegated void DieBecauseOfQuota(int rc, const char *message) {
gethostname(hostname, sizeof(hostname));
__printf("%s on %s pid %d\n", message, hostname, (long)__getpid());
PrintBacktraceUsingSymbols(2, 0, GetSymbolTable());
_Exit(rc);
exit(rc);
}
static relegated void OnXcpu(int sig) {
@ -89,7 +89,7 @@ relegated void __oom_hook(size_t request) {
__printf("\nTHE STRAW THAT BROKE THE CAMEL'S BACK\n");
PrintBacktraceUsingSymbols(2, 0, GetSymbolTable());
PrintSystemMappings(2);
_Exit(42);
exit(42);
}
static textstartup void InstallQuotaHandlers(void) {

View file

@ -37,18 +37,15 @@ testonly void testlib_showerror(const char *file, int line, const char *func,
/* TODO(jart): Pay off tech debt re duplication */
__getpid(); /* make strace easier to read */
__getpid();
__printf("%serror%s:%s:%d%s: %s() in %s(%s)\n"
__printf("%serror%s%s:%s:%d%s: %s() in %s(%s)\n"
"\t%s\n"
"\t\tneed %s %s\n"
"\t\t got %s\n"
"\t%s%s\n"
"\t%s%s\n",
!g_isterminalinarticulate ? "\e[91;1m" : "",
!g_isterminalinarticulate ? "\e[22;94;49m" : "", file, (long)line,
!g_isterminalinarticulate ? "\e[0m" : "", method, func,
g_fixturename, code, v1, symbol, v2,
!g_isterminalinarticulate ? "\e[35m" : "", strerror(errno),
program_executable_name, !g_isterminalinarticulate ? "\e[0m" : "");
RED2, UNBOLD, BLUE1, file, (long)line, RESET, method, func,
g_fixturename, code, v1, symbol, v2, SUBTLE, strerror(errno),
program_executable_name, RESET);
free_s(&v1);
free_s(&v2);
}
@ -58,67 +55,36 @@ testonly void testlib_showerror_(int line, const char *wantcode,
const char *gotcode, char *FREED_want,
char *FREED_got, const char *fmt, ...) {
int e;
char *p;
va_list va;
char hostname[32];
__getpid();
__getpid();
p = __fatalbuf;
e = errno;
p = __stpcpy(p, RED2);
p = __stpcpy(p, "error");
p = __stpcpy(p, UNBOLD);
p = __stpcpy(p, ":");
p = __stpcpy(p, BLUE1);
p = __stpcpy(p, testlib_showerror_file);
p = __stpcpy(p, ":");
p = __intcpy(p, line);
p = __stpcpy(p, RESET);
p = __stpcpy(p, ": ");
p = __stpcpy(p, testlib_showerror_func);
p = __stpcpy(p, "(");
p = __stpcpy(p, g_fixturename);
p = __stpcpy(p, ")\n\t");
p = __stpcpy(p, testlib_showerror_macro);
p = __stpcpy(p, "(");
p = __stpcpy(p, wantcode);
p = __stpcpy(p, ", ");
p = __stpcpy(p, gotcode);
__getpid();
__getpid();
__printf("%serror%s:%s%s:%d%s: %s(%s)\n"
"\t%s(%s, %s)\n",
RED2, UNBOLD, BLUE1, testlib_showerror_file, line, RESET,
testlib_showerror_func, g_fixturename, testlib_showerror_macro,
wantcode, gotcode);
if (wantcode) {
p = __stpcpy(p, ")\n\t\tneed ");
p = __stpcpy(p, FREED_want);
p = __stpcpy(p, " ");
p = __stpcpy(p, testlib_showerror_symbol);
p = __stpcpy(p, "\n\t\t got ");
p = __stpcpy(p, FREED_got);
p = __stpcpy(p, "\n");
__printf("\t\tneed %s %s\n"
"\t\t got %s\n",
FREED_want, testlib_showerror_symbol, FREED_got);
} else {
p = __stpcpy(p, ")\n\t\t");
p = __stpcpy(p, testlib_showerror_symbol);
p = __stpcpy(p, FREED_want);
p = __stpcpy(p, "\n");
__printf("\t\t→ %s%s\n", testlib_showerror_symbol, FREED_want);
}
if (!isempty(fmt)) {
*p++ = '\t';
__printf("\t");
va_start(va, fmt);
p += vsprintf(p, fmt, va);
__vprintf(fmt, va);
va_end(va);
*p++ = '\n';
__printf("\n");
}
__stpcpy(hostname, "unknown");
gethostname(hostname, sizeof(hostname));
p = __stpcpy(p, "\t");
p = __stpcpy(p, SUBTLE);
p = __stpcpy(p, strerror(e));
p = __stpcpy(p, RESET);
p = __stpcpy(p, "\n\t");
p = __stpcpy(p, SUBTLE);
p = __stpcpy(p, program_invocation_name);
p = __stpcpy(p, " @ ");
p = __stpcpy(p, hostname);
p = __stpcpy(p, RESET);
p = __stpcpy(p, "\n");
__write(__fatalbuf, p - __fatalbuf);
__printf("\t%s%s%s\n"
"\t%s%s @ %s%s\n",
SUBTLE, strerror(e), RESET, SUBTLE, program_invocation_name,
hostname, RESET);
free_s(&FREED_want);
free_s(&FREED_got);
++g_testlib_failed;

View file

@ -103,5 +103,5 @@ noasan int main(int argc, char *argv[]) {
} else if (!g_testlib_failed) {
testlib_checkformemoryleaks();
}
_Exit(min(255, g_testlib_failed));
exit(min(255, g_testlib_failed));
}

View file

@ -31,8 +31,9 @@
* @see mkdir()
*/
int makedirs(const char *path, unsigned mode) {
int rc;
int e, rc;
char *dir;
e = errno;
if (mkdir(path, mode) != -1) return 0;
if (errno != ENOENT) return -1;
dir = xdirname(path);
@ -43,5 +44,6 @@ int makedirs(const char *path, unsigned mode) {
}
free(dir);
if (rc == -1) return -1;
errno = e;
return mkdir(path, mode);
}

View file

@ -16,10 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/pcmpgtb.h"
#include "libc/intrin/pmovmskb.h"
#include "libc/intrin/punpckhbw.h"
#include "libc/intrin/punpcklbw.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/str/thompike.h"
@ -38,25 +34,30 @@ char16_t *utf8toutf16(const char *p, size_t n, size_t *z) {
wint_t x, a, b;
char16_t *r, *q;
unsigned m, j, w;
uint8_t v1[16], v2[16], vz[16];
if (z) *z = 0;
if (n == -1) n = p ? strlen(p) : 0;
if ((q = r = malloc(n * sizeof(char16_t) * 2 + sizeof(char16_t)))) {
if ((q = r = malloc((n + 16) * sizeof(char16_t) * 2 + sizeof(char16_t)))) {
for (i = 0; i < n;) {
if (i + 16 < n) { /* 34x ascii */
bzero(vz, 16);
#if defined(__SSE2__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
if (i + 16 < n) {
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
xmm_t vi, vz = {0};
do {
memcpy(v1, p + i, 16);
pcmpgtb((int8_t *)v2, (int8_t *)v1, (int8_t *)vz);
if (pmovmskb(v2) != 0xFFFF) break;
punpcklbw(v2, v1, vz);
punpckhbw(v1, v1, vz);
memcpy(q + 0, v2, 16);
memcpy(q + 8, v1, 16);
i += 16;
q += 16;
vi = *(const xmm_t *)(p + i);
*(xmm_t *)(q + 0) = __builtin_ia32_punpcklbw128(vi, vz);
*(xmm_t *)(q + 8) = __builtin_ia32_punpckhbw128(vi, vz);
if (!(m = __builtin_ia32_pmovmskb128(vi > vz) ^ 0xffff)) {
i += 16;
q += 16;
} else {
m = __builtin_ctzl(m);
i += m;
q += m;
break;
}
} while (i + 16 < n);
}
#endif
x = p[i++] & 0xff;
if (x >= 0300) {
a = ThomPikeByte(x);

View file

@ -186,6 +186,7 @@
#define ZIP_EXTRA_SIZE(P) (ZIP_EXTRA_CONTENTSIZE(P) + kZipExtraHdrSize)
void *GetZipCdir(const uint8_t *, size_t);
uint8_t *FindEmbeddedApe(const uint8_t *, size_t);
bool IsZipCdir32(const uint8_t *, size_t, size_t);
bool IsZipCdir64(const uint8_t *, size_t, size_t);
int GetZipCfileMode(const uint8_t *);

View file

@ -22,6 +22,7 @@
#include "libc/calls/struct/stat.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/mem/alloca.h"
#include "libc/runtime/runtime.h"
@ -72,12 +73,8 @@ struct Zipos *__zipos_get(void) {
if ((fd = open(program_executable_name, O_RDONLY)) != -1) {
if ((size = getfiledescriptorsize(fd)) != SIZE_MAX &&
(map = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0)) != MAP_FAILED) {
if (endswith(program_executable_name, ".com.dbg")) {
if ((base = memmem(map, size, "MZqFpD", 6))) {
size -= base - map;
} else {
base = map;
}
if ((base = FindEmbeddedApe(map, size))) {
size -= base - map;
} else {
base = map;
}

View file

@ -21,8 +21,8 @@
#include "libc/testlib/testlib.h"
TEST(getenv, test) {
putenv("x=y");
EXPECT_STREQ("y", getenv("x"));
unsetenv("x");
EXPECT_EQ(NULL, getenv("x"));
putenv("X=y");
EXPECT_STREQ("y", getenv("X"));
unsetenv("X");
EXPECT_EQ(NULL, getenv("X"));
}

View file

@ -31,10 +31,10 @@ TEST(mkntenvblock, emptyList_onlyOutputsDoubleNulStringTerminator) {
TEST(mkntenvblock, envp_becomesSortedDoubleNulTerminatedUtf16String) {
char *envp[] = {"u=b", "c=d", "韩=非", "uh=d", "hduc=d", NULL};
ASSERT_NE(-1, mkntenvblock(envvars, envp, NULL));
ASSERT_BINEQ(u"c = d   "
u"h d u c = d   "
u"u = b   "
u"u h = d   "
ASSERT_BINEQ(u"C = d   "
u"H D U C = d   "
u"U = b   "
u"U H = d   "
u"Θù= ^ù  "
u"  ",
envvars);
@ -43,11 +43,11 @@ TEST(mkntenvblock, envp_becomesSortedDoubleNulTerminatedUtf16String) {
TEST(mkntenvblock, extraVar_getsAdded) {
char *envp[] = {"u=b", "c=d", "韩=非", "uh=d", "hduc=d", NULL};
ASSERT_NE(-1, mkntenvblock(envvars, envp, "a=a"));
ASSERT_BINEQ(u"a = a   "
u"c = d   "
u"h d u c = d   "
u"u = b   "
u"u h = d   "
ASSERT_BINEQ(u"A = a   "
u"C = d   "
u"H D U C = d   "
u"U = b   "
u"U H = d   "
u"Θù= ^ù  "
u"  ",
envvars);

View file

@ -18,14 +18,19 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/nt/files.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/nr.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
STATIC_YOINK("zip_uri_support");
char testlib_enable_tmp_setup_teardown;
TEST(stat_010, testEmptyFile_sizeIsZero) {
@ -44,3 +49,43 @@ TEST(stat, enotdir) {
ASSERT_SYS(0, 0, close(creat("yo", 0644)));
ASSERT_SYS(ENOTDIR, -1, stat("yo/there", 0));
}
TEST(stat, zipos) {
struct stat st;
EXPECT_SYS(0, 0,
stat("/zip/.python/test/"
"tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt",
&st));
}
static long Stat(const char *path, struct stat *st) {
long ax, di, si, dx;
asm volatile("syscall"
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
: "0"(__NR_stat), "1"(path), "2"(st)
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
return ax;
}
BENCH(stat, bench) {
struct stat st;
EXPECT_SYS(0, 0, makedirs(".python/test", 0755));
EXPECT_SYS(0, 0,
touch(".python/test/"
"tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt",
0644));
if (!IsWindows()) {
EZBENCH2("stat syscall", donothing,
Stat(".python/test/"
"tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt",
&st));
}
EZBENCH2("stat() fs", donothing,
stat(".python/test/"
"tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt",
&st));
EZBENCH2("stat() zipos", donothing,
stat("/zip/.python/test/"
"tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt",
&st));
}

View file

@ -44,6 +44,7 @@ TEST_LIBC_CALLS_DIRECTDEPS = \
LIBC_TESTLIB \
LIBC_UNICODE \
LIBC_X \
LIBC_ZIPOS \
THIRD_PARTY_XED
TEST_LIBC_CALLS_DEPS := \
@ -56,6 +57,7 @@ o/$(MODE)/test/libc/calls/calls.pkg: \
o/$(MODE)/test/libc/calls/%.com.dbg: \
$(TEST_LIBC_CALLS_DEPS) \
o/$(MODE)/test/libc/calls/%.o \
o/$(MODE)/third_party/python/Lib/test/tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt.zip.o \
o/$(MODE)/test/libc/calls/calls.pkg \
$(LIBC_TESTMAIN) \
$(CRT) \

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 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/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/sock/internal.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/o.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
static long Write(long fd, const void *data, unsigned long size) {
long ax, di, si, dx;
asm volatile("syscall"
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
: "0"(__NR_write), "1"(fd), "2"(data), "3"(size)
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
return ax;
}
BENCH(write, bench) {
ASSERT_SYS(0, 3, open("/dev/null", O_WRONLY));
EZBENCH2("write", donothing, write(3, "hello", 5));
EZBENCH2("sys_write", donothing, sys_write(3, "hello", 5));
EZBENCH2("sys_writev", donothing,
sys_writev(3, &(struct iovec){"hello", 5}, 1));
EZBENCH2("Write", donothing, Write(3, "hello", 5));
EZBENCH2("Write", donothing, Write(3, "hello", 5));
ASSERT_SYS(0, 0, close(3));
}

View file

@ -373,11 +373,13 @@ TEST(ShowCrashReports, testDivideByZero) {
EXPECT_TRUE(WIFEXITED(ws));
EXPECT_EQ(128 + SIGFPE, WEXITSTATUS(ws));
/* NULL is stopgap until we can copy symbol tablces into binary */
#ifdef __FNO_OMIT_FRAME_POINTER__
if (!OutputHasSymbol(output, "FpuCrash")) {
fprintf(stderr, "ERROR: crash report didn't have backtrace\n%s\n",
gc(IndentLines(output, -1, 0, 4)));
__die();
}
#endif
if (!strstr(output, gc(xasprintf("%d", pid)))) {
fprintf(stderr, "ERROR: crash report didn't have pid\n%s\n",
gc(IndentLines(output, -1, 0, 4)));
@ -472,11 +474,13 @@ TEST(ShowCrashReports, testBssOverrunCrash) {
EXPECT_TRUE(WIFEXITED(ws));
EXPECT_EQ(77, WEXITSTATUS(ws));
/* NULL is stopgap until we can copy symbol tablces into binary */
#ifdef __FNO_OMIT_FRAME_POINTER__
if (!OutputHasSymbol(output, "BssOverrunCrash")) {
fprintf(stderr, "ERROR: crash report didn't have backtrace\n%s\n",
gc(IndentLines(output, -1, 0, 4)));
__die();
}
#endif
if (!strstr(output, "☺☻♥♦♣♠•◘○") || !strstr(output, "global redzone")) {
fprintf(stderr, "ERROR: crash report didn't have memory diagram\n%s\n",
gc(IndentLines(output, -1, 0, 4)));
@ -552,11 +556,13 @@ TEST(ShowCrashReports, testNpeCrash) {
gc(IndentLines(output, -1, 0, 4)));
__die();
}
#ifdef __FNO_OMIT_FRAME_POINTER__
if (!OutputHasSymbol(output, "NpeCrash")) {
fprintf(stderr, "ERROR: crash report didn't have backtrace\n%s\n",
gc(IndentLines(output, -1, 0, 4)));
__die();
}
#endif
if (!strstr(output, "∅∅∅∅")) {
fprintf(stderr, "ERROR: crash report didn't have shadow diagram\n%s\n",
gc(IndentLines(output, -1, 0, 4)));
@ -599,11 +605,13 @@ TEST(ShowCrashReports, testDataOverrunCrash) {
EXPECT_TRUE(WIFEXITED(ws));
EXPECT_EQ(77, WEXITSTATUS(ws));
/* NULL is stopgap until we can copy symbol tablces into binary */
#ifdef __FNO_OMIT_FRAME_POINTER__
if (!OutputHasSymbol(output, "DataOverrunCrash")) {
fprintf(stderr, "ERROR: crash report didn't have backtrace\n%s\n",
gc(IndentLines(output, -1, 0, 4)));
__die();
}
#endif
if (!strstr(output, "☺☻♥♦♣♠•◘○") || !strstr(output, "global redzone")) {
fprintf(stderr, "ERROR: crash report didn't have memory diagram\n%s\n",
gc(IndentLines(output, -1, 0, 4)));

View file

@ -4,7 +4,7 @@ if [ "$MODE" = dbg ]; then
exit # TODO
fi
if [ "$MODE" = opt ]; then
if [ "$MODE" = opt ] || [ "$MODE" = optlinux ]; then
exit
fi

View file

@ -6,8 +6,7 @@ exit
if [ "$MODE" = dbg ]; then
exit # TODO
fi
if [ "$MODE" = opt ]; then
if [ "$MODE" = opt ] || [ "$MODE" = optlinux ]; then
exit
fi

View file

@ -22,7 +22,7 @@
#include "libc/testlib/testlib.h"
TEST(GetDosEnviron, testOneVariable) {
#define kEnv u"A=Und wird die Welt auch in Flammen stehen\0"
#define kEnv u"a=Und wird die Welt auch in Flammen stehen\0"
size_t max = 2;
size_t size = sizeof(kEnv) >> 1;
char *block = calloc(1, size);

View file

@ -96,6 +96,7 @@ TEST(TrackMemoryInterval, TestEmpty) {
}
TEST(TrackMemoryInterval, TestFull) {
#if 0 // TODO(jart): Find way to re-enable
int i;
struct MemoryIntervals *mm;
mm = calloc(1, sizeof(struct MemoryIntervals));
@ -108,6 +109,7 @@ TEST(TrackMemoryInterval, TestFull) {
CHECK_EQ(ENOMEM, errno);
CheckMemoryIntervalsAreOk(mm);
free(mm);
#endif
}
TEST(TrackMemoryInterval, TestAppend) {

View file

@ -20,7 +20,6 @@
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nexgen32e/tinystrlen.internal.h"
#include "libc/rand/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
@ -112,40 +111,6 @@ TEST(strnlen_s, nulNotFound_ReturnsZero) {
ASSERT_EQ(0, strnlen_s(buf, 3));
}
TEST(tinystrlen, test) {
ASSERT_EQ(0, tinystrlen(""));
ASSERT_EQ(1, tinystrlen("a"));
ASSERT_EQ(3, tinystrlen("123"));
}
TEST(tinywcslen, test) {
ASSERT_EQ(0, tinywcslen(L""));
ASSERT_EQ(1, tinywcslen(L"a"));
ASSERT_EQ(3, tinywcslen(L"123"));
}
TEST(tinywcsnlen, test) {
EXPECT_EQ(0, tinywcsnlen(L"", 3));
EXPECT_EQ(0, tinywcsnlen(L"a", 0));
EXPECT_EQ(3, tinywcsnlen(L"123", 3));
EXPECT_EQ(2, tinywcsnlen(L"123", 2));
EXPECT_EQ(3, tinywcsnlen(L"123", 4));
}
TEST(tinystrlen16, test) {
ASSERT_EQ(0, tinystrlen16(u""));
ASSERT_EQ(1, tinystrlen16(u"a"));
ASSERT_EQ(3, tinystrlen16(u"123"));
}
TEST(tinystrnlen16, test) {
EXPECT_EQ(0, tinystrnlen16(u"", 3));
EXPECT_EQ(0, tinystrnlen16(u"a", 0));
EXPECT_EQ(3, tinystrnlen16(u"123", 3));
EXPECT_EQ(2, tinystrnlen16(u"123", 2));
EXPECT_EQ(3, tinystrnlen16(u"123", 4));
}
TEST(strlen, fuzz) {
char *b;
size_t n, n1, n2;

View file

@ -26,6 +26,7 @@ TEST_LIBC_XED_TESTLIB_A_OBJS = \
TEST_LIBC_XED_TESTLIB_A_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_STR \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \

View file

@ -36,6 +36,7 @@
# endif
#endif
#include "libc/str/str.h"
#include "third_party/infozip/zip/unix/osdep.h"
@ -133,8 +134,8 @@
* to_up is used to force upper case even on Unix (for dosify option).
*/
#ifdef USE_CASE_MAP
# define case_map(c) upper[(c) & 0xff]
# define to_up(c) upper[(c) & 0xff]
# define case_map(c) kToUpper[(c) & 0xff]
# define to_up(c) kToLower[(c) & 0xff]
#else
# define case_map(c) (c)
# define to_up(c) ((c) >= 'a' && (c) <= 'z' ? (c)-'a'+'A' : (c))

View file

@ -597,71 +597,6 @@ int (*cmp) OF((ZCONST zvoid *, ZCONST zvoid far *)); /* comparison function */
#endif /* !UTIL */
#ifdef MSDOS16
local unsigned ident(unsigned chr)
{
return chr; /* in al */
}
void init_upper()
{
static struct country {
uch ignore[18];
int (far *casemap)(int);
uch filler[16];
} country_info;
struct country far *info = &country_info;
union REGS regs;
struct SREGS sregs;
unsigned int c;
regs.x.ax = 0x3800; /* get country info */
regs.x.dx = FP_OFF(info);
sregs.ds = FP_SEG(info);
intdosx(&regs, &regs, &sregs);
for (c = 0; c < 128; c++) {
upper[c] = (uch) toupper(c);
lower[c] = (uch) c;
}
for (; c < sizeof(upper); c++) {
upper[c] = (uch) (*country_info.casemap)(ident(c));
/* ident() required because casemap takes its parameter in al */
lower[c] = (uch) c;
}
for (c = 0; c < sizeof(upper); c++ ) {
unsigned int u = upper[c];
if (u != c && lower[u] == (uch) u) {
lower[u] = (uch)c;
}
}
for (c = 'A'; c <= 'Z'; c++) {
lower[c] = (uch) (c - 'A' + 'a');
}
}
#else /* !MSDOS16 */
# ifndef OS2
void init_upper()
{
unsigned int c;
#if defined(ATARI) || defined(CMS_MVS)
/* this should be valid for all other platforms too. (HD 11/11/95) */
for (c = 0; c< sizeof(upper); c++) {
upper[c] = islower(c) ? toupper(c) : c;
lower[c] = isupper(c) ? tolower(c) : c;
}
#else
for (c = 0; c < sizeof(upper); c++) upper[c] = lower[c] = (uch)c;
for (c = 'a'; c <= 'z'; c++) upper[c] = (uch)(c - 'a' + 'A');
for (c = 'A'; c <= 'Z'; c++) lower[c] = (uch)(c - 'A' + 'a');
#endif
}
# endif /* !OS2 */
#endif /* ?MSDOS16 */
int namecmp(string1, string2)
ZCONST char *string1, *string2;
/* Compare the two strings ignoring case, and correctly taking into

View file

@ -2489,8 +2489,6 @@ char **argv; /* command line tokens */
mesg = (FILE *) stdout; /* cannot be made at link time for VMS */
comment_stream = (FILE *)stdin;
init_upper(); /* build case map table */
#ifdef LARGE_FILE_SUPPORT
/* test if we can support large files - 9/29/04 */
if (sizeof(zoff_t) < 8) {

View file

@ -388,8 +388,6 @@ int main(argc, argv)
/* Informational messages are written to stdout. */
mesg = stdout;
init_upper(); /* build case map table */
#ifndef USE_ZLIB
crc_32_tab = get_crc_table();
/* initialize crc table for crypt */

View file

@ -454,8 +454,6 @@ char **argv; /* command line tokens */
/* Direct info messages to stderr; stdout is used for data output. */
mesg = stderr;
init_upper(); /* build case map table */
/* Go through args */
zipfile = tempzip = NULL;
tempzf = NULL;

View file

@ -586,8 +586,6 @@ char **argv; /* command line tokens */
/* Informational messages are written to stdout. */
mesg = stdout;
init_upper(); /* build case map table */
/* Go through args */
signal(SIGINT, handler);
#ifdef SIGTERM /* Amiga has no SIGTERM */

View file

@ -1655,7 +1655,7 @@ static int ssl_parse_ecjpake_kkpp( mbedtls_ssl_context *ssl,
return( 0 );
}
/* If we got here, we no longer need our cached extension */
/* If we goth here, we no longer need our cached extension */
mbedtls_free( ssl->handshake->ecjpake_cache );
ssl->handshake->ecjpake_cache = NULL;
ssl->handshake->ecjpake_cache_len = 0;

View file

@ -839,7 +839,7 @@ class ConfigChanges(dict):
if idleConf.defaultCfg[config_type].Get(section, item) == value:
# The setting equals a default setting, remove it from user cfg.
return idleConf.userCfg[config_type].RemoveOption(section, item)
# If we got here, set the option.
# If we goth here, set the option.
return idleConf.userCfg[config_type].SetOption(section, item, value)
def save_all(self):

View file

@ -797,7 +797,7 @@ class _BaseNetwork(_IPAddressBase):
yield s1
s1, s2 = s2.subnets()
else:
# If we got here, there's a bug somewhere.
# If we goth here, there's a bug somewhere.
raise AssertionError('Error performing exclusion: '
's1: %s s2: %s other: %s' %
(s1, s2, other))
@ -806,7 +806,7 @@ class _BaseNetwork(_IPAddressBase):
elif s2 == other:
yield s1
else:
# If we got here, there's a bug somewhere.
# If we goth here, there's a bug somewhere.
raise AssertionError('Error performing exclusion: '
's1: %s s2: %s other: %s' %
(s1, s2, other))

View file

@ -886,7 +886,7 @@ class SMTP:
else:
self._rset()
raise SMTPDataError(code, resp)
#if we got here then somebody got our mail
#if we goth here then somebody got our mail
return senderrs
def send_message(self, msg, from_addr=None, to_addrs=None,

BIN
third_party/python/Lib/test/hello.com vendored Executable file

Binary file not shown.

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