diff options
Diffstat (limited to 'src')
125 files changed, 1492 insertions, 243 deletions
diff --git a/src/complex/cacosh.c b/src/complex/cacosh.c index 76127f75..55b857ce 100644 --- a/src/complex/cacosh.c +++ b/src/complex/cacosh.c @@ -1,6 +1,6 @@ #include "complex_impl.h" -/* acosh(z) = i acos(z) */ +/* acosh(z) = ±i acos(z) */ double complex cacosh(double complex z) { diff --git a/src/complex/catan.c b/src/complex/catan.c index ccc2fb53..b4fe552a 100644 --- a/src/complex/catan.c +++ b/src/complex/catan.c @@ -60,29 +60,6 @@ #include "complex_impl.h" -#define MAXNUM 1.0e308 - -static const double DP1 = 3.14159265160560607910E0; -static const double DP2 = 1.98418714791870343106E-9; -static const double DP3 = 1.14423774522196636802E-17; - -static double _redupi(double x) -{ - double t; - long i; - - t = x/M_PI; - if (t >= 0.0) - t += 0.5; - else - t -= 0.5; - - i = t; /* the multiple */ - t = i; - t = ((x - t * DP1) - t * DP2) - t * DP3; - return t; -} - double complex catan(double complex z) { double complex w; @@ -95,7 +72,7 @@ double complex catan(double complex z) a = 1.0 - x2 - (y * y); t = 0.5 * atan2(2.0 * x, a); - w = _redupi(t); + w = t; t = y - 1.0; a = x2 + (t * t); diff --git a/src/complex/catanf.c b/src/complex/catanf.c index 1d569f2d..faaa907a 100644 --- a/src/complex/catanf.c +++ b/src/complex/catanf.c @@ -55,32 +55,6 @@ #include "complex_impl.h" -#define MAXNUMF 1.0e38F - -static const double DP1 = 3.140625; -static const double DP2 = 9.67502593994140625E-4; -static const double DP3 = 1.509957990978376432E-7; - -static const float float_pi = M_PI; - -static float _redupif(float xx) -{ - float x, t; - long i; - - x = xx; - t = x/float_pi; - if (t >= 0.0f) - t += 0.5f; - else - t -= 0.5f; - - i = t; /* the multiple */ - t = i; - t = ((x - t * DP1) - t * DP2) - t * DP3; - return t; -} - float complex catanf(float complex z) { float complex w; @@ -93,7 +67,7 @@ float complex catanf(float complex z) a = 1.0f - x2 - (y * y); t = 0.5f * atan2f(2.0f * x, a); - w = _redupif(t); + w = t; t = y - 1.0f; a = x2 + (t * t); diff --git a/src/complex/catanl.c b/src/complex/catanl.c index e62526c0..cd2d2b00 100644 --- a/src/complex/catanl.c +++ b/src/complex/catanl.c @@ -67,28 +67,6 @@ long double complex catanl(long double complex z) return catan(z); } #else -static const long double PIL = 3.141592653589793238462643383279502884197169L; -static const long double DP1 = 3.14159265358979323829596852490908531763125L; -static const long double DP2 = 1.6667485837041756656403424829301998703007e-19L; -static const long double DP3 = 1.8830410776607851167459095484560349402753e-39L; - -static long double redupil(long double x) -{ - long double t; - long i; - - t = x / PIL; - if (t >= 0.0L) - t += 0.5L; - else - t -= 0.5L; - - i = t; /* the multiple */ - t = i; - t = ((x - t * DP1) - t * DP2) - t * DP3; - return t; -} - long double complex catanl(long double complex z) { long double complex w; @@ -101,7 +79,7 @@ long double complex catanl(long double complex z) a = 1.0L - x2 - (y * y); t = atan2l(2.0L * x, a) * 0.5L; - w = redupil(t); + w = t; t = y - 1.0L; a = x2 + (t * t); diff --git a/src/conf/sysconf.c b/src/conf/sysconf.c index 60d3e745..8dd5c725 100644 --- a/src/conf/sysconf.c +++ b/src/conf/sysconf.c @@ -220,8 +220,13 @@ long sysconf(int name) return (mem > LONG_MAX) ? LONG_MAX : mem; case JT_MINSIGSTKSZ & 255: case JT_SIGSTKSZ & 255: ; - long val = __getauxval(AT_MINSIGSTKSZ); - if (val < MINSIGSTKSZ) val = MINSIGSTKSZ; + /* Value from auxv/kernel is only sigfame size. Clamp it + * to at least 1k below arch's traditional MINSIGSTKSZ, + * then add 1k of working space for signal handler. */ + unsigned long sigframe_sz = __getauxval(AT_MINSIGSTKSZ); + if (sigframe_sz < MINSIGSTKSZ - 1024) + sigframe_sz = MINSIGSTKSZ - 1024; + unsigned val = sigframe_sz + 1024; if (values[name] == JT_SIGSTKSZ) val += SIGSTKSZ - MINSIGSTKSZ; return val; diff --git a/src/dirent/posix_getdents.c b/src/dirent/posix_getdents.c new file mode 100644 index 00000000..26c16ac6 --- /dev/null +++ b/src/dirent/posix_getdents.c @@ -0,0 +1,11 @@ +#include <dirent.h> +#include <limits.h> +#include <errno.h> +#include "syscall.h" + +ssize_t posix_getdents(int fd, void *buf, size_t len, int flags) +{ + if (flags) return __syscall_ret(-EOPNOTSUPP); + if (len>INT_MAX) len = INT_MAX; + return syscall(SYS_getdents, fd, buf, len); +} diff --git a/src/errno/__strerror.h b/src/errno/__strerror.h index 14925907..0398b5b6 100644 --- a/src/errno/__strerror.h +++ b/src/errno/__strerror.h @@ -97,6 +97,8 @@ E(ESHUTDOWN, "Cannot send after socket shutdown") E(EALREADY, "Operation already in progress") E(EINPROGRESS, "Operation in progress") E(ESTALE, "Stale file handle") +E(EUCLEAN, "Data consistency error") +E(ENAVAIL, "Resource not available") E(EREMOTEIO, "Remote I/O error") E(EDQUOT, "Quota exceeded") E(ENOMEDIUM, "No medium found") diff --git a/src/exit/atexit.c b/src/exit/atexit.c index 854e9fdd..92c91c9d 100644 --- a/src/exit/atexit.c +++ b/src/exit/atexit.c @@ -19,6 +19,7 @@ static struct fl void *a[COUNT]; } builtin, *head; +static int finished_atexit; static int slot; static volatile int lock[1]; volatile int *const __atexit_lockptr = lock; @@ -34,6 +35,10 @@ void __funcs_on_exit() func(arg); LOCK(lock); } + /* Unlock to prevent deadlock if a global dtor + * attempts to call atexit. */ + finished_atexit = 1; + UNLOCK(lock); } void __cxa_finalize(void *dso) @@ -44,6 +49,13 @@ int __cxa_atexit(void (*func)(void *), void *arg, void *dso) { LOCK(lock); + /* Prevent dtors from registering further atexit + * handlers that would never be run. */ + if (finished_atexit) { + UNLOCK(lock); + return -1; + } + /* Defer initialization of head so it can be in BSS */ if (!head) head = &builtin; diff --git a/src/exit/exit.c b/src/exit/exit.c index a6869b37..17b33cc6 100644 --- a/src/exit/exit.c +++ b/src/exit/exit.c @@ -1,6 +1,9 @@ #include <stdlib.h> #include <stdint.h> #include "libc.h" +#include "pthread_impl.h" +#include "atomic.h" +#include "syscall.h" static void dummy() { @@ -26,6 +29,17 @@ weak_alias(libc_exit_fini, __libc_exit_fini); _Noreturn void exit(int code) { + /* Handle potentially concurrent or recursive calls to exit, + * whose behaviors have traditionally been undefined by the + * standards. Using a custom lock here avoids pulling in lock + * machinery and lets us trap recursive calls while supporting + * multiple threads contending to be the one to exit(). */ + static volatile int exit_lock[1]; + int tid = __pthread_self()->tid; + int prev = a_cas(exit_lock, 0, tid); + if (prev == tid) a_crash(); + else if (prev) for (;;) __sys_pause(); + __funcs_on_exit(); __libc_exit_fini(); __stdio_exit(); diff --git a/src/fenv/loongarch64/fenv.S b/src/fenv/loongarch64/fenv.S new file mode 100644 index 00000000..9c38599e --- /dev/null +++ b/src/fenv/loongarch64/fenv.S @@ -0,0 +1,78 @@ +#ifndef __loongarch_soft_float + +#ifdef BROKEN_LOONGARCH_FCSR_ASM +#define FCSR $r0 +#else +#define FCSR $fcsr0 +#endif + +.global feclearexcept +.type feclearexcept,@function +feclearexcept: + li.w $t0, 0x1f0000 + and $a0, $a0, $t0 + movfcsr2gr $t1, FCSR + andn $t1, $t1, $a0 + movgr2fcsr FCSR, $t1 + li.w $a0, 0 + jr $ra + +.global feraiseexcept +.type feraiseexcept,@function +feraiseexcept: + li.w $t0, 0x1f0000 + and $a0, $a0, $t0 + movfcsr2gr $t1, FCSR + or $t1, $t1, $a0 + movgr2fcsr FCSR, $t1 + li.w $a0, 0 + jr $ra + +.global fetestexcept +.type fetestexcept,@function +fetestexcept: + li.w $t0, 0x1f0000 + and $a0, $a0, $t0 + movfcsr2gr $t1, FCSR + and $a0, $t1, $a0 + jr $ra + +.global fegetround +.type fegetround,@function +fegetround: + movfcsr2gr $t0, FCSR + andi $a0, $t0, 0x300 + jr $ra + +.global __fesetround +.hidden __fesetround +.type __fesetround,@function +__fesetround: + li.w $t0, 0x300 + and $a0, $a0, $t0 + movfcsr2gr $t1, FCSR + andn $t1, $t1, $t0 + or $t1, $t1, $a0 + movgr2fcsr FCSR, $t1 + li.w $a0, 0 + jr $ra + +.global fegetenv +.type fegetenv,@function +fegetenv: + movfcsr2gr $t0, FCSR + st.w $t0, $a0, 0 + li.w $a0, 0 + jr $ra + +.global fesetenv +.type fesetenv,@function +fesetenv: + addi.d $t0, $a0, 1 + beq $t0, $r0, 1f + ld.w $t0, $a0, 0 +1: movgr2fcsr FCSR, $t0 + li.w $a0, 0 + jr $ra + +#endif diff --git a/src/fenv/riscv32/fenv-sf.c b/src/fenv/riscv32/fenv-sf.c new file mode 100644 index 00000000..ecd3cb5c --- /dev/null +++ b/src/fenv/riscv32/fenv-sf.c @@ -0,0 +1,3 @@ +#ifndef __riscv_flen +#include "../fenv.c" +#endif diff --git a/src/fenv/riscv32/fenv.S b/src/fenv/riscv32/fenv.S new file mode 100644 index 00000000..0ea78bf9 --- /dev/null +++ b/src/fenv/riscv32/fenv.S @@ -0,0 +1,56 @@ +#ifdef __riscv_flen + +.global feclearexcept +.type feclearexcept, %function +feclearexcept: + csrc fflags, a0 + li a0, 0 + ret + +.global feraiseexcept +.type feraiseexcept, %function +feraiseexcept: + csrs fflags, a0 + li a0, 0 + ret + +.global fetestexcept +.type fetestexcept, %function +fetestexcept: + frflags t0 + and a0, t0, a0 + ret + +.global fegetround +.type fegetround, %function +fegetround: + frrm a0 + ret + +.global __fesetround +.type __fesetround, %function +__fesetround: + fsrm t0, a0 + li a0, 0 + ret + +.global fegetenv +.type fegetenv, %function +fegetenv: + frcsr t0 + sw t0, 0(a0) + li a0, 0 + ret + +.global fesetenv +.type fesetenv, %function +fesetenv: + li t2, -1 + li t1, 0 + beq a0, t2, 1f + lw t1, 0(a0) +1: fscsr t1 + li a0, 0 + ret + +#endif diff --git a/src/internal/atomic.h b/src/internal/atomic.h index 96c1552d..8f71c8cd 100644 --- a/src/internal/atomic.h +++ b/src/internal/atomic.h @@ -194,7 +194,7 @@ static inline void a_store(volatile int *p, int v) #ifndef a_barrier #define a_barrier a_barrier -static void a_barrier() +static inline void a_barrier() { volatile int tmp = 0; a_cas(&tmp, 0, 0); diff --git a/src/internal/dynlink.h b/src/internal/dynlink.h index 06f41d09..40c743e2 100644 --- a/src/internal/dynlink.h +++ b/src/internal/dynlink.h @@ -73,6 +73,10 @@ struct fdpic_dummy_loadmap { #define DL_NOMMU_SUPPORT 0 #endif +#ifndef TLSDESC_BACKWARDS +#define TLSDESC_BACKWARDS 0 +#endif + #if !DL_FDPIC #define IS_RELATIVE(x,s) ( \ (R_TYPE(x) == REL_RELATIVE) || \ diff --git a/src/internal/emulate_wait4.c b/src/internal/emulate_wait4.c new file mode 100644 index 00000000..f6303412 --- /dev/null +++ b/src/internal/emulate_wait4.c @@ -0,0 +1,55 @@ +#include <sys/wait.h> +#include "syscall.h" + +#ifndef SYS_wait4 +hidden long __emulate_wait4(int pid, int *status, int options, void *kru, int cp) +{ + idtype_t t; + int r; + siginfo_t info; + + info.si_pid = 0; + if (pid < -1) { + t = P_PGID; + pid = -pid; + } else if (pid == -1) { + t = P_ALL; + } else if (pid == 0) { + t = P_PGID; + } else { + t = P_PID; + } + + if (cp) r = __syscall_cp(SYS_waitid, t, pid, &info, options|WEXITED, kru); + else r = __syscall(SYS_waitid, t, pid, &info, options|WEXITED, kru); + + if (r<0) return r; + + if (info.si_pid && status) { + int sw=0; + switch (info.si_code) { + case CLD_CONTINUED: + sw = 0xffff; + break; + case CLD_DUMPED: + sw = info.si_status&0x7f | 0x80; + break; + case CLD_EXITED: + sw = (info.si_status&0xff) << 8; + break; + case CLD_KILLED: + sw = info.si_status&0x7f; + break; + case CLD_STOPPED: + case CLD_TRAPPED: + /* see ptrace(2); the high bits of si_status can contain */ + /* PTRACE_EVENT_ values which must be preserved */ + sw = (info.si_status << 8) + 0x7f; + break; + } + *status = sw; + } + + return info.si_pid; +} +#endif diff --git a/src/internal/fork_impl.h b/src/internal/fork_impl.h index 354e733b..f995fce2 100644 --- a/src/internal/fork_impl.h +++ b/src/internal/fork_impl.h @@ -17,3 +17,5 @@ extern hidden volatile int *const __vmlock_lockptr; hidden void __malloc_atfork(int); hidden void __ldso_atfork(int); hidden void __pthread_key_atfork(int); + +hidden void __post_Fork(int); diff --git a/src/internal/syscall.h b/src/internal/syscall.h index 4a446157..2d8a5c13 100644 --- a/src/internal/syscall.h +++ b/src/internal/syscall.h @@ -391,6 +391,29 @@ static inline long __alt_socketcall(int sys, int sock, int cp, syscall_arg_t a, #define __sys_open_cp(...) __SYSCALL_DISP(__sys_open_cp,,__VA_ARGS__) #define sys_open_cp(...) __syscall_ret(__sys_open_cp(__VA_ARGS__)) +#ifdef SYS_pause +#define __sys_pause() __syscall(SYS_pause) +#define __sys_pause_cp() __syscall_cp(SYS_pause) +#else +#define __sys_pause() __syscall(SYS_ppoll, 0, 0, 0, 0) +#define __sys_pause_cp() __syscall_cp(SYS_ppoll, 0, 0, 0, 0) +#endif + +#define sys_pause() __syscall_ret(__sys_pause()) +#define sys_pause_cp() __syscall_ret(__sys_pause_cp()) + +#ifdef SYS_wait4 +#define __sys_wait4(a,b,c,d) __syscall(SYS_wait4,a,b,c,d) +#define __sys_wait4_cp(a,b,c,d) __syscall_cp(SYS_wait4,a,b,c,d) +#else +hidden long __emulate_wait4(int, int *, int, void *, int); +#define __sys_wait4(a,b,c,d) __emulate_wait4(a,b,c,d,0) +#define __sys_wait4_cp(a,b,c,d) __emulate_wait4(a,b,c,d,1) +#endif + +#define sys_wait4(a,b,c,d) __syscall_ret(__sys_wait4(a,b,c,d)) +#define sys_wait4_cp(a,b,c,d) __syscall_ret(__sys_wait4_cp(a,b,c,d)) + hidden void __procfdname(char __buf[static 15+3*sizeof(int)], unsigned); hidden void *__vdsosym(const char *, const char *); diff --git a/src/ldso/loongarch64/dlsym.s b/src/ldso/loongarch64/dlsym.s new file mode 100644 index 00000000..26fabcdb --- /dev/null +++ b/src/ldso/loongarch64/dlsym.s @@ -0,0 +1,7 @@ +.global dlsym +.hidden __dlsym +.type dlsym,@function +dlsym: + move $a2, $ra + la.global $t0, __dlsym + jr $t0 diff --git a/src/ldso/loongarch64/tlsdesc.s b/src/ldso/loongarch64/tlsdesc.s new file mode 100644 index 00000000..4b6ea0e5 --- /dev/null +++ b/src/ldso/loongarch64/tlsdesc.s @@ -0,0 +1,37 @@ +.text +.global __tlsdesc_static +.hidden __tlsdesc_static +.type __tlsdesc_static,%function +__tlsdesc_static: + ld.d $a0, $a0, 8 + jr $ra +# size_t __tlsdesc_dynamic(size_t *a) +# { +# struct {size_t modidx,off;} *p = (void*)a[1]; +# size_t *dtv = *(size_t**)(tp - 8); +# return dtv[p->modidx] + p->off - tp; +# } +.global __tlsdesc_dynamic +.hidden __tlsdesc_dynamic +.type __tlsdesc_dynamic,%function +__tlsdesc_dynamic: + addi.d $sp, $sp, -16 + st.d $t1, $sp, 0 + st.d $t2, $sp, 8 + + ld.d $t2, $tp, -8 # t2=dtv + + ld.d $a0, $a0, 8 # a0=&{modidx,off} + ld.d $t1, $a0, 8 # t1=off + ld.d $a0, $a0, 0 # a0=modidx + slli.d $a0, $a0, 3 # a0=8*modidx + + add.d $a0, $a0, $t2 # a0=dtv+8*modidx + ld.d $a0, $a0, 0 # a0=dtv[modidx] + add.d $a0, $a0, $t1 # a0=dtv[modidx]+off + sub.d $a0, $a0, $tp # a0=dtv[modidx]+off-tp + + ld.d $t1, $sp, 0 + ld.d $t2, $sp, 8 + addi.d $sp, $sp, 16 + jr $ra diff --git a/src/ldso/riscv32/dlsym.s b/src/ldso/riscv32/dlsym.s new file mode 100644 index 00000000..2bafd72d --- /dev/null +++ b/src/ldso/riscv32/dlsym.s @@ -0,0 +1,6 @@ +.global dlsym +.hidden __dlsym +.type dlsym, %function +dlsym: + mv a2, ra + tail __dlsym diff --git a/src/ldso/riscv64/tlsdesc.s b/src/ldso/riscv64/tlsdesc.s new file mode 100644 index 00000000..bef8b322 --- /dev/null +++ b/src/ldso/riscv64/tlsdesc.s @@ -0,0 +1,32 @@ +.text +.global __tlsdesc_static +.hidden __tlsdesc_static +.type __tlsdesc_static,%function +__tlsdesc_static: + ld a0,8(a0) + jr t0 + +.global __tlsdesc_dynamic +.hidden __tlsdesc_dynamic +.type __tlsdesc_dynamic,%function +__tlsdesc_dynamic: + add sp,sp,-16 + sd t1,(sp) + sd t2,8(sp) + + ld t2,-8(tp) # t2=dtv + + ld a0,8(a0) # a0=&{modidx,off} + ld t1,8(a0) # t1=off + ld a0,(a0) # a0=modidx + sll a0,a0,3 # a0=8*modidx + + add a0,a0,t2 # a0=dtv+8*modidx + ld a0,(a0) # a0=dtv[modidx] + add a0,a0,t1 # a0=dtv[modidx]+off + sub a0,a0,tp # a0=dtv[modidx]+off-tp + + ld t1,(sp) + ld t2,8(sp) + add sp,sp,16 + jr t0 diff --git a/src/ldso/sh/dlsym.s b/src/ldso/sh/dlsym.s index 11a6fff5..34f3c35c 100644 --- a/src/ldso/sh/dlsym.s +++ b/src/ldso/sh/dlsym.s @@ -5,7 +5,7 @@ dlsym: mov.l L1, r0 1: braf r0 - mov.l @r15, r6 + sts pr, r6 .align 2 L1: .long __dlsym@PLT-(1b+4-.) diff --git a/src/legacy/getusershell.c b/src/legacy/getusershell.c index 5fecdec2..1c5d98ec 100644 --- a/src/legacy/getusershell.c +++ b/src/legacy/getusershell.c @@ -25,8 +25,10 @@ char *getusershell(void) ssize_t l; if (!f) setusershell(); if (!f) return 0; - l = getline(&line, &linesize, f); - if (l <= 0) return 0; + do { + l = getline(&line, &linesize, f); + if (l <= 0) return 0; + } while (line[0] == '#' || line[0] == '\n'); if (line[l-1]=='\n') line[l-1]=0; return line; } diff --git a/src/linux/cache.c b/src/linux/cache.c index 0eb051c2..e76f7812 100644 --- a/src/linux/cache.c +++ b/src/linux/cache.c @@ -21,7 +21,7 @@ weak_alias(__cachectl, cachectl); #ifdef SYS_riscv_flush_icache #define VDSO_FLUSH_ICACHE_SYM "__vdso_flush_icache" -#define VDSO_FLUSH_ICACHE_VER "LINUX_4.5" +#define VDSO_FLUSH_ICACHE_VER "LINUX_4.15" static void *volatile vdso_func; @@ -45,6 +45,7 @@ int __riscv_flush_icache(void *start, void *end, unsigned long int flags) if (!r) return r; if (r != -ENOSYS) return __syscall_ret(r); } + return syscall(SYS_riscv_flush_icache, start, end, flags); } weak_alias(__riscv_flush_icache, riscv_flush_icache); #endif diff --git a/src/linux/clone.c b/src/linux/clone.c index 8c1af7d3..257c1cec 100644 --- a/src/linux/clone.c +++ b/src/linux/clone.c @@ -4,18 +4,62 @@ #include <sched.h> #include "pthread_impl.h" #include "syscall.h" +#include "lock.h" +#include "fork_impl.h" + +struct clone_start_args { + int (*func)(void *); + void *arg; + sigset_t sigmask; +}; + +static int clone_start(void *arg) +{ + struct clone_start_args *csa = arg; + __post_Fork(0); + __restore_sigs(&csa->sigmask); + return csa->func(csa->arg); +} int clone(int (*func)(void *), void *stack, int flags, void *arg, ...) { + struct clone_start_args csa; va_list ap; - pid_t *ptid, *ctid; - void *tls; + pid_t *ptid = 0, *ctid = 0; + void *tls = 0; + + /* Flags that produce an invalid thread/TLS state are disallowed. */ + int badflags = CLONE_THREAD | CLONE_SETTLS | CLONE_CHILD_CLEARTID; + + if ((flags & badflags) || !stack) + return __syscall_ret(-EINVAL); va_start(ap, arg); - ptid = va_arg(ap, pid_t *); - tls = va_arg(ap, void *); - ctid = va_arg(ap, pid_t *); + if (flags & (CLONE_PIDFD | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID)) + ptid = va_arg(ap, pid_t *); + if (flags & CLONE_CHILD_SETTID) { + tls = va_arg(ap, void *); + ctid = va_arg(ap, pid_t *); + } va_end(ap); - return __syscall_ret(__clone(func, stack, flags, arg, ptid, tls, ctid)); + /* If CLONE_VM is used, it's impossible to give the child a consistent + * thread structure. In this case, the best we can do is assume the + * caller is content with an extremely restrictive execution context + * like the one vfork() would provide. */ + if (flags & CLONE_VM) return __syscall_ret( + __clone(func, stack, flags, arg, ptid, tls, ctid)); + + __block_all_sigs(&csa.sigmask); + LOCK(__abort_lock); + + /* Setup the a wrapper start function for the child process to do + * mimic _Fork in producing a consistent execution state. */ + csa.func = func; + csa.arg = arg; + int ret = __clone(clone_start, stack, flags, &csa, ptid, tls, ctid); + + __post_Fork(ret); + __restore_sigs(&csa.sigmask); + return __syscall_ret(ret); } diff --git a/src/linux/preadv2.c b/src/linux/preadv2.c new file mode 100644 index 00000000..5e7ab70f --- /dev/null +++ b/src/linux/preadv2.c @@ -0,0 +1,17 @@ +#define _GNU_SOURCE +#include <sys/uio.h> +#include <unistd.h> +#include "syscall.h" + +ssize_t preadv2(int fd, const struct iovec *iov, int count, off_t ofs, int flags) +{ +#ifdef SYS_preadv + if (!flags) { + if (ofs==-1) return readv(fd, iov, count); + return syscall_cp(SYS_preadv, fd, iov, count, + (long)(ofs), (long)(ofs>>32)); + } +#endif + return syscall_cp(SYS_preadv2, fd, iov, count, + (long)(ofs), (long)(ofs>>32), flags); +} diff --git a/src/linux/pwritev2.c b/src/linux/pwritev2.c new file mode 100644 index 00000000..ece90d7c --- /dev/null +++ b/src/linux/pwritev2.c @@ -0,0 +1,17 @@ +#define _GNU_SOURCE +#include <sys/uio.h> +#include <unistd.h> +#include "syscall.h" + +ssize_t pwritev2(int fd, const struct iovec *iov, int count, off_t ofs, int flags) +{ +#ifdef SYS_pwritev + if (!flags) { + if (ofs==-1) return writev(fd, iov, count); + return syscall_cp(SYS_pwritev, fd, iov, count, + (long)(ofs), (long)(ofs>>32)); + } +#endif + return syscall_cp(SYS_pwritev2, fd, iov, count, + (long)(ofs), (long)(ofs>>32), flags); +} diff --git a/src/linux/renameat2.c b/src/linux/renameat2.c new file mode 100644 index 00000000..b8060388 --- /dev/null +++ b/src/linux/renameat2.c @@ -0,0 +1,11 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include "syscall.h" + +int renameat2(int oldfd, const char *old, int newfd, const char *new, unsigned flags) +{ +#ifdef SYS_renameat + if (!flags) return syscall(SYS_renameat, oldfd, old, newfd, new); +#endif + return syscall(SYS_renameat2, oldfd, old, newfd, new, flags); +} diff --git a/src/linux/statx.c b/src/linux/statx.c new file mode 100644 index 00000000..4fb96e4b --- /dev/null +++ b/src/linux/statx.c @@ -0,0 +1,44 @@ +#define _GNU_SOURCE +#include <sys/stat.h> +#include <string.h> +#include <syscall.h> +#include <sys/sysmacros.h> +#include <errno.h> + +int statx(int dirfd, const char *restrict path, int flags, unsigned mask, struct statx *restrict stx) +{ + int ret = __syscall(SYS_statx, dirfd, path, flags, mask, stx); + +#ifndef SYS_fstatat + return __syscall_ret(ret); +#endif + + if (ret != -ENOSYS) return __syscall_ret(ret); + + struct stat st; + ret = fstatat(dirfd, path, &st, flags); + if (ret) return ret; + + *stx = (struct statx){0}; + stx->stx_dev_major = major(st.st_dev); + stx->stx_dev_minor = minor(st.st_dev); + stx->stx_rdev_major = major(st.st_rdev); + stx->stx_rdev_minor = minor(st.st_rdev); + stx->stx_ino = st.st_ino; + stx->stx_mode = st.st_mode; + stx->stx_nlink = st.st_nlink; + stx->stx_uid = st.st_uid; + stx->stx_gid = st.st_gid; + stx->stx_size = st.st_size; + stx->stx_blksize = st.st_blksize; + stx->stx_blocks = st.st_blocks; + stx->stx_atime.tv_sec = st.st_atim.tv_sec; + stx->stx_atime.tv_nsec = st.st_atim.tv_nsec; + stx->stx_mtime.tv_sec = st.st_mtim.tv_sec; + stx->stx_mtime.tv_nsec = st.st_mtim.tv_nsec; + stx->stx_ctime.tv_sec = st.st_ctim.tv_sec; + stx->stx_ctime.tv_nsec = st.st_ctim.tv_nsec; + stx->stx_mask = STATX_BASIC_STATS; + + return 0; +} diff --git a/src/linux/wait4.c b/src/linux/wait4.c index ff2e3e66..fb08c0d0 100644 --- a/src/linux/wait4.c +++ b/src/linux/wait4.c @@ -26,7 +26,7 @@ pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru) } #endif char *dest = ru ? (char *)&ru->ru_maxrss - 4*sizeof(long) : 0; - r = __syscall(SYS_wait4, pid, status, options, dest); + r = __sys_wait4(pid, status, options, dest); if (r>0 && ru && sizeof(time_t) > sizeof(long)) { long kru[4]; memcpy(kru, dest, 4*sizeof(long)); diff --git a/src/locale/bind_textdomain_codeset.c b/src/locale/bind_textdomain_codeset.c index 5ebfd5e8..240e83ed 100644 --- a/src/locale/bind_textdomain_codeset.c +++ b/src/locale/bind_textdomain_codeset.c @@ -5,7 +5,9 @@ char *bind_textdomain_codeset(const char *domainname, const char *codeset) { - if (codeset && strcasecmp(codeset, "UTF-8")) + if (codeset && strcasecmp(codeset, "UTF-8")) { errno = EINVAL; - return NULL; + return 0; + } + return "UTF-8"; } diff --git a/src/locale/codepages.h b/src/locale/codepages.h index 4e236ef3..a254f0f5 100644 --- a/src/locale/codepages.h +++ b/src/locale/codepages.h @@ -286,6 +286,17 @@ "\323\174\103\215\64\365\124\123\213\77\336\150\263\115\66\375\164\363\12\55" "\255\304\42\261\57\266\234\162\17\56\260\240\162\113\56\263\310\62\66\50" +"cp858\0" +"\0\40" +"\307\360\223\216\70\344\200\123\316\71\352\254\203\316\73\356\260\103\114\61" +"\311\230\143\14\75\366\310\263\117\76\377\130\303\15\76\243\140\163\15\135" +"\341\264\63\217\76\361\104\243\212\56\277\270\302\112\57\274\204\262\312\56" +"\140\207\55\66\315\72\7\43\14\60\251\104\375\163\321\113\213\122\212\315" +"\67\363\274\163\316\63\367\74\316\60\110\13\175\65\325\116\373\254\65\51" +"\360\100\243\314\62\310\220\334\214\63\317\340\134\163\327\134\233\302\314\326" +"\323\174\103\215\64\365\124\123\213\77\336\150\263\115\66\375\164\363\12\55" +"\255\304\42\261\57\266\234\162\17\56\260\240\162\113\56\263\310\62\66\50" + "cp866\0" "\0\40" "\337\201\27\236\170\343\221\127\236\171\347\241\227\236\172" diff --git a/src/locale/iconv.c b/src/locale/iconv.c index 3047c27b..52178950 100644 --- a/src/locale/iconv.c +++ b/src/locale/iconv.c @@ -49,10 +49,10 @@ static const unsigned char charmaps[] = "ucs4\0utf32\0\0\313" "ucs2\0\0\314" "eucjp\0\0\320" -"shiftjis\0sjis\0\0\321" +"shiftjis\0sjis\0cp932\0\0\321" "iso2022jp\0\0\322" "gb18030\0\0\330" -"gbk\0\0\331" +"gbk\0cp936\0windows936\0\0\331" "gb2312\0\0\332" "big5\0bigfive\0cp950\0big5hkscs\0\0\340" "euckr\0ksc5601\0ksx1001\0cp949\0\0\350" @@ -339,7 +339,10 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri } else if (d-159 <= 252-159) { c++; d -= 159; + } else { + goto ilseq; } + if (c>=84) goto ilseq; c = jis0208[c][d]; if (!c) goto ilseq; break; @@ -403,6 +406,10 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri if (c < 128) break; if (c < 0xa1) goto ilseq; case GBK: + if (c == 128) { + c = 0x20ac; + break; + } case GB18030: if (c < 128) break; c -= 0x81; @@ -495,7 +502,7 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri if (c >= 93 || d >= 94) { c += (0xa1-0x81); d += 0xa1; - if (c >= 93 || c>=0xc6-0x81 && d>0x52) + if (c > 0xc6-0x81 || c==0xc6-0x81 && d>0x52) goto ilseq; if (d-'A'<26) d = d-'A'; else if (d-'a'<26) d = d-'a'+26; @@ -538,6 +545,10 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri if (*outb < k) goto toobig; memcpy(*out, tmp, k); } else k = wctomb_utf8(*out, c); + /* This failure condition should be unreachable, but + * is included to prevent decoder bugs from translating + * into advancement outside the output buffer range. */ + if (k>4) goto ilseq; *out += k; *outb -= k; break; diff --git a/src/math/acoshl.c b/src/math/acoshl.c index 8d4b43f6..943cec17 100644 --- a/src/math/acoshl.c +++ b/src/math/acoshl.c @@ -10,14 +10,18 @@ long double acoshl(long double x) long double acoshl(long double x) { union ldshape u = {x}; - int e = u.i.se & 0x7fff; + int e = u.i.se; if (e < 0x3fff + 1) - /* |x| < 2, invalid if x < 1 or nan */ + /* 0 <= x < 2, invalid if x < 1 */ return log1pl(x-1 + sqrtl((x-1)*(x-1)+2*(x-1))); if (e < 0x3fff + 32) - /* |x| < 0x1p32 */ + /* 2 <= x < 0x1p32 */ return logl(2*x - 1/(x+sqrtl(x*x-1))); + if (e & 0x8000) + /* x < 0 or x = -0, invalid */ + return (x - x) / (x - x); + /* 0x1p32 <= x or nan */ return logl(x) + 0.693147180559945309417232121458176568L; } #elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 diff --git a/src/math/fma.c b/src/math/fma.c index 0c6f90c9..adfadca8 100644 --- a/src/math/fma.c +++ b/src/math/fma.c @@ -53,7 +53,7 @@ double fma(double x, double y, double z) return x*y + z; if (nz.e >= ZEROINFNAN) { if (nz.e > ZEROINFNAN) /* z==0 */ - return x*y + z; + return x*y; return z; } diff --git a/src/math/powl.c b/src/math/powl.c index 5b6da07b..9eb22162 100644 --- a/src/math/powl.c +++ b/src/math/powl.c @@ -57,14 +57,6 @@ * IEEE 0,8700 60000 6.5e-18 1.0e-18 * 0.99 < x < 1.01, 0 < y < 8700, uniformly distributed. * - * - * ERROR MESSAGES: - * - * message condition value returned - * pow overflow x**y > MAXNUM INFINITY - * pow underflow x**y < 1/MAXNUM 0.0 - * pow domain x<0 and y noninteger 0.0 - * */ #include "libm.h" @@ -212,25 +204,33 @@ long double powl(long double x, long double y) } if (x == 1.0) return 1.0; /* 1**y = 1, even if y is nan */ - if (x == -1.0 && !isfinite(y)) - return 1.0; /* -1**inf = 1 */ if (y == 0.0) return 1.0; /* x**0 = 1, even if x is nan */ if (y == 1.0) return x; - if (y >= LDBL_MAX) { - if (x > 1.0 || x < -1.0) - return INFINITY; - if (x != 0.0) - return 0.0; - } - if (y <= -LDBL_MAX) { - if (x > 1.0 || x < -1.0) + /* if y*log2(x) < log2(LDBL_TRUE_MIN)-1 then x^y uflows to 0 + if y*log2(x) > -log2(LDBL_TRUE_MIN)+1 > LDBL_MAX_EXP then x^y oflows + if |x|!=1 then |log2(x)| > |log(x)| > LDBL_EPSILON/2 so + x^y oflows/uflows if |y|*LDBL_EPSILON/2 > -log2(LDBL_TRUE_MIN)+1 */ + if (fabsl(y) > 2*(-LDBL_MIN_EXP+LDBL_MANT_DIG+1)/LDBL_EPSILON) { + /* y is not an odd int */ + if (x == -1.0) + return 1.0; + if (y == INFINITY) { + if (x > 1.0 || x < -1.0) + return INFINITY; return 0.0; - if (x != 0.0 || y == -INFINITY) + } + if (y == -INFINITY) { + if (x > 1.0 || x < -1.0) + return 0.0; return INFINITY; + } + if ((x > 1.0 || x < -1.0) == (y > 0)) + return huge * huge; + return twom10000 * twom10000; } - if (x >= LDBL_MAX) { + if (x == INFINITY) { if (y > 0.0) return INFINITY; return 0.0; @@ -253,7 +253,7 @@ long double powl(long double x, long double y) yoddint = 1; } - if (x <= -LDBL_MAX) { + if (x == -INFINITY) { if (y > 0.0) { if (yoddint) return -INFINITY; diff --git a/src/math/riscv32/copysign.c b/src/math/riscv32/copysign.c new file mode 100644 index 00000000..c7854178 --- /dev/null +++ b/src/math/riscv32/copysign.c @@ -0,0 +1,15 @@ +#include <math.h> + +#if __riscv_flen >= 64 + +double copysign(double x, double y) +{ + __asm__ ("fsgnj.d %0, %1, %2" : "=f"(x) : "f"(x), "f"(y)); + return x; +} + +#else + +#include "../copysign.c" + +#endif diff --git a/src/math/riscv32/copysignf.c b/src/math/riscv32/copysignf.c new file mode 100644 index 00000000..a125611a --- /dev/null +++ b/src/math/riscv32/copysignf.c @@ -0,0 +1,15 @@ +#include <math.h> + +#if __riscv_flen >= 32 + +float copysignf(float x, float y) +{ + __asm__ ("fsgnj.s %0, %1, %2" : "=f"(x) : "f"(x), "f"(y)); + return x; +} + +#else + +#include "../copysignf.c" + +#endif diff --git a/src/math/riscv32/fabs.c b/src/math/riscv32/fabs.c new file mode 100644 index 00000000..5290b6f0 --- /dev/null +++ b/src/math/riscv32/fabs.c @@ -0,0 +1,15 @@ +#include <math.h> + +#if __riscv_flen >= 64 + +double fabs(double x) +{ + __asm__ ("fabs.d %0, %1" : "=f"(x) : "f"(x)); + return x; +} + +#else + +#include "../fabs.c" + +#endif diff --git a/src/math/riscv32/fabsf.c b/src/math/riscv32/fabsf.c new file mode 100644 index 00000000..f5032e35 --- /dev/null +++ b/src/math/riscv32/fabsf.c @@ -0,0 +1,15 @@ +#include <math.h> + +#if __riscv_flen >= 32 + +float fabsf(float x) +{ + __asm__ ("fabs.s %0, %1" : "=f"(x) : "f"(x)); + return x; +} + +#else + +#include "../fabsf.c" + +#endif diff --git a/src/math/riscv32/fma.c b/src/math/riscv32/fma.c new file mode 100644 index 00000000..99b05713 --- /dev/null +++ b/src/math/riscv32/fma.c @@ -0,0 +1,15 @@ +#include <math.h> + +#if __riscv_flen >= 64 + +double fma(double x, double y, double z) +{ + __asm__ ("fmadd.d %0, %1, %2, %3" : "=f"(x) : "f"(x), "f"(y), "f"(z)); + return x; +} + +#else + +#include "../fma.c" + +#endif diff --git a/src/math/riscv32/fmaf.c b/src/math/riscv32/fmaf.c new file mode 100644 index 00000000..f9dc47ed --- /dev/null +++ b/src/math/riscv32/fmaf.c @@ -0,0 +1,15 @@ +#include <math.h> + +#if __riscv_flen >= 32 + +float fmaf(float x, float y, float z) +{ + __asm__ ("fmadd.s %0, %1, %2, %3" : "=f"(x) : "f"(x), "f"(y), "f"(z)); + return x; +} + +#else + +#include "../fmaf.c" + +#endif diff --git a/src/math/riscv32/fmax.c b/src/math/riscv32/fmax.c new file mode 100644 index 00000000..023709cd --- /dev/null +++ b/src/math/riscv32/fmax.c @@ -0,0 +1,15 @@ +#include <math.h> + +#if __riscv_flen >= 64 + +double fmax(double x, double y) +{ + __asm__ ("fmax.d %0, %1, %2" : "=f"(x) : "f"(x), "f"(y)); + return x; +} + +#else + +#include "../fmax.c" + +#endif diff --git a/src/math/riscv32/fmaxf.c b/src/math/riscv32/fmaxf.c new file mode 100644 index 00000000..863d2bd1 --- /dev/null +++ b/src/math/riscv32/fmaxf.c @@ -0,0 +1,15 @@ +#include <math.h> + +#if __riscv_flen >= 32 + +float fmaxf(float x, float y) +{ + __asm__ ("fmax.s %0, %1, %2" : "=f"(x) : "f"(x), "f"(y)); + return x; +} + +#else + +#include "../fmaxf.c" + +#endif diff --git a/src/math/riscv32/fmin.c b/src/math/riscv32/fmin.c new file mode 100644 index 00000000..a4e3b067 --- /dev/null +++ b/src/math/riscv32/fmin.c @@ -0,0 +1,15 @@ +#include <math.h> + +#if __riscv_flen >= 64 + +double fmin(double x, double y) +{ + __asm__ ("fmin.d %0, %1, %2" : "=f"(x) : "f"(x), "f"(y)); + return x; +} + +#else + +#include "../fmin.c" + +#endif diff --git a/src/math/riscv32/fminf.c b/src/math/riscv32/fminf.c new file mode 100644 index 00000000..32156e80 --- /dev/null +++ b/src/math/riscv32/fminf.c @@ -0,0 +1,15 @@ +#include <math.h> + +#if __riscv_flen >= 32 + +float fminf(float x, float y) +{ + __asm__ ("fmin.s %0, %1, %2" : "=f"(x) : "f"(x), "f"(y)); + return x; +} + +#else + +#include "../fminf.c" + +#endif diff --git a/src/math/riscv32/sqrt.c b/src/math/riscv32/sqrt.c new file mode 100644 index 00000000..867a504c --- /dev/null +++ b/src/math/riscv32/sqrt.c @@ -0,0 +1,15 @@ +#include <math.h> + +#if __riscv_flen >= 64 + +double sqrt(double x) +{ + __asm__ ("fsqrt.d %0, %1" : "=f"(x) : "f"(x)); + return x; +} + +#else + +#include "../sqrt.c" + +#endif diff --git a/src/math/riscv32/sqrtf.c b/src/math/riscv32/sqrtf.c new file mode 100644 index 00000000..610c2cf8 --- /dev/null +++ b/src/math/riscv32/sqrtf.c @@ -0,0 +1,15 @@ +#include <math.h> + +#if __riscv_flen >= 32 + +float sqrtf(float x) +{ + __asm__ ("fsqrt.s %0, %1" : "=f"(x) : "f"(x)); + return x; +} + +#else + +#include "../sqrtf.c" + +#endif diff --git a/src/math/sqrtl.c b/src/math/sqrtl.c index 1b9f19c7..a231b3f2 100644 --- a/src/math/sqrtl.c +++ b/src/math/sqrtl.c @@ -205,7 +205,7 @@ long double sqrtl(long double x) top = (top + 0x3fff) >> 1; /* r ~ 1/sqrt(m) */ - static const uint64_t three = 0xc0000000; + const uint64_t three = 0xc0000000; uint64_t r, s, d, u, i; i = (ix.hi >> 42) % 128; r = (uint32_t)__rsqrt_tab[i] << 16; @@ -227,7 +227,7 @@ long double sqrtl(long double x) r = mul64(u, r) << 1; /* |r sqrt(m) - 1| < 0x1.c001p-59, switch to 128bit */ - static const u128 threel = {.hi=three<<32, .lo=0}; + const u128 threel = {.hi=three<<32, .lo=0}; u128 rl, sl, dl, ul; rl.hi = r; rl.lo = 0; diff --git a/src/misc/initgroups.c b/src/misc/initgroups.c index 922a9581..101f5c7b 100644 --- a/src/misc/initgroups.c +++ b/src/misc/initgroups.c @@ -1,11 +1,29 @@ #define _GNU_SOURCE #include <grp.h> #include <limits.h> +#include <stdlib.h> int initgroups(const char *user, gid_t gid) { - gid_t groups[NGROUPS_MAX]; - int count = NGROUPS_MAX; - if (getgrouplist(user, gid, groups, &count) < 0) return -1; - return setgroups(count, groups); + gid_t buf[32], *groups = buf; + int count = sizeof buf / sizeof *buf, prev_count = count; + while (getgrouplist(user, gid, groups, &count) < 0) { + if (groups != buf) free(groups); + + /* Return if failure isn't buffer size */ + if (count <= prev_count) + return -1; + + /* Always increase by at least 50% to limit to + * logarithmically many retries on TOCTOU races. */ + if (count < prev_count + (prev_count>>1)) + count = prev_count + (prev_count>>1); + + groups = calloc(count, sizeof *groups); + if (!groups) return -1; + prev_count = count; + } + int ret = setgroups(count, groups); + if (groups != buf) free(groups); + return ret; } diff --git a/src/misc/mntent.c b/src/misc/mntent.c index d404fbe3..76f9c162 100644 --- a/src/misc/mntent.c +++ b/src/misc/mntent.c @@ -20,6 +20,42 @@ int endmntent(FILE *f) return 1; } +static char *unescape_ent(char *beg) +{ + char *dest = beg; + const char *src = beg; + while (*src) { + const char *val; + unsigned char cval = 0; + if (*src != '\\') { + *dest++ = *src++; + continue; + } + if (src[1] == '\\') { + ++src; + *dest++ = *src++; + continue; + } + val = src + 1; + for (int i = 0; i < 3; ++i) { + if (*val >= '0' && *val <= '7') { + cval <<= 3; + cval += *val++ - '0'; + } else { + break; + } + } + if (cval) { + *dest++ = cval; + src = val; + } else { + *dest++ = *src++; + } + } + *dest = 0; + return beg; +} + struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen) { int n[8], use_internal = (linebuf == SENTINEL); @@ -45,7 +81,7 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle len = strlen(linebuf); if (len > INT_MAX) continue; for (i = 0; i < sizeof n / sizeof *n; i++) n[i] = len; - sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", + sscanf(linebuf, " %n%*[^ \t\n]%n %n%*[^ \t\n]%n %n%*[^ \t\n]%n %n%*[^ \t\n]%n %d %d", n, n+1, n+2, n+3, n+4, n+5, n+6, n+7, &mnt->mnt_freq, &mnt->mnt_passno); } while (linebuf[n[0]] == '#' || n[1]==len); @@ -55,10 +91,10 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle linebuf[n[5]] = 0; linebuf[n[7]] = 0; - mnt->mnt_fsname = linebuf+n[0]; - mnt->mnt_dir = linebuf+n[2]; - mnt->mnt_type = linebuf+n[4]; - mnt->mnt_opts = linebuf+n[6]; + mnt->mnt_fsname = unescape_ent(linebuf+n[0]); + mnt->mnt_dir = unescape_ent(linebuf+n[2]); + mnt->mnt_type = unescape_ent(linebuf+n[4]); + mnt->mnt_opts = unescape_ent(linebuf+n[6]); return mnt; } @@ -79,5 +115,13 @@ int addmntent(FILE *f, const struct mntent *mnt) char *hasmntopt(const struct mntent *mnt, const char *opt) { - return strstr(mnt->mnt_opts, opt); + size_t l = strlen(opt); + char *p = mnt->mnt_opts; + for (;;) { + if (!strncmp(p, opt, l) && (!p[l] || p[l]==',' || p[l]=='=')) + return p; + p = strchr(p, ','); + if (!p) return 0; + p++; + } } diff --git a/src/misc/syslog.c b/src/misc/syslog.c index 7dc0c1be..710202f9 100644 --- a/src/misc/syslog.c +++ b/src/misc/syslog.c @@ -11,6 +11,7 @@ #include <fcntl.h> #include "lock.h" #include "fork_impl.h" +#include "locale_impl.h" static volatile int lock[1]; static char log_ident[32]; @@ -99,7 +100,7 @@ static void _vsyslog(int priority, const char *message, va_list ap) now = time(NULL); gmtime_r(&now, &tm); - strftime(timebuf, sizeof timebuf, "%b %e %T", &tm); + strftime_l(timebuf, sizeof timebuf, "%b %e %T", &tm, C_LOCALE); pid = (log_opt & LOG_PID) ? getpid() : 0; l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ", diff --git a/src/mq/x32/mq_open.c b/src/mq/x32/mq_open.c new file mode 100644 index 00000000..23481959 --- /dev/null +++ b/src/mq/x32/mq_open.c @@ -0,0 +1,22 @@ +#include <mqueue.h> +#include <fcntl.h> +#include <stdarg.h> +#include "syscall.h" + +mqd_t mq_open(const char *name, int flags, ...) +{ + mode_t mode = 0; + struct mq_attr *attr = 0; + long long attrbuf[8]; + if (*name == '/') name++; + if (flags & O_CREAT) { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + attr = va_arg(ap, struct mq_attr *); + if (attr) for (int i=0; i<8; i++) + attrbuf[i] = *(long *)((char *)attr + i*sizeof(long)); + va_end(ap); + } + return syscall(SYS_mq_open, name, flags, mode, attr?attrbuf:0); +} diff --git a/src/mq/x32/mq_setattr.c b/src/mq/x32/mq_setattr.c new file mode 100644 index 00000000..0c631175 --- /dev/null +++ b/src/mq/x32/mq_setattr.c @@ -0,0 +1,14 @@ +#include <mqueue.h> +#include "syscall.h" + +int mq_setattr(mqd_t mqd, const struct mq_attr *restrict new, struct mq_attr *restrict old) +{ + long long attr[8]; + if (new) for (int i=0; i<8; i++) + attr[i] = *(long *)((char *)new + i*sizeof(long)); + int ret = __syscall(SYS_mq_getsetattr, mqd, new?attr:0, old?attr:0); + if (ret < 0) return __syscall_ret(ret); + if (old) for (int i=0; i<8; i++) + *(long *)((char *)old + i*sizeof(long)) = attr[i]; + return 0; +} diff --git a/src/multibyte/mbrtowc.c b/src/multibyte/mbrtowc.c index c94819e7..7824997e 100644 --- a/src/multibyte/mbrtowc.c +++ b/src/multibyte/mbrtowc.c @@ -8,7 +8,7 @@ size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate static unsigned internal_state; unsigned c; const unsigned char *s = (const void *)src; - const unsigned N = n; + const size_t N = n; wchar_t dummy; if (!st) st = (void *)&internal_state; diff --git a/src/multibyte/mbsnrtowcs.c b/src/multibyte/mbsnrtowcs.c index 931192e2..47cbdc00 100644 --- a/src/multibyte/mbsnrtowcs.c +++ b/src/multibyte/mbsnrtowcs.c @@ -2,11 +2,13 @@ size_t mbsnrtowcs(wchar_t *restrict wcs, const char **restrict src, size_t n, size_t wn, mbstate_t *restrict st) { + static unsigned internal_state; size_t l, cnt=0, n2; wchar_t *ws, wbuf[256]; const char *s = *src; const char *tmp_s; + if (!st) st = (void *)&internal_state; if (!wcs) ws = wbuf, wn = sizeof wbuf / sizeof *wbuf; else ws = wcs; @@ -41,8 +43,8 @@ size_t mbsnrtowcs(wchar_t *restrict wcs, const char **restrict src, size_t n, si s = 0; break; } - /* have to roll back partial character */ - *(unsigned *)st = 0; + s += n; + n -= n; break; } s += l; n -= l; diff --git a/src/network/dns_parse.c b/src/network/dns_parse.c index 7f83e791..09813112 100644 --- a/src/network/dns_parse.c +++ b/src/network/dns_parse.c @@ -12,16 +12,15 @@ int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, c p = r+12; qdcount = r[4]*256 + r[5]; ancount = r[6]*256 + r[7]; - if (qdcount+ancount > 64) return -1; while (qdcount--) { while (p-r < rlen && *p-1U < 127) p++; - if (p>r+rlen-6 || *p>193 || (*p==193 && p[1]>254)) + if (p>r+rlen-6) return -1; p += 5 + !!*p; } while (ancount--) { while (p-r < rlen && *p-1U < 127) p++; - if (p>r+rlen-12 || *p>193 || (*p==193 && p[1]>254)) + if (p>r+rlen-12) return -1; p += 1 + !!*p; len = p[8]*256 + p[9]; diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c index 7abe0fa9..133c15b3 100644 --- a/src/network/getnameinfo.c +++ b/src/network/getnameinfo.c @@ -162,8 +162,10 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl, query[3] = 0; /* don't need AD flag */ int rlen = __res_send(query, qlen, reply, sizeof reply); buf[0] = 0; - if (rlen > 0) + if (rlen > 0) { + if (rlen > sizeof reply) rlen = sizeof reply; __dns_parse(reply, rlen, dns_parse_callback, buf); + } } if (!*buf) { if (flags & NI_NAMEREQD) return EAI_NONAME; diff --git a/src/network/inet_ntop.c b/src/network/inet_ntop.c index 4bfef2c5..f442f47d 100644 --- a/src/network/inet_ntop.c +++ b/src/network/inet_ntop.c @@ -34,7 +34,12 @@ const char *inet_ntop(int af, const void *restrict a0, char *restrict s, socklen for (i=best=0, max=2; buf[i]; i++) { if (i && buf[i] != ':') continue; j = strspn(buf+i, ":0"); - if (j>max) best=i, max=j; + /* The leading sequence of zeros (best==0) is + * disadvantaged compared to sequences elsewhere + * as it doesn't have a leading colon. One extra + * character is required for another sequence to + * beat it fairly. */ + if (j>max+(best==0)) best=i, max=j; } if (max>3) { buf[best] = buf[best+1] = ':'; diff --git a/src/network/lookup_name.c b/src/network/lookup_name.c index 4281482e..35218185 100644 --- a/src/network/lookup_name.c +++ b/src/network/lookup_name.c @@ -109,7 +109,7 @@ struct dpc_ctx { #define RR_CNAME 5 #define RR_AAAA 28 -#define ABUF_SIZE 768 +#define ABUF_SIZE 4800 static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen) { diff --git a/src/network/res_msend.c b/src/network/res_msend.c index 86c2fcf4..fcb52513 100644 --- a/src/network/res_msend.c +++ b/src/network/res_msend.c @@ -83,8 +83,8 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries, int fd; int timeout, attempts, retry_interval, servfail_retry; union { - struct sockaddr_in sin; struct sockaddr_in6 sin6; + struct sockaddr_in sin; } sa = {0}, ns[MAXNS] = {{0}}; socklen_t sl = sizeof sa.sin; int nns = 0; diff --git a/src/process/_Fork.c b/src/process/_Fork.c index fb0fdc2c..9c07792d 100644 --- a/src/process/_Fork.c +++ b/src/process/_Fork.c @@ -5,24 +5,16 @@ #include "lock.h" #include "pthread_impl.h" #include "aio_impl.h" +#include "fork_impl.h" static void dummy(int x) { } weak_alias(dummy, __aio_atfork); -pid_t _Fork(void) +void __post_Fork(int ret) { - pid_t ret; - sigset_t set; - __block_all_sigs(&set); - LOCK(__abort_lock); -#ifdef SYS_fork - ret = __syscall(SYS_fork); -#else - ret = __syscall(SYS_clone, SIGCHLD, 0); -#endif if (!ret) { pthread_t self = __pthread_self(); - self->tid = __syscall(SYS_gettid); + self->tid = __syscall(SYS_set_tid_address, &__thread_list_lock); self->robust_list.off = 0; self->robust_list.pending = 0; self->next = self->prev = self; @@ -32,6 +24,20 @@ pid_t _Fork(void) } UNLOCK(__abort_lock); if (!ret) __aio_atfork(1); +} + +pid_t _Fork(void) +{ + pid_t ret; + sigset_t set; + __block_all_sigs(&set); + LOCK(__abort_lock); +#ifdef SYS_fork + ret = __syscall(SYS_fork); +#else + ret = __syscall(SYS_clone, SIGCHLD, 0); +#endif + __post_Fork(ret); __restore_sigs(&set); return __syscall_ret(ret); } diff --git a/src/process/posix_spawn.c b/src/process/posix_spawn.c index 728551b3..8294598b 100644 --- a/src/process/posix_spawn.c +++ b/src/process/posix_spawn.c @@ -4,6 +4,7 @@ #include <unistd.h> #include <signal.h> #include <fcntl.h> +#include <errno.h> #include <sys/wait.h> #include "syscall.h" #include "lock.h" @@ -156,7 +157,11 @@ static int child(void *args_vp) fail: /* Since sizeof errno < PIPE_BUF, the write is atomic. */ ret = -ret; - if (ret) while (__syscall(SYS_write, p, &ret, sizeof ret) < 0); + if (ret) { + int r; + do r = __syscall(SYS_write, p, &ret, sizeof ret); + while (r<0 && r!=-EPIPE); + } _exit(127); } diff --git a/src/process/waitpid.c b/src/process/waitpid.c index 1b65bf05..80231862 100644 --- a/src/process/waitpid.c +++ b/src/process/waitpid.c @@ -3,5 +3,5 @@ pid_t waitpid(pid_t pid, int *status, int options) { - return syscall_cp(SYS_wait4, pid, status, options, 0); + return sys_wait4_cp(pid, status, options, 0); } diff --git a/src/regex/glob.c b/src/regex/glob.c index a4906446..87bae084 100644 --- a/src/regex/glob.c +++ b/src/regex/glob.c @@ -265,7 +265,7 @@ int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, i if (append(&tail, pat, strlen(pat), 0)) return GLOB_NOSPACE; cnt++; - } else + } else if (!error) return GLOB_NOMATCH; } diff --git a/src/linux/ppoll.c b/src/select/ppoll.c index e614600a..9a0bf929 100644 --- a/src/linux/ppoll.c +++ b/src/select/ppoll.c @@ -1,4 +1,4 @@ -#define _GNU_SOURCE +#define _BSD_SOURCE #include <poll.h> #include <signal.h> #include <errno.h> diff --git a/src/setjmp/loongarch64/longjmp.S b/src/setjmp/loongarch64/longjmp.S new file mode 100644 index 00000000..896d2e26 --- /dev/null +++ b/src/setjmp/loongarch64/longjmp.S @@ -0,0 +1,32 @@ +.global _longjmp +.global longjmp +.type _longjmp,@function +.type longjmp,@function +_longjmp: +longjmp: + ld.d $ra, $a0, 0 + ld.d $sp, $a0, 8 + ld.d $r21,$a0, 16 + ld.d $fp, $a0, 24 + ld.d $s0, $a0, 32 + ld.d $s1, $a0, 40 + ld.d $s2, $a0, 48 + ld.d $s3, $a0, 56 + ld.d $s4, $a0, 64 + ld.d $s5, $a0, 72 + ld.d $s6, $a0, 80 + ld.d $s7, $a0, 88 + ld.d $s8, $a0, 96 +#ifndef __loongarch_soft_float + fld.d $fs0, $a0, 104 + fld.d $fs1, $a0, 112 + fld.d $fs2, $a0, 120 + fld.d $fs3, $a0, 128 + fld.d $fs4, $a0, 136 + fld.d $fs5, $a0, 144 + fld.d $fs6, $a0, 152 + fld.d $fs7, $a0, 160 +#endif + sltui $a0, $a1, 1 + add.d $a0, $a0, $a1 + jr $ra diff --git a/src/setjmp/loongarch64/setjmp.S b/src/setjmp/loongarch64/setjmp.S new file mode 100644 index 00000000..d158a3d2 --- /dev/null +++ b/src/setjmp/loongarch64/setjmp.S @@ -0,0 +1,34 @@ +.global __setjmp +.global _setjmp +.global setjmp +.type __setjmp,@function +.type _setjmp,@function +.type setjmp,@function +__setjmp: +_setjmp: +setjmp: + st.d $ra, $a0, 0 + st.d $sp, $a0, 8 + st.d $r21,$a0, 16 + st.d $fp, $a0, 24 + st.d $s0, $a0, 32 + st.d $s1, $a0, 40 + st.d $s2, $a0, 48 + st.d $s3, $a0, 56 + st.d $s4, $a0, 64 + st.d $s5, $a0, 72 + st.d $s6, $a0, 80 + st.d $s7, $a0, 88 + st.d $s8, $a0, 96 +#ifndef __loongarch_soft_float + fst.d $fs0, $a0, 104 + fst.d $fs1, $a0, 112 + fst.d $fs2, $a0, 120 + fst.d $fs3, $a0, 128 + fst.d $fs4, $a0, 136 + fst.d $fs5, $a0, 144 + fst.d $fs6, $a0, 152 + fst.d $fs7, $a0, 160 +#endif + move $a0, $zero + jr $ra diff --git a/src/setjmp/riscv32/longjmp.S b/src/setjmp/riscv32/longjmp.S new file mode 100644 index 00000000..f9cb3318 --- /dev/null +++ b/src/setjmp/riscv32/longjmp.S @@ -0,0 +1,42 @@ +.global __longjmp +.global _longjmp +.global longjmp +.type __longjmp, %function +.type _longjmp, %function +.type longjmp, %function +__longjmp: +_longjmp: +longjmp: + lw s0, 0(a0) + lw s1, 4(a0) + lw s2, 8(a0) + lw s3, 12(a0) + lw s4, 16(a0) + lw s5, 20(a0) + lw s6, 24(a0) + lw s7, 28(a0) + lw s8, 32(a0) + lw s9, 36(a0) + lw s10, 40(a0) + lw s11, 44(a0) + lw sp, 48(a0) + lw ra, 52(a0) + +#ifndef __riscv_float_abi_soft + fld fs0, 56(a0) + fld fs1, 64(a0) + fld fs2, 72(a0) + fld fs3, 80(a0) + fld fs4, 88(a0) + fld fs5, 96(a0) + fld fs6, 104(a0) + fld fs7, 112(a0) + fld fs8, 120(a0) + fld fs9, 128(a0) + fld fs10, 136(a0) + fld fs11, 144(a0) +#endif + + seqz a0, a1 + add a0, a0, a1 + ret diff --git a/src/setjmp/riscv32/setjmp.S b/src/setjmp/riscv32/setjmp.S new file mode 100644 index 00000000..8a75cf55 --- /dev/null +++ b/src/setjmp/riscv32/setjmp.S @@ -0,0 +1,41 @@ +.global __setjmp +.global _setjmp +.global setjmp +.type __setjmp, %function +.type _setjmp, %function +.type setjmp, %function +__setjmp: +_setjmp: +setjmp: + sw s0, 0(a0) + sw s1, 4(a0) + sw s2, 8(a0) + sw s3, 12(a0) + sw s4, 16(a0) + sw s5, 20(a0) + sw s6, 24(a0) + sw s7, 28(a0) + sw s8, 32(a0) + sw s9, 36(a0) + sw s10, 40(a0) + sw s11, 44(a0) + sw sp, 48(a0) + sw ra, 52(a0) + +#ifndef __riscv_float_abi_soft + fsd fs0, 56(a0) + fsd fs1, 64(a0) + fsd fs2, 72(a0) + fsd fs3, 80(a0) + fsd fs4, 88(a0) + fsd fs5, 96(a0) + fsd fs6, 104(a0) + fsd fs7, 112(a0) + fsd fs8, 120(a0) + fsd fs9, 128(a0) + fsd fs10, 136(a0) + fsd fs11, 144(a0) +#endif + + li a0, 0 + ret diff --git a/src/signal/loongarch64/restore.s b/src/signal/loongarch64/restore.s new file mode 100644 index 00000000..d90a8ebb --- /dev/null +++ b/src/signal/loongarch64/restore.s @@ -0,0 +1,10 @@ +.global __restore_rt +.global __restore +.hidden __restore_rt +.hidden __restore +.type __restore_rt,@function +.type __restore,@function +__restore_rt: +__restore: + li.w $a7, 139 + syscall 0 diff --git a/src/signal/loongarch64/sigsetjmp.s b/src/signal/loongarch64/sigsetjmp.s new file mode 100644 index 00000000..9c0e3ae2 --- /dev/null +++ b/src/signal/loongarch64/sigsetjmp.s @@ -0,0 +1,25 @@ +.global sigsetjmp +.global __sigsetjmp +.type sigsetjmp,@function +.type __sigsetjmp,@function +sigsetjmp: +__sigsetjmp: + beq $a1, $zero, 1f + st.d $ra, $a0, 184 + st.d $s0, $a0, 200 #184+8+8 + move $s0, $a0 + + la.global $t0, setjmp + jirl $ra, $t0, 0 + + move $a1, $a0 # Return from 'setjmp' or 'longjmp' + move $a0, $s0 + ld.d $ra, $a0, 184 + ld.d $s0, $a0, 200 #184+8+8 + +.hidden __sigsetjmp_tail + la.global $t0, __sigsetjmp_tail + jr $t0 +1: + la.global $t0, setjmp + jr $t0 diff --git a/src/signal/riscv32/restore.s b/src/signal/riscv32/restore.s new file mode 100644 index 00000000..5a0af695 --- /dev/null +++ b/src/signal/riscv32/restore.s @@ -0,0 +1,10 @@ +.global __restore +.hidden __restore +.type __restore, %function +__restore: +.global __restore_rt +.hidden __restore_rt +.type __restore_rt, %function +__restore_rt: + li a7, 139 # SYS_rt_sigreturn + ecall diff --git a/src/signal/riscv32/sigsetjmp.s b/src/signal/riscv32/sigsetjmp.s new file mode 100644 index 00000000..c1caeab1 --- /dev/null +++ b/src/signal/riscv32/sigsetjmp.s @@ -0,0 +1,23 @@ +.global sigsetjmp +.global __sigsetjmp +.type sigsetjmp, %function +.type __sigsetjmp, %function +sigsetjmp: +__sigsetjmp: + bnez a1, 1f + tail setjmp +1: + + sw ra, 152(a0) + sw s0, 164(a0) + mv s0, a0 + + call setjmp + + mv a1, a0 + mv a0, s0 + lw s0, 164(a0) + lw ra, 152(a0) + +.hidden __sigsetjmp_tail + tail __sigsetjmp_tail diff --git a/src/signal/riscv64/restore.s b/src/signal/riscv64/restore.s index 40012c75..5a0af695 100644 --- a/src/signal/riscv64/restore.s +++ b/src/signal/riscv64/restore.s @@ -1,7 +1,9 @@ .global __restore +.hidden __restore .type __restore, %function __restore: .global __restore_rt +.hidden __restore_rt .type __restore_rt, %function __restore_rt: li a7, 139 # SYS_rt_sigreturn diff --git a/src/signal/sh/sigsetjmp.s b/src/signal/sh/sigsetjmp.s index 1e2270be..f0f604e2 100644 --- a/src/signal/sh/sigsetjmp.s +++ b/src/signal/sh/sigsetjmp.s @@ -27,7 +27,7 @@ __sigsetjmp: mov.l 3f, r0 4: braf r0 - mov.l @(4+8,r4), r8 + mov.l @(4+8,r6), r8 9: mov.l 5f, r0 6: braf r0 diff --git a/src/signal/sigaltstack.c b/src/signal/sigaltstack.c index d3a6e821..616625c5 100644 --- a/src/signal/sigaltstack.c +++ b/src/signal/sigaltstack.c @@ -1,11 +1,13 @@ #include <signal.h> #include <errno.h> +#include <unistd.h> #include "syscall.h" int sigaltstack(const stack_t *restrict ss, stack_t *restrict old) { if (ss) { - if (!(ss->ss_flags & SS_DISABLE) && ss->ss_size < MINSIGSTKSZ) { + size_t min = sysconf(_SC_MINSIGSTKSZ); + if (!(ss->ss_flags & SS_DISABLE) && ss->ss_size < min) { errno = ENOMEM; return -1; } diff --git a/src/signal/siglongjmp.c b/src/signal/siglongjmp.c index bc317acc..53789b23 100644 --- a/src/signal/siglongjmp.c +++ b/src/signal/siglongjmp.c @@ -5,5 +5,10 @@ _Noreturn void siglongjmp(sigjmp_buf buf, int ret) { + /* If sigsetjmp was called with nonzero savemask flag, the address + * longjmp will return to is inside of sigsetjmp. The signal mask + * will then be restored in the returned-to context instead of here, + * which matters if the context we are returning from may not have + * sufficient stack space for signal delivery. */ longjmp(buf, ret); } diff --git a/src/signal/sigpause.c b/src/signal/sigpause.c index 363d2fec..1587c391 100644 --- a/src/signal/sigpause.c +++ b/src/signal/sigpause.c @@ -4,6 +4,6 @@ int sigpause(int sig) { sigset_t mask; sigprocmask(0, 0, &mask); - sigdelset(&mask, sig); + if (sigdelset(&mask, sig)) return -1; return sigsuspend(&mask); } diff --git a/src/stat/fchmodat.c b/src/stat/fchmodat.c index bc581050..92c9d1b0 100644 --- a/src/stat/fchmodat.c +++ b/src/stat/fchmodat.c @@ -5,13 +5,16 @@ int fchmodat(int fd, const char *path, mode_t mode, int flag) { - if (!flag) return syscall(SYS_fchmodat, fd, path, mode, flag); + if (!flag) return syscall(SYS_fchmodat, fd, path, mode); + + int ret = __syscall(SYS_fchmodat2, fd, path, mode, flag); + if (ret != -ENOSYS) return __syscall_ret(ret); if (flag != AT_SYMLINK_NOFOLLOW) return __syscall_ret(-EINVAL); struct stat st; - int ret, fd2; + int fd2; char proc[15+3*sizeof(int)]; if (fstatat(fd, path, &st, flag)) diff --git a/src/stat/fstatat.c b/src/stat/fstatat.c index 04506375..9eed063b 100644 --- a/src/stat/fstatat.c +++ b/src/stat/fstatat.c @@ -36,6 +36,7 @@ static int fstatat_statx(int fd, const char *restrict path, struct stat *restric { struct statx stx; + flag |= AT_NO_AUTOMOUNT; int ret = __syscall(SYS_statx, fd, path, flag, 0x7ff, &stx); if (ret) return ret; diff --git a/src/stat/statvfs.c b/src/stat/statvfs.c index bfbb5fee..bc12da8b 100644 --- a/src/stat/statvfs.c +++ b/src/stat/statvfs.c @@ -39,6 +39,7 @@ static void fixup(struct statvfs *out, const struct statfs *in) out->f_fsid = in->f_fsid.__val[0]; out->f_flag = in->f_flags; out->f_namemax = in->f_namelen; + out->f_type = in->f_type; } int statvfs(const char *restrict path, struct statvfs *restrict buf) diff --git a/src/stdio/__stdio_write.c b/src/stdio/__stdio_write.c index d2d89475..5356553d 100644 --- a/src/stdio/__stdio_write.c +++ b/src/stdio/__stdio_write.c @@ -11,6 +11,11 @@ size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len) size_t rem = iov[0].iov_len + iov[1].iov_len; int iovcnt = 2; ssize_t cnt; + + if (!iov->iov_len) { + iov++; + iovcnt--; + } for (;;) { cnt = syscall(SYS_writev, f->fd, iov, iovcnt); if (cnt == rem) { diff --git a/src/stdio/pclose.c b/src/stdio/pclose.c index 080a4262..c64da405 100644 --- a/src/stdio/pclose.c +++ b/src/stdio/pclose.c @@ -7,7 +7,7 @@ int pclose(FILE *f) int status, r; pid_t pid = f->pipe_pid; fclose(f); - while ((r=__syscall(SYS_wait4, pid, &status, 0, 0)) == -EINTR); + while ((r=__sys_wait4(pid, &status, 0, 0)) == -EINTR); if (r<0) return __syscall_ret(r); return status; } diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c index a712d80f..76733997 100644 --- a/src/stdio/vfprintf.c +++ b/src/stdio/vfprintf.c @@ -52,7 +52,7 @@ static const unsigned char states[]['z'-'A'+1] = { S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT, S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, - S('c') = CHAR, S('C') = INT, + S('c') = INT, S('C') = UINT, S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR, S('m') = NOARG, S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE, @@ -62,7 +62,7 @@ static const unsigned char states[]['z'-'A'+1] = { S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG, S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, - S('c') = INT, S('s') = PTR, S('n') = PTR, + S('c') = UINT, S('s') = PTR, S('n') = PTR, S('l') = LLPRE, }, { /* 2: ll-prefixed */ S('d') = LLONG, S('i') = LLONG, @@ -166,7 +166,8 @@ static char *fmt_u(uintmax_t x, char *s) { unsigned long y; for ( ; x>ULONG_MAX; x/=10) *--s = '0' + x%10; - for (y=x; y; y/=10) *--s = '0' + y%10; + for (y=x; y>=10; y/=10) *--s = '0' + y%10; + if (y) *--s = '0' + y; return s; } @@ -177,10 +178,14 @@ static char *fmt_u(uintmax_t x, char *s) typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; #endif -static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) +static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t, int ps) { - uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion - + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion + int bufsize = (ps==BIGLPRE) + ? (LDBL_MANT_DIG+28)/29 + 1 + // mantissa expansion + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9 // exponent expansion + : (DBL_MANT_DIG+28)/29 + 1 + + (DBL_MAX_EXP+DBL_MANT_DIG+28+8)/9; + uint32_t big[bufsize]; uint32_t *a, *d, *r, *z; int e2=0, e, i, j, l; char buf[9+LDBL_MANT_DIG/4], *s; @@ -211,18 +216,11 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) if (y) e2--; if ((t|32)=='a') { - long double round = 8.0; - int re; - if (t&32) prefix += 9; pl += 2; - if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0; - else re=LDBL_MANT_DIG/4-1-p; - - if (re) { - round *= 1<<(LDBL_MANT_DIG%4); - while (re--) round*=16; + if (p>=0 && p<(LDBL_MANT_DIG-1+3)/4) { + double round = scalbn(1, LDBL_MANT_DIG-1-(p*4)); if (*prefix=='-') { y=-y; y-=round; @@ -437,7 +435,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, unsigned st, ps; int cnt=0, l=0; size_t i; - char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4]; + char buf[sizeof(uintmax_t)*3]; const char *prefix; int t, pl; wchar_t wc[2], *ws; @@ -563,11 +561,11 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, case 'x': case 'X': a = fmt_x(arg.i, z, t&32); if (arg.i && (fl & ALT_FORM)) prefix+=(t>>4), pl=2; - if (0) { + goto ifmt_tail; case 'o': a = fmt_o(arg.i, z); if ((fl&ALT_FORM) && p<z-a+1) p=z-a+1; - } if (0) { + goto ifmt_tail; case 'd': case 'i': pl=1; if (arg.i>INTMAX_MAX) { @@ -579,7 +577,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, } else pl=0; case 'u': a = fmt_u(arg.i, z); - } + ifmt_tail: if (xp && p<0) goto overflow; if (xp) fl &= ~ZERO_PAD; if (!arg.i && !p) { @@ -588,6 +586,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, } p = MAX(p, z-a + !arg.i); break; + narrow_c: case 'c': *(a=z-(p=1))=arg.i; fl &= ~ZERO_PAD; @@ -602,6 +601,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, fl &= ~ZERO_PAD; break; case 'C': + if (!arg.i) goto narrow_c; wc[0] = arg.i; wc[1] = 0; arg.p = wc; @@ -622,7 +622,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, case 'e': case 'f': case 'g': case 'a': case 'E': case 'F': case 'G': case 'A': if (xp && p<0) goto overflow; - l = fmt_fp(f, arg.f, w, p, fl, t); + l = fmt_fp(f, arg.f, w, p, fl, t, ps); if (l<0) goto overflow; continue; } diff --git a/src/stdio/vfwprintf.c b/src/stdio/vfwprintf.c index 53697701..59d5471b 100644 --- a/src/stdio/vfwprintf.c +++ b/src/stdio/vfwprintf.c @@ -45,7 +45,7 @@ static const unsigned char states[]['z'-'A'+1] = { S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT, S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, - S('c') = CHAR, S('C') = INT, + S('c') = INT, S('C') = UINT, S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR, S('m') = NOARG, S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE, @@ -55,7 +55,7 @@ static const unsigned char states[]['z'-'A'+1] = { S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG, S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, - S('c') = INT, S('s') = PTR, S('n') = PTR, + S('c') = UINT, S('s') = PTR, S('n') = PTR, S('l') = LLPRE, }, { /* 2: ll-prefixed */ S('d') = LLONG, S('i') = LLONG, diff --git a/src/stdio/vsnprintf.c b/src/stdio/vsnprintf.c index b3510a63..409b9c85 100644 --- a/src/stdio/vsnprintf.c +++ b/src/stdio/vsnprintf.c @@ -45,11 +45,6 @@ int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap) .cookie = &c, }; - if (n > INT_MAX) { - errno = EOVERFLOW; - return -1; - } - *c.s = 0; return vfprintf(&f, fmt, ap); } diff --git a/src/stdio/vswprintf.c b/src/stdio/vswprintf.c index fc223cf2..5e9a4dad 100644 --- a/src/stdio/vswprintf.c +++ b/src/stdio/vswprintf.c @@ -51,9 +51,6 @@ int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_lis if (!n) { return -1; - } else if (n > INT_MAX) { - errno = EOVERFLOW; - return -1; } r = vfwprintf(&f, fmt, ap); sw_write(&f, 0, 0); diff --git a/src/stdlib/qsort.c b/src/stdlib/qsort.c index 314ddc29..ab79dc6f 100644 --- a/src/stdlib/qsort.c +++ b/src/stdlib/qsort.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 by Valentin Ochs +/* Copyright (C) 2011 by Lynn Ochs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/string/strcasestr.c b/src/string/strcasestr.c index af109f36..dc598bc3 100644 --- a/src/string/strcasestr.c +++ b/src/string/strcasestr.c @@ -4,6 +4,7 @@ char *strcasestr(const char *h, const char *n) { size_t l = strlen(n); + if (!l) return (char *)h; for (; *h; h++) if (!strncasecmp(h, n, l)) return (char *)h; return 0; } diff --git a/src/termios/cfgetospeed.c b/src/termios/cfgetospeed.c index 55fa6f55..de46a1d8 100644 --- a/src/termios/cfgetospeed.c +++ b/src/termios/cfgetospeed.c @@ -9,5 +9,5 @@ speed_t cfgetospeed(const struct termios *tio) speed_t cfgetispeed(const struct termios *tio) { - return cfgetospeed(tio); + return (tio->c_cflag & CIBAUD) / (CIBAUD/CBAUD); } diff --git a/src/termios/cfsetospeed.c b/src/termios/cfsetospeed.c index c9cbdd9d..3eab092a 100644 --- a/src/termios/cfsetospeed.c +++ b/src/termios/cfsetospeed.c @@ -16,7 +16,11 @@ int cfsetospeed(struct termios *tio, speed_t speed) int cfsetispeed(struct termios *tio, speed_t speed) { - return speed ? cfsetospeed(tio, speed) : 0; + if (speed & ~CBAUD) { + errno = EINVAL; + return -1; + } + tio->c_cflag &= ~CIBAUD; + tio->c_cflag |= speed * (CIBAUD/CBAUD); + return 0; } - -weak_alias(cfsetospeed, cfsetspeed); diff --git a/src/termios/cfsetspeed.c b/src/termios/cfsetspeed.c new file mode 100644 index 00000000..2c369db9 --- /dev/null +++ b/src/termios/cfsetspeed.c @@ -0,0 +1,11 @@ +#define _BSD_SOURCE +#include <termios.h> +#include <sys/ioctl.h> +#include <errno.h> + +int cfsetspeed(struct termios *tio, speed_t speed) +{ + int r = cfsetospeed(tio, speed); + if (!r) cfsetispeed(tio, 0); + return r; +} diff --git a/src/thread/aarch64/clone.s b/src/thread/aarch64/clone.s index e3c83395..9ac272bd 100644 --- a/src/thread/aarch64/clone.s +++ b/src/thread/aarch64/clone.s @@ -24,7 +24,8 @@ __clone: // parent ret // child -1: ldp x1,x0,[sp],#16 +1: mov fp, 0 + ldp x1,x0,[sp],#16 blr x1 mov x8,#93 // SYS_exit svc #0 diff --git a/src/thread/arm/clone.s b/src/thread/arm/clone.s index bb0965da..4ff0c0e8 100644 --- a/src/thread/arm/clone.s +++ b/src/thread/arm/clone.s @@ -19,7 +19,8 @@ __clone: ldmfd sp!,{r4,r5,r6,r7} bx lr -1: mov r0,r6 +1: mov fp,#0 + mov r0,r6 bl 3f 2: mov r7,#1 svc 0 diff --git a/src/thread/loongarch64/__set_thread_area.s b/src/thread/loongarch64/__set_thread_area.s new file mode 100644 index 00000000..021307fc --- /dev/null +++ b/src/thread/loongarch64/__set_thread_area.s @@ -0,0 +1,7 @@ +.global __set_thread_area +.hidden __set_thread_area +.type __set_thread_area,@function +__set_thread_area: + move $tp, $a0 + move $a0, $zero + jr $ra diff --git a/src/thread/loongarch64/__unmapself.s b/src/thread/loongarch64/__unmapself.s new file mode 100644 index 00000000..719ad056 --- /dev/null +++ b/src/thread/loongarch64/__unmapself.s @@ -0,0 +1,7 @@ +.global __unmapself +.type __unmapself, @function +__unmapself: + li.d $a7, 215 # call munmap + syscall 0 + li.d $a7, 93 # call exit + syscall 0 diff --git a/src/thread/loongarch64/clone.s b/src/thread/loongarch64/clone.s new file mode 100644 index 00000000..cb4aacfc --- /dev/null +++ b/src/thread/loongarch64/clone.s @@ -0,0 +1,30 @@ +#__clone(func, stack, flags, arg, ptid, tls, ctid) +# a0, a1, a2, a3, a4, a5, a6 +# sys_clone(flags, stack, ptid, ctid, tls) +# a0, a1, a2, a3, a4 + +.global __clone +.hidden __clone +.type __clone,@function +__clone: + bstrins.d $a1, $zero, 3, 0 #stack to 16 align + # Save function pointer and argument pointer on new thread stack + addi.d $a1, $a1, -16 + st.d $a0, $a1, 0 # save function pointer + st.d $a3, $a1, 8 # save argument pointer + or $a0, $a2, $zero + or $a2, $a4, $zero + or $a3, $a6, $zero + or $a4, $a5, $zero + ori $a7, $zero, 220 + syscall 0 # call clone + + beqz $a0, 1f # whether child process + jirl $zero, $ra, 0 # parent process return +1: + move $fp, $zero + ld.d $t8, $sp, 0 # function pointer + ld.d $a0, $sp, 8 # argument pointer + jirl $ra, $t8, 0 # call the user's function + ori $a7, $zero, 93 + syscall 0 # child process exit diff --git a/src/thread/loongarch64/syscall_cp.s b/src/thread/loongarch64/syscall_cp.s new file mode 100644 index 00000000..c057a97b --- /dev/null +++ b/src/thread/loongarch64/syscall_cp.s @@ -0,0 +1,29 @@ +.global __cp_begin +.hidden __cp_begin +.global __cp_end +.hidden __cp_end +.global __cp_cancel +.hidden __cp_cancel +.hidden __cancel +.global __syscall_cp_asm +.hidden __syscall_cp_asm +.type __syscall_cp_asm,@function + +__syscall_cp_asm: +__cp_begin: + ld.w $a0, $a0, 0 + bnez $a0, __cp_cancel + move $t8, $a1 # reserve system call number + move $a0, $a2 + move $a1, $a3 + move $a2, $a4 + move $a3, $a5 + move $a4, $a6 + move $a5, $a7 + move $a7, $t8 + syscall 0 +__cp_end: + jr $ra +__cp_cancel: + la.local $t8, __cancel + jr $t8 diff --git a/src/thread/m68k/clone.s b/src/thread/m68k/clone.s index f6dfa06f..0134cf4e 100644 --- a/src/thread/m68k/clone.s +++ b/src/thread/m68k/clone.s @@ -18,7 +18,8 @@ __clone: beq 1f movem.l (%sp)+,%d2-%d5 rts -1: move.l %a1,-(%sp) +1: suba.l %fp,%fp + move.l %a1,-(%sp) jsr (%a0) move.l #1,%d0 trap #0 diff --git a/src/thread/microblaze/clone.s b/src/thread/microblaze/clone.s index b68cc5fc..64e3f074 100644 --- a/src/thread/microblaze/clone.s +++ b/src/thread/microblaze/clone.s @@ -22,7 +22,8 @@ __clone: rtsd r15, 8 nop -1: lwi r3, r1, 0 +1: add r19, r0, r0 + lwi r3, r1, 0 lwi r5, r1, 4 brald r15, r3 nop diff --git a/src/thread/mips/clone.s b/src/thread/mips/clone.s index 04463385..229b987e 100644 --- a/src/thread/mips/clone.s +++ b/src/thread/mips/clone.s @@ -27,7 +27,8 @@ __clone: addu $sp, $sp, 16 jr $ra nop -1: lw $25, 0($sp) +1: move $fp, $0 + lw $25, 0($sp) lw $4, 4($sp) jalr $25 nop diff --git a/src/thread/mips64/clone.s b/src/thread/mips64/clone.s index 2d86899a..8de3db6c 100644 --- a/src/thread/mips64/clone.s +++ b/src/thread/mips64/clone.s @@ -25,7 +25,8 @@ __clone: nop jr $ra nop -1: ld $25, 0($sp) # function pointer +1: move $fp, $0 + ld $25, 0($sp) # function pointer ld $4, 8($sp) # argument pointer jalr $25 # call the user's function nop diff --git a/src/thread/mipsn32/clone.s b/src/thread/mipsn32/clone.s index 4d3c8c7a..9571231a 100644 --- a/src/thread/mipsn32/clone.s +++ b/src/thread/mipsn32/clone.s @@ -25,7 +25,8 @@ __clone: nop jr $ra nop -1: lw $25, 0($sp) # function pointer +1: move $fp, $0 + lw $25, 0($sp) # function pointer lw $4, 4($sp) # argument pointer jalr $25 # call the user's function nop diff --git a/src/thread/or1k/clone.s b/src/thread/or1k/clone.s index 2473ac20..b41488a2 100644 --- a/src/thread/or1k/clone.s +++ b/src/thread/or1k/clone.s @@ -6,6 +6,8 @@ .hidden __clone .type __clone,@function __clone: + l.xori r11, r0, -4 + l.and r4, r4, r11 l.addi r4, r4, -8 l.sw 0(r4), r3 l.sw 4(r4), r6 @@ -23,7 +25,8 @@ __clone: l.jr r9 l.nop -1: l.lwz r11, 0(r1) +1: l.ori r2, r0, 0 + l.lwz r11, 0(r1) l.jalr r11 l.lwz r3, 4(r1) diff --git a/src/thread/riscv32/__set_thread_area.s b/src/thread/riscv32/__set_thread_area.s new file mode 100644 index 00000000..828154d2 --- /dev/null +++ b/src/thread/riscv32/__set_thread_area.s @@ -0,0 +1,6 @@ +.global __set_thread_area +.type __set_thread_area, %function +__set_thread_area: + mv tp, a0 + li a0, 0 + ret diff --git a/src/thread/riscv32/__unmapself.s b/src/thread/riscv32/__unmapself.s new file mode 100644 index 00000000..2849119c --- /dev/null +++ b/src/thread/riscv32/__unmapself.s @@ -0,0 +1,7 @@ +.global __unmapself +.type __unmapself, %function +__unmapself: + li a7, 215 # SYS_munmap + ecall + li a7, 93 # SYS_exit + ecall diff --git a/src/thread/riscv32/clone.s b/src/thread/riscv32/clone.s new file mode 100644 index 00000000..e2116e33 --- /dev/null +++ b/src/thread/riscv32/clone.s @@ -0,0 +1,35 @@ +# __clone(func, stack, flags, arg, ptid, tls, ctid) +# a0, a1, a2, a3, a4, a5, a6 + +# syscall(SYS_clone, flags, stack, ptid, tls, ctid) +# a7 a0, a1, a2, a3, a4 + +.global __clone +.type __clone, %function +__clone: + # Save func and arg to stack + andi a1, a1, -16 + addi a1, a1, -16 + sw a0, 0(a1) + sw a3, 4(a1) + + # Call SYS_clone + mv a0, a2 + mv a2, a4 + mv a3, a5 + mv a4, a6 + li a7, 220 # SYS_clone + ecall + + beqz a0, 1f + # Parent + ret + + # Child +1: lw a1, 0(sp) + lw a0, 4(sp) + jalr a1 + + # Exit + li a7, 93 # SYS_exit + ecall diff --git a/src/thread/riscv32/syscall_cp.s b/src/thread/riscv32/syscall_cp.s new file mode 100644 index 00000000..079d1ba0 --- /dev/null +++ b/src/thread/riscv32/syscall_cp.s @@ -0,0 +1,29 @@ +.global __cp_begin +.hidden __cp_begin +.global __cp_end +.hidden __cp_end +.global __cp_cancel +.hidden __cp_cancel +.hidden __cancel +.global __syscall_cp_asm +.hidden __syscall_cp_asm +.type __syscall_cp_asm, %function +__syscall_cp_asm: +__cp_begin: + lw t0, 0(a0) + bnez t0, __cp_cancel + + mv t0, a1 + mv a0, a2 + mv a1, a3 + mv a2, a4 + mv a3, a5 + mv a4, a6 + mv a5, a7 + lw a6, 0(sp) + mv a7, t0 + ecall +__cp_end: + ret +__cp_cancel: + tail __cancel diff --git a/src/thread/riscv64/clone.s b/src/thread/riscv64/clone.s index db908248..0e6f41a8 100644 --- a/src/thread/riscv64/clone.s +++ b/src/thread/riscv64/clone.s @@ -8,6 +8,7 @@ .type __clone, %function __clone: # Save func and arg to stack + andi a1, a1, -16 addi a1, a1, -16 sd a0, 0(a1) sd a3, 8(a1) diff --git a/src/thread/s390x/__tls_get_offset.s b/src/thread/s390x/__tls_get_offset.s index 8ee92de8..405f118b 100644 --- a/src/thread/s390x/__tls_get_offset.s +++ b/src/thread/s390x/__tls_get_offset.s @@ -1,17 +1,17 @@ .global __tls_get_offset .type __tls_get_offset,%function __tls_get_offset: - stmg %r14, %r15, 112(%r15) - aghi %r15, -160 + ear %r0, %a0 + sllg %r0, %r0, 32 + ear %r0, %a1 - la %r2, 0(%r2, %r12) - brasl %r14, __tls_get_addr + la %r1, 0(%r2, %r12) - ear %r1, %a0 - sllg %r1, %r1, 32 - ear %r1, %a1 + lg %r3, 0(%r1) + sllg %r4, %r3, 3 + lg %r5, 8(%r0) + lg %r2, 0(%r4, %r5) + ag %r2, 8(%r1) + sgr %r2, %r0 - sgr %r2, %r1 - - lmg %r14, %r15, 272(%r15) br %r14 diff --git a/src/thread/sem_post.c b/src/thread/sem_post.c index 5c2517f2..1c8f763c 100644 --- a/src/thread/sem_post.c +++ b/src/thread/sem_post.c @@ -16,6 +16,6 @@ int sem_post(sem_t *sem) if (waiters <= 1) new &= ~0x80000000; } while (a_cas(sem->__val, val, new) != val); - if (val<0) __wake(sem->__val, waiters>1 ? 1 : -1, priv); + if (val<0 || waiters) __wake(sem->__val, waiters>1 ? 1 : -1, priv); return 0; } diff --git a/src/thread/synccall.c b/src/thread/synccall.c index a6b177c0..38597254 100644 --- a/src/thread/synccall.c +++ b/src/thread/synccall.c @@ -11,7 +11,7 @@ weak_alias(dummy_0, __tl_unlock); static int target_tid; static void (*callback)(void *), *context; -static sem_t target_sem, caller_sem; +static sem_t target_sem, caller_sem, exit_sem; static void dummy(void *p) { @@ -33,7 +33,7 @@ static void handler(int sig) /* Inform caller we've complered the callback and wait * for the caller to release us to return. */ sem_post(&caller_sem); - sem_wait(&target_sem); + sem_wait(&exit_sem); /* Inform caller we are returning and state is destroyable. */ sem_post(&caller_sem); @@ -62,6 +62,7 @@ void __synccall(void (*func)(void *), void *ctx) sem_init(&target_sem, 0, 0); sem_init(&caller_sem, 0, 0); + sem_init(&exit_sem, 0, 0); if (!libc.threads_minus_1 || __syscall(SYS_gettid) != self->tid) goto single_threaded; @@ -107,12 +108,13 @@ single_threaded: /* Only release the caught threads once all threads, including the * caller, have returned from the callback function. */ for (i=0; i<count; i++) - sem_post(&target_sem); + sem_post(&exit_sem); for (i=0; i<count; i++) sem_wait(&caller_sem); sem_destroy(&caller_sem); sem_destroy(&target_sem); + sem_destroy(&exit_sem); pthread_setcancelstate(cs, 0); __tl_unlock(); diff --git a/src/time/__tz.c b/src/time/__tz.c index c34b3eb7..54ed4cf6 100644 --- a/src/time/__tz.c +++ b/src/time/__tz.c @@ -24,7 +24,6 @@ weak_alias(__tzname, tzname); static char std_name[TZNAME_MAX+1]; static char dst_name[TZNAME_MAX+1]; -const char __utc[] = "UTC"; static int dst_off; static int r0[5], r1[5]; diff --git a/src/time/__utc.c b/src/time/__utc.c new file mode 100644 index 00000000..9e8bfc58 --- /dev/null +++ b/src/time/__utc.c @@ -0,0 +1,3 @@ +#include "time_impl.h" + +const char __utc[] = "UTC"; diff --git a/src/time/__year_to_secs.c b/src/time/__year_to_secs.c index 2824ec6d..b42f5a6d 100644 --- a/src/time/__year_to_secs.c +++ b/src/time/__year_to_secs.c @@ -10,9 +10,9 @@ long long __year_to_secs(long long year, int *is_leap) return 31536000*(y-70) + 86400*leaps; } - int cycles, centuries, leaps, rem; + int cycles, centuries, leaps, rem, dummy; - if (!is_leap) is_leap = &(int){0}; + if (!is_leap) is_leap = &dummy; cycles = (year-100) / 400; rem = (year-100) % 400; if (rem < 0) { diff --git a/src/time/strftime.c b/src/time/strftime.c index cc53d536..c40246db 100644 --- a/src/time/strftime.c +++ b/src/time/strftime.c @@ -3,6 +3,7 @@ #include <string.h> #include <langinfo.h> #include <locale.h> +#include <ctype.h> #include <time.h> #include <limits.h> #include "locale_impl.h" @@ -233,7 +234,12 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st pad = 0; if (*f == '-' || *f == '_' || *f == '0') pad = *f++; if ((plus = (*f == '+'))) f++; - width = strtoul(f, &p, 10); + if (isdigit(*f)) { + width = strtoul(f, &p, 10); + } else { + width = 0; + p = (void *)f; + } if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') { if (!width && p!=f) width = 1; } else { diff --git a/src/time/strptime.c b/src/time/strptime.c index c54a0d8c..b1147242 100644 --- a/src/time/strptime.c +++ b/src/time/strptime.c @@ -59,6 +59,22 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri s = strptime(s, "%m/%d/%y", tm); if (!s) return 0; break; + case 'F': + /* Use temp buffer to implement the odd requirement + * that entire field be width-limited but the year + * subfield not itself be limited. */ + i = 0; + char tmp[20]; + if (*s == '-' || *s == '+') tmp[i++] = *s++; + while (*s=='0' && isdigit(s[1])) s++; + for (; *s && i<(size_t)w && i+1<sizeof tmp; i++) { + tmp[i] = *s++; + } + tmp[i] = 0; + char *p = strptime(tmp, "%12Y-%m-%d", tm); + if (!p) return 0; + s -= tmp+i-p; + break; case 'H': dest = &tm->tm_hour; min = 0; @@ -114,6 +130,13 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri s = strptime(s, "%H:%M", tm); if (!s) return 0; break; + case 's': + /* Parse only. Effect on tm is unspecified + * and presently no effect is implemented.. */ + if (*s == '-') s++; + if (!isdigit(*s)) return 0; + while (isdigit(*s)) s++; + break; case 'S': dest = &tm->tm_sec; min = 0; @@ -125,11 +148,30 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri break; case 'U': case 'W': - /* Throw away result, for now. (FIXME?) */ + /* Throw away result of %U, %V, %W, %g, and %G. Effect + * is unspecified and there is no clear right choice. */ dest = &dummy; min = 0; range = 54; goto numeric_range; + case 'V': + dest = &dummy; + min = 1; + range = 53; + goto numeric_range; + case 'g': + dest = &dummy; + w = 2; + goto numeric_digits; + case 'G': + dest = &dummy; + if (w<0) w=4; + goto numeric_digits; + case 'u': + dest = &tm->tm_wday; + min = 1; + range = 7; + goto numeric_range; case 'w': dest = &tm->tm_wday; min = 0; @@ -154,6 +196,28 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri adj = 1900; want_century = 0; goto numeric_digits; + case 'z': + if (*s == '+') neg = 0; + else if (*s == '-') neg = 1; + else return 0; + for (i=0; i<4; i++) if (!isdigit(s[1+i])) return 0; + tm->__tm_gmtoff = (s[1]-'0')*36000+(s[2]-'0')*3600 + + (s[3]-'0')*600 + (s[4]-'0')*60; + if (neg) tm->__tm_gmtoff = -tm->__tm_gmtoff; + s += 5; + break; + case 'Z': + if (!strncmp(s, tzname[0], len = strlen(tzname[0]))) { + tm->tm_isdst = 0; + s += len; + } else if (!strncmp(s, tzname[1], len=strlen(tzname[1]))) { + tm->tm_isdst = 1; + s += len; + } else { + /* FIXME: is this supposed to be an error? */ + while ((*s|32)-'a' <= 'z'-'a') s++; + } + break; case '%': if (*s++ != '%') return 0; break; diff --git a/src/time/timer_create.c b/src/time/timer_create.c index cd32c945..cc6c2236 100644 --- a/src/time/timer_create.c +++ b/src/time/timer_create.c @@ -1,6 +1,7 @@ #include <time.h> #include <setjmp.h> #include <limits.h> +#include <semaphore.h> #include "pthread_impl.h" #include "atomic.h" @@ -12,7 +13,7 @@ struct ksigevent { }; struct start_args { - pthread_barrier_t b; + sem_t sem1, sem2; struct sigevent *sev; }; @@ -21,10 +22,16 @@ static void dummy_0() } weak_alias(dummy_0, __pthread_tsd_run_dtors); +static void timer_handler(int sig, siginfo_t *si, void *ctx) +{ +} + static void cleanup_fromsig(void *p) { pthread_t self = __pthread_self(); __pthread_tsd_run_dtors(); + __block_app_sigs(0); + __syscall(SYS_rt_sigprocmask, SIG_BLOCK, SIGTIMER_SET, 0, _NSIG/8); self->cancel = 0; self->cancelbuf = 0; self->canceldisable = 0; @@ -42,7 +49,14 @@ static void *start(void *arg) void (*notify)(union sigval) = args->sev->sigev_notify_function; union sigval val = args->sev->sigev_value; - pthread_barrier_wait(&args->b); + /* The two-way semaphore synchronization ensures that we see + * self->cancel set by the parent if timer creation failed or + * self->timer_id if it succeeded, and informs the parent that + * we are done accessing the arguments so that the parent can + * proceed past their block lifetime. */ + while (sem_wait(&args->sem1)); + sem_post(&args->sem2); + if (self->cancel) return 0; for (;;) { @@ -61,7 +75,7 @@ static void *start(void *arg) int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict res) { - volatile static int init = 0; + static volatile int init = 0; pthread_t td; pthread_attr_t attr; int r; @@ -90,7 +104,10 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict break; case SIGEV_THREAD: if (!init) { - struct sigaction sa = { .sa_handler = SIG_DFL }; + struct sigaction sa = { + .sa_sigaction = timer_handler, + .sa_flags = SA_SIGINFO | SA_RESTART + }; __libc_sigaction(SIGTIMER, &sa, 0); a_store(&init, 1); } @@ -99,7 +116,8 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict else pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_barrier_init(&args.b, 0, 2); + sem_init(&args.sem1, 0, 0); + sem_init(&args.sem2, 0, 0); args.sev = evp; __block_app_sigs(&set); @@ -120,7 +138,8 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict td->cancel = 1; } td->timer_id = timerid; - pthread_barrier_wait(&args.b); + sem_post(&args.sem1); + while (sem_wait(&args.sem2)); if (timerid < 0) return -1; *res = (void *)(INTPTR_MIN | (uintptr_t)td>>1); break; diff --git a/src/unistd/faccessat.c b/src/unistd/faccessat.c index 557503eb..43052dd7 100644 --- a/src/unistd/faccessat.c +++ b/src/unistd/faccessat.c @@ -53,7 +53,7 @@ int faccessat(int fd, const char *filename, int amode, int flag) if (pid<0 || __syscall(SYS_read, p[0], &ret, sizeof ret) != sizeof(ret)) ret = -EBUSY; __syscall(SYS_close, p[0]); - __syscall(SYS_wait4, pid, &status, __WCLONE, 0); + __sys_wait4(pid, &status, __WCLONE, 0); __restore_sigs(&set); diff --git a/src/unistd/isatty.c b/src/unistd/isatty.c index 75a9c186..21222eda 100644 --- a/src/unistd/isatty.c +++ b/src/unistd/isatty.c @@ -6,8 +6,6 @@ int isatty(int fd) { struct winsize wsz; - unsigned long r = syscall(SYS_ioctl, fd, TIOCGWINSZ, &wsz); - if (r == 0) return 1; - if (errno != EBADF) errno = ENOTTY; - return 0; + /* +1 converts from error status (0/-1) to boolean (1/0) */ + return syscall(SYS_ioctl, fd, TIOCGWINSZ, &wsz) + 1; } diff --git a/src/unistd/pause.c b/src/unistd/pause.c index 90bbf4ca..90cc8db5 100644 --- a/src/unistd/pause.c +++ b/src/unistd/pause.c @@ -3,9 +3,5 @@ int pause(void) { -#ifdef SYS_pause - return syscall_cp(SYS_pause); -#else - return syscall_cp(SYS_ppoll, 0, 0, 0, 0); -#endif + return sys_pause_cp(); } diff --git a/src/unistd/pwrite.c b/src/unistd/pwrite.c index 869b69f0..a008b3ec 100644 --- a/src/unistd/pwrite.c +++ b/src/unistd/pwrite.c @@ -1,7 +1,18 @@ +#define _GNU_SOURCE #include <unistd.h> +#include <sys/uio.h> +#include <fcntl.h> #include "syscall.h" ssize_t pwrite(int fd, const void *buf, size_t size, off_t ofs) { + if (ofs == -1) ofs--; + int r = __syscall_cp(SYS_pwritev2, fd, + (&(struct iovec){ .iov_base = (void *)buf, .iov_len = size }), + 1, (long)(ofs), (long)(ofs>>32), RWF_NOAPPEND); + if (r != -EOPNOTSUPP && r != -ENOSYS) + return __syscall_ret(r); + if (fcntl(fd, F_GETFL) & O_APPEND) + return __syscall_ret(-EOPNOTSUPP); return syscall_cp(SYS_pwrite, fd, buf, size, __SYSCALL_LL_PRW(ofs)); } diff --git a/src/unistd/pwritev.c b/src/unistd/pwritev.c index becf9deb..44a53d85 100644 --- a/src/unistd/pwritev.c +++ b/src/unistd/pwritev.c @@ -1,10 +1,18 @@ -#define _BSD_SOURCE +#define _GNU_SOURCE #include <sys/uio.h> #include <unistd.h> +#include <fcntl.h> #include "syscall.h" ssize_t pwritev(int fd, const struct iovec *iov, int count, off_t ofs) { + if (ofs == -1) ofs--; + int r = __syscall_cp(SYS_pwritev2, fd, iov, count, + (long)(ofs), (long)(ofs>>32), RWF_NOAPPEND); + if (r != -EOPNOTSUPP && r != -ENOSYS) + return __syscall_ret(r); + if (fcntl(fd, F_GETFL) & O_APPEND) + return __syscall_ret(-EOPNOTSUPP); return syscall_cp(SYS_pwritev, fd, iov, count, (long)(ofs), (long)(ofs>>32)); } diff --git a/src/unistd/setxid.c b/src/unistd/setxid.c index 487c1a16..a629ed4b 100644 --- a/src/unistd/setxid.c +++ b/src/unistd/setxid.c @@ -30,5 +30,5 @@ int __setxid(int nr, int id, int eid, int sid) * trigger the safety kill above. */ struct ctx c = { .nr = nr, .id = id, .eid = eid, .sid = sid, .ret = 1 }; __synccall(do_setxid, &c); - return __syscall_ret(c.ret); + return __syscall_ret(c.ret > 0 ? -EAGAIN : c.ret); } |