Improve memory safety

This commit makes numerous refinements to cosmopolitan memory handling.

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

    STATIC_STACK_SIZE(0x00200000);  // 2mb stack

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

    STATIC_YOINK("stack_usage_logging");

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

    ShowCrashReports();

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,66 +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.
*/
#include "libc/alg/alg.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/vendor.internal.h"
#include "libc/nt/struct/teb.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h"
#define kBufSize 1024
#define kProcStatus "/proc/self/status"
#define kPid "TracerPid:\t"
static noasan int NtBeingDebugged(void) {
return NtGetPeb()->BeingDebugged;
}
/**
* Determines if gdb, strace, windbg, etc. is controlling process.
* @return non-zero if attached, otherwise 0
*/
int IsDebuggerPresent(bool force) {
int fd, res;
ssize_t got;
char buf[1024];
res = false;
if (!force) {
if (getenv("HEISENDEBUG")) return false;
if (IsGenuineCosmo()) return false;
}
if (IsWindows()) {
res = NtBeingDebugged();
} else if (IsLinux()) {
if ((fd = sys_openat(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
if ((got = sys_read(fd, buf, sizeof(buf) - sizeof(kPid))) != -1) {
buf[got] = '\0';
res = atoi(firstnonnull(strstr(buf, kPid), kPid) + strlen(kPid));
}
sys_close(fd);
}
}
return res;
}

View file

@ -1,37 +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.
*/
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
bool g_isrunningundermake;
/**
* Returns true if current process was spawned by GNU Make.
*/
bool IsRunningUnderMake(void) {
return g_isrunningundermake;
}
textstartup void g_isrunningundermake_init(void) {
g_isrunningundermake = !!getenv("MAKEFLAGS");
}
const void *const g_isrunningundermake_ctor[] initarray = {
g_isrunningundermake_init,
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

@ -0,0 +1,106 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/metasigaltstack.h"
#include "libc/calls/struct/sigaltstack.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
static noasan void sigaltstack2bsd(struct sigaltstack_bsd *bsd,
const struct sigaltstack *linux) {
void *sp;
int flags;
size_t size;
sp = linux->ss_sp;
flags = linux->ss_flags;
size = linux->ss_size;
bsd->ss_sp = sp;
bsd->ss_flags = flags;
bsd->ss_size = size;
}
static noasan void sigaltstack2linux(struct sigaltstack *linux,
const struct sigaltstack_bsd *bsd) {
void *sp;
int flags;
size_t size;
sp = bsd->ss_sp;
flags = bsd->ss_flags;
size = bsd->ss_size;
linux->ss_sp = sp;
linux->ss_flags = flags;
linux->ss_size = size;
}
/**
* Sets and/or gets alternate signal stack, e.g.
*
* struct sigaction sa;
* struct sigaltstack ss;
* ss.ss_flags = 0;
* ss.ss_size = SIGSTKSZ;
* ss.ss_sp = malloc(ss.ss_size);
* sa.sa_flags = SA_ONSTACK;
* sa.sa_handler = OnStackOverflow;
* __cxa_atexit(free, ss[0].ss_sp, 0);
* sigemptyset(&sa.ss_mask);
* sigaltstack(&ss, 0);
* sigaction(SIGSEGV, &sa, 0);
*
* @param neu if non-null will install new signal alt stack
* @param old if non-null will receive current signal alt stack
* @return 0 on success, or -1 w/ errno
*/
noasan int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) {
int rc;
void *a, *b;
struct sigaltstack_bsd bsd;
if (IsAsan() && ((old && __asan_check(old, sizeof(*old)).kind) ||
(neu && (__asan_check(neu, sizeof(*neu)).kind ||
__asan_check(neu->ss_sp, neu->ss_size).kind)))) {
return efault();
}
if (IsLinux()) {
a = neu;
b = old;
} else if (IsBsd()) {
if (neu) {
sigaltstack2bsd(&bsd, neu);
a = &bsd;
} else {
a = 0;
}
if (old) {
b = &bsd;
} else {
b = 0;
}
} else {
return enosys();
}
if ((rc = sys_sigaltstack(a, b)) != -1) {
if (old) {
sigaltstack2linux(old, &bsd);
}
return 0;
} else {
return -1;
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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