summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/conf/sysconf.c13
-rw-r--r--src/internal/dynlink.h2
-rw-r--r--src/internal/syscall.h6
-rw-r--r--src/linux/epoll.c1
-rw-r--r--src/linux/membarrier.c2
-rw-r--r--src/network/getaddrinfo.c2
-rw-r--r--src/network/gethostbyaddr_r.c5
-rw-r--r--src/network/gethostbyname2_r.c3
-rw-r--r--src/network/lookup_name.c2
-rw-r--r--src/network/res_mkquery.c1
-rw-r--r--src/network/res_msend.c8
-rw-r--r--src/process/aarch64/vfork.s9
-rw-r--r--src/stdio/freopen.c2
-rw-r--r--src/stdio/open_wmemstream.c6
-rw-r--r--src/temp/__randname.c3
-rw-r--r--src/thread/pthread_cancel.c2
-rw-r--r--src/thread/synccall.c2
-rw-r--r--src/time/clock_getcpuclockid.c1
-rw-r--r--src/time/clock_gettime.c3
-rw-r--r--src/time/timer_create.c6
20 files changed, 63 insertions, 16 deletions
diff --git a/src/conf/sysconf.c b/src/conf/sysconf.c
index 3baaed32..60d3e745 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,13 @@ 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: ;
+ long val = __getauxval(AT_MINSIGSTKSZ);
+ if (val < MINSIGSTKSZ) val = MINSIGSTKSZ;
+ if (values[name] == JT_SIGSTKSZ)
+ val += SIGSTKSZ - MINSIGSTKSZ;
+ return val;
case JT_ZERO & 255:
return 0;
}
diff --git a/src/internal/dynlink.h b/src/internal/dynlink.h
index 51c0639f..830354eb 100644
--- a/src/internal/dynlink.h
+++ b/src/internal/dynlink.h
@@ -93,7 +93,7 @@ struct fdpic_dummy_loadmap {
#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/syscall.h b/src/internal/syscall.h
index 4f41e1dc..4a446157 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 */
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/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/network/getaddrinfo.c b/src/network/getaddrinfo.c
index efaab306..9df045f6 100644
--- a/src/network/getaddrinfo.c
+++ b/src/network/getaddrinfo.c
@@ -66,9 +66,11 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
pthread_setcancelstate(
PTHREAD_CANCEL_DISABLE, &cs);
int r = connect(s, ta[i], tl[i]);
+ int saved_errno = errno;
pthread_setcancelstate(cs, 0);
close(s);
if (!r) continue;
+ errno = saved_errno;
}
switch (errno) {
case EADDRNOTAVAIL:
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_r.c b/src/network/gethostbyname2_r.c
index fc894877..c9f3acc4 100644
--- a/src/network/gethostbyname2_r.c
+++ b/src/network/gethostbyname2_r.c
@@ -22,7 +22,7 @@ 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_AGAIN:
*err = TRY_AGAIN;
return EAGAIN;
@@ -30,7 +30,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/lookup_name.c b/src/network/lookup_name.c
index b5232ce8..bec6ba22 100644
--- a/src/network/lookup_name.c
+++ b/src/network/lookup_name.c
@@ -153,7 +153,7 @@ 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;
qbuf[nq][3] = 0; /* don't need AD flag */
/* Ensure query IDs are distinct. */
if (nq && qbuf[nq][0] == qbuf[0][0])
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..9adaea13 100644
--- a/src/network/res_msend.c
+++ b/src/network/res_msend.c
@@ -68,14 +68,20 @@ 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;
}
+ sa.sin.sin_family = family;
if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) {
if (fd >= 0) close(fd);
pthread_setcancelstate(cs, 0);
diff --git a/src/process/aarch64/vfork.s b/src/process/aarch64/vfork.s
new file mode 100644
index 00000000..429bec8c
--- /dev/null
+++ b/src/process/aarch64/vfork.s
@@ -0,0 +1,9 @@
+.global vfork
+.type vfork,%function
+vfork:
+ mov x8, 220 // SYS_clone
+ mov x0, 0x4111 // SIGCHLD | CLONE_VM | CLONE_VFORK
+ mov x1, 0
+ svc 0
+ .hidden __syscall_ret
+ b __syscall_ret
diff --git a/src/stdio/freopen.c b/src/stdio/freopen.c
index 615d4b47..96bfbb42 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;
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/temp/__randname.c b/src/temp/__randname.c
index 2bce37a0..e9b970f1 100644
--- a/src/temp/__randname.c
+++ b/src/temp/__randname.c
@@ -1,5 +1,6 @@
#include <time.h>
#include <stdint.h>
+#include "pthread_impl.h"
/* This assumes that a check for the
template size has already been made */
@@ -10,7 +11,7 @@ char *__randname(char *template)
unsigned long r;
__clock_gettime(CLOCK_REALTIME, &ts);
- r = ts.tv_nsec*65537 ^ (uintptr_t)&ts / 16 + (uintptr_t)template;
+ r = ts.tv_sec + ts.tv_nsec + __pthread_self()->tid * 65537UL;
for (i=0; i<6; i++, r>>=5)
template[i] = 'A'+(r&15)+(r&16)*2;
diff --git a/src/thread/pthread_cancel.c b/src/thread/pthread_cancel.c
index 2f9d5e97..2d3a98ea 100644
--- a/src/thread/pthread_cancel.c
+++ b/src/thread/pthread_cancel.c
@@ -77,7 +77,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/synccall.c b/src/thread/synccall.c
index d58c851f..a6b177c0 100644
--- a/src/thread/synccall.c
+++ b/src/thread/synccall.c
@@ -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;
diff --git a/src/time/clock_getcpuclockid.c b/src/time/clock_getcpuclockid.c
index 8a0e2d4c..bce1e8ab 100644
--- a/src/time/clock_getcpuclockid.c
+++ b/src/time/clock_getcpuclockid.c
@@ -8,6 +8,7 @@ int clock_getcpuclockid(pid_t pid, clockid_t *clk)
struct timespec ts;
clockid_t id = (-pid-1)*8U + 2;
int ret = __syscall(SYS_clock_getres, id, &ts);
+ if (ret == -EINVAL) ret = -ESRCH;
if (ret) return -ret;
*clk = id;
return 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/timer_create.c b/src/time/timer_create.c
index 4bef2390..cd32c945 100644
--- a/src/time/timer_create.c
+++ b/src/time/timer_create.c
@@ -43,6 +43,8 @@ static void *start(void *arg)
union sigval val = args->sev->sigev_value;
pthread_barrier_wait(&args->b);
+ if (self->cancel)
+ return 0;
for (;;) {
siginfo_t si;
while (sigwaitinfo(SIGTIMER_SET, &si) < 0);
@@ -113,8 +115,10 @@ 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);
if (timerid < 0) return -1;