Make more fixes and improvements

- Remove PAGESIZE constant
- Fix realloc() documentation
- Fix ttyname_r() error reporting
- Make forking more reliable on Windows
- Make execvp() a few microseconds faster
- Make system() a few microseconds faster
- Tighten up the socket-related magic numbers
- Loosen restrictions on mmap() offset alignment
- Improve GetProgramExecutableName() with getenv("_")
- Use mkstemp() as basis for mktemp(), tmpfile(), tmpfd()
- Fix flakes in pthread_cancel_test, unix_test, fork_test
- Fix recently introduced futex stack overflow regression
- Let sockets be passed as stdio to subprocesses on Windows
- Improve security of bind() on Windows w/ SO_EXCLUSIVEADDRUSE
This commit is contained in:
Justine Tunney 2023-07-29 18:44:15 -07:00
parent 140a8a52e5
commit 18bb5888e1
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
311 changed files with 1239 additions and 2622 deletions

View file

@ -438,16 +438,6 @@ static long Write(int fd, const void *data, unsigned long size, int os) {
return CallSystem(fd, (long)data, size, 0, 0, 0, 0, numba, os);
}
static int Execve(const char *prog, char **argv, char **envp, int os) {
int numba;
if (IsLinux() && IsAarch64()) {
numba = 221;
} else {
numba = 59;
}
return CallSystem((long)prog, (long)argv, (long)envp, 0, 0, 0, 0, numba, os);
}
static int Access(const char *path, int mode, int os) {
if (IsLinux() && IsAarch64()) {
return SystemCall(-100, (long)path, mode, 0, 0, 0, 0, 48);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -134,12 +134,6 @@ o/$(MODE)/libc/calls/mkntenvblock.o: private \
CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED
# we must segregate codegen because:
# file contains multiple independently linkable apis
COPTS += \
-ffunction-sections \
-fdata-sections
# we always want -Os because:
# va_arg codegen is very bloated in default mode
o//libc/calls/open.o \

View file

@ -17,14 +17,14 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/timespec.h"
#include "libc/cosmo.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
static struct {
pthread_once_t once;
_Atomic(uint32_t) once;
struct timespec base_wall;
uint64_t base_tick;
} g_mono;
@ -39,7 +39,7 @@ int sys_clock_gettime_mono(struct timespec *time) {
uint64_t cycles;
struct timespec res;
if (X86_HAVE(INVTSC)) {
pthread_once(&g_mono.once, sys_clock_gettime_mono_init);
cosmo_once(&g_mono.once, sys_clock_gettime_mono_init);
cycles = rdtsc() - g_mono.base_tick;
nanos = cycles / 3;
*time = timespec_add(g_mono.base_wall, timespec_fromnanos(nanos));

View file

@ -23,6 +23,7 @@
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/cosmo.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
@ -30,10 +31,9 @@
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
static struct CopyFileRange {
pthread_once_t once;
_Atomic(uint32_t) once;
bool ok;
} g_copy_file_range;
@ -104,7 +104,7 @@ ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
int64_t *opt_in_out_outoffset, size_t uptobytes,
uint32_t flags) {
ssize_t rc;
pthread_once(&g_copy_file_range.once, copy_file_range_init);
cosmo_once(&g_copy_file_range.once, copy_file_range_init);
BEGIN_CANCELLATION_POINT;
if (!g_copy_file_range.ok) {

View file

@ -30,6 +30,17 @@
* The `O_CLOEXEC` flag shall be cleared from the resulting file
* descriptor; see dup3() to preserve it.
*
* One use case for duplicating file descriptors is to be able to
* reassign an open()'d file or pipe() to the stdio of an executed
* subprocess. On Windows, in order for this to work, the subprocess
* needs to be a Cosmopolitan program that has socket() linked.
*
* Only small programs should duplicate sockets. That's because this
* implementation uses DuplicateHandle() on Windows, which Microsoft
* says might cause its resources to leak internally. Thus it likely
* isn't a good idea to design a server that does it a lot and lives
* a long time, without contributing a patch to this implementation.
*
* @param fd remains open afterwards
* @return some arbitrary new number for fd
* @raise EPERM if pledge() is in play without stdio

View file

@ -27,13 +27,24 @@
/**
* Duplicates file descriptor, granting it specific number.
*
* The `O_CLOEXEC` flag shall be cleared from the resulting file
* descriptor; see dup3() to preserve it.
*
* Unlike dup3(), the dup2() function permits oldfd and newfd to be the
* same, in which case the only thing this function does is test if
* oldfd is open.
*
* The `O_CLOEXEC` flag shall be cleared from the resulting file
* descriptor; see dup3() to preserve it.
*
* One use case for duplicating file descriptors is to be able to
* reassign an open()'d file or pipe() to the stdio of an executed
* subprocess. On Windows, in order for this to work, the subprocess
* needs to be a Cosmopolitan program that has socket() linked.
*
* Only small programs should duplicate sockets. That's because this
* implementation uses DuplicateHandle() on Windows, which Microsoft
* says might cause its resources to leak internally. Thus it likely
* isn't a good idea to design a server that does it a lot and lives
* a long time, without contributing a patch to this implementation.
*
* @param oldfd isn't closed afterwards
* @param newfd if already assigned, is silently closed beforehand;
* unless it's equal to oldfd, in which case dup2() is a no-op

View file

@ -19,18 +19,18 @@
#include "libc/assert.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/cosmo.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
#define F_DUP2FD 10
#define F_DUP2FD_CLOEXEC 18
static struct Dup3 {
pthread_once_t once;
_Atomic(uint32_t) once;
bool demodernize;
} g_dup3;
@ -58,7 +58,7 @@ int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
return __sys_fcntl(oldfd, how, newfd);
}
pthread_once(&g_dup3.once, sys_dup3_test);
cosmo_once(&g_dup3.once, sys_dup3_test);
if (!g_dup3.demodernize) {
return __sys_dup3(oldfd, newfd, flags);

View file

@ -28,9 +28,19 @@
/**
* Duplicates file descriptor/handle.
*
* On Windows, we can't guarantee the desired file descriptor is used.
* We can however remap the standard handles (non-atomically) if their
* symbolic names are used.
* The `O_CLOEXEC` flag shall be cleared from the resulting file
* descriptor; see dup3() to preserve it.
*
* One use case for duplicating file descriptors is to be able to
* reassign an open()'d file or pipe() to the stdio of an executed
* subprocess. On Windows, in order for this to work, the subprocess
* needs to be a Cosmopolitan program that has socket() linked.
*
* Only small programs should duplicate sockets. That's because this
* implementation uses DuplicateHandle() on Windows, which Microsoft
* says might cause its resources to leak internally. Thus it likely
* isn't a good idea to design a server that does it a lot and lives
* a long time, without contributing a patch to this implementation.
*
* @param oldfd isn't closed afterwards
* @param newfd if already assigned, is silently closed beforehand;

View file

@ -42,11 +42,6 @@ int execlp(const char *prog, const char *arg, ... /*, NULL*/) {
va_list va, vb;
char pathbuf[PATH_MAX];
// resolve path of executable
if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) {
return -1;
}
// turn varargs into array
va_copy(vb, va);
va_start(va, arg);
@ -60,6 +55,15 @@ int execlp(const char *prog, const char *arg, ... /*, NULL*/) {
}
va_end(vb);
if (strchr(prog, '/')) {
return execv(prog, argv);
}
// resolve path of executable
if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) {
return -1;
}
// change argv[0] to resolved path if it's ambiguous
// otherwise the program won't have much luck finding itself
if (argv[0] && *prog != '/' && *exe == '/' && !strcmp(prog, argv[0])) {

View file

@ -21,7 +21,9 @@
#include "libc/calls/internal.h"
#include "libc/calls/ntspawn.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/mem/alloca.h"
#include "libc/nt/accounting.h"
#include "libc/nt/console.h"
@ -35,6 +37,7 @@
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/map.h"
@ -84,22 +87,36 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
//////////////////////////////////////////////////////////////////////////////
// execve operation is unrecoverable from this point
// close cloexec handles
for (i = 3; i < g_fds.n; ++i) {
if (g_fds.p[i].kind != kFdEmpty && (g_fds.p[i].flags & O_CLOEXEC)) {
// close non-stdio and cloexec handles
for (i = 0; i < g_fds.n; ++i) {
if (g_fds.p[i].kind == kFdEmpty) {
g_fds.p[i].handle = -1;
} else if (i > 2 || (g_fds.p[i].flags & O_CLOEXEC)) {
__imp_CloseHandle(g_fds.p[i].handle);
g_fds.p[i].handle = -1;
}
}
int bits;
char buf[32], *v = 0;
if (_weaken(socket)) {
for (bits = i = 0; i < 3; ++i) {
if (g_fds.p[i].kind == kFdSocket) {
bits |= 1 << i;
}
}
FormatInt32(stpcpy(buf, "__STDIO_SOCKETS="), bits);
v = buf;
}
bzero(&startinfo, sizeof(startinfo));
startinfo.cb = sizeof(struct NtStartupInfo);
startinfo.dwFlags = kNtStartfUsestdhandles;
startinfo.hStdInput = __getfdhandleactual(0);
startinfo.hStdOutput = __getfdhandleactual(1);
startinfo.hStdError = __getfdhandleactual(2);
startinfo.hStdInput = g_fds.p[0].handle;
startinfo.hStdOutput = g_fds.p[1].handle;
startinfo.hStdError = g_fds.p[2].handle;
// spawn the process
rc = ntspawn(program, argv, envp, 0, 0, 0, true, 0, 0, &startinfo, &procinfo);
rc = ntspawn(program, argv, envp, v, 0, 0, true, 0, 0, &startinfo, &procinfo);
if (rc == -1) {
STRACE("panic: unrecoverable ntspawn(%#s) error: %m", program);
__imp_ExitProcess(6543);

View file

@ -40,6 +40,11 @@
* to be valid UTF-8 in order to round-trip the WIN32 API, without being
* corrupted.
*
* On Windows, only file descriptors 0, 1 and 2 can be passed to a child
* process in such a way that allows them to be automatically discovered
* when the child process initializes. Cosmpolitan currently treats your
* other file descriptors as implicitly O_CLOEXEC.
*
* @param program will not be PATH searched, see commandv()
* @param argv[0] is the name of the program to run
* @param argv[1,n-2] optionally specify program arguments

View file

@ -27,7 +27,9 @@
/**
* Executes program, with path environment search.
*
* The current process is replaced with the executed one.
* This function is a wrapper of the execve() system call that does path
* resolution. The `PATH` environment variable is taken from your global
* `environ` rather than the `envp` argument.
*
* @param prog is the program to launch
* @param argv is [file,argv..argvₙ,NULL]
@ -47,6 +49,10 @@ int execvpe(const char *prog, char *const argv[], char *const *envp) {
return efault();
}
if (strchr(prog, '/')) {
return execve(prog, argv, envp);
}
// resolve path of executable
if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) {
return -1;

View file

@ -321,8 +321,9 @@ static textwindows int sys_fcntl_nt_setfl(int fd, unsigned *flags, unsigned arg,
//
// - O_NONBLOCK make read() raise EAGAIN
// - O_NDELAY same thing as O_NONBLOCK
// - O_ACCMODE but has a minimal effect
//
allowed = O_NONBLOCK;
allowed = O_ACCMODE | O_NONBLOCK;
if (changed & ~allowed) {
// the following access mode flags are supported, but it's currently
// not possible to change them on windows.

View file

@ -102,7 +102,7 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
st->st_ctim = FileTimeToTimeSpec(wst.ftCreationFileTime);
st->st_birthtim = st->st_ctim;
st->st_size = (uint64_t)wst.nFileSizeHigh << 32 | wst.nFileSizeLow;
st->st_blksize = PAGESIZE;
st->st_blksize = 4096;
st->st_dev = wst.dwVolumeSerialNumber;
st->st_rdev = 0;
st->st_ino = (uint64_t)wst.nFileIndexHigh << 32 | wst.nFileIndexLow;
@ -118,7 +118,7 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
&fci, sizeof(fci))) {
actualsize = fci.CompressedFileSize;
}
st->st_blocks = ROUNDUP(actualsize, PAGESIZE) / 512;
st->st_blocks = ROUNDUP(actualsize, 4096) / 512;
}
} else {
STRACE("%s failed %m", "GetFileInformationByHandle");

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/metalfile.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/cosmo.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/macros.internal.h"
@ -34,7 +35,10 @@
#define KERN_PROC_PATHNAME_FREEBSD 12
#define KERN_PROC_PATHNAME_NETBSD 5
char program_executable_name[PATH_MAX];
static struct ProgramExecutableName {
_Atomic(uint32_t) once;
char buf[PATH_MAX];
} program_executable_name;
static inline int IsAlpha(int c) {
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
@ -50,7 +54,9 @@ static inline char *StrCat(char buf[PATH_MAX], const char *a, const char *b) {
}
static inline void GetProgramExecutableNameImpl(char *p, char *e) {
int c;
char *q;
char **ep;
ssize_t rc;
size_t i, n;
union {
@ -84,9 +90,9 @@ static inline void GetProgramExecutableNameImpl(char *p, char *e) {
// if argv[0] exists then turn it into an absolute path. we also try
// adding a .com suffix since the ape auto-appends it when resolving
if (__argc && (((q = __argv[0]) && !sys_faccessat(AT_FDCWD, q, F_OK, 0)) ||
((q = StrCat(u.path, __argv[0], ".com")) &&
!sys_faccessat(AT_FDCWD, q, F_OK, 0)))) {
if (((q = __argv[0]) && !sys_faccessat(AT_FDCWD, q, F_OK, 0)) ||
((q = StrCat(u.path, __argv[0], ".com")) &&
!sys_faccessat(AT_FDCWD, q, F_OK, 0))) {
if (*q != '/') {
if (q[0] == '.' && q[1] == '/') {
q += 2;
@ -103,6 +109,19 @@ static inline void GetProgramExecutableNameImpl(char *p, char *e) {
return;
}
// if getenv("_") exists then use that
for (ep = __envp; (q = *ep); ++ep) {
if (*q++ == '_' && *q++ == '=') {
while ((c = *q++)) {
if (p + 1 < e) {
*p++ = c;
}
}
*p = 0;
return;
}
}
// if argv[0] doesn't exist, then fallback to interpreter name
if ((rc = sys_readlinkat(AT_FDCWD, "/proc/self/exe", p, e - p - 1)) > 0 ||
(rc = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", p, e - p - 1)) > 0) {
@ -125,28 +144,29 @@ static inline void GetProgramExecutableNameImpl(char *p, char *e) {
}
// otherwise give up and just copy argv[0] into it
if (!*p && __argv[0] && strlen(__argv[0]) < e - p) {
strcpy(p, __argv[0]);
if (!*p && (q = __argv[0])) {
while ((c = *q++)) {
if (p + 1 < e) {
*p++ = c;
}
}
*p = 0;
}
}
static void InitProgramExecutableName(void) {
int e;
e = errno;
GetProgramExecutableNameImpl(
program_executable_name.buf,
program_executable_name.buf + sizeof(program_executable_name.buf));
errno = e;
}
/**
* Returns absolute path of program.
*/
char *GetProgramExecutableName(void) {
int e;
static bool once;
if (!once) {
e = errno;
GetProgramExecutableNameImpl(
program_executable_name,
program_executable_name + sizeof(program_executable_name));
errno = e;
once = true;
}
return program_executable_name;
cosmo_once(&program_executable_name.once, InitProgramExecutableName);
return program_executable_name.buf;
}
/* const void *const GetProgramExecutableNameCtor[] initarray = { */
/* GetProgramExecutableName, */
/* }; */

View file

@ -48,7 +48,7 @@ __attribute__((__constructor__)) static void kTmpPathInit(void) {
char16_t path16[PATH_MAX];
if ((s = getenv("TMPDIR")) && (n = strlen(s)) < PATH_MAX / 2) {
memcpy(kTmpPath, s, n);
if (n) memcpy(kTmpPath, s, n);
if (n && kTmpPath[n - 1] != '/') {
kTmpPath[n + 0] = '/';
kTmpPath[n + 1] = 0;

View file

@ -17,6 +17,8 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/bits.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/temp.h"
@ -25,30 +27,54 @@
#include "libc/sysv/errfuns.h"
/**
* Creates temporary file name and descriptor, e.g.
* Creates temporary file name and file descriptor.
*
* The best way to construct your path template is:
*
* char path[PATH_MAX+1];
* strlcat(path, kTmpDir, sizeof(path));
* strlcat(path, "sauce.XXXXXX", sizeof(path));
*
* This usage pattern makes mkstemp() equivalent to tmpfd():
*
* int fd;
* fd = mkstemp(path);
* unlink(path);
*
* This usage pattern makes mkstemp() equivalent to mktemp():
*
* close(mkstemp(path));
* puts(path);
*
* @param template is mutated to replace last six X's with rng
* @return open file descriptor r + w exclusive or -1 w/ errno
* @raise EINVAL if `template` didn't end with `XXXXXX`
* @see tmpfd() if you don't need a path
*/
int mkstemp(char *template) {
int i, n;
uint64_t w;
int i, n, e, fd;
if ((n = strlen(template)) < 6 ||
READ16LE(template + n - 2) != READ16LE("XX") ||
READ32LE(template + n - 6) != READ32LE("XXXX")) {
return einval();
}
w = _rand64();
for (i = 0; i < 6; ++i) {
template[n - 6 + i] = "0123456789abcdefghijklmnopqrstuvwxyz"[w % 36];
w /= 36;
for (;;) {
w = _rand64();
for (i = 0; i < 6; ++i) {
template[n - 6 + i] = "0123456789abcdefghijklmnopqrstuvwxyz"[w % 36];
w /= 36;
}
e = errno;
if ((fd = open(template,
O_RDWR | O_CREAT | O_EXCL | (IsWindows() ? 0x00410000 : 0),
0600)) != -1) {
return fd;
} else if (errno == EEXIST) {
errno = e;
} else {
template[0] = 0;
return fd;
}
}
return open(template, O_RDWR | O_CREAT | O_EXCL, 0600);
}

View file

@ -16,11 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/errno.h"
#include "libc/intrin/bits.h"
#include "libc/stdio/rand.h"
#include "libc/calls/calls.h"
#include "libc/stdio/temp.h"
#include "libc/str/str.h"
/**
* Generates temporary filename.
@ -34,18 +31,11 @@
* @see mkstemp()
*/
char *mktemp(char *template) {
int i, n;
uint64_t w;
if ((n = strlen(template)) < 6 ||
READ16LE(template + n - 2) != READ16LE("XX") ||
READ32LE(template + n - 6) != READ32LE("XXXX")) {
errno = EINVAL;
int fd;
if ((fd = mkstemp(template)) != -1) {
close(fd);
return template;
} else {
return 0;
}
w = _rand64();
for (i = 0; i < 6; ++i) {
template[n - 6 + i] = "0123456789abcdefghijklmnopqrstuvwxyz"[w % 36];
w /= 36;
}
return template;
}

View file

@ -132,6 +132,7 @@
* @raise ENOTSUP if `file` is on zip file system and process is vfork()'d
* @raise ENOSPC if file system is full when `file` would be `O_CREAT`ed
* @raise EINTR if we needed to block and a signal was delivered instead
* @raise EEXIST if `O_CREAT|O_EXCL` are used and `file` already existed
* @raise ECANCELED if thread was cancelled in masked mode
* @raise ENOENT if `file` doesn't exist when `O_CREAT` isn't in `flags`
* @raise ENOENT if `file` points to a string that's empty

View file

@ -86,7 +86,7 @@ ssize_t read(int fd, void *buf, size_t size) {
rc = ebadf();
}
END_CANCELLATION_POINT;
DATATRACE("read(%d, [%#.*hhs%s], %'zu) → %'zd% m", fd, MAX(0, MIN(40, rc)),
buf, rc > 40 ? "..." : "", size, rc);
DATATRACE("read(%d, [%#.*hhs%s], %'zu) → %'zd% m", fd,
(int)MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, rc);
return rc;
}

View file

@ -50,7 +50,7 @@ ssize_t sys_readv_metal(struct Fd *fd, const struct iovec *iov, int iovlen) {
file = (struct MetalFile *)fd->handle;
for (toto = i = 0; i < iovlen && file->pos < file->size; ++i) {
got = MIN(iov[i].iov_len, file->size - file->pos);
memcpy(iov[i].iov_base, file->base, got);
if (got) memcpy(iov[i].iov_base, file->base, got);
toto += got;
}
return toto;

View file

@ -145,7 +145,7 @@ restart:
l++;
}
if (q+l >= PATH_MAX) goto toolong;
memcpy(output+q, stack+p, l);
if (l) memcpy(output+q, stack+p, l);
output[q+l] = 0;
p += l;
@ -223,7 +223,7 @@ skip_readlink:
if (q-p && !IsSlash(stack[l-1])) stack[l++] = '/';
if (l + (q-p) + 1 >= PATH_MAX) goto toolong;
memmove(output + l, output + p, q - p + 1);
memcpy(output, stack, l);
if (l) memcpy(output, stack, l);
q = l + q-p;
}

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/cosmo.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
@ -28,10 +29,9 @@
#include "libc/mem/alloca.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
static struct Splice {
pthread_once_t once;
_Atomic(uint32_t) once;
bool ok;
} g_splice;
@ -79,7 +79,7 @@ ssize_t splice(int infd, int64_t *opt_in_out_inoffset, int outfd,
int64_t *opt_in_out_outoffset, size_t uptobytes,
uint32_t flags) {
ssize_t rc;
pthread_once(&g_splice.once, splice_init);
cosmo_once(&g_splice.once, splice_init);
if (!g_splice.ok) {
rc = enosys();
} else if (IsAsan() && ((opt_in_out_inoffset &&

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/cosmo.h"
#include "libc/errno.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/fileflagandattributes.h"
@ -31,12 +32,13 @@
#include "libc/nt/struct/tokenprivileges.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
__msabi extern typeof(GetFileAttributes) *const __imp_GetFileAttributesW;
static _Bool g_winlink_allowed;
static pthread_once_t g_winlink_once;
static struct {
_Atomic(uint32_t) once;
_Bool allowed;
} g_winlink;
static textwindows void InitializeWinlink(void) {
int64_t tok;
@ -48,7 +50,7 @@ static textwindows void InitializeWinlink(void) {
tp.Privileges[0].Luid = id;
tp.Privileges[0].Attributes = kNtSePrivilegeEnabled;
if (!AdjustTokenPrivileges(tok, 0, &tp, sizeof(tp), 0, 0)) return;
g_winlink_allowed = GetLastError() != kNtErrorNotAllAssigned;
g_winlink.allowed = GetLastError() != kNtErrorNotAllAssigned;
}
textwindows int sys_symlinkat_nt(const char *target, int newdirfd,
@ -82,8 +84,8 @@ textwindows int sys_symlinkat_nt(const char *target, int newdirfd,
// windows only lets administrators do this
// even then we're required to ask for permission
pthread_once(&g_winlink_once, InitializeWinlink);
if (!g_winlink_allowed) {
cosmo_once(&g_winlink.once, InitializeWinlink);
if (!g_winlink.allowed) {
return eperm();
}

View file

@ -29,7 +29,7 @@
* @note Linux documentation says this call is "dangerous"; for highest
* assurance of data recovery after crash, consider fsync() on both
* file and directory
* @see fsync(), fdatasync(), PAGESIZE
* @see fsync(), fdatasync()
*/
int sync_file_range(int fd, int64_t offset, int64_t bytes, unsigned flags) {
int rc, olderr;

View file

@ -16,11 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/temp.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
@ -64,6 +64,7 @@
* @return file descriptor on success, or -1 w/ errno
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if signal was delivered
* @see mkstemp() if you need a path
* @see tmpfile() for stdio version
* @cancellationpoint
* @asyncsignalsafe
@ -71,45 +72,23 @@
* @vforksafe
*/
int tmpfd(void) {
FILE *f;
unsigned x;
int fd, i, j, e;
char path[PATH_MAX], *p;
e = errno;
if (IsLinux() && (fd = open(kTmpPath, O_RDWR | _O_TMPFILE, 0600)) != -1) {
return fd;
}
errno = e;
p = path;
p = stpcpy(p, kTmpPath);
p = stpcpy(p, "tmp.");
if (program_invocation_short_name &&
strlen(program_invocation_short_name) < 128) {
p = stpcpy(p, program_invocation_short_name);
*p++ = '.';
}
for (i = 0; i < 10; ++i) {
x = _rand64();
for (j = 0; j < 6; ++j) {
p[j] = "0123456789abcdefghijklmnopqrstuvwxyz"[x % 36];
x /= 36;
}
p[j] = 0;
int e, fd;
const char *prog;
char path[PATH_MAX + 1];
if (IsLinux()) {
e = errno;
if ((fd = open(path,
O_RDWR | O_CREAT | O_EXCL | (IsWindows() ? _O_TMPFILE : 0),
0600)) != -1) {
if (!IsWindows()) {
if (unlink(path)) {
notpossible;
}
}
if ((fd = open(kTmpPath, O_RDWR | _O_TMPFILE, 0600)) != -1) {
return fd;
} else if (errno == EEXIST) {
errno = e;
} else {
break;
errno = e;
}
}
return -1;
path[0] = 0;
strlcat(path, kTmpPath, sizeof(path));
if (!(prog = program_invocation_short_name)) prog = "tmp";
strlcat(path, prog, sizeof(path));
strlcat(path, ".XXXXXX", sizeof(path));
if ((fd = mkstemp(path)) == -1) return -1;
if (!IsWindows()) unassert(!unlink(path));
return fd;
}

View file

@ -17,15 +17,26 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/sysparam.h"
#include "libc/errno.h"
#include "libc/log/log.h"
static char ttyname_buf[PATH_MAX];
#include "libc/paths.h"
/**
* Returns name of terminal.
*
* This function isn't required to be thread safe, consider ttyname_r().
*
* @return terminal path on success, or null w/ errno
* @see ttyname_r()
*/
char *ttyname(int fd) {
int rc = ttyname_r(fd, ttyname_buf, sizeof(ttyname_buf));
if (rc != 0) return NULL;
return &ttyname_buf[0];
errno_t err;
static char buf[sizeof(_PATH_DEV) + MAXNAMLEN];
if (!(err = ttyname_r(fd, buf, sizeof(buf)))) {
return buf;
} else {
errno = err;
return 0;
}
}

View file

@ -25,6 +25,7 @@
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/log/log.h"
#include "libc/nt/console.h"
@ -34,66 +35,79 @@
#define FIODGNAME 0x80106678 // freebsd
static textwindows dontinline int sys_ttyname_nt(int fd, char *buf,
size_t size) {
static textwindows errno_t sys_ttyname_nt(int fd, char *buf, size_t size) {
uint32_t mode;
const char *s;
if (GetConsoleMode(g_fds.p[fd].handle, &mode)) {
if (mode & kNtEnableVirtualTerminalInput) {
strncpy(buf, "CONIN$", size);
if (strlcpy(buf,
(mode & kNtEnableVirtualTerminalInput) ? "CONIN$" : "CONOUT$",
size) < size) {
return 0;
} else {
strncpy(buf, "CONOUT$", size);
return 0;
return ERANGE;
}
} else {
return enotty();
return ENOTTY;
}
}
static int ttyname_freebsd(int fd, char *buf, size_t size) {
// clobbers errno
static errno_t ttyname_freebsd(int fd, char *buf, size_t size) {
struct fiodgname_arg {
int len;
void *buf;
} fg;
fg.buf = buf;
fg.len = size;
if (sys_ioctl(fd, FIODGNAME, &fg) != -1) return 0;
return enotty();
if (sys_ioctl(fd, FIODGNAME, &fg) != -1) {
return 0;
} else {
return ENOTTY;
}
}
static int ttyname_linux(int fd, char *buf, size_t size) {
struct stat st1, st2;
if (!isatty(fd)) return errno;
char name[PATH_MAX];
FormatInt32(stpcpy(name, "/proc/self/fd/"), fd);
// clobbers errno
static errno_t ttyname_linux(int fd, char *buf, size_t size) {
ssize_t got;
struct stat st1, st2;
char name[14 + 12 + 1];
if (!isatty(fd)) return errno;
FormatInt32(stpcpy(name, "/proc/self/fd/"), fd);
got = readlink(name, buf, size);
if (got == -1) return errno;
if ((size_t)got >= size) return erange();
if (got >= size) return ERANGE;
buf[got] = 0;
if (stat(buf, &st1) || fstat(fd, &st2)) return errno;
if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) return enodev();
if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) return ENODEV;
return 0;
}
/**
* Returns name of terminal, reentrantly.
* Returns name of terminal.
*
* @return 0 on success, or error number on error
* @raise ERANGE if `size` was too small
* @returnserrno
* @threadsafe
*/
int ttyname_r(int fd, char *buf, size_t size) {
int rc;
errno_t ttyname_r(int fd, char *buf, size_t size) {
errno_t e, res;
e = errno;
if (IsLinux()) {
rc = ttyname_linux(fd, buf, size);
res = ttyname_linux(fd, buf, size);
} else if (IsFreebsd()) {
rc = ttyname_freebsd(fd, buf, size);
res = ttyname_freebsd(fd, buf, size);
} else if (IsWindows()) {
if (__isfdkind(fd, kFdFile)) {
rc = sys_ttyname_nt(fd, buf, size);
if (__isfdopen(fd)) {
res = sys_ttyname_nt(fd, buf, size);
} else {
rc = ebadf();
res = EBADF;
}
} else {
rc = enosys();
res = ENOSYS;
}
STRACE("ttyname_r(%d, %s) → %d% m", fd, buf, rc);
return rc;
errno = e;
STRACE("ttyname_r(%d, %#.*hhs) → %s", fd, (int)size, buf,
!res ? "0" : _strerrno(res));
return res;
}

10
libc/cosmo.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef COSMOPOLITAN_LIBC_COSMO_H_
#define COSMOPOLITAN_LIBC_COSMO_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
errno_t cosmo_once(_Atomic(uint32_t) *, void (*)(void));
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_COSMO_H_ */

View file

@ -78,7 +78,7 @@
/* Programs should call GetStackSize() */
#define APE_STACKSIZE 262144 /* default 256kb stack */
#define FRAMESIZE 0x10000
#define PAGESIZE 0x1000 /* i386+ */
#define _PAGESIZE 0x1000 /* i386+ */
#else
#define APE_STACKSIZE 4194304 /* default 4mb stack */
#endif

View file

@ -421,7 +421,7 @@ static struct AsanFault __asan_fault(const signed char *s, signed char dflt) {
struct AsanFault r;
if (s[0] < 0) {
r.kind = s[0];
} else if (((uintptr_t)(s + 1) & (PAGESIZE - 1)) && s[1] < 0) {
} else if (((uintptr_t)(s + 1) & 4095) && s[1] < 0) {
r.kind = s[1];
} else {
r.kind = dflt;
@ -652,6 +652,8 @@ static wint_t __asan_symbolize_access_poison(signed char kind) {
return L'μ';
case kAsanGlobalOverrun:
return L'Ω';
case kAsanMmapSizeOverrun:
return L'Z';
default:
return L'?';
}
@ -963,14 +965,6 @@ __attribute__((__destructor__)) static void __asan_morgue_flush(void) {
}
}
static size_t __asan_user_size(size_t n) {
if (n) {
return n;
} else {
return 1;
}
}
static size_t __asan_heap_size(size_t n) {
if (n < 0x7fffffff0000) {
n = ROUNDUP(n, _Alignof(struct AsanExtra));
@ -1043,7 +1037,6 @@ static void *__asan_allocate(size_t a, size_t n, struct AsanTrace *bt,
char *p;
size_t c;
struct AsanExtra *e;
n = __asan_user_size(n);
if ((p = _weaken(dlmemalign)(a, __asan_heap_size(n)))) {
c = _weaken(dlmalloc_usable_size)(p);
e = (struct AsanExtra *)(p + c - sizeof(*e));
@ -1244,12 +1237,7 @@ void *__asan_calloc(size_t n, size_t m) {
void *__asan_realloc(void *p, size_t n) {
struct AsanTrace bt;
if (p) {
if (n) {
return __asan_realloc_impl(p, n, __asan_realloc_grow);
} else {
__asan_free(p);
return 0;
}
return __asan_realloc_impl(p, n, __asan_realloc_grow);
} else {
__asan_trace(&bt, RBP);
return __asan_allocate_heap(16, n, &bt);

View file

@ -1,28 +1,29 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_ASANCODES_H_
#define COSMOPOLITAN_LIBC_INTRIN_ASANCODES_H_
#define kAsanScale 3
#define kAsanMagic 0x7fff8000
#define kAsanNullPage -1 /* ∅ 0xff */
#define kAsanProtected -2 /* P 0xfe */
#define kAsanHeapFree -3 /* F 0xfd */
#define kAsanHeapRelocated -4 /* R 0xfc */
#define kAsanAllocaOverrun -5 /* 𝑂 0xfb */
#define kAsanHeapUnderrun -6 /* U 0xfa */
#define kAsanHeapOverrun -7 /* O 0xf9 */
#define kAsanStackUnscoped -8 /* s 0xf8 */
#define kAsanStackOverflow -9 /* ! 0xf7 */
#define kAsanGlobalOrder -10 /* I 0xf6 */
#define kAsanStackFree -11 /* r 0xf5 */
#define kAsanStackPartial -12 /* p 0xf4 */
#define kAsanStackOverrun -13 /* o 0xf3 */
#define kAsanStackMiddle -14 /* m 0xf2 */
#define kAsanStackUnderrun -15 /* u 0xf1 */
#define kAsanAllocaUnderrun -16 /* 𝑈 0xf0 */
#define kAsanUnmapped -17 /* M 0xef */
#define kAsanGlobalRedzone -18 /* G 0xee */
#define kAsanGlobalGone -19 /* 𝐺 0xed */
#define kAsanGlobalUnderrun -20 /* μ 0xec */
#define kAsanGlobalOverrun -21 /* Ω 0xeb */
#define kAsanScale 3
#define kAsanMagic 0x7fff8000
#define kAsanNullPage -1 /* ∅ 0xff */
#define kAsanProtected -2 /* P 0xfe */
#define kAsanHeapFree -3 /* F 0xfd */
#define kAsanHeapRelocated -4 /* R 0xfc */
#define kAsanAllocaOverrun -5 /* 𝑂 0xfb */
#define kAsanHeapUnderrun -6 /* U 0xfa */
#define kAsanHeapOverrun -7 /* O 0xf9 */
#define kAsanStackUnscoped -8 /* s 0xf8 */
#define kAsanStackOverflow -9 /* ! 0xf7 */
#define kAsanGlobalOrder -10 /* I 0xf6 */
#define kAsanStackFree -11 /* r 0xf5 */
#define kAsanStackPartial -12 /* p 0xf4 */
#define kAsanStackOverrun -13 /* o 0xf3 */
#define kAsanStackMiddle -14 /* m 0xf2 */
#define kAsanStackUnderrun -15 /* u 0xf1 */
#define kAsanAllocaUnderrun -16 /* 𝑈 0xf0 */
#define kAsanUnmapped -17 /* M 0xef */
#define kAsanGlobalRedzone -18 /* G 0xee */
#define kAsanGlobalGone -19 /* 𝐺 0xed */
#define kAsanGlobalUnderrun -20 /* μ 0xec */
#define kAsanGlobalOverrun -21 /* Ω 0xeb */
#define kAsanMmapSizeOverrun -22 /* Z 0xea */
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASANCODES_H_ */

View file

@ -8,9 +8,6 @@ int _bitreverse8(int) pureconst;
int _bitreverse16(int) pureconst;
uint32_t _bitreverse32(uint32_t) pureconst;
uint64_t _bitreverse64(uint64_t) pureconst;
unsigned long _roundup2pow(unsigned long) pureconst;
unsigned long _roundup2log(unsigned long) pureconst;
unsigned long _rounddown2pow(unsigned long) pureconst;
#define READ16LE(P) \
(__extension__({ \

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 2023 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,47 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/cosmo.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/thread/thread.h"
#define INIT 0
#define CALLING 1
#define FINISHED 2
/**
* Transfers memory to pipe.
* Ensures initialization function is called exactly once.
*
* @param flags can have SPLICE_F_{MOVE,NONBLOCK,MORE,GIFT}
* @return number of bytes actually transferred, or -1 w/ errno
* This is the same as `pthread_once` except that it always uses a tiny
* spinlock implementation and won't make any system calls. It's needed
* since this function is an upstream dependency of both pthread_once()
* and nsync_once(). Most code should favor calling those functions.
*
* @return 0 on success, or errno on error
*/
ssize_t vmsplice(int fd, const struct iovec *chunks, int64_t count,
uint32_t flags) {
int olderr;
ssize_t wrote;
olderr = errno;
if ((wrote = sys_vmsplice(fd, chunks, count, flags)) == -1) {
errno = olderr;
if (count) {
wrote = write(fd, chunks[0].iov_base, chunks[0].iov_len);
} else {
wrote = write(fd, NULL, 0);
}
errno_t cosmo_once(_Atomic(uint32_t) *once, void init(void)) {
uint32_t old;
switch ((old = atomic_load_explicit(once, memory_order_relaxed))) {
case INIT:
if (atomic_compare_exchange_strong_explicit(once, &old, CALLING,
memory_order_acquire,
memory_order_relaxed)) {
init();
atomic_store_explicit(once, FINISHED, memory_order_release);
return 0;
}
// fallthrough
case CALLING:
for (;;) {
if (atomic_load_explicit(once, memory_order_acquire) != CALLING) {
break;
}
}
return 0;
case FINISHED:
return 0;
default:
return EINVAL;
}
return wrote;
}

View file

@ -37,8 +37,6 @@ static const char *GetFrameName(int x) {
return "automap";
} else if (IsFixedFrame(x)) {
return "fixed";
} else if (IsArenaFrame(x)) {
return "arena";
} else if (IsStaticStackFrame(x)) {
return "stack";
} else if (IsGfdsFrame(x)) {

View file

@ -25,7 +25,7 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sol.h"
#define N (PAGESIZE / 2 / sizeof(struct DescribeFlags))
#define N (4096 / 2 / sizeof(struct DescribeFlags))
/**
* Describes clock_gettime() clock argument.

View file

@ -46,6 +46,7 @@ static const char *DescribeSigFlags(char buf[64], int x) {
{SA_RESETHAND, "RESETHAND"}, //
{SA_NOMASK, "NOMASK"}, //
{SA_ONESHOT, "ONESHOT"}, //
{0x04000000, "RESTORER"}, //
};
return DescribeFlags(buf, 64, kSigFlags, ARRAYLEN(kSigFlags), "SA_", x);
}

View file

@ -27,6 +27,7 @@ const char *(DescribeSocketProtocol)(char buf[12], int family) {
if (family == IPPROTO_UDP) return "IPPROTO_UDP";
if (family == IPPROTO_RAW) return "IPPROTO_RAW";
if (family == IPPROTO_IPV6) return "IPPROTO_IPv6";
if (family == IPPROTO_ICMPV6) return "IPPROTO_ICMPV6";
FormatInt32(buf, family);
return buf;
}

View file

@ -24,10 +24,14 @@
* Describes setsockopt() level arguments.
*/
const char *(DescribeSockLevel)(char buf[12], int x) {
if (x == SOL_SOCKET) return "SOL_SOCKET";
if (x == SOL_IP) return "SOL_IP";
if (x == SOL_ICMP) return "SOL_ICMP";
if (x == SOL_TCP) return "SOL_TCP";
if (x == SOL_UDP) return "SOL_UDP";
if (x == SOL_SOCKET) return "SOL_SOCKET";
if (x == SOL_IPV6) return "SOL_IPV6";
if (x == SOL_ICMPV6) return "SOL_ICMPV6";
if (x == SOL_RAW) return "SOL_RAW";
FormatInt32(buf, x);
return buf;
}

View file

@ -79,7 +79,7 @@ const char *(DescribeStat)(char buf[N], int rc, const struct stat *st) {
append(", .st_%s=%'lu", "rdev", st->st_rdev);
}
if (st->st_blksize != PAGESIZE) {
if (st->st_blksize != 4096) {
append(", .st_%s=%'lu", "blksize", st->st_blksize);
}

View file

@ -25,7 +25,7 @@
* @param delta is added to enabled state
* @return enabled state before `delta` was applied
*/
int ftrace_enabled(int delta) {
dontinstrument int ftrace_enabled(int delta) {
int res;
struct CosmoTib *tib;
if (__tls_enabled) {

View file

@ -18,13 +18,17 @@
*/
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/intrin/_getenv.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/extend.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/pushpop.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/macros.internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
@ -37,16 +41,26 @@ __static_yoink("_init_g_fds");
struct Fds g_fds;
static struct Fd g_fds_static[OPEN_MAX];
static textwindows dontinline void SetupWinStd(struct Fds *fds, int i, int x) {
static int Atoi(const char *str) {
int i;
for (i = 0; '0' <= *str && *str <= '9'; ++str) {
i *= 10;
i += *str - '0';
}
return i;
}
static textwindows dontinline void SetupWinStd(struct Fds *fds, int i, int x,
int sockset) {
int64_t h;
h = GetStdHandle(x);
if (!h || h == -1) return;
fds->p[i].kind = pushpop(kFdFile);
fds->p[i].kind = ((1 << i) & sockset) ? pushpop(kFdSocket) : pushpop(kFdFile);
fds->p[i].handle = h;
atomic_store_explicit(&fds->f, i + 1, memory_order_relaxed);
}
textstartup void __init_fds(void) {
textstartup void __init_fds(int argc, char **argv, char **envp) {
struct Fds *fds;
__fds_lock_obj._type = PTHREAD_MUTEX_RECURSIVE;
fds = __veil("r", &g_fds);
@ -77,9 +91,29 @@ textstartup void __init_fds(void) {
fds->p[1].handle = __veil("r", 0x3F8ull);
fds->p[2].handle = __veil("r", 0x3F8ull);
} else if (IsWindows()) {
SetupWinStd(fds, 0, kNtStdInputHandle);
SetupWinStd(fds, 1, kNtStdOutputHandle);
SetupWinStd(fds, 2, kNtStdErrorHandle);
int sockset = 0;
struct Env var;
var = _getenv(envp, "__STDIO_SOCKETS");
if (var.s) {
int i = var.i + 1;
do {
envp[i - 1] = envp[i];
} while (envp[i]);
sockset = Atoi(var.s);
}
if (sockset && !_weaken(socket)) {
#ifdef SYSDEBUG
kprintf("%s: parent process passed sockets as stdio, but this program"
" can't use them since it didn't link the socket() function\n",
argv[0]);
_Exit(1);
#else
sockset = 0; // let ReadFile() fail
#endif
}
SetupWinStd(fds, 0, kNtStdInputHandle, sockset);
SetupWinStd(fds, 1, kNtStdOutputHandle, sockset);
SetupWinStd(fds, 2, kNtStdErrorHandle, sockset);
}
fds->p[1].flags = O_WRONLY | O_APPEND;
fds->p[2].flags = O_WRONLY | O_APPEND;

View file

@ -21,6 +21,9 @@
.init.start 305,_init_g_fds
push %rdi
push %rsi
mov %r12d,%edi // argc
mov %r13,%rsi // argv
mov %r14,%rdx // environ
call __init_fds
pop %rsi
pop %rdi

View file

@ -35,7 +35,11 @@ unsigned long getauxval(unsigned long key) {
x = _getauxval(key);
if (key == AT_PAGESZ) {
if (!x.isfound) {
#ifdef __aarch64__
x.value = 16384;
#else
x.value = 4096;
#endif
}
x.isfound = true;
}

View file

@ -26,6 +26,7 @@
* Environment variables can store empty string on Unix but not Windows.
*
* @return pointer to value of `environ` entry, or null if not found
* @threadunsafe
*/
char *getenv(const char *s) {
char **p;

View file

@ -625,7 +625,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
++p;
}
for (i = j = 0; !pdot || j < prec; ++j) {
if (UNLIKELY(!((intptr_t)s & (PAGESIZE - 1)))) {
if (UNLIKELY(!((intptr_t)s & 4095))) {
if (!dang && kisdangerous(s)) break;
}
if (!type) {
@ -687,7 +687,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
s += sizeof(char16_t);
if (IsHighSurrogate(t)) {
if (!pdot || j + 1 < prec) {
if (UNLIKELY(!((intptr_t)s & (PAGESIZE - 1)))) {
if (UNLIKELY(!((intptr_t)s & 4095))) {
if (!dang && kisdangerous(s)) break;
}
u = *(const char16_t *)s;

View file

@ -1,38 +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/intrin/morton.h"
/**
* Interleaves bits.
* @see https://en.wikipedia.org/wiki/Z-order_curve
* @see unmorton()
*/
unsigned long morton(unsigned long y, unsigned long x) {
x = (x | x << 020) & 0x0000FFFF0000FFFF;
x = (x | x << 010) & 0x00FF00FF00FF00FF;
x = (x | x << 004) & 0x0F0F0F0F0F0F0F0F;
x = (x | x << 002) & 0x3333333333333333;
x = (x | x << 001) & 0x5555555555555555;
y = (y | y << 020) & 0x0000FFFF0000FFFF;
y = (y | y << 010) & 0x00FF00FF00FF00FF;
y = (y | y << 004) & 0x0F0F0F0F0F0F0F0F;
y = (y | y << 002) & 0x3333333333333333;
y = (y | y << 001) & 0x5555555555555555;
return x | y << 1;
}

View file

@ -1,16 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_BITS_MORTON_H_
#define COSMOPOLITAN_LIBC_BITS_MORTON_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#ifdef COSMO
#define morton __morton
#define unmorton __unmorton
unsigned long morton(unsigned long, unsigned long) libcesque;
axdx_t unmorton(unsigned long) libcesque;
#endif /* COSMO */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_MORTON_H_ */

View file

@ -27,7 +27,6 @@ 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)) ||
(!IsStaticStackFrame(mm->p[i].y) && IsStaticStackFrame(mm->p[i + 1].x)));
}

View file

@ -93,6 +93,7 @@ int PutEnvImpl(char *s, bool overwrite) {
* @return 0 on success, or non-zero w/ errno on error
* @raise ENOMEM if we require more vespene gas
* @see setenv(), getenv()
* @threadunsafe
*/
int putenv(char *s) {
int rc;

View file

@ -1,30 +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/intrin/bits.h"
#include "libc/intrin/bsr.h"
/**
* Returns 𝑥 rounded down to previous two power.
*
* @define (𝑥>02^log𝑥, x=00, 𝑇)
* @see _roundup2pow()
*/
unsigned long _rounddown2pow(unsigned long x) {
return x ? 1ul << _bsrl(x) : 0;
}

View file

@ -1,28 +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/intrin/bits.h"
#include "libc/intrin/bsr.h"
/**
* Returns 𝑥 rounded up to next two power and log'd.
* @see _roundup2pow()
*/
unsigned long _roundup2log(unsigned long x) {
return x > 1 ? (_bsrl(x - 1) + 1) : x ? 1 : 0;
}

View file

@ -1,30 +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/intrin/bits.h"
#include "libc/intrin/bsr.h"
/**
* Returns 𝑥 rounded up to next two power.
*
* @define (𝑥>02^logx, x=00, 𝑇)
* @see _rounddown2pow()
*/
unsigned long _roundup2pow(unsigned long x) {
return x > 1 ? 2ul << _bsrl(x - 1) : x ? 1 : 0;
}

View file

@ -30,6 +30,7 @@
* @raise EINVAL if `name` is empty or contains `'='`
* @raise ENOMEM if we require more vespene gas
* @see putenv(), getenv()
* @threadunsafe
*/
int setenv(const char *name, const char *value, int overwrite) {
int rc;

View file

@ -19,7 +19,9 @@ COSMOPOLITAN_C_START_
#define STRACE(FMT, ...) \
do { \
if (UNLIKELY(__strace > 0) && strace_enabled(0) > 0) { \
ftrace_enabled(-1); \
__stracef(STRACE_PROLOGUE FMT "\n", ##__VA_ARGS__); \
ftrace_enabled(+1); \
} \
} while (0)
#else

View file

@ -25,7 +25,7 @@
* @param delta is added to enabled state
* @return enabled state before `delta` was applied
*/
int strace_enabled(int delta) {
dontinstrument int strace_enabled(int delta) {
int res;
struct CosmoTib *tib;
if (__tls_enabled) {

View file

@ -85,7 +85,7 @@ forceinline du_int udiv128by64to64(du_int u1, du_int u0, du_int v, du_int *r) {
* @param b is divisor
* @param rem receives remainder if not NULL
*/
COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem) {
tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem) {
const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT;
utwords dividend, divisor, quotient, remainder;
si_int shift;
@ -135,3 +135,7 @@ COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem) {
if (rem) *rem = dividend.all;
return quotient.all;
}
tu_int __udivti3(tu_int a, tu_int b) {
return __udivmodti4(a, b, NULL);
}

View file

@ -1,14 +0,0 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to division,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "third_party/compiler_rt/int_lib.h"
COMPILER_RT_ABI tu_int __udivti3(tu_int a, tu_int b) {
return __udivmodti4(a, b, NULL);
}

View file

@ -1,41 +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/intrin/morton.h"
static unsigned long GetOddBits(unsigned long x) {
x = (x | x >> 000) & 0x5555555555555555;
x = (x | x >> 001) & 0x3333333333333333;
x = (x | x >> 002) & 0x0F0F0F0F0F0F0F0F;
x = (x | x >> 004) & 0x00FF00FF00FF00FF;
x = (x | x >> 010) & 0x0000FFFF0000FFFF;
x = (x | x >> 020) & 0x00000000FFFFFFFF;
return x;
}
/**
* Deinterleaves bits.
*
* @param 𝑖 is interleaved index
* @return deinterleaved coordinate {ax := 𝑦, dx := 𝑥}
* @see en.wikipedia.org/wiki/Z-order_curve
* @see morton()
*/
axdx_t unmorton(unsigned long i) {
return (axdx_t){GetOddBits(i >> 1), GetOddBits(i)};
}

View file

@ -1,33 +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/nexgen32e/x86info.h"
#include "tool/decode/lib/x86idnames.h"
const struct IdName kX86GradeNames[] = {
{X86_GRADE_UNKNOWN, "Unknown"}, //
{X86_GRADE_APPLIANCE, "Appliance"}, //
{X86_GRADE_MOBILE, "Mobile"}, //
{X86_GRADE_TABLET, "Tablet"}, //
{X86_GRADE_DESKTOP, "Desktop"}, //
{X86_GRADE_CLIENT, "Client"}, //
{X86_GRADE_DENSITY, "Density"}, //
{X86_GRADE_SERVER, "Server"}, //
{X86_GRADE_SCIENCE, "Science"}, //
{0}, //
};

View file

@ -19,6 +19,19 @@
#include "libc/nexgen32e/x86info.h"
#include "tool/decode/lib/x86idnames.h"
const struct IdName kX86GradeNames[] = {
{X86_GRADE_UNKNOWN, "Unknown"}, //
{X86_GRADE_APPLIANCE, "Appliance"}, //
{X86_GRADE_MOBILE, "Mobile"}, //
{X86_GRADE_TABLET, "Tablet"}, //
{X86_GRADE_DESKTOP, "Desktop"}, //
{X86_GRADE_CLIENT, "Client"}, //
{X86_GRADE_DENSITY, "Density"}, //
{X86_GRADE_SERVER, "Server"}, //
{X86_GRADE_SCIENCE, "Science"}, //
{0}, //
};
const struct IdName kX86MarchNames[] = {
{X86_MARCH_UNKNOWN, "Unknown"}, //
{X86_MARCH_CORE2, "Core 2"}, //

View file

@ -29,6 +29,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/cosmo.h"
#include "libc/dce.h"
#include "libc/elf/elf.h"
#include "libc/fmt/itoa.h"

View file

@ -1,356 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/mem/arena.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/intrin/bsf.h"
#include "libc/intrin/bsr.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/weaken.h"
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/hook.internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdckdint.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
#define BASE 0x50040000
#define SIZE 0x2ff80000
#define P(i) ((void *)(intptr_t)(i))
#define EXCHANGE(HOOK, SLOT) \
__arena_hook((intptr_t *)_weaken(HOOK), (intptr_t *)(&(SLOT)))
static struct Arena {
bool once;
size_t size;
size_t depth;
size_t offset[16];
void (*free)(void *);
void *(*malloc)(size_t);
void *(*calloc)(size_t, size_t);
void *(*memalign)(size_t, size_t);
void *(*realloc)(void *, size_t);
void *(*realloc_in_place)(void *, size_t);
size_t (*malloc_usable_size)(const void *);
size_t (*bulk_free)(void *[], size_t);
int (*malloc_trim)(size_t);
} __arena;
static wontreturn void __arena_die(void) {
if (_weaken(__die)) _weaken(__die)();
_exit(83);
}
forceinline void __arena_check(void) {
unassert(__arena.depth);
}
forceinline void __arena_check_pointer(void *p) {
unassert(BASE + __arena.offset[__arena.depth - 1] <= (uintptr_t)p &&
(uintptr_t)p < BASE + __arena.offset[__arena.depth]);
}
forceinline bool __arena_is_arena_pointer(void *p) {
return BASE <= (uintptr_t)p && (uintptr_t)p < BASE + SIZE;
}
forceinline size_t __arena_get_size(void *p) {
return *(const size_t *)((const char *)p - sizeof(size_t));
}
static void __arena_free(void *p) {
__arena_check();
if (p) {
__arena_check_pointer(p);
if (!(BASE <= (uintptr_t)p && (uintptr_t)p < BASE + SIZE)) {
__arena.free(p);
}
}
}
static size_t __arena_bulk_free(void *p[], size_t n) {
size_t i;
for (i = 0; i < n; ++i) {
__arena_free(p[i]);
p[i] = 0;
}
return 0;
}
static dontinline bool __arena_grow(size_t offset, size_t request) {
size_t greed;
greed = __arena.size + 1;
do {
greed += greed >> 1;
greed = ROUNDUP(greed, FRAMESIZE);
} while (greed < offset + request);
if (greed <= SIZE) {
if (mmap(P(BASE + __arena.size), greed - __arena.size,
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
-1, 0) != MAP_FAILED) {
__arena.size = greed;
return true;
}
} else {
enomem();
}
if (_weaken(__oom_hook)) {
_weaken(__oom_hook)(request);
}
return false;
}
static inline void *__arena_alloc(size_t a, size_t n) {
size_t o;
if (!n) n = 1;
o = ROUNDUP(__arena.offset[__arena.depth] + sizeof(size_t), a);
if (o + n >= n) {
if (n <= sizeof(size_t)) {
n = sizeof(size_t);
} else {
n = ROUNDUP(n, sizeof(size_t));
}
if (o + n <= SIZE) {
if (UNLIKELY(o + n > __arena.size)) {
if (!__arena_grow(o, n)) return 0;
}
__arena.offset[__arena.depth] = o + n;
*(size_t *)(BASE + o - sizeof(size_t)) = n;
return (void *)(BASE + o);
}
}
enomem();
return 0;
}
static void *__arena_malloc(size_t n) {
__arena_check();
return __arena_alloc(16, n);
}
static void *__arena_calloc(size_t n, size_t z) {
__arena_check();
if (ckd_mul(&n, n, z)) n = -1;
return __arena_alloc(16, n);
}
static void *__arena_memalign(size_t a, size_t n) {
__arena_check();
if (a <= sizeof(size_t)) {
return __arena_alloc(8, n);
} else {
return __arena_alloc(2ul << _bsrl(a - 1), n);
}
}
static size_t __arena_malloc_usable_size(const void *p) {
__arena_check();
__arena_check_pointer(p);
if (__arena_is_arena_pointer(p)) {
return __arena_get_size(p);
} else {
return __arena.malloc_usable_size(p);
}
}
static void *__arena_realloc(void *p, size_t n) {
char *q;
size_t m, o, z;
__arena_check();
if (p) {
__arena_check_pointer(p);
if (__arena_is_arena_pointer(p)) {
if (n) {
if ((m = __arena_get_size(p)) >= n) {
return p;
} else if (n <= SIZE) {
z = 2ul << _bsrl(n - 1);
if (__arena.offset[__arena.depth] - m == (o = (intptr_t)p - BASE)) {
if (UNLIKELY(o + z > __arena.size)) {
if (o + z <= SIZE) {
if (!__arena_grow(o, z)) {
return 0;
}
} else {
enomem();
return 0;
}
}
__arena.offset[__arena.depth] = o + z;
*(size_t *)((char *)p - sizeof(size_t)) = z;
return p;
} else if ((q = __arena_alloc(1ul << _bsfl((intptr_t)p), z))) {
memmove(q, p, m);
return q;
} else {
return 0;
}
} else {
enomem();
return 0;
}
} else {
return 0;
}
} else {
return __arena.realloc(p, n);
}
} else {
if (n <= 16) {
n = 16;
} else {
n = 2ul << _bsrl(n - 1);
}
return __arena_alloc(16, n);
}
}
static void *__arena_realloc_in_place(void *p, size_t n) {
char *q;
size_t m, z;
__arena_check();
if (p) {
__arena_check_pointer(p);
if (__arena_is_arena_pointer(p)) {
if (n) {
if ((m = __arena_get_size(p)) >= n) {
return p;
} else {
return 0;
}
} else {
return 0;
}
} else {
return __arena.realloc_in_place(p, n);
}
} else {
return 0;
}
}
static int __arena_malloc_trim(size_t n) {
return 0;
}
static void __arena_hook(intptr_t *h, intptr_t *f) {
intptr_t t;
if (h) {
t = *h;
*h = *f;
*f = t;
}
}
static void __arena_install(void) {
EXCHANGE(hook_free, __arena.free);
EXCHANGE(hook_malloc, __arena.malloc);
EXCHANGE(hook_calloc, __arena.calloc);
EXCHANGE(hook_realloc, __arena.realloc);
EXCHANGE(hook_memalign, __arena.memalign);
EXCHANGE(hook_bulk_free, __arena.bulk_free);
EXCHANGE(hook_malloc_trim, __arena.malloc_trim);
EXCHANGE(hook_realloc_in_place, __arena.realloc_in_place);
EXCHANGE(hook_malloc_usable_size, __arena.malloc_usable_size);
}
static void __arena_destroy(void) {
if (__arena.depth) __arena_install();
if (__arena.size) munmap(P(BASE), __arena.size);
bzero(&__arena, sizeof(__arena));
}
static void __arena_init(void) {
__arena.free = __arena_free;
__arena.malloc = __arena_malloc;
__arena.calloc = __arena_calloc;
__arena.realloc = __arena_realloc;
__arena.memalign = __arena_memalign;
__arena.bulk_free = __arena_bulk_free;
__arena.malloc_trim = __arena_malloc_trim;
__arena.realloc_in_place = __arena_realloc_in_place;
__arena.malloc_usable_size = __arena_malloc_usable_size;
atexit(__arena_destroy);
}
/**
* Pushes memory arena.
*
* This allocator gives a ~3x performance boost over dlmalloc, mostly
* because it isn't thread safe and it doesn't do defragmentation.
*
* Calling this function will push a new arena. It may be called
* multiple times from the main thread recursively. The first time it's
* called, it hooks all the regular memory allocation functions. Any
* allocations that were made previously outside the arena, will be
* passed on to the previous hooks. Then, the basic idea, is rather than
* bothering with free() you can just call __arena_pop() to bulk free.
*
* Arena allocations also have a slight size advantage, since 32-bit
* pointers are always used. The maximum amount of arena memory is
* 805,175,296 bytes.
*
* @see __arena_pop()
*/
void __arena_push(void) {
if (UNLIKELY(!__arena.once)) {
__arena_init();
__arena.once = true;
}
if (!__arena.depth) {
__arena_install();
} else {
unassert(__arena.depth < ARRAYLEN(__arena.offset) - 1);
}
__arena.offset[__arena.depth + 1] = __arena.offset[__arena.depth];
++__arena.depth;
}
/**
* Pops memory arena.
*
* This pops the most recently created arena, freeing all the memory
* that was allocated between the push and pop arena calls. If this is
* the last arena on the stack, then the old malloc hooks are restored.
*
* @see __arena_push()
*/
void __arena_pop(void) {
size_t a, b, greed;
__arena_check();
if (!--__arena.depth) __arena_install();
a = __arena.offset[__arena.depth];
b = __arena.offset[__arena.depth + 1];
greed = a;
greed += FRAMESIZE;
greed <<= 1;
if (__arena.size > greed) {
munmap(P(BASE + greed), __arena.size - greed);
__arena.size = greed;
b = MIN(b, greed);
a = MIN(b, a);
}
bzero(P(BASE + a), b - a);
}

View file

@ -1,11 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_MEM_ARENA_H_
#define COSMOPOLITAN_LIBC_MEM_ARENA_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void __arena_push(void);
void __arena_pop(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_MEM_ARENA_H_ */

View file

@ -27,9 +27,7 @@ void (*hook_free)(void *) = dlfree;
*
* Releases the chunk of memory pointed to by p, that had been
* previously allocated using malloc or a related routine such as
* realloc. It has no effect if p is null. If p was not malloced or
* already freed, free(p) will by default cause the current program to
* abort.
* realloc. It has no effect if p is null.
*
* @param p is allocation address, which may be NULL
* @see dlfree()

View file

@ -30,11 +30,14 @@ void *(*hook_malloc)(size_t) = dlmalloc;
* on ANSI C systems.
*
* If n is zero, malloc returns a minimum-sized chunk. (The minimum size
* is 32 bytes on 64bit systems.) Note that size_t is an unsigned type,
* so calls with arguments that would be negative if signed are
* interpreted as requests for huge amounts of space, which will often
* fail. The maximum supported value of n differs across systems, but is
* in all cases less than the maximum representable value of a size_t.
* is 32 bytes on 64bit systems.) It should be assumed that zero bytes
* are possible access, since that'll be enforced by `MODE=asan`.
*
* Note that size_t is an unsigned type, so calls with arguments that
* would be negative if signed are interpreted as requests for huge
* amounts of space, which will often fail. The maximum supported value
* of n differs across systems, but is in all cases less than the
* maximum representable value of a size_t.
*
* @param rdi is number of bytes needed, coerced to 1+
* @return new memory, or NULL w/ errno

View file

@ -16,8 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/errno.h"
#include "libc/mem/mem.h"
#include "libc/stdckdint.h"
/**
* Allocates granular aligned memory of granular size, i.e.
@ -31,5 +32,9 @@
* @threadsafe
*/
void *pvalloc(size_t n) {
return memalign(FRAMESIZE, ROUNDUP(n, FRAMESIZE));
if (ckd_add(&n, n, FRAMESIZE - 1)) {
errno = ENOMEM;
return 0;
}
return memalign(FRAMESIZE, n & -FRAMESIZE);
}

View file

@ -29,8 +29,12 @@ void *(*hook_realloc)(void *, size_t) = dlrealloc;
* does chunk p up to the minimum of (n, p's size) bytes, or null if no
* space is available.
*
* If p is NULL, realloc is equivalent to malloc.
* If p is not NULL and n is 0, realloc is equivalent to free.
* If p is NULL, then realloc() is equivalent to malloc().
*
* If p is not NULL and n is 0, then realloc() shrinks the allocation to
* zero bytes. The allocation isn't freed and still continues to be a
* uniquely allocated piece of memory. However it should be assumed that
* zero bytes can be accessed, since that's enforced by `MODE=asan`.
*
* The returned pointer may or may not be the same as p. The algorithm
* prefers extending p in most cases when possible, otherwise it employs
@ -54,8 +58,6 @@ void *(*hook_realloc)(void *, size_t) = dlrealloc;
* @param p is address of current allocation or NULL
* @param n is number of bytes needed
* @return rax is result, or NULL w/ errno w/o free(p)
* @note realloc(p=0, n=0) malloc(32)
* @note realloc(p0, n=0) free(p)
* @see dlrealloc()
* @threadsafe
*/

View file

@ -32,7 +32,7 @@ char *strndup(const char *s, size_t n) {
char *s2;
size_t len = strnlen(s, n);
if ((s2 = malloc(len + 1))) {
memcpy(s2, s, len);
if (len) memcpy(s2, s, len);
s2[len] = '\0';
return s2;
}

View file

@ -85,6 +85,11 @@ bool32 TransactNamedPipe(int64_t hNamedPipe, void *lpInBuffer,
uint32_t nOutBufferSize, uint32_t *lpBytesRead,
struct NtOverlapped *lpOverlapped);
bool32 GetNamedPipeInfo(int64_t hNamedPipe, uint32_t *opt_out_lpFlags,
uint32_t *opt_out_lpOutBufferSize,
uint32_t *opt_out_lpInBufferSize,
uint32_t *opt_out_lpMaxInstances);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NT_IPC_H_ */

View file

@ -0,0 +1,18 @@
#include "libc/nt/codegen.h"
.imp kernel32,__imp_GetNamedPipeInfo,GetNamedPipeInfo
.text.windows
.ftrace1
GetNamedPipeInfo:
.ftrace2
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
mov __imp_GetNamedPipeInfo(%rip),%rax
jmp __sysv2nt6
#elif defined(__aarch64__)
mov x0,#0
ret
#endif
.endfn GetNamedPipeInfo,globl
.previous

View file

@ -93,6 +93,7 @@ imp 'GetModuleFileName' GetModuleFileNameW kernel32 3
imp 'GetModuleHandle' GetModuleHandleA kernel32 1
imp 'GetModuleHandleEx' GetModuleHandleExW kernel32 3
imp 'GetModuleHandleW' GetModuleHandleW kernel32 1
imp 'GetNamedPipeInfo' GetNamedPipeInfo kernel32 5
imp 'GetNumberOfConsoleInputEvents' GetNumberOfConsoleInputEvents kernel32 2
imp 'GetNumberOfConsoleMouseButtons' GetNumberOfConsoleMouseButtons kernel32 1
imp 'GetOverlappedResult' GetOverlappedResult kernel32 4
@ -246,8 +247,8 @@ imp 'VirtualAlloc' VirtualAlloc kernel32 4
imp 'VirtualAllocEx' VirtualAllocEx kernel32 5
imp 'VirtualFree' VirtualFree kernel32 3
imp 'VirtualLock' VirtualLock kernel32 2
imp 'VirtualUnlock' VirtualUnlock kernel32 2
imp 'VirtualQuery' VirtualQuery kernel32 3
imp 'VirtualUnlock' VirtualUnlock kernel32 2
imp 'WaitForMultipleObjectsEx' WaitForMultipleObjectsEx kernel32 5
imp 'WaitForSingleObjectEx' WaitForSingleObjectEx kernel32 3
imp 'WideCharToMultiByte' WideCharToMultiByte kernel32 8

View file

@ -644,7 +644,7 @@ errno_t clone(void *func, void *stk, size_t stksz, int flags, void *arg,
if (!func) {
rc = EINVAL;
} else if (!IsTiny() &&
((flags & CLONE_VM) && (stksz < PAGESIZE || (stksz & 15)))) {
((flags & CLONE_VM) && (stksz < 4096 || (stksz & 15)))) {
rc = EINVAL;
} else if (IsAsan() &&
(((flags & CLONE_SETTLS) && !__asan_is_valid(tls, 64)) ||

View file

@ -148,7 +148,7 @@ textstartup void cosmo(long *sp, struct Syslib *m1) {
#endif
// initialize file system
__init_fds();
__init_fds(argc, argv, envp);
// set helpful globals
__argc = argc;

View file

@ -102,11 +102,11 @@ textstartup void __enable_tls(void) {
// Here's the layout we're currently using:
//
// .balign PAGESIZE
// .balign 4096
// _tdata_start:
// .tdata
// _tdata_size = . - _tdata_start
// .balign PAGESIZE
// .balign 4096
// _tbss_start:
// _tdata_start + _tbss_offset:
// .tbss

View file

@ -52,6 +52,7 @@
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/sock/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
@ -68,7 +69,9 @@ bool32 __onntconsoleevent_nt(uint32_t);
void kmalloc_unlock(void);
static textwindows wontreturn void AbortFork(const char *func) {
STRACE("fork() %s() failed %d", func, GetLastError());
#ifdef SYSDEBUG
kprintf("fork() %s() failed with win32 error %d\n", func, GetLastError());
#endif
ExitProcess(177);
}
@ -104,7 +107,15 @@ static dontinline textwindows bool ForkIo2(int64_t h, void *buf, size_t n,
}
static dontinline textwindows bool WriteAll(int64_t h, void *buf, size_t n) {
return ForkIo2(h, buf, n, WriteFile, "WriteFile", false);
bool ok;
ok = ForkIo2(h, buf, n, WriteFile, "WriteFile", false);
#ifdef SYSDEBUG
if (!ok) {
kprintf("failed to write %zu bytes to forked child: %d\n", n,
GetLastError());
}
#endif
return ok;
}
static textwindows dontinline void ReadOrDie(int64_t h, void *buf, size_t n) {
@ -320,8 +331,13 @@ textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
}
for (i = 0; i < _mmi.i && ok; ++i) {
if ((_mmi.p[i].flags & MAP_TYPE) != MAP_SHARED) {
ok = WriteAll(writer, (void *)((uint64_t)_mmi.p[i].x << 16),
_mmi.p[i].size);
uint32_t op;
char *p = (char *)((uint64_t)_mmi.p[i].x << 16);
// XXX: forking destroys thread guard pages currently
VirtualProtect(
p, _mmi.p[i].size,
__prot2nt(_mmi.p[i].prot | PROT_READ, _mmi.p[i].iscow), &op);
ok = WriteAll(writer, p, _mmi.p[i].size);
}
}
if (ok) ok = WriteAll(writer, __data_start, __data_end - __data_start);

View file

@ -51,7 +51,7 @@ int __inflate(void *, size_t, const void *, size_t);
void *_Mmap(void *, size_t, int, int, int, int64_t) dontasan;
int _Munmap(char *, size_t) dontasan;
void __on_arithmetic_overflow(void);
void __init_fds(void);
void __init_fds(int, char **, char **);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -141,10 +141,6 @@ forceinline pureconst bool IsShadowFrame(int x) {
return 0x7fff <= x && x < 0x10008000;
}
forceinline pureconst bool IsArenaFrame(int x) {
return 0x5004 <= x && x <= 0x7ffb;
}
forceinline pureconst bool IsStaticStackFrame(int x) {
intptr_t stack = GetStaticStackAddr(0);
return (int)(stack >> 16) <= x &&
@ -192,19 +188,6 @@ forceinline pureconst bool OverlapsImageSpace(const void *p, size_t n) {
}
}
forceinline pureconst bool OverlapsArenaSpace(const void *p, size_t n) {
intptr_t BegA, EndA, BegB, EndB;
if (n) {
BegA = (intptr_t)p;
EndA = BegA + (n - 1);
BegB = 0x50000000;
EndB = 0x7ffdffff;
return MAX(BegA, BegB) < MIN(EndA, EndB);
} else {
return 0;
}
}
forceinline pureconst bool OverlapsShadowSpace(const void *p, size_t n) {
intptr_t BegA, EndA, BegB, EndB;
if (n) {

View file

@ -245,9 +245,10 @@ dontasan inline void *_Mmap(void *addr, size_t size, int prot, int flags,
int fd, int64_t off) {
char *p = addr;
struct DirectMap dm;
size_t requested_size;
int a, b, i, f, m, n, x;
bool needguard, clashes;
unsigned long guardsize;
unsigned long page_size;
size_t virtualused, virtualneed;
if (VERY_UNLIKELY(!size)) {
@ -274,11 +275,12 @@ dontasan inline void *_Mmap(void *addr, size_t size, int prot, int flags,
flags = MAP_SHARED; // cf. MAP_SHARED_VALIDATE
}
requested_size = size;
page_size = getauxval(AT_PAGESZ);
if (flags & MAP_ANONYMOUS) {
fd = -1;
off = 0;
size = ROUNDUP(size, FRAMESIZE);
if (IsWindows()) prot |= PROT_WRITE; // kludge
if ((flags & MAP_TYPE) == MAP_FILE) {
STRACE("need MAP_PRIVATE or MAP_SHARED");
return VIP(einval());
@ -289,8 +291,8 @@ dontasan inline void *_Mmap(void *addr, size_t size, int prot, int flags,
} else if (VERY_UNLIKELY(off < 0)) {
STRACE("mmap negative offset");
return VIP(einval());
} else if (VERY_UNLIKELY(!ALIGNED(off))) {
STRACE("mmap off isn't 64kb aligned");
} else if (off & ((IsWindows() ? FRAMESIZE : page_size) - 1)) {
STRACE("mmap offset isn't properly aligned");
return VIP(einval());
} else if (VERY_UNLIKELY(INT64_MAX - size < off)) {
STRACE("mmap too large");
@ -326,8 +328,7 @@ dontasan inline void *_Mmap(void *addr, size_t size, int prot, int flags,
OnUnrecoverableMmapError("FIXED UNTRACK FAILED");
}
}
} else if (p && !clashes && !OverlapsArenaSpace(p, size) &&
!OverlapsShadowSpace(p, size)) {
} else if (p && !clashes && !OverlapsShadowSpace(p, size)) {
x = FRAME(p);
} else if (!Automap(n, a, &x)) {
STRACE("automap has no room for %d frames with %d alignment", n, a);
@ -335,7 +336,6 @@ dontasan inline void *_Mmap(void *addr, size_t size, int prot, int flags,
}
needguard = false;
guardsize = getauxval(AT_PAGESZ);
p = (char *)ADDR_32_TO_48(x);
if ((f & MAP_TYPE) == MAP_STACK) {
if (~f & MAP_ANONYMOUS) {
@ -374,11 +374,15 @@ dontasan inline void *_Mmap(void *addr, size_t size, int prot, int flags,
if ((dm = sys_mmap(p + size - SIGSTKSZ, SIGSTKSZ, prot,
f | MAP_GROWSDOWN_linux, fd, off))
.addr != MAP_FAILED) {
npassert(sys_mmap(p, guardsize, PROT_NONE,
npassert(sys_mmap(p, page_size, PROT_NONE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)
.addr == p);
dm.addr = p;
return FinishMemory(p, size, prot, flags, fd, off, f, x, n, dm);
p = FinishMemory(p, size, prot, flags, fd, off, f, x, n, dm);
if (IsAsan() && p != MAP_FAILED) {
__asan_poison(p, page_size, kAsanStackOverflow);
}
return p;
} else if (errno == ENOTSUP) {
// WSL doesn't support MAP_GROWSDOWN
needguard = true;
@ -399,14 +403,14 @@ dontasan inline void *_Mmap(void *addr, size_t size, int prot, int flags,
}
if (p != MAP_FAILED) {
if (IsAsan()) {
__asan_poison(p + requested_size, size - requested_size,
kAsanMmapSizeOverrun);
}
if (needguard) {
if (!IsWindows()) {
// make windows fork() code simpler
mprotect(p, guardsize, PROT_NONE);
}
unassert(!mprotect(p, page_size, PROT_NONE));
if (IsAsan()) {
__repstosb((void *)(((intptr_t)p >> 3) + 0x7fff8000),
kAsanStackOverflow, guardsize / 8);
__asan_poison(p, page_size, kAsanStackOverflow);
}
}
}
@ -415,7 +419,7 @@ dontasan inline void *_Mmap(void *addr, size_t size, int prot, int flags,
}
/**
* Beseeches system for page-table entries, e.g.
* Creates virtual memory, e.g.
*
* char *m;
* m = mmap(NULL, FRAMESIZE, PROT_READ | PROT_WRITE,
@ -430,9 +434,7 @@ dontasan inline void *_Mmap(void *addr, size_t size, int prot, int flags,
* needs to be made mandatory because of Windows although you can
* use __sys_mmap() to circumvent it on System Five in which case
* runtime support services, e.g. asan memory safety, could break
* @param size must be >0 and needn't be a multiple of FRAMESIZE, but
* will be rounded up to FRAMESIZE automatically if MAP_ANONYMOUS
* is specified
* @param size must be >0 otherwise EINVAL is raised
* @param prot can have PROT_READ/PROT_WRITE/PROT_EXEC/PROT_NONE/etc.
* @param flags should have one of the following masked by `MAP_TYPE`
* - `MAP_FILE` in which case `MAP_ANONYMOUS` shouldn't be used
@ -459,8 +461,8 @@ dontasan inline void *_Mmap(void *addr, size_t size, int prot, int flags,
* @param fd is an open()'d file descriptor, whose contents shall be
* made available w/ automatic reading at the chosen address
* @param off specifies absolute byte index of fd's file for mapping,
* should be zero if MAP_ANONYMOUS is specified, and sadly needs
* to be 64kb aligned too
* should be zero if MAP_ANONYMOUS is specified, which SHOULD be
* aligned to FRAMESIZE
* @return virtual base address of new mapping, or MAP_FAILED w/ errno
*/
void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {

View file

@ -27,6 +27,7 @@ textwindows int sys_mprotect_nt(void *addr, size_t size, int prot) {
uint32_t op;
char *a, *b, *x, *y, *p;
__mmi_lock();
size = (size + 4095) & -4096;
p = addr;
i = FindMemoryInterval(&_mmi, (intptr_t)p >> 16);
if (i == _mmi.i || (!i && p + size <= (char *)ADDR_32_TO_48(_mmi.p[0].x))) {
@ -41,9 +42,14 @@ textwindows int sys_mprotect_nt(void *addr, size_t size, int prot) {
// we unfortunately must do something similar to this for cow
for (; i < _mmi.i; ++i) {
x = (char *)ADDR_32_TO_48(_mmi.p[i].x);
y = x + _mmi.p[i].size;
y = (char *)ADDR_32_TO_48(_mmi.p[i].y) + 65536;
if ((x <= p && p < y) || (x < p + size && p + size <= y) ||
(p < x && y < p + size)) {
if (p <= x && p + size >= y) {
_mmi.p[i].prot = prot;
} else {
_mmi.p[i].prot |= prot;
}
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)) {

View file

@ -23,6 +23,8 @@
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
@ -41,7 +43,7 @@ int mprotect(void *addr, size_t size, int prot) {
rc = einval(); // unix checks prot before checking size
} else if (!size) {
return 0; // make new technology consistent with unix
} else if (UNLIKELY((intptr_t)addr & 4095)) {
} else if (UNLIKELY((intptr_t)addr & (getauxval(AT_PAGESZ) - 1))) {
rc = einval(); // unix checks prot before checking size
} else if (!IsWindows()) {
rc = sys_mprotect(addr, size, prot);

View file

@ -23,13 +23,14 @@
* Creates client socket file descriptor for incoming connection.
*
* @param fd is the server socket file descriptor
* @param out_addr will receive the remote address
* @param inout_addrsize provides and receives addr's byte length
* @param opt_out_addr will receive the remote address
* @param opt_inout_addrsize provides and receives addr's byte length
* @return client fd which needs close(), or -1 w/ errno
* @cancellationpoint
* @asyncsignalsafe
* @restartable (unless SO_RCVTIMEO)
*/
int accept(int fd, struct sockaddr *out_addr, uint32_t *inout_addrsize) {
return accept4(fd, out_addr, inout_addrsize, 0);
int accept(int fd, struct sockaddr *opt_out_addr,
uint32_t *opt_inout_addrsize) {
return accept4(fd, opt_out_addr, opt_inout_addrsize, 0);
}

View file

@ -32,8 +32,8 @@
* Creates client socket file descriptor for incoming connection.
*
* @param fd is the server socket file descriptor
* @param out_addr will receive the remote address
* @param inout_addrsize provides and receives out_addr's byte length
* @param opt_out_addr will receive the remote address
* @param opt_inout_addrsize provides and receives out_addr's byte length
* @param flags can have SOCK_{CLOEXEC,NONBLOCK}, which may apply to
* both the newly created socket and the server one
* @return client fd which needs close(), or -1 w/ errno
@ -41,7 +41,7 @@
* @asyncsignalsafe
* @restartable (unless SO_RCVTIMEO)
*/
int accept4(int fd, struct sockaddr *out_addr, uint32_t *inout_addrsize,
int accept4(int fd, struct sockaddr *opt_out_addr, uint32_t *opt_inout_addrsize,
int flags) {
int rc;
struct sockaddr_storage ss = {0};
@ -61,11 +61,13 @@ int accept4(int fd, struct sockaddr *out_addr, uint32_t *inout_addrsize,
if (IsBsd()) {
__convert_bsd_to_sockaddr(&ss);
}
__write_sockaddr(&ss, out_addr, inout_addrsize);
__write_sockaddr(&ss, opt_out_addr, opt_inout_addrsize);
}
END_CANCELLATION_POINT;
STRACE("accept4(%d, [%s]) -> %d% lm", fd,
DescribeSockaddr(out_addr, inout_addrsize ? *inout_addrsize : 0), rc);
DescribeSockaddr(opt_out_addr,
opt_inout_addrsize ? *opt_inout_addrsize : 0),
rc);
return rc;
}

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