mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 14:58:30 +00:00
Make improvements
- Expand redbean UNIX module - Expand redbean documentation - Ensure Lua copyright is embedded in binary - Increase the PATH_MAX limit especially on NT - Use column major sorting for linenoise completions - Fix some suboptimalities in redbean's new UNIX API - Figured out right flags for Multics newline in raw mode
This commit is contained in:
parent
cf3174dc74
commit
2046c0d2ae
305 changed files with 6602 additions and 4221 deletions
|
@ -24,7 +24,7 @@
|
|||
struct FindComBinary {
|
||||
bool once;
|
||||
const char *res;
|
||||
char buf[PATH_MAX];
|
||||
char buf[PATH_MAX + 1];
|
||||
};
|
||||
|
||||
static struct FindComBinary g_findcombinary;
|
||||
|
|
|
@ -30,6 +30,7 @@ int GetDosArgv(const char16_t *, char *, size_t, char **, size_t);
|
|||
Elf64_Ehdr *MapElfRead(const char *, struct MappedFile *) hidden;
|
||||
int GetDosEnviron(const char16_t *, char *, size_t, char **, size_t);
|
||||
bool __intercept_flag(int *, char *[], const char *);
|
||||
int sys_mprotect_nt(void *, size_t, int) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
|
||||
bool IsMemtracked(int x, int y) {
|
||||
static inline bool IsMemtrackedImpl(int x, int y) {
|
||||
unsigned i;
|
||||
i = FindMemoryInterval(&_mmi, x);
|
||||
if (i == _mmi.i) return false;
|
||||
|
@ -29,3 +29,9 @@ bool IsMemtracked(int x, int y) {
|
|||
if (_mmi.p[i].x != _mmi.p[i - 1].y + 1) return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsMemtracked(int x, int y) {
|
||||
bool res;
|
||||
res = IsMemtrackedImpl(x, y);
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ struct MemoryIntervals {
|
|||
size_t i, n;
|
||||
struct MemoryInterval *p;
|
||||
struct MemoryInterval s[OPEN_MAX];
|
||||
_Alignas(64) char lock;
|
||||
};
|
||||
|
||||
extern hidden struct MemoryIntervals _mmi;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
|
@ -198,6 +199,133 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size,
|
|||
return addr;
|
||||
}
|
||||
|
||||
static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags,
|
||||
int fd, int64_t off) {
|
||||
#if defined(SYSDEBUG) && (_KERNTRACE || _NTTRACE)
|
||||
if (IsWindows()) {
|
||||
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → ...", addr, size,
|
||||
DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off);
|
||||
}
|
||||
#endif
|
||||
char *p = addr;
|
||||
struct DirectMap dm;
|
||||
size_t virtualused, virtualneed;
|
||||
int a, b, i, f, m, n, x;
|
||||
|
||||
if (UNLIKELY(!size)) {
|
||||
STRACE("size=0");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
if (UNLIKELY(!IsLegalSize(size))) {
|
||||
STRACE("size isn't 48-bit");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
if (UNLIKELY(!IsLegalPointer(p))) {
|
||||
STRACE("p isn't 48-bit");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
if (UNLIKELY(!ALIGNED(p))) {
|
||||
STRACE("p isn't 64kb aligned");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
if (UNLIKELY(fd < -1)) {
|
||||
STRACE("mmap(%.12p, %'zu, fd=%d) EBADF", p, size, fd);
|
||||
return VIP(ebadf());
|
||||
}
|
||||
|
||||
if (UNLIKELY(!((fd != -1) ^ !!(flags & MAP_ANONYMOUS)))) {
|
||||
STRACE("fd anonymous mismatch");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
if (UNLIKELY(!(!!(flags & MAP_PRIVATE) ^ !!(flags & MAP_SHARED)))) {
|
||||
STRACE("MAP_SHARED ^ MAP_PRIVATE");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
if (UNLIKELY(off < 0)) {
|
||||
STRACE("neg off");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
if (UNLIKELY(INT64_MAX - size < off)) {
|
||||
STRACE("too large");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
if (UNLIKELY(!ALIGNED(off))) {
|
||||
STRACE("p isn't 64kb aligned");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
if ((flags & MAP_FIXED_NOREPLACE) && IsMapped(p, size)) {
|
||||
#ifdef SYSDEBUG
|
||||
if (OverlapsImageSpace(p, size)) {
|
||||
STRACE("overlaps image");
|
||||
} else {
|
||||
STRACE("overlaps existing");
|
||||
}
|
||||
#endif
|
||||
return VIP(efault());
|
||||
}
|
||||
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
STRACE("fd is zipos handle");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
if (__virtualmax < LONG_MAX &&
|
||||
(__builtin_add_overflow((virtualused = GetMemtrackSize(&_mmi)), size,
|
||||
&virtualneed) ||
|
||||
virtualneed > __virtualmax)) {
|
||||
STRACE("%'zu size + %'zu inuse exceeds virtual memory limit %'zu", size,
|
||||
virtualused, __virtualmax);
|
||||
return VIP(enomem());
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
size = ROUNDUP(size, FRAMESIZE);
|
||||
if (IsWindows()) {
|
||||
prot |= PROT_WRITE; /* kludge */
|
||||
}
|
||||
}
|
||||
|
||||
n = (int)(size >> 16) + !!(size & (FRAMESIZE - 1));
|
||||
assert(n > 0);
|
||||
f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED;
|
||||
if (flags & MAP_FIXED) {
|
||||
x = FRAME(p);
|
||||
if (IsWindows()) {
|
||||
if (UntrackMemoryIntervals(p, size)) {
|
||||
OnUnrecoverableMmapError("FIXED UNTRACK FAILED");
|
||||
}
|
||||
}
|
||||
} else if (!NeedAutomap(p, size)) {
|
||||
x = FRAME(p);
|
||||
} else if (!Automap(n, &x)) {
|
||||
STRACE("AUTOMAP OUT OF MEMORY D:");
|
||||
return VIP(enomem());
|
||||
}
|
||||
|
||||
p = (char *)ADDR(x);
|
||||
if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */
|
||||
dm = sys_mmap(p, size, prot, f & ~MAP_GROWSDOWN, fd, off);
|
||||
if (dm.addr == MAP_FAILED) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Beseeches system for page-table entries, e.g.
|
||||
*
|
||||
|
@ -229,100 +357,10 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size,
|
|||
*/
|
||||
noasan void *mmap(void *addr, size_t size, int prot, int flags, int fd,
|
||||
int64_t off) {
|
||||
#if defined(SYSDEBUG) && (_KERNTRACE || _NTTRACE)
|
||||
if (IsWindows()) {
|
||||
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → ...", addr, size,
|
||||
DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off);
|
||||
}
|
||||
#endif
|
||||
void *res;
|
||||
char *p = addr;
|
||||
struct DirectMap dm;
|
||||
size_t virtualused, virtualneed;
|
||||
int a, b, i, f, m, n, x;
|
||||
if (UNLIKELY(!size)) {
|
||||
STRACE("size=0");
|
||||
res = VIP(einval());
|
||||
} else if (UNLIKELY(!IsLegalSize(size))) {
|
||||
STRACE("size isn't 48-bit");
|
||||
res = VIP(einval());
|
||||
} else if (UNLIKELY(!IsLegalPointer(p))) {
|
||||
STRACE("p isn't 48-bit");
|
||||
res = VIP(einval());
|
||||
} else if (UNLIKELY(!ALIGNED(p))) {
|
||||
STRACE("p isn't 64kb aligned");
|
||||
res = VIP(einval());
|
||||
} else if (UNLIKELY(fd < -1)) {
|
||||
STRACE("mmap(%.12p, %'zu, fd=%d) EBADF", p, size, fd);
|
||||
res = VIP(ebadf());
|
||||
} else if (UNLIKELY(!((fd != -1) ^ !!(flags & MAP_ANONYMOUS)))) {
|
||||
STRACE("fd anonymous mismatch");
|
||||
res = VIP(einval());
|
||||
} else if (UNLIKELY(!(!!(flags & MAP_PRIVATE) ^ !!(flags & MAP_SHARED)))) {
|
||||
STRACE("MAP_SHARED ^ MAP_PRIVATE");
|
||||
res = VIP(einval());
|
||||
} else if (UNLIKELY(off < 0)) {
|
||||
STRACE("neg off");
|
||||
res = VIP(einval());
|
||||
} else if (UNLIKELY(INT64_MAX - size < off)) {
|
||||
STRACE("too large");
|
||||
res = VIP(einval());
|
||||
} else if (UNLIKELY(!ALIGNED(off))) {
|
||||
STRACE("p isn't 64kb aligned");
|
||||
res = VIP(einval());
|
||||
} else if ((flags & MAP_FIXED_NOREPLACE) && IsMapped(p, size)) {
|
||||
#ifdef SYSDEBUG
|
||||
if (OverlapsImageSpace(p, size)) {
|
||||
STRACE("overlaps image");
|
||||
} else {
|
||||
STRACE("overlaps existing");
|
||||
}
|
||||
#endif
|
||||
res = VIP(efault());
|
||||
} else if (__isfdkind(fd, kFdZip)) {
|
||||
STRACE("fd is zipos handle");
|
||||
res = VIP(einval());
|
||||
} else if (__virtualmax < LONG_MAX &&
|
||||
(__builtin_add_overflow((virtualused = GetMemtrackSize(&_mmi)),
|
||||
size, &virtualneed) ||
|
||||
virtualneed > __virtualmax)) {
|
||||
STRACE("%'zu size + %'zu inuse exceeds virtual memory limit %'zu", size,
|
||||
virtualused, __virtualmax);
|
||||
res = VIP(enomem());
|
||||
} else {
|
||||
if (fd == -1) {
|
||||
size = ROUNDUP(size, FRAMESIZE);
|
||||
if (IsWindows()) {
|
||||
prot |= PROT_WRITE; /* kludge */
|
||||
}
|
||||
}
|
||||
n = (int)(size >> 16) + !!(size & (FRAMESIZE - 1));
|
||||
assert(n > 0);
|
||||
f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED;
|
||||
if (flags & MAP_FIXED) {
|
||||
x = FRAME(p);
|
||||
if (IsWindows()) {
|
||||
if (UntrackMemoryIntervals(p, size)) {
|
||||
OnUnrecoverableMmapError("FIXED UNTRACK FAILED");
|
||||
}
|
||||
}
|
||||
} else if (!NeedAutomap(p, size)) {
|
||||
x = FRAME(p);
|
||||
} else if (!Automap(n, &x)) {
|
||||
STRACE("AUTOMAP OUT OF MEMORY D:");
|
||||
return VIP(enomem());
|
||||
}
|
||||
p = (char *)ADDR(x);
|
||||
if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */
|
||||
dm = sys_mmap(p, size, prot, f & ~MAP_GROWSDOWN, fd, off);
|
||||
if (dm.addr == MAP_FAILED) res = MAP_FAILED;
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
res = MapMemory(p, size, prot, flags, fd, off, f, x, n);
|
||||
} else {
|
||||
res = MapMemories(p, size, prot, flags, fd, off, f, x, n);
|
||||
}
|
||||
}
|
||||
_spinlock(&_mmi.lock);
|
||||
res = Mmap(addr, size, prot, flags, fd, off);
|
||||
_spunlock(&_mmi.lock);
|
||||
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → %p% m", addr, size,
|
||||
DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off, res);
|
||||
return res;
|
||||
|
|
63
libc/runtime/mprotect-nt.greg.c
Normal file
63
libc/runtime/mprotect-nt.greg.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*-*- 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 2022 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/intrin/spinlock.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
|
||||
#define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16))
|
||||
|
||||
privileged int sys_mprotect_nt(void *addr, size_t size, int prot) {
|
||||
int rc = 0;
|
||||
unsigned i;
|
||||
uint32_t op;
|
||||
char *a, *b, *x, *y, *p;
|
||||
_spinlock(&_mmi.lock);
|
||||
p = addr;
|
||||
i = FindMemoryInterval(&_mmi, (intptr_t)p >> 16);
|
||||
if (i == _mmi.i || (!i && p + size <= ADDR(_mmi.p[0].x))) {
|
||||
// memory isn't in memtrack
|
||||
// let's just trust the user then
|
||||
// it's probably part of the executable
|
||||
if (!VirtualProtect(addr, size, __prot2nt(prot, false), &op)) {
|
||||
rc = -1;
|
||||
}
|
||||
} else {
|
||||
// memory is in memtrack, so use memtrack, to do dimensioning
|
||||
// we unfortunately must do something similar to this for cow
|
||||
for (; i < _mmi.i; ++i) {
|
||||
x = ADDR(_mmi.p[i].x);
|
||||
y = x + _mmi.p[i].size;
|
||||
if ((x <= p && p < y) || (x < p + size && p + size <= y) ||
|
||||
(p < x && y < p + size)) {
|
||||
a = MIN(MAX(p, x), y);
|
||||
b = MAX(MIN(p + size, y), x);
|
||||
if (!VirtualProtect(a, b - a, __prot2nt(prot, _mmi.p[i].iscow), &op)) {
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_spunlock(&_mmi.lock);
|
||||
return rc;
|
||||
}
|
|
@ -16,26 +16,16 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/asmflag.h"
|
||||
#include "libc/bits/likely.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect;
|
||||
|
||||
#define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16))
|
||||
|
||||
/**
|
||||
* Modifies restrictions on virtual memory address range.
|
||||
*
|
||||
|
@ -44,12 +34,8 @@ __msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect;
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @see mmap()
|
||||
*/
|
||||
noasan noubsan privileged int mprotect(void *addr, size_t size, int prot) {
|
||||
bool cf;
|
||||
privileged int mprotect(void *addr, size_t size, int prot) {
|
||||
int64_t rc;
|
||||
unsigned i;
|
||||
uint32_t op;
|
||||
char *a, *b, *x, *y, *p;
|
||||
if (SupportsWindows() && (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC |
|
||||
PROT_GROWSDOWN | PROT_GROWSUP))) {
|
||||
rc = einval(); // unix checks prot before checking size
|
||||
|
@ -58,48 +44,9 @@ noasan noubsan privileged int mprotect(void *addr, size_t size, int prot) {
|
|||
} else if (UNLIKELY((intptr_t)addr & 4095)) {
|
||||
rc = einval();
|
||||
} else if (!IsWindows()) {
|
||||
asm volatile(CFLAG_ASM("clc\n\tsyscall")
|
||||
: CFLAG_CONSTRAINT(cf), "=a"(rc)
|
||||
: "1"(__NR_mprotect), "D"(addr), "S"(size), "d"(prot)
|
||||
: "rcx", "r11", "memory", "cc");
|
||||
if (cf) {
|
||||
errno = rc;
|
||||
rc = -1;
|
||||
} else if (rc > -4096ul) {
|
||||
errno = -rc;
|
||||
rc = -1;
|
||||
}
|
||||
rc = sys_mprotect(addr, size, prot);
|
||||
} else {
|
||||
rc = 0;
|
||||
p = addr;
|
||||
i = FindMemoryInterval(&_mmi, (intptr_t)p >> 16);
|
||||
if (i == _mmi.i || (!i && p + size <= ADDR(_mmi.p[0].x))) {
|
||||
// memory isn't in memtrack
|
||||
// let's just trust the user then
|
||||
// it's probably part of the executable
|
||||
if (!VirtualProtect(addr, size, __prot2nt(prot, false), &op)) {
|
||||
rc = -1;
|
||||
}
|
||||
} else {
|
||||
// memory is in memtrack, so use memtrack, to do dimensioning
|
||||
// we unfortunately must do something similar to this for cow
|
||||
for (; i < _mmi.i; ++i) {
|
||||
x = ADDR(_mmi.p[i].x);
|
||||
y = x + _mmi.p[i].size;
|
||||
if ((x <= p && p < y) || (x < p + size && p + size <= y) ||
|
||||
(p < x && y < p + size)) {
|
||||
a = MIN(MAX(p, x), y);
|
||||
b = MAX(MIN(p + size, y), x);
|
||||
if (!VirtualProtect(a, b - a, __prot2nt(prot, _mmi.p[i].iscow),
|
||||
&op)) {
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = sys_mprotect_nt(addr, size, prot);
|
||||
}
|
||||
STRACE("mprotect(%p, %'zu, %s) → %d% m", addr, size, DescribeProtFlags(prot),
|
||||
rc);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/memory.h"
|
||||
|
@ -31,6 +32,7 @@
|
|||
noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
|
||||
int i, rc = 0;
|
||||
char *a, *b, *x, *y;
|
||||
_spinlock(&_mmi.lock);
|
||||
for (i = FindMemoryInterval(&_mmi, (intptr_t)addr >> 16); i < _mmi.i; ++i) {
|
||||
x = ADDR(_mmi.p[i].x);
|
||||
y = x + _mmi.p[i].size;
|
||||
|
@ -47,30 +49,6 @@ noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
_spunlock(&_mmi.lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if 0
|
||||
noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
|
||||
char *a, *b;
|
||||
int rc, x, y, l, r, i;
|
||||
rc = 0;
|
||||
for (i = FindMemoryInterval(&_mmi, (intptr_t)addr >> 16); i < _mmi.i; ++i) {
|
||||
if ((ADDR(_mmi.p[i].x) <= addr && addr < ADDR(_mmi.p[i].y + 1)) ||
|
||||
(ADDR(_mmi.p[i].x) < addr + size &&
|
||||
addr + size <= ADDR(_mmi.p[i].y + 1)) ||
|
||||
(addr < ADDR(_mmi.p[i].x) && ADDR(_mmi.p[i].y + 1) < addr + size)) {
|
||||
a = MIN(MAX(addr, ADDR(_mmi.p[i].x)), ADDR(_mmi.p[i].y + 1));
|
||||
b = MAX(MIN(addr + size, ADDR(_mmi.p[i].y + 1)), ADDR(_mmi.p[i].x));
|
||||
if (!FlushViewOfFile(a, b - a)) {
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
// TODO(jart): FlushFileBuffers too on g_fds handle if MS_SYNC?
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
|
@ -35,6 +36,76 @@
|
|||
#define ADDR(x) ((int64_t)((uint64_t)(x) << 32) >> 16)
|
||||
#define FRAME(x) ((int)((intptr_t)(x) >> 16))
|
||||
|
||||
static noasan int Munmap(void *v, size_t n) {
|
||||
char poison, *p = v;
|
||||
intptr_t a, b, x, y;
|
||||
assert(!__vforked);
|
||||
|
||||
if (UNLIKELY(!n)) {
|
||||
STRACE("munmap(%.12p, %'zu) %s (n=0)", p, n);
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (UNLIKELY(!IsLegalSize(n))) {
|
||||
STRACE("munmap(%.12p, %'zu) EINVAL (n isn't 48-bit)", p, n);
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (UNLIKELY(!IsLegalPointer(p))) {
|
||||
STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 48-bit)", p, n);
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (UNLIKELY(!IsLegalPointer(p + (n - 1)))) {
|
||||
STRACE("munmap(%.12p, %'zu) EINVAL (p+(n-1) isn't 48-bit)", p, n);
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (UNLIKELY(!ALIGNED(p))) {
|
||||
STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 64kb aligned)", p, n);
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (!IsMemtracked(FRAME(p), FRAME(p + (n - 1)))) {
|
||||
STRACE("munmap(%.12p, %'zu) EFAULT (interval not tracked)", p, n);
|
||||
return efault();
|
||||
}
|
||||
|
||||
if (UntrackMemoryIntervals(p, n) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (IsWindows()) {
|
||||
return 0; // UntrackMemoryIntervals does it for NT
|
||||
}
|
||||
|
||||
if (sys_munmap(p, n) == -1) {
|
||||
return -1; // ouch
|
||||
}
|
||||
|
||||
if (IsAsan() && !OverlapsShadowSpace(p, n)) {
|
||||
a = ((intptr_t)p >> 3) + 0x7fff8000;
|
||||
b = a + (n >> 3);
|
||||
if (IsMemtracked(FRAME(a), FRAME(b - 1))) {
|
||||
x = ROUNDUP(a, FRAMESIZE);
|
||||
y = ROUNDDOWN(b, FRAMESIZE);
|
||||
if (x < y) {
|
||||
// delete shadowspace if unmapping ≥512kb
|
||||
__repstosb((void *)a, kAsanUnmapped, x - a);
|
||||
Munmap((void *)x, y - x);
|
||||
__repstosb((void *)y, kAsanUnmapped, b - y);
|
||||
} else {
|
||||
// otherwise just poison and assume reuse
|
||||
__repstosb((void *)a, kAsanUnmapped, b - a);
|
||||
}
|
||||
} else {
|
||||
STRACE("unshadow(%.12p, %p) EFAULT", a, b - a);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases memory pages.
|
||||
*
|
||||
|
@ -49,66 +120,11 @@
|
|||
* and for files size needs to be perfect to the byte bc openbsd
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
noasan int munmap(void *v, size_t n) {
|
||||
/* asan runtime depends on this function */
|
||||
noasan int munmap(void *p, size_t n) {
|
||||
int rc;
|
||||
char poison, *p = v;
|
||||
intptr_t a, b, x, y;
|
||||
assert(!__vforked);
|
||||
if (UNLIKELY(!n)) {
|
||||
STRACE("munmap(%.12p, %'zu) %s (n=0)", p, n);
|
||||
return einval();
|
||||
}
|
||||
if (UNLIKELY(!IsLegalSize(n))) {
|
||||
STRACE("munmap(%.12p, %'zu) EINVAL (n isn't 48-bit)", p, n);
|
||||
return einval();
|
||||
}
|
||||
if (UNLIKELY(!IsLegalPointer(p))) {
|
||||
STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 48-bit)", p, n);
|
||||
return einval();
|
||||
}
|
||||
if (UNLIKELY(!IsLegalPointer(p + (n - 1)))) {
|
||||
STRACE("munmap(%.12p, %'zu) EINVAL (p+(n-1) isn't 48-bit)", p, n);
|
||||
return einval();
|
||||
}
|
||||
if (UNLIKELY(!ALIGNED(p))) {
|
||||
STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 64kb aligned)", p, n);
|
||||
return einval();
|
||||
}
|
||||
if (!IsMemtracked(FRAME(p), FRAME(p + (n - 1)))) {
|
||||
STRACE("munmap(%.12p, %'zu) EFAULT (interval not tracked)", p, n);
|
||||
return efault();
|
||||
}
|
||||
if (UntrackMemoryIntervals(p, n) != -1) {
|
||||
if (!IsWindows()) {
|
||||
rc = sys_munmap(p, n);
|
||||
if (rc != -1) {
|
||||
if (IsAsan() && !OverlapsShadowSpace(p, n)) {
|
||||
a = ((intptr_t)p >> 3) + 0x7fff8000;
|
||||
b = a + (n >> 3);
|
||||
if (IsMemtracked(FRAME(a), FRAME(b - 1))) {
|
||||
x = ROUNDUP(a, FRAMESIZE);
|
||||
y = ROUNDDOWN(b, FRAMESIZE);
|
||||
if (x < y) {
|
||||
/* delete shadowspace if unmapping ≥512kb */
|
||||
__repstosb((void *)a, kAsanUnmapped, x - a);
|
||||
munmap((void *)x, y - x);
|
||||
__repstosb((void *)y, kAsanUnmapped, b - y);
|
||||
} else {
|
||||
/* otherwise just poison and assume reuse */
|
||||
__repstosb((void *)a, kAsanUnmapped, b - a);
|
||||
}
|
||||
} else {
|
||||
STRACE("unshadow(%.12p, %p) EFAULT", a, b - a);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = 0; /* UntrackMemoryIntervals does it for NT */
|
||||
}
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
_spinlock(&_mmi.lock);
|
||||
rc = Munmap(p, n);
|
||||
_spunlock(&_mmi.lock);
|
||||
STRACE("munmap(%.12p, %'zu) → %d% m", p, n, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
57
libc/runtime/paginate.c
Normal file
57
libc/runtime/paginate.c
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*-*- 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 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/**
|
||||
* Displays wall of text in terminal with pagination.
|
||||
*/
|
||||
void __paginate(int fd, const char *s) {
|
||||
int tfd, pid;
|
||||
char *args[3] = {0};
|
||||
char tmppath[PATH_MAX + 1];
|
||||
char progpath[PATH_MAX + 1];
|
||||
if (strcmp(nulltoempty(getenv("TERM")), "dumb") && isatty(0) && isatty(1) &&
|
||||
((args[0] = commandv("less", progpath, sizeof(progpath))) ||
|
||||
(args[0] = commandv("more", progpath, sizeof(progpath))))) {
|
||||
snprintf(tmppath, sizeof(tmppath), "%s%s-%s-%d.txt", kTmpPath,
|
||||
program_invocation_short_name, "paginate", getpid());
|
||||
if ((tfd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0644)) != -1) {
|
||||
write(tfd, s, strlen(s));
|
||||
close(tfd);
|
||||
args[1] = tmppath;
|
||||
if ((pid = vfork()) != -1) {
|
||||
if (!pid) {
|
||||
execv(args[0], args);
|
||||
_Exit(127);
|
||||
}
|
||||
waitpid(pid, 0, 0);
|
||||
unlink(tmppath);
|
||||
return;
|
||||
}
|
||||
unlink(tmppath);
|
||||
}
|
||||
}
|
||||
write(fd, s, strlen(s));
|
||||
}
|
|
@ -44,6 +44,7 @@
|
|||
#include "libc/runtime/stack.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
|
@ -52,12 +53,13 @@
|
|||
#include "tool/decode/lib/idname.h"
|
||||
#include "tool/decode/lib/x86idnames.h"
|
||||
|
||||
STATIC_YOINK("strerror"); // for kprintf()
|
||||
STATIC_YOINK("strsignal"); // for kprintf()
|
||||
|
||||
#define PRINT(FMT, ...) \
|
||||
do { \
|
||||
kprintf(prologue); \
|
||||
kprintf(FMT "%n", ##__VA_ARGS__); \
|
||||
kprintf(FMT "\n", ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
static const struct AuxiliaryValue {
|
||||
|
@ -137,8 +139,8 @@ textstartup void __printargs(const char *prologue) {
|
|||
unsigned i, n;
|
||||
uintptr_t *auxp;
|
||||
struct utsname uts;
|
||||
char path[PATH_MAX];
|
||||
struct termios termios;
|
||||
char path[PATH_MAX + 1];
|
||||
int e, x, st, ft, flags;
|
||||
struct pollfd pfds[128];
|
||||
struct AuxiliaryValue *auxinfo;
|
||||
|
@ -157,7 +159,7 @@ textstartup void __printargs(const char *prologue) {
|
|||
kprintf(" %s", uts.release);
|
||||
}
|
||||
}
|
||||
kprintf("%n");
|
||||
kprintf("\n");
|
||||
} else {
|
||||
PRINT(" uname() failed %m");
|
||||
}
|
||||
|
@ -177,7 +179,7 @@ textstartup void __printargs(const char *prologue) {
|
|||
FindNameById(kX86GradeNames,
|
||||
getx86processormodel(kX86ProcessorModelKey)->grade));
|
||||
}
|
||||
kprintf("%n");
|
||||
kprintf("\n");
|
||||
if ((x = KCPUIDS(16H, EAX) & 0x7fff)) {
|
||||
kprintf(prologue);
|
||||
kprintf(" %dmhz %s", x, "freq");
|
||||
|
@ -187,7 +189,7 @@ textstartup void __printargs(const char *prologue) {
|
|||
if ((x = KCPUIDS(16H, ECX) & 0x7fff)) {
|
||||
kprintf(" / %dmhz %s", x, "bus");
|
||||
}
|
||||
kprintf("%n");
|
||||
kprintf("\n");
|
||||
}
|
||||
if (X86_HAVE(HYPERVISOR)) {
|
||||
unsigned eax, ebx, ecx, edx;
|
||||
|
@ -203,8 +205,9 @@ textstartup void __printargs(const char *prologue) {
|
|||
PRINT(" L%d%s%s %u-way %,u byte cache w/%s "
|
||||
"%,u sets of %,u byte lines shared across %u threads%s",
|
||||
CPUID4_CACHE_LEVEL,
|
||||
CPUID4_CACHE_TYPE == 1 ? " data"
|
||||
: CPUID4_CACHE_TYPE == 2 ? " code" : "",
|
||||
CPUID4_CACHE_TYPE == 1 ? " data"
|
||||
: CPUID4_CACHE_TYPE == 2 ? " code"
|
||||
: "",
|
||||
CPUID4_IS_FULLY_ASSOCIATIVE ? " fully-associative" : "",
|
||||
CPUID4_WAYS_OF_ASSOCIATIVITY, CPUID4_CACHE_SIZE_IN_BYTES,
|
||||
CPUID4_PHYSICAL_LINE_PARTITIONS > 1 ? " physically partitioned" : "",
|
||||
|
@ -233,7 +236,7 @@ textstartup void __printargs(const char *prologue) {
|
|||
if (X86_HAVE(RDPID)) kprintf(" RDPID");
|
||||
if (X86_HAVE(LA57)) kprintf(" LA57");
|
||||
if (X86_HAVE(FSGSBASE)) kprintf(" FSGSBASE");
|
||||
kprintf("%n");
|
||||
kprintf("\n");
|
||||
|
||||
PRINT("");
|
||||
PRINT("FILE DESCRIPTORS");
|
||||
|
@ -355,7 +358,7 @@ textstartup void __printargs(const char *prologue) {
|
|||
if (termios.c_iflag & IMAXBEL) kprintf(" IMAXBEL");
|
||||
if (termios.c_iflag & IUTF8) kprintf(" IUTF8");
|
||||
if (termios.c_iflag & IUCLC) kprintf(" IUCLC");
|
||||
kprintf("%n");
|
||||
kprintf("\n");
|
||||
kprintf(prologue);
|
||||
kprintf(" c_oflag =");
|
||||
if (termios.c_oflag & OPOST) kprintf(" OPOST");
|
||||
|
@ -408,15 +411,15 @@ textstartup void __printargs(const char *prologue) {
|
|||
} else if ((termios.c_oflag & FFDLY) == FF1) {
|
||||
kprintf(" FF1");
|
||||
}
|
||||
kprintf("%n");
|
||||
kprintf("\n");
|
||||
kprintf(prologue);
|
||||
kprintf(" c_cflag =");
|
||||
if (termios.c_cflag & ISIG) kprintf(" ISIG");
|
||||
if (termios.c_cflag & CSTOPB) kprintf(" CSTOPB");
|
||||
if (termios.c_cflag & CREAD) kprintf(" CREAD");
|
||||
if (termios.c_cflag & PARENB) kprintf(" PARENB");
|
||||
if (termios.c_cflag & PARODD) kprintf(" PARODD");
|
||||
if (termios.c_cflag & CSTOPB) kprintf(" CSTOPB");
|
||||
if (termios.c_cflag & PARODD) kprintf(" PARODD");
|
||||
if (termios.c_cflag & HUPCL) kprintf(" HUPCL");
|
||||
if (termios.c_cflag & CREAD) kprintf(" CREAD");
|
||||
if (termios.c_cflag & CLOCAL) kprintf(" CLOCAL");
|
||||
if ((termios.c_cflag & CSIZE) == CS5) {
|
||||
kprintf(" CS5");
|
||||
|
@ -427,7 +430,7 @@ textstartup void __printargs(const char *prologue) {
|
|||
} else if ((termios.c_cflag & CSIZE) == CS8) {
|
||||
kprintf(" CS8");
|
||||
}
|
||||
kprintf("%n");
|
||||
kprintf("\n");
|
||||
kprintf(prologue);
|
||||
kprintf(" c_lflag =");
|
||||
if (termios.c_lflag & ISIG) kprintf(" ISIG");
|
||||
|
@ -445,7 +448,7 @@ textstartup void __printargs(const char *prologue) {
|
|||
if (termios.c_lflag & FLUSHO) kprintf(" FLUSHO");
|
||||
if (termios.c_lflag & PENDIN) kprintf(" PENDIN");
|
||||
if (termios.c_lflag & XCASE) kprintf(" XCASE");
|
||||
kprintf("%n");
|
||||
kprintf("\n");
|
||||
PRINT(" c_ispeed = %u", termios.c_ispeed);
|
||||
PRINT(" c_ospeed = %u", termios.c_ospeed);
|
||||
PRINT(" c_cc[VINTR] = CTRL-%c", CTRL(termios.c_cc[VINTR]));
|
||||
|
|
|
@ -54,7 +54,7 @@ void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) {
|
|||
if (mm->p[i].h != -1) {
|
||||
kprintf(" h=%ld", mm->p[i].h);
|
||||
}
|
||||
kprintf("%n");
|
||||
kprintf("\n");
|
||||
}
|
||||
kprintf("# %ld frames mapped w/ %'ld frames gapped%n", maptally, gaptally);
|
||||
kprintf("# %ld frames mapped w/ %'ld frames gapped\n", maptally, gaptally);
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ long GetMaxFd(void);
|
|||
char *GetProgramExecutableName(void);
|
||||
char *GetInterpreterExecutableName(char *, size_t);
|
||||
void __printargs(const char *);
|
||||
void __paginate(int, const char *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -69,10 +69,12 @@ o/$(MODE)/libc/runtime/ezmap.o \
|
|||
o/$(MODE)/libc/runtime/getdosargv.o \
|
||||
o/$(MODE)/libc/runtime/getdosenviron.o \
|
||||
o/$(MODE)/libc/runtime/hook.greg.o \
|
||||
o/$(MODE)/libc/runtime/mprotect.greg.o \
|
||||
o/$(MODE)/libc/runtime/mprotect-nt.greg.o \
|
||||
o/$(MODE)/libc/runtime/ismemtracked.greg.o \
|
||||
o/$(MODE)/libc/runtime/isheap.o \
|
||||
o/$(MODE)/libc/runtime/memtracknt.o \
|
||||
o/$(MODE)/libc/runtime/memtrack.greg.o \
|
||||
o/$(MODE)/libc/runtime/ismemtracked.greg.o \
|
||||
o/$(MODE)/libc/runtime/metalprintf.greg.o \
|
||||
o/$(MODE)/libc/runtime/printargs.greg.o \
|
||||
o/$(MODE)/libc/runtime/mman.greg.o \
|
||||
|
|
|
@ -94,7 +94,7 @@ vfork.bsd:
|
|||
#ifdef SYSDEBUG
|
||||
.rodata.str1.1
|
||||
.Llog: .ascii STRACE_PROLOGUE
|
||||
.asciz "vfork()%n"
|
||||
.asciz "vfork()\n"
|
||||
.previous
|
||||
#endif /* DEBUGSYS */
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
#include "libc/str/utf16.h"
|
||||
|
||||
|
@ -120,6 +121,15 @@ forceinline void MakeLongDoubleLongAgain(void) {
|
|||
asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw));
|
||||
}
|
||||
|
||||
static inline size_t StrLen16(const char16_t *s) {
|
||||
size_t n;
|
||||
for (n = 0;; ++n) {
|
||||
if (!s[n]) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__msabi static textwindows int OnEarlyWinCrash(struct NtExceptionPointers *ep) {
|
||||
uint32_t wrote;
|
||||
char buf[64], *p = buf;
|
||||
|
@ -209,6 +219,9 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
|||
}
|
||||
}
|
||||
env16 = GetEnvironmentStrings();
|
||||
for (char16_t *e = env16; *e; e += StrLen16(e) + 1) {
|
||||
NTTRACE("GetEnvironmentStrings() → %!#hs", e);
|
||||
}
|
||||
NTTRACE("WinMainNew() loading environment");
|
||||
GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp,
|
||||
ARRAYLEN(wa->envp) - 1);
|
||||
|
@ -257,7 +270,6 @@ __msabi textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
|||
extern uint64_t ts asm("kStartTsc");
|
||||
os = WINDOWS; /* madness https://news.ycombinator.com/item?id=21019722 */
|
||||
ts = rdtsc();
|
||||
__nomultics = true;
|
||||
__pid = GetCurrentProcessId();
|
||||
__wincrashearly = AddVectoredExceptionHandler(1, (void *)OnEarlyWinCrash);
|
||||
cmdline = GetCommandLine();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue