Fix some issues and do some code cleanup

This commit is contained in:
Justine Tunney 2022-05-23 10:15:53 -07:00
parent 1f229e4efc
commit 312ed5c67c
72 changed files with 880 additions and 982 deletions

View file

@ -130,18 +130,18 @@ int geteuid(void) nosideeffect;
int getgid(void) nosideeffect;
int gethostname(char *, size_t);
int getloadavg(double *, int);
int getpgid(int);
int getpgid(int) nosideeffect libcesque;
int getpgrp(void) nosideeffect;
int getpid(void);
int getpid(void) nosideeffect libcesque;
int getppid(void);
int getpriority(int, unsigned);
int getresgid(uint32_t *, uint32_t *, uint32_t *);
int getresuid(uint32_t *, uint32_t *, uint32_t *);
int getrlimit(int, struct rlimit *);
int getrusage(int, struct rusage *);
int getsid(int) nosideeffect;
int gettid(void);
int getuid(void) nosideeffect;
int getsid(int) nosideeffect libcesque;
int gettid(void) libcesque;
int getuid(void) nosideeffect libcesque;
int kill(int, int);
int killpg(int, int);
int link(const char *, const char *) dontthrow;

View file

@ -80,8 +80,6 @@ noinstrument int clock_gettime(int clockid, struct timespec *ts) {
* Returns fast system clock_gettime() if it exists.
*/
void *__get_clock_gettime(void) {
// TODO(jart): Re-enable this.
return 0;
void *vdso;
static bool once;
static void *result;

View file

@ -24,6 +24,7 @@
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/enum/version.h"
#include "libc/nt/version.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
@ -57,7 +58,7 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request,
if (tio->c_lflag & (IEXTEN | ISIG)) {
inmode |= kNtEnableProcessedInput;
}
if (NtGetVersion() >= kNtVersionWindows10) {
if (IsAtLeastWindows10()) {
inmode |= kNtEnableVirtualTerminalInput;
}
ok = SetConsoleMode(in, inmode);
@ -71,7 +72,7 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request,
if (!(tio->c_oflag & ONLCR)) {
outmode |= kNtDisableNewlineAutoReturn;
}
if (NtGetVersion() >= kNtVersionWindows10) {
if (IsAtLeastWindows10()) {
outmode |= kNtEnableVirtualTerminalProcessing;
}
ok = SetConsoleMode(out, outmode);

View file

@ -16,17 +16,13 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/metastat.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Returns true if file descriptor is backed by character i/o.
@ -44,15 +40,7 @@ bool32 ischardev(int fd) {
int e;
union metastat st;
if (__isfdkind(fd, kFdZip)) {
e = errno;
if (weaken(__zipos_fstat)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, &st.cosmo) !=
-1) {
return S_ISCHR(st.cosmo.st_mode);
} else {
errno = e;
return false;
}
return false;
} else if (IsMetal()) {
return true;
} else if (!IsWindows()) {

View file

@ -97,7 +97,8 @@ static long double nowl_vdso(void) {
long double nowl_setup(void) {
uint64_t ticks;
if ((g_now.clock_gettime = __get_clock_gettime())) {
if (0 && (g_now.clock_gettime = __get_clock_gettime())) {
// TODO(jart): Re-enable this.
nowl = nowl_vdso;
} else if (X86_HAVE(INVTSC)) {
RefreshTime();
@ -107,5 +108,3 @@ long double nowl_setup(void) {
}
return nowl();
}
long double (*nowl)(void) = nowl_setup;

View file

@ -1,5 +1,5 @@
/*-*- 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
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
@ -16,13 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/macros.internal.h"
/**
* Maximum amount of virtual memory in bytes.
*
* mmap() will return ENOMEM once this is reached.
*
* By default no limit is imposed.
*/
size_t __virtualmax = -1;
.initbss 201,_init_nowl
nowl: .quad 0
.endobj nowl,globl
.previous
.init.start 201,_init_nowl
ezlea nowl_setup,ax
stosq
.init.end 201,_init_nowl

View file

@ -81,7 +81,13 @@ textwindows void _check_sigalrm(void) {
textwindows int sys_setitimer_nt(int which, const struct itimerval *newvalue,
struct itimerval *out_opt_oldvalue) {
long double elapsed, untilnext;
if (which != ITIMER_REAL) return einval();
if (which != ITIMER_REAL ||
(newvalue && (!(0 <= newvalue->it_value.tv_usec &&
newvalue->it_value.tv_usec < 1000000) ||
!(0 <= newvalue->it_interval.tv_usec &&
newvalue->it_interval.tv_usec < 1000000)))) {
return einval();
}
if (out_opt_oldvalue) {
if (__hastimer) {
elapsed = nowl() - __lastalrm;

View file

@ -48,7 +48,7 @@ static inline textwindows noasan int NtGetBuildNumber(void) {
* @return 0 on success, or -1 w/ errno
*/
int uname(struct utsname *lool) {
int rc, v;
int rc;
char *out, *p;
size_t i, j, len;
char tmp[sizeof(struct utsname)];
@ -87,7 +87,6 @@ int uname(struct utsname *lool) {
rc = enosys();
}
} else {
v = NtGetVersion();
p = lool->release;
p = FormatUint32(p, NtGetMajorVersion()), *p++ = '.';
p = FormatUint32(p, NtGetMinorVersion()), *p++ = '-';

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -18,16 +18,20 @@
*/
#include "libc/macros.internal.h"
// Blocks until data from stream buffer is written out.
.initbss 201,_init___virtualmax
// Maximum amount of virtual memory in bytes.
//
// @param rdi is the stream handle, or 0 for all streams
// @return 0 on success or -1 w/ errno
// @see fflush_unlocked()
// @threadsafe
fflush: ezlea fflush_unlocked,ax
test %rdi,%rdi
jz 1f
mov %rdi,%r11
jmp stdio_unlock
1: jmp *%rax
.endfn fflush,globl
// mmap() will return ENOMEM once this is reached.
//
// By default no limit is imposed.
__virtualmax:
.quad 0
.endobj __virtualmax,globl
.previous
.init.start 201,_init___virtualmax
push $-1
pop %rax
stosq
.init.end 201,_init___virtualmax

View file

@ -199,7 +199,7 @@ static char *__asan_utf8cpy(char *p, unsigned c) {
return p;
}
static void *__asan_memset(void *p, char c, size_t n) {
static void __asan_memset(void *p, char c, size_t n) {
char *b;
size_t i;
uint64_t x;
@ -207,29 +207,29 @@ static void *__asan_memset(void *p, char c, size_t n) {
x = 0x0101010101010101ul * (c & 255);
switch (n) {
case 0:
return p;
break;
case 1:
__builtin_memcpy(b, &x, 1);
return p;
break;
case 2:
__builtin_memcpy(b, &x, 2);
return p;
break;
case 3:
__builtin_memcpy(b, &x, 2);
__builtin_memcpy(b + 1, &x, 2);
return p;
break;
case 4:
__builtin_memcpy(b, &x, 4);
return p;
break;
case 5:
case 6:
case 7:
__builtin_memcpy(b, &x, 4);
__builtin_memcpy(b + n - 4, &x, 4);
return p;
break;
case 8:
__builtin_memcpy(b, &x, 8);
return p;
break;
case 9:
case 10:
case 11:
@ -240,7 +240,7 @@ static void *__asan_memset(void *p, char c, size_t n) {
case 16:
__builtin_memcpy(b, &x, 8);
__builtin_memcpy(b + n - 8, &x, 8);
return p;
break;
default:
if (n <= 64) {
i = 0;
@ -253,83 +253,10 @@ static void *__asan_memset(void *p, char c, size_t n) {
} else {
__repstosb(p, c, n);
}
return p;
break;
}
}
static void *__asan_mempcpy(void *dst, const void *src, size_t n) {
size_t i;
char *d;
const char *s;
uint64_t a, b;
d = dst;
s = src;
switch (n) {
case 0:
return d;
case 1:
*d = *s;
return d + 1;
case 2:
__builtin_memcpy(&a, s, 2);
__builtin_memcpy(d, &a, 2);
return d + 2;
case 3:
__builtin_memcpy(&a, s, 2);
__builtin_memcpy(&b, s + 1, 2);
__builtin_memcpy(d, &a, 2);
__builtin_memcpy(d + 1, &b, 2);
return d + 3;
case 4:
__builtin_memcpy(&a, s, 4);
__builtin_memcpy(d, &a, 4);
return d + 4;
case 5:
case 6:
case 7:
__builtin_memcpy(&a, s, 4);
__builtin_memcpy(&b, s + n - 4, 4);
__builtin_memcpy(d, &a, 4);
__builtin_memcpy(d + n - 4, &b, 4);
return d + n;
case 8:
__builtin_memcpy(&a, s, 8);
__builtin_memcpy(d, &a, 8);
return d + 8;
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
__builtin_memcpy(&a, s, 8);
__builtin_memcpy(&b, s + n - 8, 8);
__builtin_memcpy(d, &a, 8);
__builtin_memcpy(d + n - 8, &b, 8);
return d + n;
default:
if (n <= 64) {
i = 0;
do {
__builtin_memcpy(&a, s + i, 8);
asm volatile("" ::: "memory");
__builtin_memcpy(d + i, &a, 8);
} while ((i += 8) + 8 <= n);
for (; i < n; ++i) d[i] = s[i];
return d + i;
} else {
return __repmovsb(d, s, n);
}
}
}
static void *__asan_memcpy(void *dst, const void *src, size_t n) {
__asan_mempcpy(dst, src, n);
return dst;
}
static char *__asan_hexcpy(char *p, uint64_t x, uint8_t k) {
while (k) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
return p;
@ -736,7 +663,7 @@ static void __asan_report_memory_origin(const unsigned char *addr, int size,
if (_base <= addr && addr < _end) {
__asan_report_memory_origin_image((intptr_t)addr, size);
} else if (IsAutoFrame((intptr_t)addr >> 16)) {
/* __asan_report_memory_origin_heap(addr, size); */
__asan_report_memory_origin_heap(addr, size);
}
}
@ -946,8 +873,8 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
#define __asan_trace __asan_rawtrace
static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
struct AsanTrace *bt) {
void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
struct AsanTrace *bt) {
char *p;
size_t c;
struct AsanExtra *e;
@ -960,7 +887,7 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
__asan_poison(p + n, c - n, overrun);
__asan_memset(p, 0xF9, n);
__asan_write48(&e->size, n);
__asan_memcpy(&e->bt, bt, sizeof(*bt));
__builtin_memcpy(&e->bt, bt, sizeof(*bt));
}
return p;
}
@ -1082,7 +1009,7 @@ static void *__asan_realloc_grow(void *p, size_t n, size_t m,
struct AsanTrace *bt) {
char *q;
if ((q = __asan_allocate(16, n, kAsanHeapUnderrun, kAsanHeapOverrun, bt))) {
__asan_memcpy(q, p, m);
__builtin_memcpy(q, p, m);
__asan_deallocate(p, kAsanHeapRelocated);
}
return q;

View file

@ -46,7 +46,6 @@ relegated wontreturn void __assert_fail(const char *expr, const char *file,
} else {
rc = 24;
}
if (weaken(__die)) weaken(__die)();
__restorewintty();
_Exit(rc);
}

View file

@ -23,6 +23,7 @@ const char *DescribeMapFlags(int);
const char *DescribeProtFlags(int);
const char *DescribeRemapFlags(int);
const char *DescribeRlimitName(int);
const char *DescribePersonalityFlags(int);
const char *DescribeSeccompOperationFlags(int);
const char *DescribePollFlags(char *, size_t, int);
const char *DescribeStat(int, const struct stat *);

View file

@ -0,0 +1,43 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/describeflags.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/sysv/consts/personality.h"
static const struct DescribeFlags kPersonalityFlags[] = {
{ADDR_COMPAT_LAYOUT, "ADDR_COMPAT_LAYOUT"}, //
{READ_IMPLIES_EXEC, "READ_IMPLIES_EXEC"}, //
{ADDR_LIMIT_3GB, "ADDR_LIMIT_3GB"}, //
{FDPIC_FUNCPTRS, "FDPIC_FUNCPTRS"}, //
{STICKY_TIMEOUTS, "STICKY_TIMEOUTS"}, //
{MMAP_PAGE_ZERO, "MMAP_PAGE_ZERO"}, //
{ADDR_LIMIT_32BIT, "ADDR_LIMIT_32BIT"}, //
{WHOLE_SECONDS, "WHOLE_SECONDS"}, //
{ADDR_NO_RANDOMIZE, "ADDR_NO_RANDOMIZE"}, //
{SHORT_INODE, "SHORT_INODE"}, //
{UNAME26, "UNAME26"}, //
};
const char *DescribePersonalityFlags(int x) {
_Alignas(char) static char personalityflags[128];
return DescribeFlags(personalityflags, sizeof(personalityflags),
kPersonalityFlags, ARRAYLEN(kPersonalityFlags), "", x);
}

View file

@ -22,7 +22,17 @@
/**
* Returns process id.
*
* This function does not need to issue a system call. The PID is
* tracked by a global variable which is updated atfork(). The only
* exception is when the process is vfork()'d in which case a system
* call shall be issued.
*
* On Linux, and only Linux, the process id is guaranteed to be the same
* as gettid() for the main thread.
*
* @asyncsignalsafe
* @threadsafe
* @vforksafe
*/
int getpid(void) {

View file

@ -32,8 +32,25 @@ __msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId;
* if this is the main thread. On NetBSD, gettid() for the main thread
* is always 1.
*
* This function issues a system call. That stops being the case as soon
* as __install_tls() is called. That'll happen automatically, when you
* call clone() and provide the TLS parameter. We assume that when a TLS
* block exists, then
*
* *(int *)(__get_tls() + 0x38)
*
* will contain the thread id. Therefore when issuing clone() calls, the
* `CLONE_CHILD_SETTID` and `CLONE_CHILD_CLEARTID` flags should use that
* index as its `ctid` memory.
*
* gettid (single threaded) l: 126𝑐 41𝑛𝑠
* gettid (tls enabled) l: 2𝑐 1𝑛𝑠
*
* The TLS convention is important for reentrant lock performance.
*
* @return thread id greater than zero or -1 w/ errno
* @asyncsignalsafe
* @threadsafe
*/
privileged int gettid(void) {
int rc;
@ -42,9 +59,7 @@ privileged int gettid(void) {
if (__tls_enabled) {
rc = *(int *)(__get_tls() + 0x38);
if (rc && rc != -1) {
return rc;
}
return rc;
}
if (IsWindows()) {

View file

@ -46,9 +46,14 @@ $(LIBC_INTRIN_A_OBJS): \
OVERRIDE_CFLAGS += \
-foptimize-sibling-calls
# we can't use asan and ubsan because:
# this is asan and ubsan
# we need -ffreestanding because:
# we don't want __builtin_memcpy() calling memcpy()
o/$(MODE)/libc/intrin/asan.o \
o/$(MODE)/libc/intrin/ubsan.o: \
OVERRIDE_CFLAGS += \
-ffreestanding \
-fno-sanitize=all \
-fno-stack-protector
@ -145,12 +150,6 @@ o/$(MODE)/libc/intrin/describeopenflags.greg.o: \
OVERRIDE_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED
o/$(MODE)/libc/intrin/asan.o \
o/$(MODE)/libc/intrin/ubsan.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all \
-fno-stack-protector
o//libc/intrin/memmove.o: \
OVERRIDE_CFLAGS += \
-fno-toplevel-reorder

View file

@ -857,7 +857,6 @@ privileged void kvprintf(const char *fmt, va_list v) {
*
* Specifiers:
*
* - `P` pid
* - `c` char
* - `o` octal
* - `b` binary
@ -873,6 +872,7 @@ privileged void kvprintf(const char *fmt, va_list v) {
* - `X` uppercase
* - `T` timestamp
* - `x` hexadecimal
* - `P` pid (or tid if threaded)
*
* Types:
*

View file

@ -22,9 +22,9 @@
/**
* Returns New Technology version, e.g.
*
* if (IsWindows() && NtGetVersion() >=k NtVersionWindows10) {...}
*
* This can only be called on Windows.
*
* @see IsAtLeastWindows10()
*/
textwindows noasan int NtGetVersion(void) {
return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion;

View file

@ -25,16 +25,8 @@
//
// @return 0 on success, or -1 w/ errno
sched_yield:
push %rbp
mov %rsp,%rbp
testb IsWindows()
jnz 1f
// UNIX Support
mov __NR_sched_yield,%eax
syscall
jmp 2f
#if SupportsWindows()
// Windows Support
//
// A value of zero, together with the bAlertable parameter set to
@ -44,12 +36,34 @@ sched_yield:
// threads ready to run and no user APCs are queued, the function
// returns immediately, and the thread continues execution.
// Quoth MSDN
1: xor %ecx,%ecx
testb IsWindows()
jz 1f
push %rbp
mov %rsp,%rbp
xor %ecx,%ecx
xor %edx,%edx
ntcall __imp_SleepEx
xor %eax,%eax
2: pop %rbp
pop %rbp
ret
#endif
#if SupportsSystemv()
// UNIX Support
1: mov __NR_sched_yield,%eax
#if SupportsBsd() && SupportsLinux()
clc
#endif
syscall
#if SupportsBsd()
jc systemfive_errno
#endif
#if SupportsLinux()
cmp $-4095,%rax
jae systemfive_error
#endif
#endif
2: ret
.endfn sched_yield,globl
.previous

View file

@ -44,23 +44,28 @@
* 0x003c 0x04 errno
*
*/
privileged void *__initialize_tls(char tib[hasatleast 64]) {
*(intptr_t *)tib = (intptr_t)tib;
*(intptr_t *)(tib + 0x08) = 0;
*(int *)(tib + 0x10) = -1; // exit code
*(intptr_t *)(tib + 0x30) = (intptr_t)tib;
*(int *)(tib + 0x38) = -1; // tid
*(int *)(tib + 0x3c) = __errno;
privileged void *__initialize_tls(char tib[64]) {
if (tib) {
*(intptr_t *)tib = (intptr_t)tib;
*(intptr_t *)(tib + 0x08) = 0;
*(int *)(tib + 0x10) = -1; // exit code
*(intptr_t *)(tib + 0x30) = (intptr_t)tib;
*(int *)(tib + 0x38) = -1; // tid
*(int *)(tib + 0x3c) = 0;
}
return tib;
}
/**
* Installs thread information block on main process.
*/
privileged void __install_tls(char tib[hasatleast 64]) {
privileged void __install_tls(char tib[64]) {
int ax, dx;
uint64_t magic;
unsigned char *p;
assert(tib);
assert(!__tls_enabled);
assert(*(int *)(tib + 0x38) != -1);
if (IsWindows()) {
if (!__tls_index) {
__tls_index = TlsAlloc();

View file

@ -8,8 +8,8 @@ extern bool __threaded;
extern bool __tls_enabled;
extern unsigned __tls_index;
void *__initialize_tls(char[hasatleast 64]);
void __install_tls(char[hasatleast 64]);
void *__initialize_tls(char[64]);
void __install_tls(char[64]);
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__)
/**

View file

@ -4,17 +4,18 @@
/**
* Known versions of the New Technology executive.
* @see IsAtLeastWindows10()
* @see NtGetVersion()
*/
#define kNtVersionWindows10 0x0a00
#define kNtVersionWindows81 0x0603
#define kNtVersionWindows8 0x0602
#define kNtVersionWindows7 0x0601
#define kNtVersionWindows10 0x0a00
#define kNtVersionWindows81 0x0603
#define kNtVersionWindows8 0x0602
#define kNtVersionWindows7 0x0601
#define kNtVersionWindowsVista 0x0600 /* intended baseline */
#define kNtVersionWindowsXp64 0x0502 /* end of the road */
#define kNtVersionWindowsXp 0x0501 /* snowball's chance */
#define kNtVersionWindows2000 0x0500 /* the golden age */
#define kNtVersionFuture 0x0b00
#define kNtVersionWindowsXp64 0x0502 /* end of the road */
#define kNtVersionWindowsXp 0x0501 /* snowball's chance */
#define kNtVersionWindows2000 0x0500 /* the golden age */
#define kNtVersionFuture 0x0b00
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NT_ENUM_VERSION_H_ */

View file

@ -8,16 +8,14 @@ bool IsAtLeastWindows10(void) pureconst;
bool32 GetVersionEx(struct NtOsVersionInfo *lpVersionInformation);
#if defined(__GCC_ASM_FLAG_OUTPUTS__) && !defined(__STRICT_ANSI__)
#define IsAtLeastWindows10() \
({ \
long ReG; \
bool NoTbelow; \
asm("mov\t%%gs:96,%1\r\n" \
"cmpb\t%2,280(%1)" \
: "=@ccnb"(NoTbelow), "=l"(ReG) \
: "i"(10)); \
NoTbelow; \
})
#define IsAtLeastWindows10() (GetNtMajorVersion() >= 10)
static pureconst inline unsigned char GetNtMajorVersion(void) {
uintptr_t _x;
asm("mov\t%%gs:96,%q0\r\n"
"mov\t280(%q0),%b0"
: "=q"(_x));
return _x;
}
#endif
COSMOPOLITAN_C_END_

View file

@ -0,0 +1,55 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Invokes clone() system call on GNU/Systemd.
//
// @param rdi is flags
// @param rsi is top of stack
// @param rdx is ptid
// @param rcx is ctid
// @param r8 is tls
// @param r9 is func
// @param 8(rsp) is arg
// @return tid of child on success, or -1 w/ errno
sys_clone_linux:
push %rbp
mov %rsp,%rbp
.profilable
push %rbx
mov %rcx,%r10
mov 16(%rbp),%rbx
mov $56,%eax # __NR_clone
syscall
test %rax,%rax
jz 2f
cmp $-4095,%rax
jae 1f
0: pop %rbx
pop %rbp
ret
1: call systemfive_error
jmp 0b
2: xor %ebp,%ebp # child thread
mov %rbx,%rdi # arg
call *%r9 # func(arg)
xchg %eax,%edi # func(arg) exitcode
mov $60,%eax # __NR_exit(exitcode)
syscall
.endfn sys_clone_linux,globl,hidden

View file

@ -419,40 +419,8 @@ static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags,
////////////////////////////////////////////////////////////////////////////////
// GNU/SYSTEMD
int CloneLinux(int (*func)(void *), char *stk, size_t stksz, int flags,
void *arg, int *ptid, void *tls, size_t tlssz, int *ctid) {
#ifdef __chibicc__
return -1; // TODO
#else
int ax;
intptr_t *stack = (intptr_t *)(stk + stksz);
*--stack = (intptr_t)arg;
// %rax = syscall(%rax = __NR_clone,
// %rdi = flags,
// %rsi = child_stack,
// %rdx = parent_tidptr,
// %r10 = child_tidptr,
// %r8 = new_tls);
asm volatile("mov\t%4,%%r10\n\t" // ctid
"mov\t%5,%%r8\n\t" // tls
"mov\t%6,%%r9\n\t" // func
"syscall\n\t"
"test\t%0,%0\n\t"
"jnz\t1f\n\t"
"xor\t%%ebp,%%ebp\n\t"
"pop\t%%rdi\n\t" // arg
"call\t*%%r9\n\t" // func
"xchg\t%%eax,%%edi\n\t"
"mov\t$0x3c,%%eax\n\t"
"syscall\n1:"
: "=a"(ax)
: "0"(__NR_clone_linux), "D"(flags), "S"(stack), "g"(ctid),
"g"(tls), "g"(func), "d"(ptid)
: "rcx", "r8", "r9", "r10", "r11", "memory");
if (ax > -4096u) errno = -ax, ax = -1;
return ax;
#endif
}
int sys_clone_linux(int flags, char *stk, int *ptid, int *ctid, void *tls,
int (*func)(void *), void *arg);
////////////////////////////////////////////////////////////////////////////////
// COSMOPOLITAN
@ -542,13 +510,23 @@ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg,
int rc;
struct CloneArgs *wt;
if (flags & CLONE_THREAD) {
__threaded = true;
}
// transition program to threaded state
if ((flags & CLONE_SETTLS) && !__tls_enabled) {
if (~flags & CLONE_THREAD) {
STRACE("clone() tls w/o thread");
return einval();
}
if (__threaded) {
STRACE("clone() tls/non-tls mixed order");
return einval();
}
__initialize_tls(tibdefault);
*(int *)((char *)tibdefault + 0x38) = gettid();
*(int *)((char *)tibdefault + 0x3c) = __errno;
__install_tls(tibdefault);
__threaded = true;
} else if (flags & CLONE_THREAD) {
__threaded = true;
}
if (IsAsan() &&
@ -566,7 +544,8 @@ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg,
((flags & CLONE_SETTLS) && (tlssz < 64 || (tlssz & 7))))) {
rc = einval();
} else if (IsLinux()) {
rc = CloneLinux(func, stk, stksz, flags, arg, ptid, tls, tlssz, ctid);
rc =
sys_clone_linux(flags, (char *)stk + stksz, ptid, ctid, tls, func, arg);
} else if (!IsTiny() &&
(flags & ~(CLONE_SETTLS | CLONE_PARENT_SETTID |
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) !=

View file

@ -26,7 +26,9 @@
* @assume stack addresses are always greater than heap addresses
* @assume stack memory isn't stored beneath %rsp (-mno-red-zone)
*/
noasan bool _isheap(void *p) {
return kAutomapStart <= (intptr_t)p &&
(intptr_t)p < kAutomapStart + kAutomapSize;
optimizesize noasan bool _isheap(void *p) {
intptr_t x, y;
x = kAutomapStart;
y = x + kAutomapSize;
return x <= (intptr_t)p && (intptr_t)p < y;
}

View file

@ -4,8 +4,7 @@
#include "libc/bits/midpoint.h"
#include "libc/dce.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/version.h"
#include "libc/runtime/runtime.h"
#include "libc/nt/version.h"
#include "libc/runtime/stack.h"
#include "libc/sysv/consts/ss.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
@ -29,7 +28,7 @@ COSMOPOLITAN_C_START_
ROUNDUP(VSPACE / FRAMESIZE * (intptr_t)sizeof(struct MemoryInterval), \
FRAMESIZE)
#define _kMem(NORMAL, WIN7) \
(!(IsWindows() && NtGetVersion() < kNtVersionWindows10) ? NORMAL : WIN7)
(!IsWindows() || IsAtLeastWindows10() ? NORMAL : WIN7)
struct MemoryInterval {
int x;

View file

@ -16,59 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/pushpop.h"
#include "libc/nt/enum/version.h"
#include "libc/nt/runtime.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/internal.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/nr.h"
#define STACK_SMASH_MESSAGE "stack smashed\n"
/**
* Aborts program under enemy fire to avoid being taken alive.
*/
privileged noasan void __stack_chk_fail(void) {
size_t len;
const char *msg;
int64_t ax, cx, si;
if (!IsWindows()) {
msg = STACK_SMASH_MESSAGE;
len = pushpop(sizeof(STACK_SMASH_MESSAGE) - 1);
if (!IsMetal()) {
asm volatile("syscall"
: "=a"(ax)
: "0"(__NR_write), "D"(pushpop(STDERR_FILENO)), "S"(msg),
"d"(len)
: "rcx", "r11", "cc", "memory");
asm volatile("syscall"
: "=a"(ax)
: "0"(__NR_exit_group), "D"(pushpop(23))
: "rcx", "r11", "cc", "memory");
}
asm volatile("rep outsb"
: "=S"(si), "=c"(cx)
: "0"(msg), "1"(len), "d"(0x3F8 /* COM1 */)
: "memory");
asm("push\t$0\n\t"
"push\t$0\n\t"
"cli\n\t"
"lidt\t(%rsp)");
for (;;) asm("ud2");
}
if (NtGetVersion() < kNtVersionFuture) {
do {
asm volatile("syscall"
: "=a"(ax), "=c"(cx)
: "0"(NtGetVersion() < kNtVersionWindows8 ? 0x0029
: NtGetVersion() < kNtVersionWindows81 ? 0x002a
: NtGetVersion() < kNtVersionWindows10 ? 0x002b
: 0x002c),
"1"(pushpop(-1L)), "d"(42)
: "r11", "cc", "memory");
} while (!ax);
}
for (;;) {
TerminateProcess(GetCurrentProcess(), 42);
}
privileged noasan noinstrument void __stack_chk_fail(void) {
kprintf("stack smashed\n");
__restorewintty();
_Exit(207);
}

View file

@ -39,6 +39,7 @@ int fclose(FILE *f) {
if (!f) return 0;
__fflush_unregister(f);
fflush(f);
free_s(&f->getln);
if (!f->nofree) {
free_s(&f->buf);
}

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=8 sts=2 sw=2 fenc=utf-8 :vi
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,83 +16,19 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/arraylist.internal.h"
#include "libc/bits/bits.h"
#include "libc/bits/pushpop.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/intrin/spinlock.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/fflush.internal.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
/**
* Blocks until data from stream buffer is written out.
*
* @param f is the stream handle, or 0 for all streams
* @return is 0 on success or -1 on error
* @threadsafe
*/
int fflush_unlocked(FILE *f) {
int rc = 0;
size_t i;
if (!f) {
_spinlock(&__fflush.lock);
for (i = __fflush.handles.i; i; --i) {
if ((f = __fflush.handles.p[i - 1])) {
if (fflush(f) == -1) {
rc = -1;
}
}
}
_spunlock(&__fflush.lock);
} else if (f->fd != -1) {
if (__fflush_impl(f) == -1) {
rc = -1;
}
} else if (f->beg && f->beg < f->size) {
f->buf[f->beg] = 0;
}
return rc;
}
textstartup int __fflush_register(FILE *f) {
int fflush(FILE *f) {
int rc;
size_t i;
struct StdioFlush *sf;
_spinlock(&__fflush.lock);
sf = &__fflush;
if (!sf->handles.p) {
sf->handles.p = sf->handles_initmem;
pushmov(&sf->handles.n, ARRAYLEN(sf->handles_initmem));
__cxa_atexit(fflush_unlocked, 0, 0);
}
for (i = sf->handles.i; i; --i) {
if (!sf->handles.p[i - 1]) {
sf->handles.p[i - 1] = f;
_spunlock(&__fflush.lock);
return 0;
}
}
rc = append(&sf->handles, &f);
_spunlock(&__fflush.lock);
if (f) flockfile(f);
rc = fflush_unlocked(f);
if (f) funlockfile(f);
return rc;
}
void __fflush_unregister(FILE *f) {
size_t i;
struct StdioFlush *sf;
_spinlock(&__fflush.lock);
sf = &__fflush;
sf = pushpop(sf);
for (i = sf->handles.i; i; --i) {
if (sf->handles.p[i - 1] == f) {
pushmov(&sf->handles.p[i - 1], 0);
break;
}
}
_spunlock(&__fflush.lock);
}

View file

@ -0,0 +1,98 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/arraylist.internal.h"
#include "libc/bits/bits.h"
#include "libc/bits/pushpop.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/intrin/spinlock.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/fflush.internal.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
/**
* Blocks until data from stream buffer is written out.
*
* @param f is the stream handle, or 0 for all streams
* @return is 0 on success or -1 on error
*/
int fflush_unlocked(FILE *f) {
int rc = 0;
size_t i;
if (!f) {
_spinlock(&__fflush.lock);
for (i = __fflush.handles.i; i; --i) {
if ((f = __fflush.handles.p[i - 1])) {
if (fflush(f) == -1) {
rc = -1;
}
}
}
_spunlock(&__fflush.lock);
} else if (f->fd != -1) {
if (__fflush_impl(f) == -1) {
rc = -1;
}
} else if (f->beg && f->beg < f->size) {
f->buf[f->beg] = 0;
}
return rc;
}
textstartup int __fflush_register(FILE *f) {
int rc;
size_t i;
struct StdioFlush *sf;
_spinlock(&__fflush.lock);
sf = &__fflush;
if (!sf->handles.p) {
sf->handles.p = sf->handles_initmem;
pushmov(&sf->handles.n, ARRAYLEN(sf->handles_initmem));
__cxa_atexit(fflush_unlocked, 0, 0);
}
for (i = sf->handles.i; i; --i) {
if (!sf->handles.p[i - 1]) {
sf->handles.p[i - 1] = f;
_spunlock(&__fflush.lock);
return 0;
}
}
rc = append(&sf->handles, &f);
_spunlock(&__fflush.lock);
return rc;
}
void __fflush_unregister(FILE *f) {
size_t i;
struct StdioFlush *sf;
_spinlock(&__fflush.lock);
sf = &__fflush;
sf = pushpop(sf);
for (i = sf->handles.i; i; --i) {
if (sf->handles.p[i - 1] == f) {
pushmov(&sf->handles.p[i - 1], 0);
break;
}
}
_spunlock(&__fflush.lock);
}

View file

@ -18,12 +18,14 @@
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/internal.h"
#include "libc/sysv/consts/o.h"
int __fflush_impl(FILE *f) {
size_t i;
ssize_t rc;
free_s(&f->getln);
if (f->beg && !f->end && (f->iomode & O_ACCMODE) != O_RDONLY) {
for (i = 0; i < f->beg; i += rc) {
if ((rc = write(f->fd, f->buf + i, f->beg - i)) == -1) {

View file

@ -18,13 +18,35 @@
*/
#include "libc/stdio/stdio.h"
/**
* Retrieves line from stream, e.g.
*
* char *line;
* while ((line = _chomp(fgetln(stdin, 0)))) {
* printf("%s\n", line);
* }
*
* The returned memory is owned by the stream. It'll be reused when
* fgetln() is called again. It's free()'d upon fclose() / fflush()
*
* @param stream specifies non-null open input stream
* @param len optionally receives byte length of line
* @return nul-terminated line string, including the `\n` character
* unless a line happened before EOF without `\n`, otherwise it
* returns `NULL` and feof() and ferror() can examine the state
* @see getdelim()
*/
char *fgetln(FILE *stream, size_t *len) {
char *res;
ssize_t rc;
size_t n = 0;
if ((rc = getdelim(&stream->getln, &n, '\n', stream)) > 0) {
*len = rc;
return stream->getln;
flockfile(stream);
if ((rc = getdelim_unlocked(&stream->getln, &n, '\n', stream)) > 0) {
if (len) *len = rc;
res = stream->getln;
} else {
return 0;
res = 0;
}
funlockfile(stream);
return res;
}

View file

@ -28,16 +28,18 @@
void flockfile(FILE *f) {
int me, owner;
unsigned tries;
if (!__threaded) return;
for (tries = 0, me = gettid();;) {
owner = 0;
if (_lockcmpxchgp(&f->lock, &owner, me) || owner == me) {
return;
}
if (++tries & 7) {
__builtin_ia32_pause();
} else {
sched_yield();
if (__threaded) {
for (tries = 0, me = gettid();;) {
owner = 0;
if (_lockcmpxchgp(&f->lock, &owner, me) || owner == me) {
break;
}
if (++tries & 7) {
__builtin_ia32_pause();
} else {
sched_yield();
}
}
}
++f->reent;
}

View file

@ -29,7 +29,7 @@ int fputc_unlocked(int c, FILE *f) {
unsigned char b;
if (c != '\n' && f->beg < f->size && f->bufmode != _IONBF) {
f->buf[f->beg++] = c;
return c & 0xff;
return c & 255;
} else {
b = c;
if (!fwrite_unlocked(&b, 1, 1, f)) return -1;

View file

@ -34,5 +34,8 @@ int ftrylockfile(FILE *f) {
owner = 0;
}
}
if (!owner) {
++f->reent;
}
return owner;
}

View file

@ -16,12 +16,24 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/spinlock.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/stdio/stdio.h"
/**
* Releases lock on stdio object.
*/
void funlockfile(FILE *f) {
_spunlock(&f->lock);
int owner;
bool shouldunlock;
assert(f->reent > 0);
shouldunlock = --f->reent <= 0;
if (__threaded) {
assert(f->lock == gettid());
if (shouldunlock) {
owner = 0;
__atomic_store(&f->lock, &owner, __ATOMIC_RELAXED);
}
}
}

View file

@ -16,64 +16,18 @@
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/errno.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
static ssize_t getdelim_unlocked(char **s, size_t *n, int delim, FILE *f) {
char *p;
ssize_t rc;
size_t i, m;
if ((f->iomode & O_ACCMODE) == O_WRONLY) {
f->state = errno = EBADF;
return -1;
}
if (f->beg > f->end) {
f->state = errno = EINVAL;
return -1;
}
if (!*s) *n = 0;
for (i = 0;; i += m) {
m = f->end - f->beg;
if ((p = memchr(f->buf + f->beg, delim, m))) m = p + 1 - (f->buf + f->beg);
if (i + m + 1 > *n) {
*n = i + m + 1;
*s = realloc(*s, *n);
if (!*s) {
abort();
}
}
memcpy(*s + i, f->buf + f->beg, m);
(*s)[i + m] = '\0';
if ((f->beg += m) == f->end) f->beg = f->end = 0;
if (p) {
return i + m;
} else if (f->fd == -1) {
break;
} else if ((rc = read(f->fd, f->buf, f->size)) != -1) {
if (!rc) break;
f->end = rc;
} else if (errno != EINTR) {
f->state = errno;
return -1;
}
}
f->state = -1;
if (i + m) {
return i + m;
} else {
return -1;
}
}
/**
* Reads string from stream.
* Reads string from stream, e.g.
*
* char *line = NULL;
* size_t linesize = 0;
* while (getdelim(&line, &linesize, '\n', stdin) > 0) {
* _chomp(line);
* printf("%s\n", line);
* }
* free(line);
*
* @param s is the caller's buffer (in/out) which is extended or
* allocated automatically, also NUL-terminated is guaranteed
@ -81,8 +35,9 @@ static ssize_t getdelim_unlocked(char **s, size_t *n, int delim, FILE *f) {
* @param delim is the stop char (and NUL is implicitly too)
* @return number of bytes read >0, including delim, excluding NUL,
* or -1 w/ errno on EOF or error; see ferror() and feof()
* @note this function can't punt EINTR to caller
* @see getline(), _chomp(), gettok_r()
* @note this function will ignore EINTR if it occurs mid-line
* @raises EBADF if stream isn't open for reading
* @see fgetln(), getline(), _chomp(), gettok_r()
*/
ssize_t getdelim(char **s, size_t *n, int delim, FILE *f) {
ssize_t rc;

View file

@ -0,0 +1,81 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
/**
* Reads string from unlocked stream.
* @see getdelim() for documentation
*/
ssize_t getdelim_unlocked(char **s, size_t *n, int delim, FILE *f) {
ssize_t rc;
char *p, *s2;
size_t i, m, n2;
if ((f->iomode & O_ACCMODE) == O_WRONLY) {
f->state = errno = EBADF;
return -1;
}
if (f->beg > f->end) {
f->state = errno = EINVAL;
return -1;
}
if (!*s) *n = 0;
for (i = 0;; i += m) {
m = f->end - f->beg;
if ((p = memchr(f->buf + f->beg, delim, m))) {
m = p + 1 - (f->buf + f->beg);
}
if (i + m + 1 > *n) {
n2 = i + m + 1;
s2 = realloc(*s, n2);
if (s2) {
*s = s2;
*n = n2;
} else {
f->state = errno;
return -1;
}
}
memcpy(*s + i, f->buf + f->beg, m);
(*s)[i + m] = '\0';
if ((f->beg += m) == f->end) {
f->beg = f->end = 0;
}
if (p) {
return i + m;
} else if (f->fd == -1) {
break;
} else if ((rc = read(f->fd, f->buf, f->size)) != -1) {
if (!rc) break;
f->end = rc;
} else if (errno != EINTR) {
f->state = errno;
return -1;
}
}
f->state = -1;
if (i + m) {
return i + m;
} else {
return -1;
}
}

View file

@ -19,7 +19,15 @@
#include "libc/stdio/stdio.h"
/**
* Reads line from stream.
* Reads line from stream, e.g.
*
* char *line = NULL;
* size_t linesize = 0;
* while (getline(&line, &linesize, stdin) > 0) {
* _chomp(line);
* printf("%s\n", line);
* }
* free(line);
*
* This function delegates to getdelim(), which provides further
* documentation. Concerning lines, please note the \n or \r\n are
@ -30,7 +38,7 @@
* NUL-termination is guaranteed FTMP
* @return number of bytes read, including delim, excluding NUL, or -1
* w/ errno on EOF or error; see ferror() and feof()
* @see xgetline(), getdelim(), gettok_r()
* @see fgetln(), xgetline(), getdelim(), gettok_r()
*/
ssize_t getline(char **line, size_t *n, FILE *f) {
return getdelim(line, n, '\n', f);

View file

@ -25,7 +25,8 @@ typedef struct FILE {
uint32_t nofree; /* 0x24 */
int pid; /* 0x28 */
int lock; /* 0x2c */
char *getln; /* 0x30 */
int reent; /* 0x30 */
char *getln; /* 0x38 */
} FILE;
extern FILE *stdin;
@ -39,6 +40,7 @@ int getc(FILE *) paramsnonnull();
int putc(int, FILE *) paramsnonnull();
int fflush(FILE *);
int fgetc(FILE *) paramsnonnull();
char *fgetln(FILE *, size_t *) paramsnonnull((1));
int ungetc(int, FILE *) paramsnonnull();
int fileno(FILE *) paramsnonnull() nosideeffect;
int fputc(int, FILE *) paramsnonnull();
@ -120,9 +122,9 @@ int fwide(FILE *, int);
cosmopolitan § standard i/o » without mutexes
*/
void flockfile(FILE *);
void funlockfile(FILE *);
int ftrylockfile(FILE *);
void flockfile(FILE *) paramsnonnull();
void funlockfile(FILE *) paramsnonnull();
int ftrylockfile(FILE *) paramsnonnull();
int getc_unlocked(FILE *) paramsnonnull();
int getchar_unlocked(void);
int putc_unlocked(int, FILE *) paramsnonnull();
@ -149,6 +151,7 @@ int fputws_unlocked(const wchar_t *, FILE *);
wint_t ungetwc_unlocked(wint_t, FILE *) paramsnonnull();
int ungetc_unlocked(int, FILE *) paramsnonnull();
int fseeko_unlocked(FILE *, int64_t, int) paramsnonnull();
ssize_t getdelim_unlocked(char **, size_t *, int, FILE *) paramsnonnull();
int fprintf_unlocked(FILE *, const char *, ...) printfesque(2)
paramsnonnull((1, 2)) dontthrow nocallback;
int vfprintf_unlocked(FILE *, const char *, va_list)

View file

@ -1573,18 +1573,6 @@ syscon sock SOCK_NONBLOCK 0x0800 0x0800 0x20000000 0x4000 0x20000000
syscon sock SOCK_DCCP 6 0 0 0 0 0 # what is it?
syscon sock SOCK_PACKET 10 0 0 0 0 0 # what is it?
syscon prsnlty ADDR_COMPAT_LAYOUT 0x0200000 0 0 0 0 0 # linux only
syscon prsnlty READ_IMPLIES_EXEC 0x0400000 0 0 0 0 0 # linux only
syscon prsnlty ADDR_LIMIT_3GB 0x8000000 0 0 0 0 0 # linux only
syscon prsnlty FDPIC_FUNCPTRS 0x0080000 0 0 0 0 0 # linux only
syscon prsnlty STICKY_TIMEOUTS 0x4000000 0 0 0 0 0 # linux only
syscon prsnlty MMAP_PAGE_ZERO 0x0100000 0 0 0 0 0 # linux only
syscon prsnlty ADDR_LIMIT_32BIT 0x0800000 0 0 0 0 0 # linux only
syscon prsnlty WHOLE_SECONDS 0x2000000 0 0 0 0 0 # linux only
syscon prsnlty ADDR_NO_RANDOMIZE 0x0040000 0 0 0 0 0 # linux only
syscon prsnlty SHORT_INODE 0x1000000 0 0 0 0 0 # linux only
syscon prsnlty UNAME26 0x0020000 0 0 0 0 0 # linux only
syscon misc TH_FIN 1 1 1 1 1 1 # consensus
syscon misc TH_SYN 2 2 2 2 2 2 # consensus
syscon misc TH_RST 4 4 4 4 4 4 # consensus

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,ADDR_COMPAT_LAYOUT,0x0200000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,ADDR_LIMIT_32BIT,0x0800000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,ADDR_LIMIT_3GB,0x8000000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,ADDR_NO_RANDOMIZE,0x0040000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,FDPIC_FUNCPTRS,0x0080000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,MMAP_PAGE_ZERO,0x0100000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,READ_IMPLIES_EXEC,0x0400000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,SHORT_INODE,0x1000000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,STICKY_TIMEOUTS,0x4000000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,UNAME26,0x0020000,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon prsnlty,WHOLE_SECONDS,0x2000000,0,0,0,0,0

View file

@ -1,34 +1,17 @@
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_
#include "libc/runtime/symbolic.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern const long ADDR_COMPAT_LAYOUT;
extern const long READ_IMPLIES_EXEC;
extern const long ADDR_LIMIT_3GB;
extern const long FDPIC_FUNCPTRS;
extern const long STICKY_TIMEOUTS;
extern const long MMAP_PAGE_ZERO;
extern const long ADDR_LIMIT_32BIT;
extern const long WHOLE_SECONDS;
extern const long ADDR_NO_RANDOMIZE;
extern const long SHORT_INODE;
extern const long UNAME26;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#define ADDR_COMPAT_LAYOUT SYMBOLIC(ADDR_COMPAT_LAYOUT)
#define READ_IMPLIES_EXEC SYMBOLIC(READ_IMPLIES_EXEC)
#define ADDR_LIMIT_3GB SYMBOLIC(ADDR_LIMIT_3GB)
#define FDPIC_FUNCPTRS SYMBOLIC(FDPIC_FUNCPTRS)
#define STICKY_TIMEOUTS SYMBOLIC(STICKY_TIMEOUTS)
#define MMAP_PAGE_ZERO SYMBOLIC(MMAP_PAGE_ZERO)
#define ADDR_LIMIT_32BIT SYMBOLIC(ADDR_LIMIT_32BIT)
#define WHOLE_SECONDS SYMBOLIC(WHOLE_SECONDS)
#define ADDR_NO_RANDOMIZE SYMBOLIC(ADDR_NO_RANDOMIZE)
#define SHORT_INODE SYMBOLIC(SHORT_INODE)
#define UNAME26 SYMBOLIC(UNAME26)
#define ADDR_COMPAT_LAYOUT 0x0200000
#define READ_IMPLIES_EXEC 0x0400000
#define ADDR_LIMIT_3GB 0x8000000
#define FDPIC_FUNCPTRS 0x0080000
#define STICKY_TIMEOUTS 0x4000000
#define MMAP_PAGE_ZERO 0x0100000
#define ADDR_LIMIT_32BIT 0x0800000
#define WHOLE_SECONDS 0x2000000
#define ADDR_NO_RANDOMIZE 0x0040000
#define SHORT_INODE 0x1000000
#define UNAME26 0x0020000
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_ */