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

@ -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;
}

View file

@ -17,15 +17,14 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/syscall_fd.internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/errfuns.h"
textwindows int sys_bind_nt(struct Fd *fd, const void *addr,
uint32_t addrsize) {
npassert(fd->kind == kFdSocket);
unassert(fd->kind == kFdSocket);
if (__sys_bind_nt(fd->handle, addr, addrsize) != -1) {
return 0;
} else {

View file

@ -32,7 +32,11 @@
*
* struct sockaddr_in in = {AF_INET, htons(12345), {htonl(0x7f000001)}};
* int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
* bind(fd, &in, sizeof(in));
* bind(fd, (struct sockaddr *)&in, sizeof(in));
*
* On Windows, Cosmopolitan's implementation of bind() takes care of
* always setting the WIN32-specific `SO_EXCLUSIVEADDRUSE` option on
* inet stream sockets in order to safeguard your servers from tests
*
* @param fd is the file descriptor returned by socket()
* @param addr is usually the binary-encoded ip:port on which to listen

View file

@ -65,7 +65,7 @@ const char *(DescribeSockaddr)(char buf[128], const struct sockaddr *sa,
unix = (const struct sockaddr_un *)sa;
n = strnlen(unix->sun_path, sizeof(unix->sun_path));
n = MIN(n, 128 - 1);
memcpy(buf, unix->sun_path, n);
if (n) memcpy(buf, unix->sun_path, n);
buf[n] = 0;
}
}

View file

@ -16,14 +16,19 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/mem/mem.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/iphlpapi.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/so.h"
@ -42,13 +47,22 @@ __static_yoink("_dupsockfd");
textwindows int sys_socket_nt(int family, int type, int protocol) {
int64_t h;
struct SockFd *sockfd;
int fd, oflags, truetype;
int fd, oflags, truetype, yes = 1;
fd = __reservefd(-1);
if (fd == -1) return -1;
truetype = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
if ((h = WSASocket(family, truetype, protocol, NULL, 0,
kNtWsaFlagOverlapped)) != -1) {
oflags = 0;
// sets SO_EXCLUSIVEADDRUSE on all sockets so they won't get pilfered
// you can read a blog post on this subject in the find_unused_port()
// pydoc of this file third_party/python/Lib/test/support/__init__.py
// this needs to happen right after socket is called or it won't work
if (family == AF_INET || family == AF_INET6) {
unassert(__sys_setsockopt_nt(h, SOL_SOCKET, -5, &yes, 4) != -1);
}
oflags = O_RDWR;
if (type & SOCK_CLOEXEC) oflags |= O_CLOEXEC;
if (type & SOCK_NONBLOCK) oflags |= O_NONBLOCK;
sockfd = calloc(1, sizeof(struct SockFd));
@ -62,6 +76,7 @@ textwindows int sys_socket_nt(int family, int type, int protocol) {
g_fds.p[fd].handle = h;
g_fds.p[fd].extra = (uintptr_t)sockfd;
__fds_unlock();
return fd;
} else {
__releasefd(fd);

View file

@ -22,26 +22,31 @@
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/errfuns.h"
/**
* Creates new system resource for network communication, e.g.
*
* int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
*
* @param family can be AF_UNIX, AF_INET, etc.
* @param family can be AF_UNIX, AF_INET, AF_INET6, etc.
* @param type can be SOCK_STREAM (for TCP), SOCK_DGRAM (e.g. UDP), or
* SOCK_RAW (IP) so long as IP_HDRINCL was passed to setsockopt();
* and additionally, may be or'd with SOCK_NONBLOCK, SOCK_CLOEXEC
* @param protocol can be IPPROTO_TCP, IPPROTO_UDP, or IPPROTO_ICMP
* @return socket file descriptor or -1 w/ errno
* @error ENETDOWN, EPFNOSUPPORT, etc.
* @raise EAFNOSUPPORT if `family` isn't supported by system or platform
* @see libc/sysv/consts.sh
* @asyncsignalsafe
*/
int socket(int family, int type, int protocol) {
int rc;
if (family == AF_UNSPEC) family = AF_INET;
if (!IsWindows()) {
if (family == AF_UNSPEC) {
family = AF_INET;
}
if (family == -1) {
rc = eafnosupport();
} else if (!IsWindows()) {
rc = sys_socket(family, type, protocol);
} else {
rc = sys_socket_nt(family, type, protocol);

View file

@ -285,7 +285,9 @@ DIR *opendir(const char *name) {
res->zip.offset = GetZipCdirOffset(zip->cdir);
res->zip.records = GetZipCdirRecords(zip->cdir);
res->zip.prefix = malloc(zipname.len + 2);
memcpy(res->zip.prefix, zipname.path, zipname.len);
if (zipname.len) {
memcpy(res->zip.prefix, zipname.path, zipname.len);
}
if (zipname.len && res->zip.prefix[zipname.len - 1] != '/') {
res->zip.prefix[zipname.len++] = '/';
}
@ -364,7 +366,9 @@ static struct dirent *readdir_impl(DIR *dir) {
ent->d_off = dir->zip.offset;
ent->d_reclen = MIN(n, 255);
ent->d_type = S_ISDIR(mode) ? DT_DIR : DT_REG;
memcpy(ent->d_name, s, ent->d_reclen);
if (ent->d_reclen) {
memcpy(ent->d_name, s, ent->d_reclen);
}
ent->d_name[ent->d_reclen] = 0;
} else {
lastent = (struct dirent *)dir->buf;
@ -377,7 +381,9 @@ static struct dirent *readdir_impl(DIR *dir) {
ent->d_off = -1;
ent->d_reclen = n;
ent->d_type = DT_DIR;
memcpy(ent->d_name, s, ent->d_reclen);
if (ent->d_reclen) {
memcpy(ent->d_name, s, ent->d_reclen);
}
ent->d_name[ent->d_reclen] = 0;
}
}
@ -474,7 +480,9 @@ errno_t readdir_r(DIR *dir, struct dirent *output, struct dirent **result) {
return err;
}
if (entry) {
memcpy(output, entry, entry->d_reclen);
if (entry->d_reclen) {
memcpy(output, entry, entry->d_reclen);
}
} else {
output = 0;
}

View file

@ -47,7 +47,7 @@ char *fgets_unlocked(char *s, int size, FILE *f) {
if ((t = memchr(b, '\n', n))) {
n = t + 1 - b;
}
memcpy(p, b, n);
if (n) memcpy(p, b, n);
f->beg += n;
size -= n - 1;
p += n;

View file

@ -18,6 +18,7 @@
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
@ -39,7 +40,8 @@ int mkostempsmi(char *tpl, int slen, unsigned flags, uint64_t *rando, int mode,
if (len < wildlen || slen > len - wildlen) return einval();
char *ss = tpl + len - wildlen - slen;
npassert(memcmp(ss, WILDCARD, wildlen) == 0);
flags = (flags & ~(flags & O_ACCMODE)) | O_RDWR | O_CREAT | O_EXCL;
flags = (flags & ~(flags & O_ACCMODE)) | O_RDWR | O_CREAT | O_EXCL |
(IsWindows() ? 0x00410000 : 0);
unsigned attempts = ATTEMPTS;
do {
char *p = ss;
@ -74,8 +76,7 @@ static uint64_t g_mkostemps_reseed;
* or -1 w/ errno
* @see kTmpPath
*/
dontdiscard int mkostempsm(char *template, int suffixlen, unsigned flags,
int mode) {
int mkostempsm(char *template, int suffixlen, unsigned flags, int mode) {
int fd;
if (g_mkostemps_reseed++ % RESEED == 0) g_mkostemps_rand = _rand64();
fd = mkostempsmi(template, suffixlen, flags, &g_mkostemps_rand, mode, open);

View file

@ -87,13 +87,13 @@ errno_t posix_spawn(int *pid, const char *path,
posix_spawnattr_getflags(attrp, &flags);
if (flags & POSIX_SPAWN_SETSID) {
if (setsid()) {
STRACE("posix_spawn fail #%d", 1);
STRACE("posix_spawn fail #%d% m", 1);
_Exit(127);
}
}
if (flags & POSIX_SPAWN_SETPGROUP) {
if (setpgid(0, (*attrp)->pgroup)) {
STRACE("posix_spawn fail #%d", 1);
STRACE("posix_spawn fail #%d% m", 2);
_Exit(127);
}
}
@ -103,14 +103,14 @@ errno_t posix_spawn(int *pid, const char *path,
}
if ((flags & POSIX_SPAWN_RESETIDS) &&
(setgid(getgid()) || setuid(getuid()))) {
STRACE("posix_spawn fail #%d", 2);
STRACE("posix_spawn fail #%d% m", 3);
_Exit(127);
}
if (flags & POSIX_SPAWN_SETSIGDEF) {
for (s = 1; s < 32; s++) {
if (sigismember(&(*attrp)->sigdefault, s)) {
if (sigaction(s, &dfl, 0) == -1) {
STRACE("posix_spawn fail #%d", 3);
STRACE("posix_spawn fail #%d% m", 4);
_Exit(127);
}
}
@ -119,7 +119,7 @@ errno_t posix_spawn(int *pid, const char *path,
}
if (file_actions) {
if (RunFileActions(*file_actions) == -1) {
STRACE("posix_spawn fail #%d", 4);
STRACE("posix_spawn fail #%d% m", 5);
_Exit(127);
}
}
@ -128,21 +128,21 @@ errno_t posix_spawn(int *pid, const char *path,
posix_spawnattr_getschedpolicy(attrp, &policy);
posix_spawnattr_getschedparam(attrp, &param);
if (sched_setscheduler(0, policy, &param) == -1) {
STRACE("posix_spawn fail #%d", 5);
STRACE("posix_spawn fail #%d% m", 6);
_Exit(127);
}
}
if (flags & POSIX_SPAWN_SETSCHEDPARAM) {
posix_spawnattr_getschedparam(attrp, &param);
if (sched_setparam(0, &param) == -1) {
STRACE("posix_spawn fail #%d", 6);
STRACE("posix_spawn fail #%d% m", 7);
_Exit(127);
}
}
}
if (!envp) envp = environ;
execve(path, argv, envp);
STRACE("posix_spawn fail #%d", 7);
STRACE("posix_spawn fail #%d% m", 8);
_Exit(127);
} else if (child != -1) {
if (pid) *pid = child;

View file

@ -46,34 +46,34 @@
int system(const char *cmdline) {
int pid, wstatus;
sigset_t chldmask, savemask;
struct sigaction ignore, saveint, savequit;
if (!cmdline) return 1;
BLOCK_CANCELLATIONS;
ignore.sa_flags = 0;
ignore.sa_handler = SIG_IGN;
sigemptyset(&ignore.sa_mask);
sigaction(SIGINT, &ignore, &saveint);
sigaction(SIGQUIT, &ignore, &savequit);
sigemptyset(&chldmask);
sigaddset(&chldmask, SIGINT);
sigaddset(&chldmask, SIGQUIT);
sigaddset(&chldmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
if (!(pid = fork())) {
sigaction(SIGINT, &saveint, 0);
sigaction(SIGQUIT, &savequit, 0);
sigprocmask(SIG_SETMASK, &savemask, 0);
_Exit(_cocmd(3, (char *[]){"system", "-c", cmdline, 0}, environ));
} else if (pid != -1) {
} else if (pid == -1) {
wstatus = -1;
} else {
struct sigaction ignore, saveint, savequit;
ignore.sa_flags = 0;
ignore.sa_handler = SIG_IGN;
sigemptyset(&ignore.sa_mask);
sigaction(SIGINT, &ignore, &saveint);
sigaction(SIGQUIT, &ignore, &savequit);
while (wait4(pid, &wstatus, 0, 0) == -1) {
if (errno != EINTR) {
wstatus = -1;
break;
}
}
} else {
wstatus = -1;
sigaction(SIGINT, &saveint, 0);
sigaction(SIGQUIT, &savequit, 0);
}
sigaction(SIGINT, &saveint, 0);
sigaction(SIGQUIT, &savequit, 0);
sigprocmask(SIG_SETMASK, &savemask, 0);
ALLOW_CANCELLATIONS;
return wstatus;

View file

@ -180,7 +180,6 @@ syscon compat SIGIOT 6 6 6 6 6 6 6 6 # PDP-11 feature; same
# open() flags
#
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD Windoze Commentary
syscon open O_RDWR 2 2 2 2 2 2 2 2 # consensus
syscon open O_APPEND 0x00000400 0x00000400 8 8 8 8 8 0x00000400 # bsd consensus & kNtFileAppendData; won't pose issues w/ mknod(S_IFIFO) [SYNC libc/calls/open-nt.c]
syscon open O_CREAT 0x00000040 0x00000040 0x00000200 0x00000200 0x00000200 0x00000200 0x00000200 0x00000040 # bsd consensus & NT faked as Linux [SYNC libc/calls/open-nt.c]
syscon open O_EXCL 0x00000080 0x00000080 0x00000800 0x00000800 0x00000800 0x00000800 0x00000800 0x00000080 # bsd consensus & NT faked as Linux [SYNC libc/calls/open-nt.c]
@ -606,45 +605,23 @@ syscon poll POLLWRBAND 0x0200 0x0200 0x0100 0x0100 0x0100 0x0100
syscon poll POLLWRNORM 0x0100 0x0100 4 4 4 4 4 0x0010 # bsd consensus
syscon poll POLLRDHUP 0x2000 0x2000 0x10 0x10 0x10 0x10 0x10 2 # bsd consensus (POLLHUP on non-Linux)
# epoll
#
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon epoll EPOLL_CLOEXEC 0x080000 0x080000 0x01000000 0x01000000 0x100000 0x010000 0x010000 0x80000 # O_CLOEXEC
syscon epoll EPOLL_CTL_ADD 1 1 1 1 1 1 1 1 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLL_CTL_DEL 2 2 2 2 2 2 2 2 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLL_CTL_MOD 3 3 3 3 3 3 3 3 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLIN 1 1 1 1 1 1 1 1 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLOUT 4 4 4 4 4 4 4 4 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLERR 8 8 8 8 8 8 8 8 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLPRI 2 2 2 2 2 2 2 2 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLHUP 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLRDNORM 0x40 0x40 0x40 0x40 0x40 0x40 0x40 0x40 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLRDBAND 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLWRNORM 0x0100 0x0100 0x0100 0x0100 0x0100 0x0100 0x0100 0x0100 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLWRBAND 0x0200 0x0200 0x0200 0x0200 0x0200 0x0200 0x0200 0x0200 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLMSG 0x0400 0x0400 0x0400 0x0400 0x0400 0x0400 0x0400 0x0400 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLRDHUP 0x2000 0x2000 0x2000 0x2000 0x2000 0x2000 0x2000 0x2000 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLEXCLUSIVE 0x10000000 0x10000000 0x10000000 0x10000000 0x10000000 0x10000000 0x10000000 0x10000000 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLWAKEUP 0x20000000 0x20000000 0x20000000 0x20000000 0x20000000 0x20000000 0x20000000 0x20000000 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLONESHOT 0x40000000 0x40000000 0x40000000 0x40000000 0x40000000 0x40000000 0x40000000 0x40000000 # forced consensus, linux only natively, polyfilled elsewhere
syscon epoll EPOLLET 0x80000000 0x80000000 0x80000000 0x80000000 0x80000000 0x80000000 0x80000000 0x80000000 # forced consensus, linux only natively, polyfilled elsewhere
# {set,get}sockopt(fd, level=SOL_SOCKET, X, ...)
#
# Unsupported magic numbers are set to zero.
#
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon so SOL_SOCKET 1 1 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff # yes it's actually 0xffff; bsd+nt consensus (todo: what's up with ipproto_icmp overlap)
syscon so SO_DEBUG 1 1 1 1 1 1 1 1 # debugging is enabled; consensus
syscon so SO_TYPE 3 3 0x1008 0x1008 0x1008 0x1008 0x1008 0x1008 # bsd consensus
syscon so SO_ERROR 4 4 0x1007 0x1007 0x1007 0x1007 0x1007 0x1007 # takes int pointer and stores/clears the pending error code; bsd consensus
syscon so SO_ACCEPTCONN 30 30 2 2 2 2 2 2 # takes int pointer and stores boolean indicating if listen() was called on fd; bsd consensus
syscon so SO_REUSEPORT 15 15 0x0200 0x0200 0x0200 0x0200 0x0200 4 # bsd consensus (NT calls it SO_REUSEADDR)
syscon so SO_REUSEPORT 15 15 0x0200 0x0200 0x0200 0x0200 0x0200 0 # bsd consensus; no windows support
syscon so SO_REUSEADDR 2 2 4 4 4 4 4 4 # bsd consensus (default behavior on NT)
syscon so SO_EXCLUSIVEADDRUSE 0 0 0 0 0 0 0 ~4 # bsd consensus (default behavior on NT)
syscon so SO_KEEPALIVE 9 9 8 8 8 8 8 8 # bsd consensus
syscon so SO_DONTROUTE 5 5 0x10 0x10 0x10 0x10 0x10 0x10 # bsd consensus
syscon so SO_BROADCAST 6 6 0x20 0x20 0x20 0x20 0x20 0x20 # socket is configured for broadcast messages; bsd consensus
syscon so SO_USELOOPBACK 0 0 0x40 0x40 0x40 0x40 0x40 0x40 # bsd consensus
syscon so SO_LINGER 13 13 0x1080 0x1080 0x80 0x80 0x80 0x80 # takes struct linger; causes close() return value to actually mean something; SO_LINGER_SEC on XNU; bsd consensus
syscon so SO_DONTLINGER 0 0 0 0 0 0 0 ~0x80 # disables so_linger on windows
syscon so SO_OOBINLINE 10 10 0x0100 0x0100 0x0100 0x0100 0x0100 0x0100 # bsd consensus
syscon so SO_SNDBUF 7 7 0x1001 0x1001 0x1001 0x1001 0x1001 0x1001 # bsd consensus
syscon so SO_RCVBUF 8 8 0x1002 0x1002 0x1002 0x1002 0x1002 0x1002 # bsd consensus
@ -652,120 +629,6 @@ syscon so SO_RCVTIMEO 20 20 0x1006 0x1006 0x1006 0x1006 0x100c
syscon so SO_SNDTIMEO 21 21 0x1005 0x1005 0x1005 0x1005 0x100b 0x1005 # send timeout; takes struct timeval; bsd consensus
syscon so SO_RCVLOWAT 18 18 0x1004 0x1004 0x1004 0x1004 0x1004 0x1004 # bsd consensus
syscon so SO_SNDLOWAT 19 19 0x1003 0x1003 0x1003 0x1003 0x1003 0x1003 # bsd consensus
syscon so SO_TIMESTAMP 29 29 0x0400 0x0400 0x0400 0x0800 0x2000 0
syscon so SO_SETFIB 0 0 0 0 0x1014 0 0 0
syscon so SO_DOMAIN 39 39 0 0 0x1019 0x1024 0 0
syscon so SO_MAX_PACING_RATE 47 47 0 0 0x1018 0 0 0
syscon so SO_PEERCRED 17 17 0 0 0 0x1022 0 0
syscon so SO_EXCLUSIVEADDRUSE 0 0 0 0 0 0 0 0xfffffffb # hoo boy
syscon so LOCAL_PEERCRED 0 0 1 1 1 0 0 0
syscon so SO_PROTOCOL 38 38 0 0 0x1016 0x1025 0 0
syscon so SO_ATTACH_BPF 50 50 0 0 0 0 0 0
syscon so SO_ATTACH_FILTER 26 26 0 0 0 0 0 0
syscon so SO_ATTACH_REUSEPORT_CBPF 51 51 0 0 0 0 0 0
syscon so SO_ATTACH_REUSEPORT_EBPF 52 52 0 0 0 0 0 0
syscon so SO_BINDTODEVICE 25 25 0 0 0 0 0 0
syscon so SO_BPF_EXTENSIONS 48 48 0 0 0 0 0 0
syscon so SO_BSDCOMPAT 14 14 0 0 0 0 0 0
syscon so SO_BUSY_POLL 46 46 0 0 0 0 0 0
syscon so SO_CNX_ADVICE 53 53 0 0 0 0 0 0
syscon so SO_DETACH_BPF 27 27 0 0 0 0 0 0
syscon so SO_DETACH_FILTER 27 27 0 0 0 0 0 0
syscon so SO_GET_FILTER 26 26 0 0 0 0 0 0
syscon so SO_INCOMING_CPU 49 49 0 0 0 0 0 0
syscon so SO_LOCK_FILTER 44 44 0 0 0 0 0 0
syscon so SO_MARK 36 36 0 0 0 0 0 0
syscon so SO_NOFCS 43 43 0 0 0 0 0 0
syscon so SO_NO_CHECK 11 11 0 0 0 0 0 0
syscon so SO_PASSCRED 0x10 0x10 0 0 0 0 0 0
syscon so SO_PASSSEC 34 34 0 0 0 0 0 0
syscon so SO_PEEK_OFF 42 42 0 0 0 0 0 0
syscon so SO_PEERNAME 28 28 0 0 0 0 0 0
syscon so SO_PEERSEC 31 31 0 0 0 0 0 0
syscon so SO_PRIORITY 12 12 0 0 0 0 0 0
syscon so SO_RCVBUFFORCE 33 33 0 0 0 0 0 0
syscon so SO_RXQ_OVFL 40 40 0 0 0 0 0 0
syscon so SO_SECURITY_AUTHENTICATION 22 22 0 0 0 0 0 0
syscon so SO_SECURITY_ENCRYPTION_NETWORK 24 24 0 0 0 0 0 0
syscon so SO_SECURITY_ENCRYPTION_TRANSPORT 23 23 0 0 0 0 0 0
syscon so SO_SELECT_ERR_QUEUE 45 45 0 0 0 0 0 0
syscon so SO_SNDBUFFORCE 0x20 0x20 0 0 0 0 0 0
syscon so SO_TIMESTAMPING 37 37 0 0 0 0 0 0
syscon so SO_TIMESTAMPNS 35 35 0 0 0 0 0 0
syscon so SO_WIFI_STATUS 41 41 0 0 0 0 0 0
# these are IPPROTO_* on non-Linux
syscon sol SOL_IP 0 0 0 0 0 0 0 0 # consensus
syscon sol SOL_SOCKET 1 1 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff # yes it's actually 0xffff; bsd+nt consensus (todo: what's up with ipproto_icmp overlap)
syscon sol SOL_TCP 6 6 6 6 6 6 6 6 # consensus
syscon sol SOL_UDP 17 17 17 17 17 17 17 17 # consensus
syscon sol SOL_RAW 255 255 -1 -1 -1 -1 -1 -1
syscon sol SOL_IPV6 41 41 41 41 41 41 41 41
syscon sol SOL_ICMPV6 58 58 58 58 58 58 58 -1
syscon sol SOL_AAL 265 265 -1 -1 -1 -1 -1 -1
syscon sol SOL_ALG 279 279 -1 -1 -1 -1 -1 -1
syscon sol SOL_ATM 264 264 -1 -1 -1 -1 -1 -1
syscon sol SOL_BLUETOOTH 274 274 -1 -1 -1 -1 -1 -1
syscon sol SOL_CAIF 278 278 -1 -1 -1 -1 -1 -1
syscon sol SOL_DCCP 269 269 -1 -1 -1 -1 -1 -1
syscon sol SOL_DECNET 261 261 -1 -1 -1 -1 -1 -1
syscon sol SOL_IRDA 266 266 -1 -1 -1 -1 -1 -1
syscon sol SOL_IUCV 277 277 -1 -1 -1 -1 -1 -1
syscon sol SOL_KCM 281 281 -1 -1 -1 -1 -1 -1
syscon sol SOL_LLC 268 268 -1 -1 -1 -1 -1 -1
syscon sol SOL_NETBEUI 267 267 -1 -1 -1 -1 -1 -1
syscon sol SOL_NETLINK 270 270 -1 -1 -1 -1 -1 -1
syscon sol SOL_NFC 280 280 -1 -1 -1 -1 -1 -1
syscon sol SOL_PACKET 263 263 -1 -1 -1 -1 -1 -1
syscon sol SOL_PNPIPE 275 275 -1 -1 -1 -1 -1 -1
syscon sol SOL_PPPOL2TP 273 273 -1 -1 -1 -1 -1 -1
syscon sol SOL_RDS 276 276 -1 -1 -1 -1 -1 -1
syscon sol SOL_RXRPC 272 272 -1 -1 -1 -1 -1 -1
syscon sol SOL_TIPC 271 271 -1 -1 -1 -1 -1 -1
syscon sol SOL_X25 262 262 -1 -1 -1 -1 -1 -1
# IPPROTO_*
#
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon iproto IPPROTO_IP 0 0 0 0 0 0 0 0 # consensus
syscon iproto IPPROTO_ICMP 1 1 1 1 1 1 1 1 # consensus
syscon iproto IPPROTO_TCP 6 6 6 6 6 6 6 6 # consensus
syscon iproto IPPROTO_UDP 17 17 17 17 17 17 17 17 # consensus
syscon iproto IPPROTO_RAW 255 255 255 255 255 255 255 255 # consensus
syscon iproto IPPROTO_HOPOPTS 0 0 0 0 0 0 0 -1 # consensus
syscon iproto IPPROTO_IDP 22 22 22 22 22 22 22 22 # consensus
syscon iproto IPPROTO_IGMP 2 2 2 2 2 2 2 2 # consensus
syscon iproto IPPROTO_PUP 12 12 12 12 12 12 12 12 # consensus
syscon iproto IPPROTO_AH 51 51 51 51 51 51 51 -1 # unix consensus
syscon iproto IPPROTO_DSTOPTS 60 60 60 60 60 60 60 -1 # unix consensus
syscon iproto IPPROTO_EGP 8 8 8 8 8 8 8 -1 # unix consensus
syscon iproto IPPROTO_ENCAP 98 98 98 98 98 98 98 -1 # unix consensus
syscon iproto IPPROTO_ESP 50 50 50 50 50 50 50 -1 # unix consensus
syscon iproto IPPROTO_FRAGMENT 44 44 44 44 44 44 44 -1 # unix consensus
syscon iproto IPPROTO_GRE 47 47 47 47 47 47 47 -1 # unix consensus
syscon iproto IPPROTO_ICMPV6 58 58 58 58 58 58 58 -1 # unix consensus
syscon iproto IPPROTO_IPIP 4 4 4 4 4 4 4 -1 # unix consensus
syscon iproto IPPROTO_IPV6 41 41 41 41 41 41 41 -1 # unix consensus
syscon iproto IPPROTO_NONE 59 59 59 59 59 59 59 -1 # unix consensus
syscon iproto IPPROTO_PIM 103 103 103 103 103 103 103 -1 # unix consensus
syscon iproto IPPROTO_ROUTING 43 43 43 43 43 43 43 -1 # unix consensus
syscon iproto IPPROTO_RSVP 46 46 46 46 46 46 46 -1 # unix consensus
syscon iproto IPPROTO_TP 29 29 29 29 29 29 29 -1 # unix consensus
syscon iproto IPPROTO_MPLS 137 137 -1 -1 137 137 137 -1
syscon iproto IPPROTO_MTP 92 92 92 92 92 -1 -1 -1
syscon iproto IPPROTO_SCTP 132 132 132 132 132 -1 -1 -1
syscon iproto IPPROTO_MH 135 135 -1 -1 135 -1 -1 -1
syscon iproto IPPROTO_UDPLITE 136 136 -1 -1 136 -1 -1 -1
syscon iproto IPPROTO_BEETPH 94 94 -1 -1 -1 -1 -1 -1
syscon iproto IPPROTO_COMP 108 108 -1 -1 -1 -1 -1 -1
syscon iproto IPPROTO_DCCP 33 33 -1 -1 -1 -1 -1 -1
syscon alg ALG_SET_KEY 1 1 0 0 0 0 0 0
syscon alg ALG_SET_IV 2 2 0 0 0 0 0 0
syscon alg ALG_SET_OP 3 3 0 0 0 0 0 0
syscon alg ALG_SET_AEAD_ASSOCLEN 4 4 0 0 0 0 0 0
syscon alg ALG_SET_AEAD_AUTHSIZE 5 5 0 0 0 0 0 0
syscon alg ALG_SET_DRBG_ENTROPY 6 6 0 0 0 0 0 0
# {set,get}sockopt(fd, level=SOL_TCP, X, ...)
# » most elite of all tuning groups
@ -1004,48 +867,48 @@ syscon ioctl SIOGIFINDEX 0x8933 0x8933 0 0 0 0 0 0
syscon af AF_UNSPEC 0 0 0 0 0 0 0 0 # consensus
syscon af AF_UNIX 1 1 1 1 1 1 1 1 # consensus
syscon af AF_LOCAL 1 1 1 1 1 1 1 1 # consensus
syscon af AF_FILE 1 1 0 0 0 0 0 0
syscon af AF_INET 2 2 2 2 2 2 2 2 # consensus
syscon af AF_INET6 10 10 30 30 28 24 24 23
syscon af AF_AX25 3 3 0 0 0 0 0 0
syscon af AF_IPX 4 4 23 23 23 23 23 6 # bsd consensus
syscon af AF_APPLETALK 5 5 0x10 0x10 0x10 0x10 0x10 0x10 # bsd consensus
syscon af AF_NETROM 6 6 0 0 0 0 0 0
syscon af AF_BRIDGE 7 7 0 0 0 0 0 0
syscon af AF_ATMPVC 8 8 0 0 0 0 0 0
syscon af AF_X25 9 9 0 0 0 0 0 0
syscon af AF_ROSE 11 11 0 0 0 0 0 0
syscon af AF_NETBEUI 13 13 0 0 0 0 0 0
syscon af AF_SECURITY 14 14 0 0 0 0 0 0
syscon af AF_KEY 15 15 0 0 0 30 0 0
syscon af AF_ROUTE 16 16 17 17 17 17 34 0 # bsd consensus
syscon af AF_NETLINK 16 16 0 0 0 0 0 0
syscon af AF_PACKET 17 17 0 0 0 0 0 0
syscon af AF_LINK 0 0 18 18 18 18 18 0
syscon af AF_ASH 18 18 0 0 0 0 0 0
syscon af AF_ECONET 19 19 0 0 0 0 0 0
syscon af AF_ATMSVC 20 20 0 0 0 0 0 0
syscon af AF_RDS 21 21 0 0 0 0 0 0
syscon af AF_ROUTE 16 16 17 17 17 17 34 -1 # bsd consensus
syscon af AF_LINK -1 -1 18 18 18 18 18 -1
syscon af AF_SNA 22 22 11 11 11 11 11 11 # bsd consensus
syscon af AF_IRDA 23 23 0 0 0 0 0 0
syscon af AF_PPPOX 24 24 0 0 0 0 0 0
syscon af AF_WANPIPE 25 25 0 0 0 0 0 0
syscon af AF_LLC 26 26 0 0 0 0 0 0
syscon af AF_IB 27 27 0 0 0 0 0 0
syscon af AF_MPLS 28 28 0 0 0 33 33 0
syscon af AF_CAN 29 29 0 0 0 0 35 0
syscon af AF_TIPC 30 30 0 0 0 0 0 0
syscon af AF_BLUETOOTH 31 31 0 0 36 0x20 31 0
syscon af AF_IUCV 0x20 0x20 0 0 0 0 0 0
syscon af AF_RXRPC 33 33 0 0 0 0 0 0
syscon af AF_ISDN 34 34 28 28 26 26 26 0
syscon af AF_PHONET 35 35 0 0 0 0 0 0
syscon af AF_IEEE802154 36 36 0 0 0 0 0 0
syscon af AF_CAIF 37 37 0 0 0 0 0 0
syscon af AF_ALG 38 38 0 0 0 0 0 0
syscon af AF_NFC 39 39 0 0 0 0 0 0
syscon af AF_VSOCK 40 40 0 0 0 0 0 0
syscon af AF_KCM 41 41 0 0 0 0 0 0
syscon af AF_FILE 1 1 -1 -1 -1 -1 -1 -1
syscon af AF_AX25 3 3 -1 -1 -1 -1 -1 -1
syscon af AF_NETROM 6 6 -1 -1 -1 -1 -1 -1
syscon af AF_BRIDGE 7 7 -1 -1 -1 -1 -1 -1
syscon af AF_ATMPVC 8 8 -1 -1 -1 -1 -1 -1
syscon af AF_X25 9 9 -1 -1 -1 -1 -1 -1
syscon af AF_ROSE 11 11 -1 -1 -1 -1 -1 -1
syscon af AF_NETBEUI 13 13 -1 -1 -1 -1 -1 -1
syscon af AF_SECURITY 14 14 -1 -1 -1 -1 -1 -1
syscon af AF_KEY 15 15 -1 -1 -1 30 -1 -1
syscon af AF_NETLINK 16 16 -1 -1 -1 -1 -1 -1
syscon af AF_PACKET 17 17 -1 -1 -1 -1 -1 -1
syscon af AF_ASH 18 18 -1 -1 -1 -1 -1 -1
syscon af AF_ECONET 19 19 -1 -1 -1 -1 -1 -1
syscon af AF_ATMSVC 20 20 -1 -1 -1 -1 -1 -1
syscon af AF_RDS 21 21 -1 -1 -1 -1 -1 -1
syscon af AF_IRDA 23 23 -1 -1 -1 -1 -1 -1
syscon af AF_PPPOX 24 24 -1 -1 -1 -1 -1 -1
syscon af AF_WANPIPE 25 25 -1 -1 -1 -1 -1 -1
syscon af AF_LLC 26 26 -1 -1 -1 -1 -1 -1
syscon af AF_IB 27 27 -1 -1 -1 -1 -1 -1
syscon af AF_MPLS 28 28 -1 -1 -1 33 33 -1
syscon af AF_CAN 29 29 -1 -1 -1 -1 35 -1
syscon af AF_TIPC 30 30 -1 -1 -1 -1 -1 -1
syscon af AF_BLUETOOTH 31 31 -1 -1 36 0x20 31 -1
syscon af AF_IUCV 0x20 0x20 -1 -1 -1 -1 -1 -1
syscon af AF_RXRPC 33 33 -1 -1 -1 -1 -1 -1
syscon af AF_ISDN 34 34 28 28 26 26 26 -1
syscon af AF_PHONET 35 35 -1 -1 -1 -1 -1 -1
syscon af AF_IEEE802154 36 36 -1 -1 -1 -1 -1 -1
syscon af AF_CAIF 37 37 -1 -1 -1 -1 -1 -1
syscon af AF_ALG 38 38 -1 -1 -1 -1 -1 -1
syscon af AF_NFC 39 39 -1 -1 -1 -1 -1 -1
syscon af AF_VSOCK 40 40 -1 -1 -1 -1 -1 -1
syscon af AF_KCM 41 41 -1 -1 -1 -1 -1 -1
syscon af AF_MAX 42 42 40 40 42 36 37 35
syscon pf PF_UNIX 1 1 1 1 1 1 1 1 # consensus

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon alg,ALG_SET_AEAD_ASSOCLEN,4,4,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon alg,ALG_SET_AEAD_AUTHSIZE,5,5,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon alg,ALG_SET_DRBG_ENTROPY,6,6,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon alg,ALG_SET_IV,2,2,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon alg,ALG_SET_KEY,1,1,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon alg,ALG_SET_OP,3,3,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon epoll,EPOLLERR,8,8,8,8,8,8,8,8

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