diff options
Diffstat (limited to 'src')
225 files changed, 2077 insertions, 609 deletions
| diff --git a/src/aio/aio.c b/src/aio/aio.c index a1a3e791..d7e063bf 100644 --- a/src/aio/aio.c +++ b/src/aio/aio.c @@ -82,6 +82,8 @@ static size_t io_thread_stack_size;  static struct aio_queue *__aio_get_queue(int fd, int need)  { +	sigset_t allmask, origmask; +	int masked = 0;  	if (fd < 0) {  		errno = EBADF;  		return 0; @@ -93,6 +95,9 @@ static struct aio_queue *__aio_get_queue(int fd, int need)  	if ((!map || !map[a] || !map[a][b] || !map[a][b][c] || !(q=map[a][b][c][d])) && need) {  		pthread_rwlock_unlock(&maplock);  		if (fcntl(fd, F_GETFD) < 0) return 0; +		sigfillset(&allmask); +		masked = 1; +		pthread_sigmask(SIG_BLOCK, &allmask, &origmask);  		pthread_rwlock_wrlock(&maplock);  		if (!io_thread_stack_size) {  			unsigned long val = __getauxval(AT_MINSIGSTKSZ); @@ -119,6 +124,7 @@ static struct aio_queue *__aio_get_queue(int fd, int need)  	if (q) pthread_mutex_lock(&q->lock);  out:  	pthread_rwlock_unlock(&maplock); +	if (masked) pthread_sigmask(SIG_SETMASK, &origmask, 0);  	return q;  } @@ -401,18 +407,26 @@ void __aio_atfork(int who)  	if (who<0) {  		pthread_rwlock_rdlock(&maplock);  		return; +	} else if (!who) { +		pthread_rwlock_unlock(&maplock); +		return;  	} -	if (who>0 && map) for (int a=0; a<(-1U/2+1)>>24; a++) +	aio_fd_cnt = 0; +	if (pthread_rwlock_tryrdlock(&maplock)) { +		/* Obtaining lock may fail if _Fork was called nor via +		 * fork. In this case, no further aio is possible from +		 * child and we can just null out map so __aio_close +		 * does not attempt to do anything. */ +		map = 0; +		return; +	} +	if (map) for (int a=0; a<(-1U/2+1)>>24; a++)  		if (map[a]) for (int b=0; b<256; b++)  			if (map[a][b]) for (int c=0; c<256; c++)  				if (map[a][b][c]) for (int d=0; d<256; d++)  					map[a][b][c][d] = 0; -	pthread_rwlock_unlock(&maplock); +	/* Re-initialize the rwlock rather than unlocking since there +	 * may have been more than one reference on it in the parent. +	 * We are not a lock holder anyway; the thread in the parent was. */ +	pthread_rwlock_init(&maplock, 0);  } - -weak_alias(aio_cancel, aio_cancel64); -weak_alias(aio_error, aio_error64); -weak_alias(aio_fsync, aio_fsync64); -weak_alias(aio_read, aio_read64); -weak_alias(aio_write, aio_write64); -weak_alias(aio_return, aio_return64); diff --git a/src/aio/aio_suspend.c b/src/aio/aio_suspend.c index 1c1060e3..1f0c9aaa 100644 --- a/src/aio/aio_suspend.c +++ b/src/aio/aio_suspend.c @@ -9,7 +9,7 @@ int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec  {  	int i, tid = 0, ret, expect = 0;  	struct timespec at; -	volatile int dummy_fut, *pfut; +	volatile int dummy_fut = 0, *pfut;  	int nzcnt = 0;  	const struct aiocb *cb = 0; @@ -73,7 +73,3 @@ int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec  		}  	}  } - -#if !_REDIR_TIME64 -weak_alias(aio_suspend, aio_suspend64); -#endif diff --git a/src/aio/lio_listio.c b/src/aio/lio_listio.c index 0799c15d..a672812f 100644 --- a/src/aio/lio_listio.c +++ b/src/aio/lio_listio.c @@ -139,5 +139,3 @@ int lio_listio(int mode, struct aiocb *restrict const *restrict cbs, int cnt, st  	return 0;  } - -weak_alias(lio_listio, lio_listio64); 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 3baaed32..8dd5c725 100644 --- a/src/conf/sysconf.c +++ b/src/conf/sysconf.c @@ -4,6 +4,7 @@  #include <sys/resource.h>  #include <signal.h>  #include <sys/sysinfo.h> +#include <sys/auxv.h>  #include "syscall.h"  #include "libc.h" @@ -19,6 +20,8 @@  #define JT_AVPHYS_PAGES JT(9)  #define JT_ZERO JT(10)  #define JT_DELAYTIMER_MAX JT(11) +#define JT_MINSIGSTKSZ JT(12) +#define JT_SIGSTKSZ JT(13)  #define RLIM(x) (-32768|(RLIMIT_ ## x)) @@ -165,6 +168,9 @@ long sysconf(int name)  		[_SC_XOPEN_STREAMS] = JT_ZERO,  		[_SC_THREAD_ROBUST_PRIO_INHERIT] = -1,  		[_SC_THREAD_ROBUST_PRIO_PROTECT] = -1, + +		[_SC_MINSIGSTKSZ] = JT_MINSIGSTKSZ, +		[_SC_SIGSTKSZ] = JT_SIGSTKSZ,  	};  	if (name >= sizeof(values)/sizeof(values[0]) || !values[name]) { @@ -212,6 +218,18 @@ long sysconf(int name)  		mem *= si.mem_unit;  		mem /= PAGE_SIZE;  		return (mem > LONG_MAX) ? LONG_MAX : mem; +	case JT_MINSIGSTKSZ & 255: +	case JT_SIGSTKSZ & 255: ; +		/* 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;  	case JT_ZERO & 255:  		return 0;  	} diff --git a/src/dirent/alphasort.c b/src/dirent/alphasort.c index bee672eb..ab2624e2 100644 --- a/src/dirent/alphasort.c +++ b/src/dirent/alphasort.c @@ -5,5 +5,3 @@ int alphasort(const struct dirent **a, const struct dirent **b)  {  	return strcoll((*a)->d_name, (*b)->d_name);  } - -weak_alias(alphasort, alphasort64); 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/dirent/readdir.c b/src/dirent/readdir.c index 569fc705..5a03b363 100644 --- a/src/dirent/readdir.c +++ b/src/dirent/readdir.c @@ -25,5 +25,3 @@ struct dirent *readdir(DIR *dir)  	dir->tell = de->d_off;  	return de;  } - -weak_alias(readdir, readdir64); diff --git a/src/dirent/readdir_r.c b/src/dirent/readdir_r.c index e2a818f3..0d5de5f5 100644 --- a/src/dirent/readdir_r.c +++ b/src/dirent/readdir_r.c @@ -25,5 +25,3 @@ int readdir_r(DIR *restrict dir, struct dirent *restrict buf, struct dirent **re  	*result = buf;  	return 0;  } - -weak_alias(readdir_r, readdir64_r); diff --git a/src/dirent/scandir.c b/src/dirent/scandir.c index 7ee195dd..7456b9b8 100644 --- a/src/dirent/scandir.c +++ b/src/dirent/scandir.c @@ -43,5 +43,3 @@ int scandir(const char *path, struct dirent ***res,  	*res = names;  	return cnt;  } - -weak_alias(scandir, scandir64); diff --git a/src/dirent/versionsort.c b/src/dirent/versionsort.c index d4c48923..97696105 100644 --- a/src/dirent/versionsort.c +++ b/src/dirent/versionsort.c @@ -6,6 +6,3 @@ int versionsort(const struct dirent **a, const struct dirent **b)  {  	return strverscmp((*a)->d_name, (*b)->d_name);  } - -#undef versionsort64 -weak_alias(versionsort, versionsort64); 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/fcntl/creat.c b/src/fcntl/creat.c index 8f8aab64..c9c43910 100644 --- a/src/fcntl/creat.c +++ b/src/fcntl/creat.c @@ -4,5 +4,3 @@ int creat(const char *filename, mode_t mode)  {  	return open(filename, O_CREAT|O_WRONLY|O_TRUNC, mode);  } - -weak_alias(creat, creat64); diff --git a/src/fcntl/open.c b/src/fcntl/open.c index 1d817a2d..4c3c8275 100644 --- a/src/fcntl/open.c +++ b/src/fcntl/open.c @@ -19,5 +19,3 @@ int open(const char *filename, int flags, ...)  	return __syscall_ret(fd);  } - -weak_alias(open, open64); diff --git a/src/fcntl/openat.c b/src/fcntl/openat.c index ad165ec3..83a9e0d0 100644 --- a/src/fcntl/openat.c +++ b/src/fcntl/openat.c @@ -15,5 +15,3 @@ int openat(int fd, const char *filename, int flags, ...)  	return syscall_cp(SYS_openat, fd, filename, flags|O_LARGEFILE, mode);  } - -weak_alias(openat, openat64); diff --git a/src/fcntl/posix_fadvise.c b/src/fcntl/posix_fadvise.c index 75b8e1ae..07346d21 100644 --- a/src/fcntl/posix_fadvise.c +++ b/src/fcntl/posix_fadvise.c @@ -14,5 +14,3 @@ int posix_fadvise(int fd, off_t base, off_t len, int advice)  		__SYSCALL_LL_E(len), advice);  #endif  } - -weak_alias(posix_fadvise, posix_fadvise64); diff --git a/src/fcntl/posix_fallocate.c b/src/fcntl/posix_fallocate.c index c57a24ae..80a65cbf 100644 --- a/src/fcntl/posix_fallocate.c +++ b/src/fcntl/posix_fallocate.c @@ -6,5 +6,3 @@ int posix_fallocate(int fd, off_t base, off_t len)  	return -__syscall(SYS_fallocate, fd, 0, __SYSCALL_LL_E(base),  		__SYSCALL_LL_E(len));  } - -weak_alias(posix_fallocate, posix_fallocate64); 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/include/sys/auxv.h b/src/include/sys/auxv.h index 9358a4a5..63c5bfe9 100644 --- a/src/include/sys/auxv.h +++ b/src/include/sys/auxv.h @@ -5,6 +5,6 @@  #include <features.h> -hidden unsigned long __getauxval(unsigned long); +unsigned long __getauxval(unsigned long);  #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 51c0639f..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) || \ @@ -92,8 +96,12 @@ struct fdpic_dummy_loadmap {  #define DT_DEBUG_INDIRECT 0  #endif +#ifndef DT_DEBUG_INDIRECT_REL +#define DT_DEBUG_INDIRECT_REL 0 +#endif +  #define AUX_CNT 32 -#define DYN_CNT 32 +#define DYN_CNT 37  typedef void (*stage2_func)(unsigned char *, size_t *); 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 5892c13b..f995fce2 100644 --- a/src/internal/fork_impl.h +++ b/src/internal/fork_impl.h @@ -2,7 +2,6 @@  extern hidden volatile int *const __at_quick_exit_lockptr;  extern hidden volatile int *const __atexit_lockptr; -extern hidden volatile int *const __dlerror_lockptr;  extern hidden volatile int *const __gettext_lockptr;  extern hidden volatile int *const __locale_lockptr;  extern hidden volatile int *const __random_lockptr; @@ -17,3 +16,6 @@ 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/ksigaction.h b/src/internal/ksigaction.h index 8ebd5938..ef333f33 100644 --- a/src/internal/ksigaction.h +++ b/src/internal/ksigaction.h @@ -6,8 +6,13 @@  struct k_sigaction {  	void (*handler)(int);  	unsigned long flags; +#ifdef SA_RESTORER  	void (*restorer)(void); +#endif  	unsigned mask[2]; +#ifndef SA_RESTORER +	void *unused; +#endif  };  hidden void __restore(), __restore_rt(); diff --git a/src/internal/syscall.h b/src/internal/syscall.h index 4f41e1dc..2d8a5c13 100644 --- a/src/internal/syscall.h +++ b/src/internal/syscall.h @@ -58,7 +58,7 @@ hidden long __syscall_ret(unsigned long),  #define __syscall_cp(...) __SYSCALL_DISP(__syscall_cp,__VA_ARGS__)  #define syscall_cp(...) __syscall_ret(__syscall_cp(__VA_ARGS__)) -static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, long c, long d, long e, long f) +static inline long __alt_socketcall(int sys, int sock, int cp, syscall_arg_t a, syscall_arg_t b, syscall_arg_t c, syscall_arg_t d, syscall_arg_t e, syscall_arg_t f)  {  	long r;  	if (cp) r = __syscall_cp(sys, a, b, c, d, e, f); @@ -71,9 +71,9 @@ static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, l  	return r;  }  #define __socketcall(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 0, \ -	(long)(a), (long)(b), (long)(c), (long)(d), (long)(e), (long)(f)) +	__scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f))  #define __socketcall_cp(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 1, \ -	(long)(a), (long)(b), (long)(c), (long)(d), (long)(e), (long)(f)) +	__scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f))  /* fixup legacy 16-bit junk */ @@ -391,6 +391,29 @@ static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, l  #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/ipc/semtimedop.c b/src/ipc/semtimedop.c index 1632e7b0..a104af21 100644 --- a/src/ipc/semtimedop.c +++ b/src/ipc/semtimedop.c @@ -7,7 +7,8 @@  #define IS32BIT(x) !((x)+0x80000000ULL>>32)  #define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63)) -#if !defined(SYS_semtimedop) && !defined(SYS_ipc) +#if !defined(SYS_semtimedop) && !defined(SYS_ipc) || \ +	SYS_semtimedop == SYS_semtimedop_time64  #define NO_TIME32 1  #else  #define NO_TIME32 0 diff --git a/src/ldso/dlerror.c b/src/ldso/dlerror.c index afe59253..dae0f3a9 100644 --- a/src/ldso/dlerror.c +++ b/src/ldso/dlerror.c @@ -3,8 +3,7 @@  #include <stdarg.h>  #include "pthread_impl.h"  #include "dynlink.h" -#include "lock.h" -#include "fork_impl.h" +#include "atomic.h"  #define malloc __libc_malloc  #define calloc __libc_calloc @@ -23,28 +22,31 @@ char *dlerror()  		return s;  } -static volatile int freebuf_queue_lock[1]; -static void **freebuf_queue; -volatile int *const __dlerror_lockptr = freebuf_queue_lock; +/* Atomic singly-linked list, used to store list of thread-local dlerror + * buffers for deferred free. They cannot be freed at thread exit time + * because, by the time it's known they can be freed, the exiting thread + * is in a highly restrictive context where it cannot call (even the + * libc-internal) free. It also can't take locks; thus the atomic list. */ + +static void *volatile freebuf_queue;  void __dl_thread_cleanup(void)  {  	pthread_t self = __pthread_self(); -	if (self->dlerror_buf && self->dlerror_buf != (void *)-1) { -		LOCK(freebuf_queue_lock); -		void **p = (void **)self->dlerror_buf; -		*p = freebuf_queue; -		freebuf_queue = p; -		UNLOCK(freebuf_queue_lock); -	} +	if (!self->dlerror_buf || self->dlerror_buf == (void *)-1) +		return; +	void *h; +	do { +		h = freebuf_queue; +		*(void **)self->dlerror_buf = h; +	} while (a_cas_p(&freebuf_queue, h, self->dlerror_buf) != h);  }  hidden void __dl_vseterr(const char *fmt, va_list ap)  { -	LOCK(freebuf_queue_lock); -	void **q = freebuf_queue; -	freebuf_queue = 0; -	UNLOCK(freebuf_queue_lock); +	void **q; +	do q = freebuf_queue; +	while (q && a_cas_p(&freebuf_queue, q, 0) != q);  	while (q) {  		void **p = *q; 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/ftw.c b/src/legacy/ftw.c index 506bd29c..e757fc6f 100644 --- a/src/legacy/ftw.c +++ b/src/legacy/ftw.c @@ -7,5 +7,3 @@ int ftw(const char *path, int (*fn)(const char *, const struct stat *, int), int  	 * actually undefined, but works on all real-world machines. */  	return nftw(path, (int (*)())fn, fd_limit, FTW_PHYS);  } - -weak_alias(ftw, ftw64); 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/epoll.c b/src/linux/epoll.c index 93baa814..e56e8f4c 100644 --- a/src/linux/epoll.c +++ b/src/linux/epoll.c @@ -5,6 +5,7 @@  int epoll_create(int size)  { +	if (size<=0) return __syscall_ret(-EINVAL);  	return epoll_create1(0);  } diff --git a/src/linux/fallocate.c b/src/linux/fallocate.c index 7d68bc8f..9146350e 100644 --- a/src/linux/fallocate.c +++ b/src/linux/fallocate.c @@ -7,6 +7,3 @@ int fallocate(int fd, int mode, off_t base, off_t len)  	return syscall(SYS_fallocate, fd, mode, __SYSCALL_LL_E(base),  		__SYSCALL_LL_E(len));  } - -#undef fallocate64 -weak_alias(fallocate, fallocate64); diff --git a/src/linux/getdents.c b/src/linux/getdents.c index 796c1e5c..97f76e14 100644 --- a/src/linux/getdents.c +++ b/src/linux/getdents.c @@ -8,5 +8,3 @@ int getdents(int fd, struct dirent *buf, size_t len)  	if (len>INT_MAX) len = INT_MAX;  	return syscall(SYS_getdents, fd, buf, len);  } - -weak_alias(getdents, getdents64); diff --git a/src/linux/membarrier.c b/src/linux/membarrier.c index 343f7360..f64fe7e1 100644 --- a/src/linux/membarrier.c +++ b/src/linux/membarrier.c @@ -35,7 +35,7 @@ int __membarrier(int cmd, int flags)  		__tl_lock();  		sem_init(&barrier_sem, 0, 0);  		struct sigaction sa = { -			.sa_flags = SA_RESTART, +			.sa_flags = SA_RESTART | SA_ONSTACK,  			.sa_handler = bcast_barrier  		};  		memset(&sa.sa_mask, -1, sizeof sa.sa_mask); 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/prlimit.c b/src/linux/prlimit.c index 3df9ffba..fcf45aab 100644 --- a/src/linux/prlimit.c +++ b/src/linux/prlimit.c @@ -21,6 +21,3 @@ int prlimit(pid_t pid, int resource, const struct rlimit *new_limit, struct rlim  	}  	return r;  } - -#undef prlimit64 -weak_alias(prlimit, prlimit64); 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/sendfile.c b/src/linux/sendfile.c index 9afe6dd6..fc1577d3 100644 --- a/src/linux/sendfile.c +++ b/src/linux/sendfile.c @@ -5,5 +5,3 @@ ssize_t sendfile(int out_fd, int in_fd, off_t *ofs, size_t count)  {  	return syscall(SYS_sendfile, out_fd, in_fd, ofs, count);  } - -weak_alias(sendfile, sendfile64); 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 83650e34..fb08c0d0 100644 --- a/src/linux/wait4.c +++ b/src/linux/wait4.c @@ -12,7 +12,7 @@ pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru)  	if (ru) {  		long long kru64[18];  		r = __syscall(SYS_wait4_time64, pid, status, options, kru64); -		if (!r) { +		if (r > 0) {  			ru->ru_utime = (struct timeval)  				{ .tv_sec = kru64[0], .tv_usec = kru64[1] };  			ru->ru_stime = (struct timeval) @@ -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/malloc/mallocng/free.c b/src/malloc/mallocng/free.c index 418a085c..43f32aad 100644 --- a/src/malloc/mallocng/free.c +++ b/src/malloc/mallocng/free.c @@ -119,7 +119,7 @@ void free(void *p)  	if (((uintptr_t)(start-1) ^ (uintptr_t)end) >= 2*PGSZ && g->last_idx) {  		unsigned char *base = start + (-(uintptr_t)start & (PGSZ-1));  		size_t len = (end-base) & -PGSZ; -		if (len) { +		if (len && USE_MADV_FREE) {  			int e = errno;  			madvise(base, len, MADV_FREE);  			errno = e; diff --git a/src/malloc/mallocng/glue.h b/src/malloc/mallocng/glue.h index 151c48b8..77f4c812 100644 --- a/src/malloc/mallocng/glue.h +++ b/src/malloc/mallocng/glue.h @@ -24,6 +24,8 @@  #define realloc __libc_realloc  #define free __libc_free +#define USE_MADV_FREE 0 +  #if USE_REAL_ASSERT  #include <assert.h>  #else 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/logf.c b/src/math/logf.c index 7ee5d7fe..e4c2237c 100644 --- a/src/math/logf.c +++ b/src/math/logf.c @@ -53,7 +53,7 @@ float logf(float x)  	tmp = ix - OFF;  	i = (tmp >> (23 - LOGF_TABLE_BITS)) % N;  	k = (int32_t)tmp >> 23; /* arithmetic shift */ -	iz = ix - (tmp & 0x1ff << 23); +	iz = ix - (tmp & 0xff800000);  	invc = T[i].invc;  	logc = T[i].logc;  	z = (double_t)asfloat(iz); 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/getopt.c b/src/misc/getopt.c index c3f66995..b02b81c3 100644 --- a/src/misc/getopt.c +++ b/src/misc/getopt.c @@ -87,7 +87,8 @@ int getopt(int argc, char * const argv[], const char *optstring)  	if (optstring[i] == ':') {  		optarg = 0;  		if (optstring[i+1] != ':' || optpos) { -			optarg = argv[optind++] + optpos; +			optarg = argv[optind++]; +			if (optpos) optarg += optpos;  			optpos = 0;  		}  		if (optind > argc) { diff --git a/src/misc/getrlimit.c b/src/misc/getrlimit.c index bf676307..a5558d81 100644 --- a/src/misc/getrlimit.c +++ b/src/misc/getrlimit.c @@ -26,5 +26,3 @@ int getrlimit(int resource, struct rlimit *rlim)  	return ret;  #endif  } - -weak_alias(getrlimit, getrlimit64); 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/lockf.c b/src/misc/lockf.c index 16a80bec..0162442b 100644 --- a/src/misc/lockf.c +++ b/src/misc/lockf.c @@ -28,5 +28,3 @@ int lockf(int fd, int op, off_t size)  	errno = EINVAL;  	return -1;  } - -weak_alias(lockf, lockf64); 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/nftw.c b/src/misc/nftw.c index 8dcff7fe..71bc62ee 100644 --- a/src/misc/nftw.c +++ b/src/misc/nftw.c @@ -31,6 +31,8 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,  	int err;  	struct FTW lev; +	st.st_dev = st.st_ino = 0; +  	if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) {  		if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st))  			type = FTW_SLN; @@ -46,7 +48,7 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,  		type = FTW_F;  	} -	if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev) +	if ((flags & FTW_MOUNT) && h && type != FTW_NS && st.st_dev != h->dev)  		return 0;  	new.chain = h; @@ -138,5 +140,3 @@ int nftw(const char *path, int (*fn)(const char *, const struct stat *, int, str  	pthread_setcancelstate(cs, 0);  	return r;  } - -weak_alias(nftw, nftw64); diff --git a/src/misc/setrlimit.c b/src/misc/setrlimit.c index 5b713cf3..edb413fa 100644 --- a/src/misc/setrlimit.c +++ b/src/misc/setrlimit.c @@ -49,5 +49,3 @@ int setrlimit(int resource, const struct rlimit *rlim)  	return __syscall_ret(ret);  #endif  } - -weak_alias(setrlimit, setrlimit64); 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/mman/mmap.c b/src/mman/mmap.c index eff88d82..43e5e029 100644 --- a/src/mman/mmap.c +++ b/src/mman/mmap.c @@ -37,5 +37,3 @@ void *__mmap(void *start, size_t len, int prot, int flags, int fd, off_t off)  }  weak_alias(__mmap, mmap); - -weak_alias(mmap, mmap64); diff --git a/src/mq/mq_notify.c b/src/mq/mq_notify.c index 221591c7..0e1e6c7a 100644 --- a/src/mq/mq_notify.c +++ b/src/mq/mq_notify.c @@ -4,11 +4,14 @@  #include <sys/socket.h>  #include <signal.h>  #include <unistd.h> +#include <semaphore.h>  #include "syscall.h"  struct args { -	pthread_barrier_t barrier; +	sem_t sem;  	int sock; +	mqd_t mqd; +	int err;  	const struct sigevent *sev;  }; @@ -20,8 +23,19 @@ static void *start(void *p)  	int s = args->sock;  	void (*func)(union sigval) = args->sev->sigev_notify_function;  	union sigval val = args->sev->sigev_value; +	struct sigevent sev2; +	static const char zeros[32]; +	int err; + +	sev2.sigev_notify = SIGEV_THREAD; +	sev2.sigev_signo = s; +	sev2.sigev_value.sival_ptr = (void *)&zeros; + +	args->err = err = -__syscall(SYS_mq_notify, args->mqd, &sev2); +	sem_post(&args->sem); +	if (err) return 0; -	pthread_barrier_wait(&args->barrier); +	pthread_detach(pthread_self());  	n = recv(s, buf, sizeof(buf), MSG_NOSIGNAL|MSG_WAITALL);  	close(s);  	if (n==sizeof buf && buf[sizeof buf - 1] == 1) @@ -35,8 +49,8 @@ int mq_notify(mqd_t mqd, const struct sigevent *sev)  	pthread_attr_t attr;  	pthread_t td;  	int s; -	struct sigevent sev2; -	static const char zeros[32]; +	int cs; +	sigset_t allmask, origmask;  	if (!sev || sev->sigev_notify != SIGEV_THREAD)  		return syscall(SYS_mq_notify, mqd, sev); @@ -44,30 +58,35 @@ int mq_notify(mqd_t mqd, const struct sigevent *sev)  	s = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, 0);  	if (s < 0) return -1;  	args.sock = s; +	args.mqd = mqd;  	if (sev->sigev_notify_attributes) attr = *sev->sigev_notify_attributes;  	else pthread_attr_init(&attr); -	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); -	pthread_barrier_init(&args.barrier, 0, 2); +	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); +	sem_init(&args.sem, 0, 0); +	sigfillset(&allmask); +	pthread_sigmask(SIG_BLOCK, &allmask, &origmask);  	if (pthread_create(&td, &attr, start, &args)) {  		__syscall(SYS_close, s); +		pthread_sigmask(SIG_SETMASK, &origmask, 0);  		errno = EAGAIN;  		return -1;  	} +	pthread_sigmask(SIG_SETMASK, &origmask, 0); -	pthread_barrier_wait(&args.barrier); -	pthread_barrier_destroy(&args.barrier); - -	sev2.sigev_notify = SIGEV_THREAD; -	sev2.sigev_signo = s; -	sev2.sigev_value.sival_ptr = (void *)&zeros; +	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); +	sem_wait(&args.sem); +	sem_destroy(&args.sem); -	if (syscall(SYS_mq_notify, mqd, &sev2) < 0) { -		pthread_cancel(td); +	if (args.err) {  		__syscall(SYS_close, s); +		pthread_join(td, 0); +		pthread_setcancelstate(cs, 0); +		errno = args.err;  		return -1;  	} +	pthread_setcancelstate(cs, 0);  	return 0;  } 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/accept4.c b/src/network/accept4.c index 59ab1726..765a38ed 100644 --- a/src/network/accept4.c +++ b/src/network/accept4.c @@ -9,6 +9,10 @@ int accept4(int fd, struct sockaddr *restrict addr, socklen_t *restrict len, int  	if (!flg) return accept(fd, addr, len);  	int ret = socketcall_cp(accept4, fd, addr, len, flg, 0, 0);  	if (ret>=0 || (errno != ENOSYS && errno != EINVAL)) return ret; +	if (flg & ~(SOCK_CLOEXEC|SOCK_NONBLOCK)) { +		errno = EINVAL; +		return -1; +	}  	ret = accept(fd, addr, len);  	if (ret<0) return ret;  	if (flg & SOCK_CLOEXEC) diff --git a/src/network/dns_parse.c b/src/network/dns_parse.c index e6ee19d9..09813112 100644 --- a/src/network/dns_parse.c +++ b/src/network/dns_parse.c @@ -1,7 +1,7 @@  #include <string.h>  #include "lookup.h" -int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *), void *ctx) +int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *, int), void *ctx)  {  	int qdcount, ancount;  	const unsigned char *p; @@ -12,21 +12,20 @@ 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>193 || (*p==193 && p[1]>254) || p>r+rlen-6) +		if (p>r+rlen-6)  			return -1;  		p += 5 + !!*p;  	}  	while (ancount--) {  		while (p-r < rlen && *p-1U < 127) p++; -		if (*p>193 || (*p==193 && p[1]>254) || p>r+rlen-6) +		if (p>r+rlen-12)  			return -1;  		p += 1 + !!*p;  		len = p[8]*256 + p[9]; -		if (p+len > r+rlen) return -1; -		if (callback(ctx, p[1], p+10, len, r) < 0) return -1; +		if (len+10 > r+rlen-p) return -1; +		if (callback(ctx, p[1], p+10, len, r, rlen) < 0) return -1;  		p += 10 + len;  	}  	return 0; diff --git a/src/network/gai_strerror.c b/src/network/gai_strerror.c index 9596580e..56b71503 100644 --- a/src/network/gai_strerror.c +++ b/src/network/gai_strerror.c @@ -6,7 +6,7 @@ static const char msgs[] =  	"Name does not resolve\0"  	"Try again\0"  	"Non-recoverable error\0" -	"Unknown error\0" +	"Name has no usable address\0"  	"Unrecognized address family or invalid length\0"  	"Unrecognized socket type\0"  	"Unrecognized service\0" diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c index 9df045f6..64ad259a 100644 --- a/src/network/getaddrinfo.c +++ b/src/network/getaddrinfo.c @@ -16,6 +16,7 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru  	char canon[256], *outcanon;  	int nservs, naddrs, nais, canon_len, i, j, k;  	int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0; +	int no_family = 0;  	struct aibuf *out;  	if (!host && !serv) return EAI_NONAME; @@ -82,7 +83,7 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru  			default:  				return EAI_SYSTEM;  			} -			if (family == tf[i]) return EAI_NONAME; +			if (family == tf[i]) no_family = 1;  			family = tf[1-i];  		}  	} @@ -93,6 +94,8 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru  	naddrs = __lookup_name(addrs, canon, host, family, flags);  	if (naddrs < 0) return naddrs; +	if (no_family) return EAI_NODATA; +  	nais = nservs * naddrs;  	canon_len = strlen(canon);  	out = calloc(1, nais * sizeof(*out) + canon_len + 1); diff --git a/src/network/gethostbyaddr.c b/src/network/gethostbyaddr.c index 598e2241..c3cacaac 100644 --- a/src/network/gethostbyaddr.c +++ b/src/network/gethostbyaddr.c @@ -20,5 +20,5 @@ struct hostent *gethostbyaddr(const void *a, socklen_t l, int af)  		err = gethostbyaddr_r(a, l, af, h,  			(void *)(h+1), size-sizeof *h, &res, &h_errno);  	} while (err == ERANGE); -	return err ? 0 : h; +	return res;  } diff --git a/src/network/gethostbyaddr_r.c b/src/network/gethostbyaddr_r.c index 0f1e61aa..ceaf3935 100644 --- a/src/network/gethostbyaddr_r.c +++ b/src/network/gethostbyaddr_r.c @@ -54,10 +54,11 @@ int gethostbyaddr_r(const void *a, socklen_t l, int af,  	case EAI_OVERFLOW:  		return ERANGE;  	default: -	case EAI_MEMORY: -	case EAI_SYSTEM:  	case EAI_FAIL:  		*err = NO_RECOVERY; +		return EBADMSG; +	case EAI_SYSTEM: +		*err = NO_RECOVERY;  		return errno;  	case 0:  		break; diff --git a/src/network/gethostbyname2.c b/src/network/gethostbyname2.c index dc9d6621..bd0da7f8 100644 --- a/src/network/gethostbyname2.c +++ b/src/network/gethostbyname2.c @@ -21,5 +21,5 @@ struct hostent *gethostbyname2(const char *name, int af)  		err = gethostbyname2_r(name, af, h,  			(void *)(h+1), size-sizeof *h, &res, &h_errno);  	} while (err == ERANGE); -	return err ? 0 : h; +	return res;  } diff --git a/src/network/gethostbyname2_r.c b/src/network/gethostbyname2_r.c index fc894877..a5eb67fe 100644 --- a/src/network/gethostbyname2_r.c +++ b/src/network/gethostbyname2_r.c @@ -22,7 +22,10 @@ int gethostbyname2_r(const char *name, int af,  	if (cnt<0) switch (cnt) {  	case EAI_NONAME:  		*err = HOST_NOT_FOUND; -		return ENOENT; +		return 0; +	case EAI_NODATA: +		*err = NO_DATA; +		return 0;  	case EAI_AGAIN:  		*err = TRY_AGAIN;  		return EAGAIN; @@ -30,7 +33,6 @@ int gethostbyname2_r(const char *name, int af,  	case EAI_FAIL:  		*err = NO_RECOVERY;  		return EBADMSG; -	case EAI_MEMORY:  	case EAI_SYSTEM:  		*err = NO_RECOVERY;  		return errno; diff --git a/src/network/getifaddrs.c b/src/network/getifaddrs.c index fed75bd8..74df4d6c 100644 --- a/src/network/getifaddrs.c +++ b/src/network/getifaddrs.c @@ -39,8 +39,8 @@ struct ifaddrs_storage {  };  struct ifaddrs_ctx { -	struct ifaddrs_storage *first; -	struct ifaddrs_storage *last; +	struct ifaddrs *first; +	struct ifaddrs *last;  	struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE];  }; @@ -195,9 +195,9 @@ static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h)  	}  	if (ifs->ifa.ifa_name) { -		if (!ctx->first) ctx->first = ifs; -		if (ctx->last) ctx->last->ifa.ifa_next = &ifs->ifa; -		ctx->last = ifs; +		if (!ctx->first) ctx->first = &ifs->ifa; +		if (ctx->last) ctx->last->ifa_next = &ifs->ifa; +		ctx->last = &ifs->ifa;  	} else {  		free(ifs);  	} @@ -210,7 +210,7 @@ int getifaddrs(struct ifaddrs **ifap)  	int r;  	memset(ctx, 0, sizeof *ctx);  	r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx); -	if (r == 0) *ifap = &ctx->first->ifa; -	else freeifaddrs(&ctx->first->ifa); +	if (r == 0) *ifap = ctx->first; +	else freeifaddrs(ctx->first);  	return r;  } diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c index 949e1811..133c15b3 100644 --- a/src/network/getnameinfo.c +++ b/src/network/getnameinfo.c @@ -58,6 +58,7 @@ static void reverse_hosts(char *buf, const unsigned char *a, unsigned scopeid, i  		if ((p=strchr(line, '#'))) *p++='\n', *p=0;  		for (p=line; *p && !isspace(*p); p++); +		if (!*p) continue;  		*p++ = 0;  		if (__lookup_ipliteral(&iplit, line, AF_UNSPEC)<=0)  			continue; @@ -108,10 +109,10 @@ static void reverse_services(char *buf, int port, int dgram)  	__fclose_ca(f);  } -static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet) +static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen)  {  	if (rr != RR_PTR) return 0; -	if (__dn_expand(packet, (const unsigned char *)packet + 512, +	if (__dn_expand(packet, (const unsigned char *)packet + plen,  	    data, c, 256) <= 0)  		*(char *)c = 0;  	return 0; @@ -161,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/getservbyport_r.c b/src/network/getservbyport_r.c index b7f21c6b..e4cc3079 100644 --- a/src/network/getservbyport_r.c +++ b/src/network/getservbyport_r.c @@ -26,7 +26,7 @@ int getservbyport_r(int port, const char *prots,  	/* Align buffer */  	i = (uintptr_t)buf & sizeof(char *)-1;  	if (!i) i = sizeof(char *); -	if (buflen < 3*sizeof(char *)-i) +	if (buflen <= 3*sizeof(char *)-i)  		return ERANGE;  	buf += sizeof(char *)-i;  	buflen -= sizeof(char *)-i; @@ -46,6 +46,8 @@ int getservbyport_r(int port, const char *prots,  	case EAI_MEMORY:  	case EAI_SYSTEM:  		return ENOMEM; +	case EAI_OVERFLOW: +		return ERANGE;  	default:  		return ENOENT;  	case 0: 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/inet_pton.c b/src/network/inet_pton.c index d36c3689..bcbdd9ef 100644 --- a/src/network/inet_pton.c +++ b/src/network/inet_pton.c @@ -54,6 +54,7 @@ int inet_pton(int af, const char *restrict s, void *restrict a0)  			if (s[j]!='.' || (i<6 && brk<0)) return 0;  			need_v4=1;  			i++; +			ip[i&7]=0;  			break;  		}  		s += j+1; diff --git a/src/network/lookup.h b/src/network/lookup.h index ef662725..54b2f8b5 100644 --- a/src/network/lookup.h +++ b/src/network/lookup.h @@ -50,6 +50,6 @@ hidden int __lookup_ipliteral(struct address buf[static 1], const char *name, in  hidden int __get_resolv_conf(struct resolvconf *, char *, size_t);  hidden int __res_msend_rc(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int, const struct resolvconf *); -hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *); +hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *, int), void *);  #endif diff --git a/src/network/lookup_ipliteral.c b/src/network/lookup_ipliteral.c index 2fddab73..1e766206 100644 --- a/src/network/lookup_ipliteral.c +++ b/src/network/lookup_ipliteral.c @@ -15,7 +15,7 @@ int __lookup_ipliteral(struct address buf[static 1], const char *name, int famil  	struct in6_addr a6;  	if (__inet_aton(name, &a4) > 0) {  		if (family == AF_INET6) /* wrong family */ -			return EAI_NONAME; +			return EAI_NODATA;  		memcpy(&buf[0].addr, &a4, sizeof a4);  		buf[0].family = AF_INET;  		buf[0].scopeid = 0; @@ -34,7 +34,7 @@ int __lookup_ipliteral(struct address buf[static 1], const char *name, int famil  	if (inet_pton(AF_INET6, name, &a6) <= 0)  		return 0;  	if (family == AF_INET) /* wrong family */ -		return EAI_NONAME; +		return EAI_NODATA;  	memcpy(&buf[0].addr, &a6, sizeof a6);  	buf[0].family = AF_INET6; diff --git a/src/network/lookup_name.c b/src/network/lookup_name.c index b5232ce8..35218185 100644 --- a/src/network/lookup_name.c +++ b/src/network/lookup_name.c @@ -79,7 +79,7 @@ static int name_from_hosts(struct address buf[static MAXADDRS], char canon[stati  		case 0:  			continue;  		default: -			badfam = EAI_NONAME; +			badfam = EAI_NODATA;  			break;  		} @@ -102,45 +102,50 @@ struct dpc_ctx {  	struct address *addrs;  	char *canon;  	int cnt; +	int rrtype;  };  #define RR_A 1  #define RR_CNAME 5  #define RR_AAAA 28 -static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet) +#define ABUF_SIZE 4800 + +static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen)  {  	char tmp[256]; +	int family;  	struct dpc_ctx *ctx = c; -	if (ctx->cnt >= MAXADDRS) return -1; +	if (rr == RR_CNAME) { +		if (__dn_expand(packet, (const unsigned char *)packet + plen, +		    data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp)) +			strcpy(ctx->canon, tmp); +		return 0; +	} +	if (ctx->cnt >= MAXADDRS) return 0; +	if (rr != ctx->rrtype) return 0;  	switch (rr) {  	case RR_A:  		if (len != 4) return -1; -		ctx->addrs[ctx->cnt].family = AF_INET; -		ctx->addrs[ctx->cnt].scopeid = 0; -		memcpy(ctx->addrs[ctx->cnt++].addr, data, 4); +		family = AF_INET;  		break;  	case RR_AAAA:  		if (len != 16) return -1; -		ctx->addrs[ctx->cnt].family = AF_INET6; -		ctx->addrs[ctx->cnt].scopeid = 0; -		memcpy(ctx->addrs[ctx->cnt++].addr, data, 16); -		break; -	case RR_CNAME: -		if (__dn_expand(packet, (const unsigned char *)packet + 512, -		    data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp)) -			strcpy(ctx->canon, tmp); +		family = AF_INET6;  		break;  	} +	ctx->addrs[ctx->cnt].family = family; +	ctx->addrs[ctx->cnt].scopeid = 0; +	memcpy(ctx->addrs[ctx->cnt++].addr, data, len);  	return 0;  }  static int name_from_dns(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, const struct resolvconf *conf)  { -	unsigned char qbuf[2][280], abuf[2][512]; +	unsigned char qbuf[2][280], abuf[2][ABUF_SIZE];  	const unsigned char *qp[2] = { qbuf[0], qbuf[1] };  	unsigned char *ap[2] = { abuf[0], abuf[1] }; -	int qlens[2], alens[2]; +	int qlens[2], alens[2], qtypes[2];  	int i, nq = 0;  	struct dpc_ctx ctx = { .addrs = buf, .canon = canon };  	static const struct { int af; int rr; } afrr[2] = { @@ -153,7 +158,8 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static  			qlens[nq] = __res_mkquery(0, name, 1, afrr[i].rr,  				0, 0, 0, qbuf[nq], sizeof *qbuf);  			if (qlens[nq] == -1) -				return EAI_NONAME; +				return 0; +			qtypes[nq] = afrr[i].rr;  			qbuf[nq][3] = 0; /* don't need AD flag */  			/* Ensure query IDs are distinct. */  			if (nq && qbuf[nq][0] == qbuf[0][0]) @@ -171,11 +177,14 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static  		if ((abuf[i][3] & 15) != 0) return EAI_FAIL;  	} -	for (i=0; i<nq; i++) +	for (i=nq-1; i>=0; i--) { +		ctx.rrtype = qtypes[i]; +		if (alens[i] > sizeof(abuf[i])) alens[i] = sizeof abuf[i];  		__dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx); +	}  	if (ctx.cnt) return ctx.cnt; -	return EAI_NONAME; +	return EAI_NODATA;  }  static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family) diff --git a/src/network/res_mkquery.c b/src/network/res_mkquery.c index 33f50cb9..614bf786 100644 --- a/src/network/res_mkquery.c +++ b/src/network/res_mkquery.c @@ -13,6 +13,7 @@ int __res_mkquery(int op, const char *dname, int class, int type,  	int n;  	if (l && dname[l-1]=='.') l--; +	if (l && dname[l-1]=='.') return -1;  	n = 17+l+!!l;  	if (l>253 || buflen<n || op>15u || class>255u || type>255u)  		return -1; diff --git a/src/network/res_msend.c b/src/network/res_msend.c index 3e018009..fcb52513 100644 --- a/src/network/res_msend.c +++ b/src/network/res_msend.c @@ -1,5 +1,6 @@  #include <sys/socket.h>  #include <netinet/in.h> +#include <netinet/tcp.h>  #include <netdb.h>  #include <arpa/inet.h>  #include <stdint.h> @@ -16,17 +17,65 @@  static void cleanup(void *p)  { -	__syscall(SYS_close, (intptr_t)p); +	struct pollfd *pfd = p; +	for (int i=0; pfd[i].fd >= -1; i++) +		if (pfd[i].fd >= 0) __syscall(SYS_close, pfd[i].fd);  }  static unsigned long mtime()  {  	struct timespec ts; -	clock_gettime(CLOCK_REALTIME, &ts); +	if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0 && errno == ENOSYS) +		clock_gettime(CLOCK_REALTIME, &ts);  	return (unsigned long)ts.tv_sec * 1000  		+ ts.tv_nsec / 1000000;  } +static int start_tcp(struct pollfd *pfd, int family, const void *sa, socklen_t sl, const unsigned char *q, int ql) +{ +	struct msghdr mh = { +		.msg_name = (void *)sa, +		.msg_namelen = sl, +		.msg_iovlen = 2, +		.msg_iov = (struct iovec [2]){ +			{ .iov_base = (uint8_t[]){ ql>>8, ql }, .iov_len = 2 }, +			{ .iov_base = (void *)q, .iov_len = ql } } +	}; +	int r; +	int fd = socket(family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); +	pfd->fd = fd; +	pfd->events = POLLOUT; +	if (!setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, +	    &(int){1}, sizeof(int))) { +		r = sendmsg(fd, &mh, MSG_FASTOPEN|MSG_NOSIGNAL); +		if (r == ql+2) pfd->events = POLLIN; +		if (r >= 0) return r; +		if (errno == EINPROGRESS) return 0; +	} +	r = connect(fd, sa, sl); +	if (!r || errno == EINPROGRESS) return 0; +	close(fd); +	pfd->fd = -1; +	return -1; +} + +static void step_mh(struct msghdr *mh, size_t n) +{ +	/* Adjust iovec in msghdr to skip first n bytes. */ +	while (mh->msg_iovlen && n >= mh->msg_iov->iov_len) { +		n -= mh->msg_iov->iov_len; +		mh->msg_iov++; +		mh->msg_iovlen--; +	} +	if (!mh->msg_iovlen) return; +	mh->msg_iov->iov_base = (char *)mh->msg_iov->iov_base + n; +	mh->msg_iov->iov_len -= n; +} + +/* Internal contract for __res_msend[_rc]: asize must be >=512, nqueries + * must be sufficiently small to be safe as VLA size. In practice it's + * either 1 or 2, anyway. */ +  int __res_msend_rc(int nqueries, const unsigned char *const *queries,  	const int *qlens, unsigned char *const *answers, int *alens, int asize,  	const struct resolvconf *conf) @@ -34,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; @@ -44,7 +93,10 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,  	int next;  	int i, j;  	int cs; -	struct pollfd pfd; +	struct pollfd pfd[nqueries+2]; +	int qpos[nqueries], apos[nqueries]; +	unsigned char alen_buf[nqueries][2]; +	int r;  	unsigned long t0, t1, t2;  	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); @@ -68,29 +120,22 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,  	}  	/* Get local address and open/bind a socket */ -	sa.sin.sin_family = family;  	fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);  	/* Handle case where system lacks IPv6 support */  	if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) { +		for (i=0; i<nns && conf->ns[nns].family == AF_INET6; i++); +		if (i==nns) { +			pthread_setcancelstate(cs, 0); +			return -1; +		}  		fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);  		family = AF_INET; +		sl = sizeof sa.sin;  	} -	if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) { -		if (fd >= 0) close(fd); -		pthread_setcancelstate(cs, 0); -		return -1; -	} - -	/* Past this point, there are no errors. Each individual query will -	 * yield either no reply (indicated by zero length) or an answer -	 * packet which is up to the caller to interpret. */ - -	pthread_cleanup_push(cleanup, (void *)(intptr_t)fd); -	pthread_setcancelstate(cs, 0);  	/* Convert any IPv4 addresses in a mixed environment to v4-mapped */ -	if (family == AF_INET6) { +	if (fd >= 0 && family == AF_INET6) {  		setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0);  		for (i=0; i<nns; i++) {  			if (ns[i].sin.sin_family != AF_INET) continue; @@ -104,16 +149,38 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,  		}  	} +	sa.sin.sin_family = family; +	if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) { +		if (fd >= 0) close(fd); +		pthread_setcancelstate(cs, 0); +		return -1; +	} + +	/* Past this point, there are no errors. Each individual query will +	 * yield either no reply (indicated by zero length) or an answer +	 * packet which is up to the caller to interpret. */ + +	for (i=0; i<nqueries; i++) pfd[i].fd = -1; +	pfd[nqueries].fd = fd; +	pfd[nqueries].events = POLLIN; +	pfd[nqueries+1].fd = -2; + +	pthread_cleanup_push(cleanup, pfd); +	pthread_setcancelstate(cs, 0); +  	memset(alens, 0, sizeof *alens * nqueries); -	pfd.fd = fd; -	pfd.events = POLLIN;  	retry_interval = timeout / attempts;  	next = 0;  	t0 = t2 = mtime();  	t1 = t2 - retry_interval;  	for (; t2-t0 < timeout; t2=mtime()) { +		/* This is the loop exit condition: that all queries +		 * have an accepted answer. */ +		for (i=0; i<nqueries && alens[i]>0; i++); +		if (i==nqueries) break; +  		if (t2-t1 >= retry_interval) {  			/* Query all configured namservers in parallel */  			for (i=0; i<nqueries; i++) @@ -127,10 +194,20 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,  		}  		/* Wait for a response, or until time to retry */ -		if (poll(&pfd, 1, t1+retry_interval-t2) <= 0) continue; +		if (poll(pfd, nqueries+1, t1+retry_interval-t2) <= 0) continue; -		while ((rlen = recvfrom(fd, answers[next], asize, 0, -		  (void *)&sa, (socklen_t[1]){sl})) >= 0) { +		while (next < nqueries) { +			struct msghdr mh = { +				.msg_name = (void *)&sa, +				.msg_namelen = sl, +				.msg_iovlen = 1, +				.msg_iov = (struct iovec []){ +					{ .iov_base = (void *)answers[next], +					  .iov_len = asize } +				} +			}; +			rlen = recvmsg(fd, &mh, 0); +			if (rlen < 0) break;  			/* Ignore non-identifiable packets */  			if (rlen < 4) continue; @@ -170,12 +247,72 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,  			else  				memcpy(answers[i], answers[next], rlen); -			if (next == nqueries) goto out; +			/* Ignore further UDP if all slots full or TCP-mode */ +			if (next == nqueries) pfd[nqueries].events = 0; + +			/* If answer is truncated (TC bit), fallback to TCP */ +			if ((answers[i][2] & 2) || (mh.msg_flags & MSG_TRUNC)) { +				alens[i] = -1; +				pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); +				r = start_tcp(pfd+i, family, ns+j, sl, queries[i], qlens[i]); +				pthread_setcancelstate(cs, 0); +				if (r >= 0) { +					qpos[i] = r; +					apos[i] = 0; +				} +				continue; +			} +		} + +		for (i=0; i<nqueries; i++) if (pfd[i].revents & POLLOUT) { +			struct msghdr mh = { +				.msg_iovlen = 2, +				.msg_iov = (struct iovec [2]){ +					{ .iov_base = (uint8_t[]){ qlens[i]>>8, qlens[i] }, .iov_len = 2 }, +					{ .iov_base = (void *)queries[i], .iov_len = qlens[i] } } +			}; +			step_mh(&mh, qpos[i]); +			r = sendmsg(pfd[i].fd, &mh, MSG_NOSIGNAL); +			if (r < 0) goto out; +			qpos[i] += r; +			if (qpos[i] == qlens[i]+2) +				pfd[i].events = POLLIN; +		} + +		for (i=0; i<nqueries; i++) if (pfd[i].revents & POLLIN) { +			struct msghdr mh = { +				.msg_iovlen = 2, +				.msg_iov = (struct iovec [2]){ +					{ .iov_base = alen_buf[i], .iov_len = 2 }, +					{ .iov_base = answers[i], .iov_len = asize } } +			}; +			step_mh(&mh, apos[i]); +			r = recvmsg(pfd[i].fd, &mh, 0); +			if (r <= 0) goto out; +			apos[i] += r; +			if (apos[i] < 2) continue; +			int alen = alen_buf[i][0]*256 + alen_buf[i][1]; +			if (alen < 13) goto out; +			if (apos[i] < alen+2 && apos[i] < asize+2) +				continue; +			int rcode = answers[i][3] & 15; +			if (rcode != 0 && rcode != 3) +				goto out; + +			/* Storing the length here commits the accepted answer. +			 * Immediately close TCP socket so as not to consume +			 * resources we no longer need. */ +			alens[i] = alen; +			__syscall(SYS_close, pfd[i].fd); +			pfd[i].fd = -1;  		}  	}  out:  	pthread_cleanup_pop(1); +	/* Disregard any incomplete TCP results */ +	for (i=0; i<nqueries; i++) if (alens[i]<0) alens[i] = 0; +  	return 0;  } diff --git a/src/network/res_send.c b/src/network/res_send.c index ee4abf1f..9593164d 100644 --- a/src/network/res_send.c +++ b/src/network/res_send.c @@ -1,8 +1,16 @@  #include <resolv.h> +#include <string.h>  int __res_send(const unsigned char *msg, int msglen, unsigned char *answer, int anslen)  { -	int r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen); +	int r; +	if (anslen < 512) { +		unsigned char buf[512]; +		r = __res_send(msg, msglen, buf, sizeof buf); +		if (r >= 0) memcpy(answer, buf, r < anslen ? r : anslen); +		return r; +	} +	r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen);  	return r<0 || !anslen ? -1 : anslen;  } diff --git a/src/network/sendmsg.c b/src/network/sendmsg.c index 80cc5f41..acdfdf29 100644 --- a/src/network/sendmsg.c +++ b/src/network/sendmsg.c @@ -8,13 +8,16 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)  {  #if LONG_MAX > INT_MAX  	struct msghdr h; -	struct cmsghdr chbuf[1024/sizeof(struct cmsghdr)+1], *c; +	/* Kernels before 2.6.38 set SCM_MAX_FD to 255, allocate enough +	 * space to support an SCM_RIGHTS ancillary message with 255 fds. +	 * Kernels since 2.6.38 set SCM_MAX_FD to 253. */ +	struct cmsghdr chbuf[CMSG_SPACE(255*sizeof(int))/sizeof(struct cmsghdr)+1], *c;  	if (msg) {  		h = *msg;  		h.__pad1 = h.__pad2 = 0;  		msg = &h;  		if (h.msg_controllen) { -			if (h.msg_controllen > 1024) { +			if (h.msg_controllen > sizeof chbuf) {  				errno = ENOMEM;  				return -1;  			} diff --git a/src/process/_Fork.c b/src/process/_Fork.c index da063868..9c07792d 100644 --- a/src/process/_Fork.c +++ b/src/process/_Fork.c @@ -5,25 +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); -	__aio_atfork(-1); -	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,7 +23,21 @@ pid_t _Fork(void)  		if (libc.need_locks) libc.need_locks = -1;  	}  	UNLOCK(__abort_lock); -	__aio_atfork(!ret); +	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/fork.c b/src/process/fork.c index 54bc2892..56f19313 100644 --- a/src/process/fork.c +++ b/src/process/fork.c @@ -9,7 +9,6 @@ static volatile int *const dummy_lockptr = 0;  weak_alias(dummy_lockptr, __at_quick_exit_lockptr);  weak_alias(dummy_lockptr, __atexit_lockptr); -weak_alias(dummy_lockptr, __dlerror_lockptr);  weak_alias(dummy_lockptr, __gettext_lockptr);  weak_alias(dummy_lockptr, __locale_lockptr);  weak_alias(dummy_lockptr, __random_lockptr); @@ -24,7 +23,6 @@ weak_alias(dummy_lockptr, __vmlock_lockptr);  static volatile int *const *const atfork_locks[] = {  	&__at_quick_exit_lockptr,  	&__atexit_lockptr, -	&__dlerror_lockptr,  	&__gettext_lockptr,  	&__locale_lockptr,  	&__random_lockptr, @@ -38,6 +36,8 @@ static volatile int *const *const atfork_locks[] = {  static void dummy(int x) { }  weak_alias(dummy, __fork_handler);  weak_alias(dummy, __malloc_atfork); +weak_alias(dummy, __aio_atfork); +weak_alias(dummy, __pthread_key_atfork);  weak_alias(dummy, __ldso_atfork);  static void dummy_0(void) { } @@ -52,6 +52,8 @@ pid_t fork(void)  	int need_locks = libc.need_locks > 0;  	if (need_locks) {  		__ldso_atfork(-1); +		__pthread_key_atfork(-1); +		__aio_atfork(-1);  		__inhibit_ptc();  		for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)  			if (*atfork_locks[i]) LOCK(*atfork_locks[i]); @@ -77,6 +79,8 @@ pid_t fork(void)  				if (ret) UNLOCK(*atfork_locks[i]);  				else **atfork_locks[i] = 0;  		__release_ptc(); +		if (ret) __aio_atfork(0); +		__pthread_key_atfork(!ret);  		__ldso_atfork(!ret);  	}  	__restore_sigs(&set); 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/riscv64/vfork.s b/src/process/riscv64/vfork.s new file mode 100644 index 00000000..c93dca23 --- /dev/null +++ b/src/process/riscv64/vfork.s @@ -0,0 +1,12 @@ +.global vfork +.type vfork,@function +vfork: +	/* riscv does not have SYS_vfork, so we must use clone instead */ +	/* note: riscv's clone = clone(flags, sp, ptidptr, tls, ctidptr) */ +	li a7, 220 +	li a0, 0x100 | 0x4000 | 17 /* flags = CLONE_VM | CLONE_VFORK | SIGCHLD */ +	mv a1, sp +	/* the other arguments are ignoreable */ +	ecall +	.hidden __syscall_ret +	j __syscall_ret 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 9de080ed..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;  	} @@ -306,6 +306,3 @@ void globfree(glob_t *g)  	g->gl_pathc = 0;  	g->gl_pathv = NULL;  } - -weak_alias(glob, glob64); -weak_alias(globfree, globfree64); diff --git a/src/search/hsearch.c b/src/search/hsearch.c index b3ac8796..2634a67f 100644 --- a/src/search/hsearch.c +++ b/src/search/hsearch.c @@ -41,9 +41,9 @@ static int resize(size_t nel, struct hsearch_data *htab)  {  	size_t newsize;  	size_t i, j; +	size_t oldsize = htab->__tab->mask + 1;  	ENTRY *e, *newe;  	ENTRY *oldtab = htab->__tab->entries; -	ENTRY *oldend = htab->__tab->entries + htab->__tab->mask + 1;  	if (nel > MAXSIZE)  		nel = MAXSIZE; @@ -56,7 +56,7 @@ static int resize(size_t nel, struct hsearch_data *htab)  	htab->__tab->mask = newsize - 1;  	if (!oldtab)  		return 1; -	for (e = oldtab; e < oldend; e++) +	for (e = oldtab; e < oldtab + oldsize; e++)  		if (e->key) {  			for (i=keyhash(e->key),j=1; ; i+=j++) {  				newe = htab->__tab->entries + (i & htab->__tab->mask); diff --git a/src/select/poll.c b/src/select/poll.c index c84c8a99..7883dfab 100644 --- a/src/select/poll.c +++ b/src/select/poll.c @@ -8,8 +8,13 @@ int poll(struct pollfd *fds, nfds_t n, int timeout)  #ifdef SYS_poll  	return syscall_cp(SYS_poll, fds, n, timeout);  #else +#if SYS_ppoll_time64 == SYS_ppoll +	typedef long long ppoll_ts_t[2]; +#else +	typedef long ppoll_ts_t[2]; +#endif  	return syscall_cp(SYS_ppoll, fds, n, timeout>=0 ? -		&((struct timespec){ .tv_sec = timeout/1000, -		.tv_nsec = timeout%1000*1000000 }) : 0, 0, _NSIG/8); +		((ppoll_ts_t){ timeout/1000, timeout%1000*1000000 }) : 0, +		0, _NSIG/8);  #endif  } 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/select/select.c b/src/select/select.c index 8a786884..f1d72863 100644 --- a/src/select/select.c +++ b/src/select/select.c @@ -33,6 +33,7 @@ int select(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict  			((syscall_arg_t[]){ 0, _NSIG/8 }));  	if (SYS_pselect6 == SYS_pselect6_time64 || r!=-ENOSYS)  		return __syscall_ret(r); +	s = CLAMP(s);  #endif  #ifdef SYS_select  	return syscall_cp(SYS_select, n, rfds, wfds, efds, 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/powerpc/longjmp.S b/src/setjmp/powerpc/longjmp.S index 611389fe..465e4cd7 100644 --- a/src/setjmp/powerpc/longjmp.S +++ b/src/setjmp/powerpc/longjmp.S @@ -42,10 +42,10 @@ longjmp:  	bl 1f  	.hidden __hwcap  	.long __hwcap-. -1:	mflr 4 -	lwz 5, 0(4) -	lwzx 4, 4, 5 -	andis. 4, 4, 0x80 +1:	mflr 6 +	lwz 5, 0(6) +	lwzx 6, 6, 5 +	andis. 6, 6, 0x80  	beq 1f  	.long 0x11c35b01 /* evldd 14,88(3) */  	.long 0x11e36301 /* ... */ diff --git a/src/setjmp/riscv32/longjmp.S b/src/setjmp/riscv32/longjmp.S new file mode 100644 index 00000000..b4e5458d --- /dev/null +++ b/src/setjmp/riscv32/longjmp.S @@ -0,0 +1,48 @@ +.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 +#ifdef __riscv_float_abi_double +#define FLX fld +#else +#define FLX flw +#endif + +	FLX fs0,  56(a0) +	FLX fs1,  64(a0) +	FLX fs2,  72(a0) +	FLX fs3,  80(a0) +	FLX fs4,  88(a0) +	FLX fs5,  96(a0) +	FLX fs6,  104(a0) +	FLX fs7,  112(a0) +	FLX fs8,  120(a0) +	FLX fs9,  128(a0) +	FLX fs10, 136(a0) +	FLX 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..5a1a41ef --- /dev/null +++ b/src/setjmp/riscv32/setjmp.S @@ -0,0 +1,47 @@ +.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 +#ifdef __riscv_float_abi_double +#define FSX fsd +#else +#define FSX fsw +#endif + +	FSX fs0,  56(a0) +	FSX fs1,  64(a0) +	FSX fs2,  72(a0) +	FSX fs3,  80(a0) +	FSX fs4,  88(a0) +	FSX fs5,  96(a0) +	FSX fs6,  104(a0) +	FSX fs7,  112(a0) +	FSX fs8,  120(a0) +	FSX fs9,  128(a0) +	FSX fs10, 136(a0) +	FSX fs11, 144(a0) +#endif + +	li a0, 0 +	ret diff --git a/src/setjmp/riscv64/longjmp.S b/src/setjmp/riscv64/longjmp.S index 41e2d210..982475c7 100644 --- a/src/setjmp/riscv64/longjmp.S +++ b/src/setjmp/riscv64/longjmp.S @@ -23,18 +23,24 @@ longjmp:  	ld ra,    104(a0)  #ifndef __riscv_float_abi_soft -	fld fs0,  112(a0) -	fld fs1,  120(a0) -	fld fs2,  128(a0) -	fld fs3,  136(a0) -	fld fs4,  144(a0) -	fld fs5,  152(a0) -	fld fs6,  160(a0) -	fld fs7,  168(a0) -	fld fs8,  176(a0) -	fld fs9,  184(a0) -	fld fs10, 192(a0) -	fld fs11, 200(a0) +#ifdef __riscv_float_abi_double +#define FLX fld +#else +#define FLX flw +#endif + +	FLX fs0,  112(a0) +	FLX fs1,  120(a0) +	FLX fs2,  128(a0) +	FLX fs3,  136(a0) +	FLX fs4,  144(a0) +	FLX fs5,  152(a0) +	FLX fs6,  160(a0) +	FLX fs7,  168(a0) +	FLX fs8,  176(a0) +	FLX fs9,  184(a0) +	FLX fs10, 192(a0) +	FLX fs11, 200(a0)  #endif  	seqz a0, a1 diff --git a/src/setjmp/riscv64/setjmp.S b/src/setjmp/riscv64/setjmp.S index 51249672..0795bf7d 100644 --- a/src/setjmp/riscv64/setjmp.S +++ b/src/setjmp/riscv64/setjmp.S @@ -23,18 +23,24 @@ setjmp:  	sd ra,    104(a0)  #ifndef __riscv_float_abi_soft -	fsd fs0,  112(a0) -	fsd fs1,  120(a0) -	fsd fs2,  128(a0) -	fsd fs3,  136(a0) -	fsd fs4,  144(a0) -	fsd fs5,  152(a0) -	fsd fs6,  160(a0) -	fsd fs7,  168(a0) -	fsd fs8,  176(a0) -	fsd fs9,  184(a0) -	fsd fs10, 192(a0) -	fsd fs11, 200(a0) +#ifdef __riscv_float_abi_double +#define FSX fsd +#else +#define FSX fsw +#endif + +	FSX fs0,  112(a0) +	FSX fs1,  120(a0) +	FSX fs2,  128(a0) +	FSX fs3,  136(a0) +	FSX fs4,  144(a0) +	FSX fs5,  152(a0) +	FSX fs6,  160(a0) +	FSX fs7,  168(a0) +	FSX fs8,  176(a0) +	FSX fs9,  184(a0) +	FSX fs10, 192(a0) +	FSX fs11, 200(a0)  #endif  	li a0, 0 diff --git a/src/signal/mips/restore.s b/src/signal/loongarch64/restore.s index b6dadce0..d90a8ebb 100644 --- a/src/signal/mips/restore.s +++ b/src/signal/loongarch64/restore.s @@ -1,15 +1,10 @@ -.set noreorder -  .global __restore_rt -.hidden __restore_rt -.type   __restore_rt,@function -__restore_rt: -	li $2, 4193 -	syscall -  .global __restore +.hidden __restore_rt  .hidden __restore +.type   __restore_rt,@function  .type   __restore,@function +__restore_rt:  __restore: -	li $2, 4119 -	syscall +	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/mips64/restore.s b/src/signal/mips64/restore.s deleted file mode 100644 index 401f8e73..00000000 --- a/src/signal/mips64/restore.s +++ /dev/null @@ -1,11 +0,0 @@ -.set	noreorder -.global	__restore_rt -.global	__restore -.hidden __restore_rt -.hidden __restore -.type	__restore_rt,@function -.type	__restore,@function -__restore_rt: -__restore: -	li	$2,5211 -	syscall diff --git a/src/signal/mipsn32/restore.s b/src/signal/mipsn32/restore.s deleted file mode 100644 index 4cd4e1b4..00000000 --- a/src/signal/mipsn32/restore.s +++ /dev/null @@ -1,11 +0,0 @@ -.set	noreorder -.global	__restore_rt -.global	__restore -.hidden __restore_rt -.hidden __restore -.type	__restore_rt,@function -.type	__restore,@function -__restore_rt: -__restore: -	li	$2,6211 -	syscall 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/sigaction.c b/src/signal/sigaction.c index 2203471b..e45308fa 100644 --- a/src/signal/sigaction.c +++ b/src/signal/sigaction.c @@ -44,8 +44,11 @@ int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigact  			}  		}  		ksa.handler = sa->sa_handler; -		ksa.flags = sa->sa_flags | SA_RESTORER; +		ksa.flags = sa->sa_flags; +#ifdef SA_RESTORER +		ksa.flags |= SA_RESTORER;  		ksa.restorer = (sa->sa_flags & SA_SIGINFO) ? __restore_rt : __restore; +#endif  		memcpy(&ksa.mask, &sa->sa_mask, _NSIG/8);  	}  	int r = __syscall(SYS_rt_sigaction, sig, sa?&ksa:0, old?&ksa_old:0, _NSIG/8); 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/__xstat.c b/src/stat/__xstat.c index 630936a0..b4560df7 100644 --- a/src/stat/__xstat.c +++ b/src/stat/__xstat.c @@ -22,11 +22,6 @@ int __xstat(int ver, const char *path, struct stat *buf)  	return stat(path, buf);  } -weak_alias(__fxstat, __fxstat64); -weak_alias(__fxstatat, __fxstatat64); -weak_alias(__lxstat, __lxstat64); -weak_alias(__xstat, __xstat64); -  #endif  int __xmknod(int ver, const char *path, mode_t mode, dev_t *dev) 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/fstat.c b/src/stat/fstat.c index 27db0ccb..fd28b8ac 100644 --- a/src/stat/fstat.c +++ b/src/stat/fstat.c @@ -11,7 +11,3 @@ int __fstat(int fd, struct stat *st)  }  weak_alias(__fstat, fstat); - -#if !_REDIR_TIME64 -weak_alias(fstat, fstat64); -#endif diff --git a/src/stat/fstatat.c b/src/stat/fstatat.c index 74c51cf5..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; @@ -151,7 +152,3 @@ int __fstatat(int fd, const char *restrict path, struct stat *restrict st, int f  }  weak_alias(__fstatat, fstatat); - -#if !_REDIR_TIME64 -weak_alias(fstatat, fstatat64); -#endif diff --git a/src/stat/lstat.c b/src/stat/lstat.c index 6fe004de..6822fcae 100644 --- a/src/stat/lstat.c +++ b/src/stat/lstat.c @@ -5,7 +5,3 @@ int lstat(const char *restrict path, struct stat *restrict buf)  {  	return fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);  } - -#if !_REDIR_TIME64 -weak_alias(lstat, lstat64); -#endif diff --git a/src/stat/stat.c b/src/stat/stat.c index ea70efc4..23570e7a 100644 --- a/src/stat/stat.c +++ b/src/stat/stat.c @@ -5,7 +5,3 @@ int stat(const char *restrict path, struct stat *restrict buf)  {  	return fstatat(AT_FDCWD, path, buf, 0);  } - -#if !_REDIR_TIME64 -weak_alias(stat, stat64); -#endif diff --git a/src/stat/statvfs.c b/src/stat/statvfs.c index f65d1b54..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) @@ -56,8 +57,3 @@ int fstatvfs(int fd, struct statvfs *buf)  	fixup(buf, &kbuf);  	return 0;  } - -weak_alias(statvfs, statvfs64); -weak_alias(statfs, statfs64); -weak_alias(fstatvfs, fstatvfs64); -weak_alias(fstatfs, fstatfs64); 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/fgetpos.c b/src/stdio/fgetpos.c index 50813d2c..392f7323 100644 --- a/src/stdio/fgetpos.c +++ b/src/stdio/fgetpos.c @@ -7,5 +7,3 @@ int fgetpos(FILE *restrict f, fpos_t *restrict pos)  	*(long long *)pos = off;  	return 0;  } - -weak_alias(fgetpos, fgetpos64); diff --git a/src/stdio/fgets.c b/src/stdio/fgets.c index 6171f398..4a100b39 100644 --- a/src/stdio/fgets.c +++ b/src/stdio/fgets.c @@ -12,13 +12,14 @@ char *fgets(char *restrict s, int n, FILE *restrict f)  	FLOCK(f); -	if (n--<=1) { +	if (n<=1) {  		f->mode |= f->mode-1;  		FUNLOCK(f); -		if (n) return 0; +		if (n<1) return 0;  		*s = 0;  		return s;  	} +	n--;  	while (n) {  		if (f->rpos != f->rend) { diff --git a/src/stdio/fopen.c b/src/stdio/fopen.c index e1b91e12..80bc341e 100644 --- a/src/stdio/fopen.c +++ b/src/stdio/fopen.c @@ -29,5 +29,3 @@ FILE *fopen(const char *restrict filename, const char *restrict mode)  	__syscall(SYS_close, fd);  	return 0;  } - -weak_alias(fopen, fopen64); diff --git a/src/stdio/freopen.c b/src/stdio/freopen.c index 615d4b47..1641a4c5 100644 --- a/src/stdio/freopen.c +++ b/src/stdio/freopen.c @@ -40,6 +40,8 @@ FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *re  		fclose(f2);  	} +	f->mode = 0; +	f->locale = 0;  	FUNLOCK(f);  	return f; @@ -49,5 +51,3 @@ fail:  	fclose(f);  	return NULL;  } - -weak_alias(freopen, freopen64); diff --git a/src/stdio/fseek.c b/src/stdio/fseek.c index c07f7e95..c7425802 100644 --- a/src/stdio/fseek.c +++ b/src/stdio/fseek.c @@ -46,5 +46,3 @@ int fseek(FILE *f, long off, int whence)  }  weak_alias(__fseeko, fseeko); - -weak_alias(fseeko, fseeko64); diff --git a/src/stdio/fsetpos.c b/src/stdio/fsetpos.c index 77ab8d82..779cb3cc 100644 --- a/src/stdio/fsetpos.c +++ b/src/stdio/fsetpos.c @@ -4,5 +4,3 @@ int fsetpos(FILE *f, const fpos_t *pos)  {  	return __fseeko(f, *(const long long *)pos, SEEK_SET);  } - -weak_alias(fsetpos, fsetpos64); diff --git a/src/stdio/ftell.c b/src/stdio/ftell.c index 1a2afbbc..1e1a08d8 100644 --- a/src/stdio/ftell.c +++ b/src/stdio/ftell.c @@ -37,5 +37,3 @@ long ftell(FILE *f)  }  weak_alias(__ftello, ftello); - -weak_alias(ftello, ftello64); diff --git a/src/stdio/open_wmemstream.c b/src/stdio/open_wmemstream.c index ed1b561d..b8ae4a79 100644 --- a/src/stdio/open_wmemstream.c +++ b/src/stdio/open_wmemstream.c @@ -40,8 +40,12 @@ fail:  static size_t wms_write(FILE *f, const unsigned char *buf, size_t len)  {  	struct cookie *c = f->cookie; -	size_t len2; +	size_t len2 = f->wpos - f->wbase;  	wchar_t *newbuf; +	if (len2) { +		f->wpos = f->wbase; +		if (wms_write(f, f->wbase, len2) < len2) return 0; +	}  	if (len + c->pos >= c->space) {  		len2 = 2*c->space+1 | c->pos+len+1;  		if (len2 > SSIZE_MAX/4) return 0; 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/tmpfile.c b/src/stdio/tmpfile.c index ae493987..2fa8803f 100644 --- a/src/stdio/tmpfile.c +++ b/src/stdio/tmpfile.c @@ -27,5 +27,3 @@ FILE *tmpfile(void)  	}  	return 0;  } - -weak_alias(tmpfile, tmpfile64); diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c index 9b961e7f..514a44dd 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, @@ -132,7 +132,7 @@ static void pop_arg(union arg *arg, int type, va_list *ap)  static void out(FILE *f, const char *s, size_t l)  { -	if (!(f->flags & F_ERR)) __fwritex((void *)s, l, f); +	if (!ferror(f)) __fwritex((void *)s, l, f);  }  static void pad(FILE *f, char c, int w, int l, int fl) @@ -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,16 @@ 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 max_mant_dig = (ps==BIGLPRE) ? LDBL_MANT_DIG : DBL_MANT_DIG; +	int max_exp = (ps==BIGLPRE) ? LDBL_MAX_EXP : DBL_MAX_EXP; +	/* One slot for 29 bits left of radix point, a slot for every 29-21=8 +	 * bits right of the radix point, and one final zero slot. */ +	int max_mant_slots = 1 + (max_mant_dig-29+7)/8 + 1; +	int max_exp_slots = (max_exp+max_mant_dig+28+8)/9; +	int bufsize = max_mant_slots + max_exp_slots; +	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 +218,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; @@ -268,7 +268,7 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)  	if (y) y *= 0x1p28, e2-=28;  	if (e2<0) a=r=z=big; -	else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1; +	else a=r=z=big+sizeof(big)/sizeof(*big) - max_mant_slots - 1;  	do {  		*z = y; @@ -437,7 +437,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; @@ -478,8 +478,8 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,  		if (*s=='*') {  			if (isdigit(s[1]) && s[2]=='$') {  				l10n=1; -				nl_type[s[1]-'0'] = INT; -				w = nl_arg[s[1]-'0'].i; +				if (!f) nl_type[s[1]-'0'] = INT, w = 0; +				else w = nl_arg[s[1]-'0'].i;  				s+=3;  			} else if (!l10n) {  				w = f ? va_arg(*ap, int) : 0; @@ -491,8 +491,8 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,  		/* Read precision */  		if (*s=='.' && s[1]=='*') {  			if (isdigit(s[2]) && s[3]=='$') { -				nl_type[s[2]-'0'] = INT; -				p = nl_arg[s[2]-'0'].i; +				if (!f) nl_type[s[2]-'0'] = INT, p = 0; +				else p = nl_arg[s[2]-'0'].i;  				s+=4;  			} else if (!l10n) {  				p = f ? va_arg(*ap, int) : 0; @@ -521,13 +521,18 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,  		if (st==NOARG) {  			if (argpos>=0) goto inval;  		} else { -			if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos]; -			else if (f) pop_arg(&arg, st, ap); +			if (argpos>=0) { +				if (!f) nl_type[argpos]=st; +				else arg=nl_arg[argpos]; +			} else if (f) pop_arg(&arg, st, ap);  			else return 0;  		}  		if (!f) continue; +		/* Do not process any new directives once in error state. */ +		if (ferror(f)) return -1; +  		z = buf + sizeof(buf);  		prefix = "-+   0X0x";  		pl = 0; @@ -558,11 +563,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) { @@ -574,7 +579,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) { @@ -583,6 +588,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; @@ -597,6 +603,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; @@ -617,7 +624,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;  		} @@ -672,7 +679,7 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)  	FLOCK(f);  	olderr = f->flags & F_ERR; -	if (f->mode < 1) f->flags &= ~F_ERR; +	f->flags &= ~F_ERR;  	if (!f->buf_size) {  		saved_buf = f->buf;  		f->buf = internal_buf; @@ -688,7 +695,7 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)  		f->buf_size = 0;  		f->wpos = f->wbase = f->wend = 0;  	} -	if (f->flags & F_ERR) ret = -1; +	if (ferror(f)) ret = -1;  	f->flags |= olderr;  	FUNLOCK(f);  	va_end(ap2); diff --git a/src/stdio/vfwprintf.c b/src/stdio/vfwprintf.c index 85b036c3..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, @@ -125,7 +125,13 @@ static void pop_arg(union arg *arg, int type, va_list *ap)  static void out(FILE *f, const wchar_t *s, size_t l)  { -	while (l-- && !(f->flags & F_ERR)) fputwc(*s++, f); +	while (l-- && !ferror(f)) fputwc(*s++, f); +} + +static void pad(FILE *f, int n, int fl) +{ +	if ((fl & LEFT_ADJ) || !n || ferror(f)) return; +	fprintf(f, "%*s", n, "");  }  static int getint(wchar_t **s) { @@ -242,6 +248,10 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_  		}  		if (!f) continue; + +		/* Do not process any new directives once in error state. */ +		if (ferror(f)) return -1; +  		t = s[-1];  		if (ps && (t&15)==3) t&=~32; @@ -258,25 +268,22 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_  			}  			continue;  		case 'c': +		case 'C':  			if (w<1) w=1; -			if (w>1 && !(fl&LEFT_ADJ)) fprintf(f, "%*s", w-1, ""); -			fputwc(btowc(arg.i), f); -			if (w>1 && (fl&LEFT_ADJ)) fprintf(f, "%*s", w-1, ""); +			pad(f, w-1, fl); +			out(f, &(wchar_t){t=='C' ? arg.i : btowc(arg.i)}, 1); +			pad(f, w-1, fl^LEFT_ADJ);  			l = w;  			continue; -		case 'C': -			fputwc(arg.i, f); -			l = 1; -			continue;  		case 'S':  			a = arg.p;  			z = a + wcsnlen(a, p<0 ? INT_MAX : p);  			if (p<0 && *z) goto overflow;  			p = z-a;  			if (w<p) w=p; -			if (!(fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, ""); +			pad(f, w-p, fl);  			out(f, a, p); -			if ((fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, ""); +			pad(f, w-p, fl^LEFT_ADJ);  			l=w;  			continue;  		case 'm': @@ -289,14 +296,14 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_  			if (p<0 && *bs) goto overflow;  			p=l;  			if (w<p) w=p; -			if (!(fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, ""); +			pad(f, w-p, fl);  			bs = arg.p;  			while (l--) {  				i=mbtowc(&wc, bs, MB_LEN_MAX);  				bs+=i; -				fputwc(wc, f); +				out(f, &wc, 1);  			} -			if ((fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, ""); +			pad(f, w-p, fl^LEFT_ADJ);  			l=w;  			continue;  		} @@ -340,8 +347,8 @@ overflow:  int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)  {  	va_list ap2; -	int nl_type[NL_ARGMAX] = {0}; -	union arg nl_arg[NL_ARGMAX]; +	int nl_type[NL_ARGMAX+1] = {0}; +	union arg nl_arg[NL_ARGMAX+1];  	int olderr;  	int ret; @@ -357,7 +364,7 @@ int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)  	olderr = f->flags & F_ERR;  	f->flags &= ~F_ERR;  	ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type); -	if (f->flags & F_ERR) ret = -1; +	if (ferror(f)) ret = -1;  	f->flags |= olderr;  	FUNLOCK(f);  	va_end(ap2); 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 7f98c5c9..5e9a4dad 100644 --- a/src/stdio/vswprintf.c +++ b/src/stdio/vswprintf.c @@ -18,6 +18,7 @@ static size_t sw_write(FILE *f, const unsigned char *s, size_t l)  	if (s!=f->wbase && sw_write(f, f->wbase, f->wpos-f->wbase)==-1)  		return -1;  	while (c->l && l && (i=mbtowc(c->ws, (void *)s, l))>=0) { +		if (!i) i=1;  		s+=i;  		l-=i;  		c->l--; @@ -50,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/string/strverscmp.c b/src/string/strverscmp.c index 4daf276d..16c1da22 100644 --- a/src/string/strverscmp.c +++ b/src/string/strverscmp.c @@ -18,9 +18,9 @@ int strverscmp(const char *l0, const char *r0)  		else if (c!='0') z=0;  	} -	if (l[dp]!='0' && r[dp]!='0') { -		/* If we're not looking at a digit sequence that began -		 * with a zero, longest digit string is greater. */ +	if (l[dp]-'1'<9U && r[dp]-'1'<9U) { +		/* If we're looking at non-degenerate digit sequences starting +		 * with nonzero digits, longest digit string is greater. */  		for (j=i; isdigit(l[j]); j++)  			if (!isdigit(r[j])) return 1;  		if (isdigit(r[j])) return -1; diff --git a/src/string/wcscmp.c b/src/string/wcscmp.c index 26eeee70..286ec3ea 100644 --- a/src/string/wcscmp.c +++ b/src/string/wcscmp.c @@ -3,5 +3,5 @@  int wcscmp(const wchar_t *l, const wchar_t *r)  {  	for (; *l==*r && *l && *r; l++, r++); -	return *l - *r; +	return *l < *r ? -1 : *l > *r;  } diff --git a/src/string/wcsncmp.c b/src/string/wcsncmp.c index 4ab32a92..2b3558bf 100644 --- a/src/string/wcsncmp.c +++ b/src/string/wcsncmp.c @@ -3,5 +3,5 @@  int wcsncmp(const wchar_t *l, const wchar_t *r, size_t n)  {  	for (; n && *l==*r && *l && *r; n--, l++, r++); -	return n ? *l - *r : 0; +	return n ? (*l < *r ? -1 : *l > *r) : 0;  } diff --git a/src/string/wmemcmp.c b/src/string/wmemcmp.c index 2a193263..717d77b1 100644 --- a/src/string/wmemcmp.c +++ b/src/string/wmemcmp.c @@ -3,5 +3,5 @@  int wmemcmp(const wchar_t *l, const wchar_t *r, size_t n)  {  	for (; n && *l==*r; n--, l++, r++); -	return n ? *l-*r : 0; +	return n ? (*l < *r ? -1 : *l > *r) : 0;  } diff --git a/src/temp/mkostemp.c b/src/temp/mkostemp.c index d8dcb805..e3dfdd91 100644 --- a/src/temp/mkostemp.c +++ b/src/temp/mkostemp.c @@ -5,5 +5,3 @@ int mkostemp(char *template, int flags)  {  	return __mkostemps(template, 0, flags);  } - -weak_alias(mkostemp, mkostemp64); diff --git a/src/temp/mkostemps.c b/src/temp/mkostemps.c index ef24eeae..093d2380 100644 --- a/src/temp/mkostemps.c +++ b/src/temp/mkostemps.c @@ -26,4 +26,3 @@ int __mkostemps(char *template, int len, int flags)  }  weak_alias(__mkostemps, mkostemps); -weak_alias(__mkostemps, mkostemps64); diff --git a/src/temp/mkstemp.c b/src/temp/mkstemp.c index 166b8afe..76c835bb 100644 --- a/src/temp/mkstemp.c +++ b/src/temp/mkstemp.c @@ -4,5 +4,3 @@ int mkstemp(char *template)  {  	return __mkostemps(template, 0, 0);  } - -weak_alias(mkstemp, mkstemp64); diff --git a/src/temp/mkstemps.c b/src/temp/mkstemps.c index 6b7531b5..f8eabfec 100644 --- a/src/temp/mkstemps.c +++ b/src/temp/mkstemps.c @@ -5,5 +5,3 @@ int mkstemps(char *template, int len)  {  	return __mkostemps(template, len, 0);  } - -weak_alias(mkstemps, mkstemps64); 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/__set_thread_area.c b/src/thread/aarch64/__set_thread_area.c new file mode 100644 index 00000000..2ec788e8 --- /dev/null +++ b/src/thread/aarch64/__set_thread_area.c @@ -0,0 +1,27 @@ +#include <elf.h> +#include "libc.h" + +#define BITRANGE(a,b) (2*(1UL<<(b))-(1UL<<(a))) + +int __set_thread_area(void *p) +{ +	__asm__ __volatile__ ("msr tpidr_el0,%0" : : "r"(p) : "memory"); + +	/* Mask off hwcap bits for SME and unknown future features. This is +	 * necessary because SME is not safe to use without libc support for +	 * it, and we do not (yet) have such support. */ +	for (size_t *v = libc.auxv; *v; v+=2) { +		if (v[0]==AT_HWCAP) { +			v[1] &= ~BITRANGE(42,63); /* 42-47 are SME */ +		} else if (v[0]==AT_HWCAP2) { +			v[1] &= ~(BITRANGE(23,30) +			        | BITRANGE(37,42) +			        | BITRANGE(57,62)); +		} else if (v[0]==AT_HWCAP3 || v[0]==AT_HWCAP4) { +			v[0] = AT_IGNORE; +			v[1] = 0; +		} +	} + +	return 0; +} diff --git a/src/thread/aarch64/clone.s b/src/thread/aarch64/clone.s index e3c83395..aff8155b 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 x29, 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/aarch64/__set_thread_area.s b/src/thread/loongarch64/__set_thread_area.s index fd0df34b..021307fc 100644 --- a/src/thread/aarch64/__set_thread_area.s +++ b/src/thread/loongarch64/__set_thread_area.s @@ -2,6 +2,6 @@  .hidden __set_thread_area  .type   __set_thread_area,@function  __set_thread_area: -	msr tpidr_el0,x0 -	mov w0,#0 -	ret +	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/pthread_atfork.c b/src/thread/pthread_atfork.c index 76497401..26d32543 100644 --- a/src/thread/pthread_atfork.c +++ b/src/thread/pthread_atfork.c @@ -1,7 +1,13 @@  #include <pthread.h> +#include <errno.h>  #include "libc.h"  #include "lock.h" +#define malloc __libc_malloc +#define calloc undef +#define realloc undef +#define free undef +  static struct atfork_funcs {  	void (*prepare)(void);  	void (*parent)(void); @@ -34,7 +40,7 @@ void __fork_handler(int who)  int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))  {  	struct atfork_funcs *new = malloc(sizeof *new); -	if (!new) return -1; +	if (!new) return ENOMEM;  	LOCK(lock);  	new->next = funcs; diff --git a/src/thread/pthread_cancel.c b/src/thread/pthread_cancel.c index 2f9d5e97..139a6fc8 100644 --- a/src/thread/pthread_cancel.c +++ b/src/thread/pthread_cancel.c @@ -56,7 +56,12 @@ static void cancel_handler(int sig, siginfo_t *si, void *ctx)  	_sigaddset(&uc->uc_sigmask, SIGCANCEL); -	if (self->cancelasync || pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)__cp_end) { +	if (self->cancelasync) { +		pthread_sigmask(SIG_SETMASK, &uc->uc_sigmask, 0); +		__cancel(); +	} + +	if (pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)__cp_end) {  		uc->uc_mcontext.MC_PC = (uintptr_t)__cp_cancel;  #ifdef CANCEL_GOT  		uc->uc_mcontext.MC_GOT = CANCEL_GOT; @@ -77,7 +82,7 @@ void __testcancel()  static void init_cancellation()  {  	struct sigaction sa = { -		.sa_flags = SA_SIGINFO | SA_RESTART, +		.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK,  		.sa_sigaction = cancel_handler  	};  	memset(&sa.sa_mask, -1, _NSIG/8); diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index 6f187ee8..087f6206 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -107,6 +107,16 @@ _Noreturn void __pthread_exit(void *result)  	/* At this point we are committed to thread termination. */ +	/* After the kernel thread exits, its tid may be reused. Clear it +	 * to prevent inadvertent use and inform functions that would use +	 * it that it's no longer available. At this point the killlock +	 * may be released, since functions that use it will consistently +	 * see the thread as having exited. Release it now so that no +	 * remaining locks (except thread list) are held if we end up +	 * resetting need_locks below. */ +	self->tid = 0; +	UNLOCK(self->killlock); +  	/* Process robust list in userspace to handle non-pshared mutexes  	 * and the detached thread case where the robust list head will  	 * be invalid when the kernel would process it. */ @@ -159,12 +169,6 @@ _Noreturn void __pthread_exit(void *result)  	a_store(&self->detach_state, DT_EXITED);  	__wake(&self->detach_state, 1, 1); -	/* After the kernel thread exits, its tid may be reused. Clear it -	 * to prevent inadvertent use and inform functions that would use -	 * it that it's no longer available. */ -	self->tid = 0; -	UNLOCK(self->killlock); -  	for (;;) __syscall(SYS_exit, 0);  } diff --git a/src/thread/pthread_detach.c b/src/thread/pthread_detach.c index 77772af2..d73a500e 100644 --- a/src/thread/pthread_detach.c +++ b/src/thread/pthread_detach.c @@ -5,8 +5,12 @@ static int __pthread_detach(pthread_t t)  {  	/* If the cas fails, detach state is either already-detached  	 * or exiting/exited, and pthread_join will trap or cleanup. */ -	if (a_cas(&t->detach_state, DT_JOINABLE, DT_DETACHED) != DT_JOINABLE) -		return __pthread_join(t, 0); +	if (a_cas(&t->detach_state, DT_JOINABLE, DT_DETACHED) != DT_JOINABLE) { +		int cs; +		__pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); +		__pthread_join(t, 0); +		__pthread_setcancelstate(cs, 0); +	}  	return 0;  } diff --git a/src/thread/pthread_key_create.c b/src/thread/pthread_key_create.c index d1120941..39770c7a 100644 --- a/src/thread/pthread_key_create.c +++ b/src/thread/pthread_key_create.c @@ -1,4 +1,5 @@  #include "pthread_impl.h" +#include "fork_impl.h"  volatile size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX;  void *__pthread_tsd_main[PTHREAD_KEYS_MAX] = { 0 }; @@ -20,6 +21,13 @@ static void dummy_0(void)  weak_alias(dummy_0, __tl_lock);  weak_alias(dummy_0, __tl_unlock); +void __pthread_key_atfork(int who) +{ +	if (who<0) __pthread_rwlock_rdlock(&key_lock); +	else if (!who) __pthread_rwlock_unlock(&key_lock); +	else key_lock = (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER; +} +  int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *))  {  	pthread_t self = __pthread_self(); 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..056c9110 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   %r3, %a0 +	sllg  %r3, %r3, 32 +	ear   %r3, %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    %r0, 0(%r1) +	sllg  %r4, %r0, 3 +	lg    %r5, 8(%r3) +	lg    %r2, 0(%r4, %r5) +	ag    %r2, 8(%r1) +	sgr   %r2, %r3 -	sgr   %r2, %r1 - -	lmg   %r14, %r15, 272(%r15)  	br    %r14 diff --git a/src/thread/sem_getvalue.c b/src/thread/sem_getvalue.c index d9d83071..c0b7762d 100644 --- a/src/thread/sem_getvalue.c +++ b/src/thread/sem_getvalue.c @@ -1,8 +1,9 @@  #include <semaphore.h> +#include <limits.h>  int sem_getvalue(sem_t *restrict sem, int *restrict valp)  {  	int val = sem->__val[0]; -	*valp = val < 0 ? 0 : val; +	*valp = val & SEM_VALUE_MAX;  	return 0;  } diff --git a/src/thread/sem_post.c b/src/thread/sem_post.c index 31e3293d..1c8f763c 100644 --- a/src/thread/sem_post.c +++ b/src/thread/sem_post.c @@ -1,17 +1,21 @@  #include <semaphore.h> +#include <limits.h>  #include "pthread_impl.h"  int sem_post(sem_t *sem)  { -	int val, waiters, priv = sem->__val[2]; +	int val, new, waiters, priv = sem->__val[2];  	do {  		val = sem->__val[0];  		waiters = sem->__val[1]; -		if (val == SEM_VALUE_MAX) { +		if ((val & SEM_VALUE_MAX) == SEM_VALUE_MAX) {  			errno = EOVERFLOW;  			return -1;  		} -	} while (a_cas(sem->__val, val, val+1+(val<0)) != val); -	if (val<0 || waiters) __wake(sem->__val, 1, priv); +		new = val + 1; +		if (waiters <= 1) +			new &= ~0x80000000; +	} while (a_cas(sem->__val, val, new) != val); +	if (val<0 || waiters) __wake(sem->__val, waiters>1 ? 1 : -1, priv);  	return 0;  } diff --git a/src/thread/sem_timedwait.c b/src/thread/sem_timedwait.c index 58d3ebfe..aa67376c 100644 --- a/src/thread/sem_timedwait.c +++ b/src/thread/sem_timedwait.c @@ -1,4 +1,5 @@  #include <semaphore.h> +#include <limits.h>  #include "pthread_impl.h"  static void cleanup(void *p) @@ -13,14 +14,15 @@ int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict at)  	if (!sem_trywait(sem)) return 0;  	int spins = 100; -	while (spins-- && sem->__val[0] <= 0 && !sem->__val[1]) a_spin(); +	while (spins-- && !(sem->__val[0] & SEM_VALUE_MAX) && !sem->__val[1]) +		a_spin();  	while (sem_trywait(sem)) { -		int r; +		int r, priv = sem->__val[2];  		a_inc(sem->__val+1); -		a_cas(sem->__val, 0, -1); +		a_cas(sem->__val, 0, 0x80000000);  		pthread_cleanup_push(cleanup, (void *)(sem->__val+1)); -		r = __timedwait_cp(sem->__val, -1, CLOCK_REALTIME, at, sem->__val[2]); +		r = __timedwait_cp(sem->__val, 0x80000000, CLOCK_REALTIME, at, priv);  		pthread_cleanup_pop(1);  		if (r) {  			errno = r; diff --git a/src/thread/sem_trywait.c b/src/thread/sem_trywait.c index 04edf46b..beb435da 100644 --- a/src/thread/sem_trywait.c +++ b/src/thread/sem_trywait.c @@ -1,12 +1,12 @@  #include <semaphore.h> +#include <limits.h>  #include "pthread_impl.h"  int sem_trywait(sem_t *sem)  {  	int val; -	while ((val=sem->__val[0]) > 0) { -		int new = val-1-(val==1 && sem->__val[1]); -		if (a_cas(sem->__val, val, new)==val) return 0; +	while ((val=sem->__val[0]) & SEM_VALUE_MAX) { +		if (a_cas(sem->__val, val, val-1)==val) return 0;  	}  	errno = EAGAIN;  	return -1; diff --git a/src/thread/synccall.c b/src/thread/synccall.c index d58c851f..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); @@ -45,7 +45,7 @@ void __synccall(void (*func)(void *), void *ctx)  {  	sigset_t oldmask;  	int cs, i, r; -	struct sigaction sa = { .sa_flags = SA_RESTART, .sa_handler = handler }; +	struct sigaction sa = { .sa_flags = SA_RESTART | SA_ONSTACK, .sa_handler = handler };  	pthread_t self = __pthread_self(), td;  	int count = 0; @@ -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/clock_gettime.c b/src/time/clock_gettime.c index c7e66a51..4d2ec22f 100644 --- a/src/time/clock_gettime.c +++ b/src/time/clock_gettime.c @@ -42,6 +42,9 @@ static int cgt_init(clockid_t clk, struct timespec *ts)  			p = cgt_time32_wrap;  		}  	} +#ifdef VDSO_CGT_WORKAROUND +	if (!__vdsosym(VDSO_CGT32_VER, VDSO_CGT32_SYM)) p = 0; +#endif  #endif  	int (*f)(clockid_t, struct timespec *) =  		(int (*)(clockid_t, struct timespec *))p; 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 4bef2390..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,16 @@ 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 (;;) {  		siginfo_t si;  		while (sigwaitinfo(SIGTIMER_SET, &si) < 0); @@ -59,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; @@ -88,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);  		} @@ -97,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); @@ -113,10 +133,13 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict  		ksev.sigev_signo = SIGTIMER;  		ksev.sigev_notify = SIGEV_THREAD_ID;  		ksev.sigev_tid = td->tid; -		if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0) +		if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0) {  			timerid = -1; +			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/dup3.c b/src/unistd/dup3.c index f919f791..40798bde 100644 --- a/src/unistd/dup3.c +++ b/src/unistd/dup3.c @@ -9,12 +9,14 @@ int __dup3(int old, int new, int flags)  	int r;  #ifdef SYS_dup2  	if (old==new) return __syscall_ret(-EINVAL); -	if (flags & O_CLOEXEC) { +	if (flags) {  		while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);  		if (r!=-ENOSYS) return __syscall_ret(r); +		if (flags & ~O_CLOEXEC) return __syscall_ret(-EINVAL);  	}  	while ((r=__syscall(SYS_dup2, old, new))==-EBUSY); -	if (flags & O_CLOEXEC) __syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC); +	if (r >= 0 && (flags & O_CLOEXEC)) +		__syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC);  #else  	while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);  #endif 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/ftruncate.c b/src/unistd/ftruncate.c index b41be0fa..54ff34bc 100644 --- a/src/unistd/ftruncate.c +++ b/src/unistd/ftruncate.c @@ -5,5 +5,3 @@ int ftruncate(int fd, off_t length)  {  	return syscall(SYS_ftruncate, fd, __SYSCALL_LL_O(length));  } - -weak_alias(ftruncate, ftruncate64); 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/lseek.c b/src/unistd/lseek.c index b4984f3e..f5b66682 100644 --- a/src/unistd/lseek.c +++ b/src/unistd/lseek.c @@ -12,4 +12,3 @@ off_t __lseek(int fd, off_t offset, int whence)  }  weak_alias(__lseek, lseek); -weak_alias(__lseek, lseek64); diff --git a/src/unistd/mipsn32/lseek.c b/src/unistd/mipsn32/lseek.c index 60e74a51..0f6cbcaa 100644 --- a/src/unistd/mipsn32/lseek.c +++ b/src/unistd/mipsn32/lseek.c @@ -17,4 +17,3 @@ off_t __lseek(int fd, off_t offset, int whence)  }  weak_alias(__lseek, lseek); -weak_alias(__lseek, lseek64); 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/pipe2.c b/src/unistd/pipe2.c index f24f74fb..a096990b 100644 --- a/src/unistd/pipe2.c +++ b/src/unistd/pipe2.c @@ -8,6 +8,7 @@ int pipe2(int fd[2], int flag)  	if (!flag) return pipe(fd);  	int ret = __syscall(SYS_pipe2, fd, flag);  	if (ret != -ENOSYS) return __syscall_ret(ret); +	if (flag & ~(O_CLOEXEC|O_NONBLOCK)) return __syscall_ret(-EINVAL);  	ret = pipe(fd);  	if (ret) return ret;  	if (flag & O_CLOEXEC) { diff --git a/src/unistd/pread.c b/src/unistd/pread.c index 5681b045..b03fb0ad 100644 --- a/src/unistd/pread.c +++ b/src/unistd/pread.c @@ -5,5 +5,3 @@ ssize_t pread(int fd, void *buf, size_t size, off_t ofs)  {  	return syscall_cp(SYS_pread, fd, buf, size, __SYSCALL_LL_PRW(ofs));  } - -weak_alias(pread, pread64); diff --git a/src/unistd/preadv.c b/src/unistd/preadv.c index 8376d60f..890ab403 100644 --- a/src/unistd/preadv.c +++ b/src/unistd/preadv.c @@ -8,5 +8,3 @@ ssize_t preadv(int fd, const struct iovec *iov, int count, off_t ofs)  	return syscall_cp(SYS_preadv, fd, iov, count,  		(long)(ofs), (long)(ofs>>32));  } - -weak_alias(preadv, preadv64); diff --git a/src/unistd/pwrite.c b/src/unistd/pwrite.c index ca376576..a008b3ec 100644 --- a/src/unistd/pwrite.c +++ b/src/unistd/pwrite.c @@ -1,9 +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));  } - -weak_alias(pwrite, pwrite64); diff --git a/src/unistd/pwritev.c b/src/unistd/pwritev.c index f5a612c4..44a53d85 100644 --- a/src/unistd/pwritev.c +++ b/src/unistd/pwritev.c @@ -1,12 +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));  } - -weak_alias(pwritev, pwritev64); 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);  } diff --git a/src/unistd/truncate.c b/src/unistd/truncate.c index 97296800..077351e1 100644 --- a/src/unistd/truncate.c +++ b/src/unistd/truncate.c @@ -5,5 +5,3 @@ int truncate(const char *path, off_t length)  {  	return syscall(SYS_truncate, path, __SYSCALL_LL_O(length));  } - -weak_alias(truncate, truncate64); diff --git a/src/unistd/x32/lseek.c b/src/unistd/x32/lseek.c index 32636429..5f93292f 100644 --- a/src/unistd/x32/lseek.c +++ b/src/unistd/x32/lseek.c @@ -12,4 +12,3 @@ off_t __lseek(int fd, off_t offset, int whence)  }  weak_alias(__lseek, lseek); -weak_alias(__lseek, lseek64); | 
