aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2023-06-20 17:09:23 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-06-20 17:09:23 +0000
commitfab0604c72a1462045ed6cbeadbcd878f1632373 (patch)
treec01721a7a3a23834136f90492c0d5ab69c790829
parentf8d7e17e64d0414d89399a56f91c26f14397fc4e (diff)
parentcb3779c7f0312092f1cf86c6e935ea0171b8c25b (diff)
downloadmusl-fab0604c72a1462045ed6cbeadbcd878f1632373.tar.gz
Upgrade musl to v1.2.4 am: cb3779c7f0
Original change: https://android-review.googlesource.com/c/platform/external/musl/+/2628409 Change-Id: I4abdbd42164071f4d518fdedabe42b98c71b1185 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--METADATA22
-rw-r--r--VERSION2
-rw-r--r--WHATSNEW69
-rw-r--r--arch/microblaze/bits/signal.h1
-rw-r--r--arch/mips/bits/signal.h1
-rw-r--r--arch/mips/ksigaction.h5
-rw-r--r--arch/mips/reloc.h1
-rw-r--r--arch/mips64/bits/signal.h1
-rw-r--r--arch/mips64/ksigaction.h2
-rw-r--r--arch/mips64/reloc.h1
-rw-r--r--arch/mipsn32/bits/signal.h1
-rw-r--r--arch/mipsn32/ksigaction.h2
-rw-r--r--arch/mipsn32/reloc.h1
-rw-r--r--arch/or1k/bits/signal.h1
-rw-r--r--arch/riscv64/bits/signal.h1
-rw-r--r--compat/time32/__xstat.c8
-rw-r--r--compat/time32/aio_suspend_time32.c2
-rw-r--r--compat/time32/fstat_time32.c2
-rw-r--r--compat/time32/fstatat_time32.c2
-rw-r--r--compat/time32/lstat_time32.c2
-rw-r--r--compat/time32/stat_time32.c2
-rwxr-xr-xconfigure8
-rw-r--r--include/aio.h2
-rw-r--r--include/arpa/nameser.h71
-rw-r--r--include/dirent.h2
-rw-r--r--include/elf.h1
-rw-r--r--include/fcntl.h2
-rw-r--r--include/ftw.h2
-rw-r--r--include/glob.h2
-rw-r--r--include/netdb.h1
-rw-r--r--include/sched.h2
-rw-r--r--include/stdio.h2
-rw-r--r--include/stdlib.h4
-rw-r--r--include/string.h2
-rw-r--r--include/sys/mman.h2
-rw-r--r--include/sys/resource.h2
-rw-r--r--include/sys/sendfile.h2
-rw-r--r--include/sys/stat.h2
-rw-r--r--include/sys/statfs.h2
-rw-r--r--include/sys/statvfs.h2
-rw-r--r--include/sys/types.h2
-rw-r--r--include/sys/uio.h2
-rw-r--r--include/sys/wait.h2
-rw-r--r--include/unistd.h2
-rw-r--r--ldso/dynlink.c49
-rw-r--r--src/aio/aio.c32
-rw-r--r--src/aio/aio_suspend.c6
-rw-r--r--src/aio/lio_listio.c2
-rw-r--r--src/dirent/alphasort.c2
-rw-r--r--src/dirent/readdir.c2
-rw-r--r--src/dirent/readdir_r.c2
-rw-r--r--src/dirent/scandir.c2
-rw-r--r--src/dirent/versionsort.c3
-rw-r--r--src/fcntl/creat.c2
-rw-r--r--src/fcntl/open.c2
-rw-r--r--src/fcntl/openat.c2
-rw-r--r--src/fcntl/posix_fadvise.c2
-rw-r--r--src/fcntl/posix_fallocate.c2
-rw-r--r--src/internal/dynlink.h4
-rw-r--r--src/internal/fork_impl.h2
-rw-r--r--src/internal/ksigaction.h5
-rw-r--r--src/ipc/semtimedop.c3
-rw-r--r--src/ldso/dlerror.c34
-rw-r--r--src/legacy/ftw.c2
-rw-r--r--src/linux/fallocate.c3
-rw-r--r--src/linux/getdents.c2
-rw-r--r--src/linux/prlimit.c3
-rw-r--r--src/linux/sendfile.c2
-rw-r--r--src/linux/wait4.c2
-rw-r--r--src/malloc/mallocng/free.c2
-rw-r--r--src/malloc/mallocng/glue.h2
-rw-r--r--src/math/logf.c2
-rw-r--r--src/misc/getopt.c3
-rw-r--r--src/misc/getrlimit.c2
-rw-r--r--src/misc/lockf.c2
-rw-r--r--src/misc/nftw.c6
-rw-r--r--src/misc/setrlimit.c2
-rw-r--r--src/mman/mmap.c2
-rw-r--r--src/mq/mq_notify.c47
-rw-r--r--src/network/accept4.c4
-rw-r--r--src/network/dns_parse.c10
-rw-r--r--src/network/gai_strerror.c2
-rw-r--r--src/network/getaddrinfo.c5
-rw-r--r--src/network/gethostbyaddr.c2
-rw-r--r--src/network/gethostbyname2.c2
-rw-r--r--src/network/gethostbyname2_r.c3
-rw-r--r--src/network/getifaddrs.c14
-rw-r--r--src/network/getnameinfo.c5
-rw-r--r--src/network/getservbyport_r.c4
-rw-r--r--src/network/inet_pton.c1
-rw-r--r--src/network/lookup.h2
-rw-r--r--src/network/lookup_ipliteral.c4
-rw-r--r--src/network/lookup_name.c45
-rw-r--r--src/network/res_msend.c177
-rw-r--r--src/network/res_send.c10
-rw-r--r--src/network/sendmsg.c7
-rw-r--r--src/process/_Fork.c3
-rw-r--r--src/process/fork.c8
-rw-r--r--src/process/riscv64/vfork.s12
-rw-r--r--src/regex/glob.c3
-rw-r--r--src/search/hsearch.c4
-rw-r--r--src/select/poll.c9
-rw-r--r--src/select/select.c1
-rw-r--r--src/setjmp/powerpc/longjmp.S8
-rw-r--r--src/signal/mips/restore.s15
-rw-r--r--src/signal/mips64/restore.s11
-rw-r--r--src/signal/mipsn32/restore.s11
-rw-r--r--src/signal/sigaction.c5
-rw-r--r--src/stat/__xstat.c5
-rw-r--r--src/stat/fstat.c4
-rw-r--r--src/stat/fstatat.c4
-rw-r--r--src/stat/lstat.c4
-rw-r--r--src/stat/stat.c4
-rw-r--r--src/stat/statvfs.c5
-rw-r--r--src/stdio/fgetpos.c2
-rw-r--r--src/stdio/fgets.c5
-rw-r--r--src/stdio/fopen.c2
-rw-r--r--src/stdio/freopen.c2
-rw-r--r--src/stdio/fseek.c2
-rw-r--r--src/stdio/fsetpos.c2
-rw-r--r--src/stdio/ftell.c2
-rw-r--r--src/stdio/tmpfile.c2
-rw-r--r--src/stdio/vfprintf.c23
-rw-r--r--src/stdio/vfwprintf.c39
-rw-r--r--src/stdio/vswprintf.c1
-rw-r--r--src/string/strverscmp.c6
-rw-r--r--src/string/wcscmp.c2
-rw-r--r--src/string/wcsncmp.c2
-rw-r--r--src/string/wmemcmp.c2
-rw-r--r--src/temp/mkostemp.c2
-rw-r--r--src/temp/mkostemps.c1
-rw-r--r--src/temp/mkstemp.c2
-rw-r--r--src/temp/mkstemps.c2
-rw-r--r--src/thread/pthread_atfork.c8
-rw-r--r--src/thread/pthread_cancel.c7
-rw-r--r--src/thread/pthread_create.c16
-rw-r--r--src/thread/pthread_detach.c8
-rw-r--r--src/thread/pthread_key_create.c8
-rw-r--r--src/thread/sem_getvalue.c3
-rw-r--r--src/thread/sem_post.c12
-rw-r--r--src/thread/sem_timedwait.c10
-rw-r--r--src/thread/sem_trywait.c6
-rw-r--r--src/unistd/dup3.c6
-rw-r--r--src/unistd/ftruncate.c2
-rw-r--r--src/unistd/lseek.c1
-rw-r--r--src/unistd/mipsn32/lseek.c1
-rw-r--r--src/unistd/pipe2.c1
-rw-r--r--src/unistd/pread.c2
-rw-r--r--src/unistd/preadv.c2
-rw-r--r--src/unistd/pwrite.c2
-rw-r--r--src/unistd/pwritev.c2
-rw-r--r--src/unistd/truncate.c2
-rw-r--r--src/unistd/x32/lseek.c1
153 files changed, 713 insertions, 393 deletions
diff --git a/METADATA b/METADATA
index c159b71c..d6e128bd 100644
--- a/METADATA
+++ b/METADATA
@@ -1,13 +1,9 @@
-name: "musl"
-description:
- "musl is an implementation of the C standard library built on top of the "
- "Linux system call API, including interfaces defined in the base language "
- "standard, POSIX, and widely agreed-upon extensions. musl is lightweight, "
- "fast, simple, free, and strives to be correct in the sense of "
- "standards-conformance and safety. "
- " "
- ""
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update musl
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+name: "musl"
+description: "musl is an implementation of the C standard library built on top of the Linux system call API, including interfaces defined in the base language standard, POSIX, and widely agreed-upon extensions. musl is lightweight, fast, simple, free, and strives to be correct in the sense of standards-conformance and safety. "
third_party {
url {
type: HOMEPAGE
@@ -17,7 +13,11 @@ third_party {
type: GIT
value: "git://git.musl-libc.org/musl"
}
- version: "v1.2.2"
- last_upgrade_date { year: 2021 month: 6 day: 10 }
+ version: "v1.2.4"
license_type: NOTICE
+ last_upgrade_date {
+ year: 2023
+ month: 6
+ day: 15
+ }
}
diff --git a/VERSION b/VERSION
index 0495c4a8..e8ea05db 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.2.3
+1.2.4
diff --git a/WHATSNEW b/WHATSNEW
index f9bb2482..c5c8c9f4 100644
--- a/WHATSNEW
+++ b/WHATSNEW
@@ -2327,3 +2327,72 @@ bugs fixed:
arch-specific bugs fixed:
- powerpc (32-bit) struct shmid_ds layout was wrong for some fields
- time64 struct layout was wrong in sound ioctl fallback (32-bit archs)
+
+
+
+1.2.4 release notes
+
+new features:
+- large dns record lookups via tcp fallback
+- new getaddrinfo EAI_NODATA result to distinguish NODATA/NxDomain
+- support for new RELR compressed format for relative relocations
+- sysconf keys for querying signal stack size requirements
+- real vfork on riscv64
+
+performance:
+- mallocng no longer uses MADV_FREE (high performance cost, little gain)
+- vdso clock_gettime is supported once again on 32-bit arm
+
+compatibility:
+- gethostbyname family now distinguishes NO_DATA from HOST_NOT_FOUND
+- res_send now works with caller-provided edns0 queries
+- arpa/nameser.h RR types list is now up-to-date
+- previously-missing POSIX confstr keys have been added
+- mntent interfaces now accept missing fields
+- alt signal stack, if any, is now used for internal signals
+- the LFS64 macros are no longer exposed without _LARGEFILE64_SOURCE
+- memmem (POSIX-future) is now exposed in default feature profile
+- pthread_atfork now admits calls from an application-provided malloc
+- debugger tracking of shared libraries now works on MIPS PIE binaries
+- sendmsg now supports up to SCM_MAX_FD fds in SCM_RIGHTS messages
+
+bugs fixed:
+- gethostbyname[2]_r wrongly returned nonzero (error) on negative result
+- parallel v4/v6 address queries could fail on query id collisions
+- spurious getaddrinfo/AI_ADDRCONFIG failures due to errno clobbering
+- dns search domains ending in dot (including lone dot) broke lookups
+- ipv6 servers in resolv.conf broke lookups on systems with v6 disabled
+- systems with bindv6only failed to query both v4 and v6 nameservers
+- res_mkquery mishandled consecutive final dots in name
+- res_send could malfunction for very small answer buffer sizes
+- resolver dns backend accepted answers with wrong (A vs AAAA) RR type
+- getservbyport_r returned junk or ENOENT (vs ERANGE) on buffer size errors
+- dns result parsing of malformed responses could process uninitialized data
+- freopen didn't reset stream orientation (byte/wide) & encoding rule
+- fwprintf didn't print most fields on open_wmemstream FILEs
+- wide printf %lc ignored field width
+- wide printf erroneously processed %n after encoding errors
+- use of wide printf %9$ argument slot overflowed undersized buffer
+- swprintf malfunctioned on nul character in output
+- strverscmp ordered digit sequences vs nondigits incorrectly
+- timer_create/SIGEV_THREAD failure leaked the thread
+- semaphores were subject to missed-wake under certain usage patterns
+- several possible rare deadlocks with lock handling at thread exit
+- several possible rare deadlocks with aio and multithreaded fork
+- dynamic linker relro processing was broken on archs w/variable pagesize
+- async cancellation could run cancellation handlers in invalid context
+- pthread_detach was wrongly a cancellation point in rare race code path
+- use-after-close/double-close errors in mq_notify error paths
+- mq_notify event thread wrongly ran with signals unmasked
+- wcs{,n}cmp, wmemcmp returned wrong results when difference overflowed
+- accept4, pipe2, and dup3 handled unknown flags wrong in fallback cases
+- CPU_SETSIZE macro had wrong unit
+- select fallback for pre-time64 kernels truncated timeout (vs clamping)
+
+arch-specific bugs fixed:
+- x32 new socketcalls took fallback path due to pointer sign extension
+- x32 wait4 didn't fill rusage structure (time64 regression)
+- x32 semtimedop mismatched timespec ABI with kernel (time64 regression)
+- sigaction signal mask was bogus on or1k, microblaze, mips, and riscv
+- powerpc-sf longjmp asm clobbered value argument
+- or1k poll function passed timeout to syscall in wrong form
diff --git a/arch/microblaze/bits/signal.h b/arch/microblaze/bits/signal.h
index 490f83bf..f25b7c6a 100644
--- a/arch/microblaze/bits/signal.h
+++ b/arch/microblaze/bits/signal.h
@@ -46,7 +46,6 @@ typedef struct __ucontext {
#define SA_RESTART 0x10000000
#define SA_NODEFER 0x40000000
#define SA_RESETHAND 0x80000000
-#define SA_RESTORER 0x04000000
#endif
diff --git a/arch/mips/bits/signal.h b/arch/mips/bits/signal.h
index 1b69e762..a3b3857a 100644
--- a/arch/mips/bits/signal.h
+++ b/arch/mips/bits/signal.h
@@ -66,7 +66,6 @@ typedef struct __ucontext {
#define SA_RESTART 0x10000000
#define SA_NODEFER 0x40000000
#define SA_RESETHAND 0x80000000
-#define SA_RESTORER 0x04000000
#undef SIG_BLOCK
#undef SIG_UNBLOCK
diff --git a/arch/mips/ksigaction.h b/arch/mips/ksigaction.h
index 63fdfab0..485abf75 100644
--- a/arch/mips/ksigaction.h
+++ b/arch/mips/ksigaction.h
@@ -4,10 +4,7 @@ struct k_sigaction {
unsigned flags;
void (*handler)(int);
unsigned long mask[4];
- /* The following field is past the end of the structure the
- * kernel will read or write, and exists only to avoid having
- * mips-specific preprocessor conditionals in sigaction.c. */
- void (*restorer)();
+ void *unused;
};
hidden void __restore(), __restore_rt();
diff --git a/arch/mips/reloc.h b/arch/mips/reloc.h
index 88d23639..f4023b16 100644
--- a/arch/mips/reloc.h
+++ b/arch/mips/reloc.h
@@ -29,6 +29,7 @@
#define NEED_MIPS_GOT_RELOCS 1
#define DT_DEBUG_INDIRECT DT_MIPS_RLD_MAP
+#define DT_DEBUG_INDIRECT_REL DT_MIPS_RLD_MAP_REL
#define ARCH_SYM_REJECT_UND(s) (!((s)->st_other & STO_MIPS_PLT))
#define CRTJMP(pc,sp) __asm__ __volatile__( \
diff --git a/arch/mips64/bits/signal.h b/arch/mips64/bits/signal.h
index 4f91c9fc..ffec7fd0 100644
--- a/arch/mips64/bits/signal.h
+++ b/arch/mips64/bits/signal.h
@@ -85,7 +85,6 @@ typedef struct __ucontext {
#define SA_RESTART 0x10000000
#define SA_NODEFER 0x40000000
#define SA_RESETHAND 0x80000000
-#define SA_RESTORER 0x04000000
#undef SIG_BLOCK
#undef SIG_UNBLOCK
diff --git a/arch/mips64/ksigaction.h b/arch/mips64/ksigaction.h
index c16e4731..b4d0fa5f 100644
--- a/arch/mips64/ksigaction.h
+++ b/arch/mips64/ksigaction.h
@@ -4,7 +4,7 @@ struct k_sigaction {
unsigned flags;
void (*handler)(int);
unsigned long mask[2];
- void (*restorer)();
+ void *unused;
};
hidden void __restore(), __restore_rt();
diff --git a/arch/mips64/reloc.h b/arch/mips64/reloc.h
index fdb5edc9..145d8b0b 100644
--- a/arch/mips64/reloc.h
+++ b/arch/mips64/reloc.h
@@ -38,6 +38,7 @@
#define NEED_MIPS_GOT_RELOCS 1
#define DT_DEBUG_INDIRECT DT_MIPS_RLD_MAP
+#define DT_DEBUG_INDIRECT_REL DT_MIPS_RLD_MAP_REL
#define ARCH_SYM_REJECT_UND(s) (!((s)->st_other & STO_MIPS_PLT))
#define CRTJMP(pc,sp) __asm__ __volatile__( \
diff --git a/arch/mipsn32/bits/signal.h b/arch/mipsn32/bits/signal.h
index 4f91c9fc..ffec7fd0 100644
--- a/arch/mipsn32/bits/signal.h
+++ b/arch/mipsn32/bits/signal.h
@@ -85,7 +85,6 @@ typedef struct __ucontext {
#define SA_RESTART 0x10000000
#define SA_NODEFER 0x40000000
#define SA_RESETHAND 0x80000000
-#define SA_RESTORER 0x04000000
#undef SIG_BLOCK
#undef SIG_UNBLOCK
diff --git a/arch/mipsn32/ksigaction.h b/arch/mipsn32/ksigaction.h
index b565f1fc..485abf75 100644
--- a/arch/mipsn32/ksigaction.h
+++ b/arch/mipsn32/ksigaction.h
@@ -4,7 +4,7 @@ struct k_sigaction {
unsigned flags;
void (*handler)(int);
unsigned long mask[4];
- void (*restorer)();
+ void *unused;
};
hidden void __restore(), __restore_rt();
diff --git a/arch/mipsn32/reloc.h b/arch/mipsn32/reloc.h
index 47c6e591..bf00bd6a 100644
--- a/arch/mipsn32/reloc.h
+++ b/arch/mipsn32/reloc.h
@@ -29,6 +29,7 @@
#define NEED_MIPS_GOT_RELOCS 1
#define DT_DEBUG_INDIRECT DT_MIPS_RLD_MAP
+#define DT_DEBUG_INDIRECT_REL DT_MIPS_RLD_MAP_REL
#define ARCH_SYM_REJECT_UND(s) (!((s)->st_other & STO_MIPS_PLT))
#define CRTJMP(pc,sp) __asm__ __volatile__( \
diff --git a/arch/or1k/bits/signal.h b/arch/or1k/bits/signal.h
index be576d1d..c45be676 100644
--- a/arch/or1k/bits/signal.h
+++ b/arch/or1k/bits/signal.h
@@ -43,7 +43,6 @@ typedef struct __ucontext {
#define SA_RESTART 0x10000000
#define SA_NODEFER 0x40000000
#define SA_RESETHAND 0x80000000
-#define SA_RESTORER 0x04000000
#endif
diff --git a/arch/riscv64/bits/signal.h b/arch/riscv64/bits/signal.h
index 287367db..fd6157a3 100644
--- a/arch/riscv64/bits/signal.h
+++ b/arch/riscv64/bits/signal.h
@@ -76,7 +76,6 @@ typedef struct __ucontext
#define SA_RESTART 0x10000000
#define SA_NODEFER 0x40000000
#define SA_RESETHAND 0x80000000
-#define SA_RESTORER 0x04000000
#endif
diff --git a/compat/time32/__xstat.c b/compat/time32/__xstat.c
index acfbd3cc..e52b5deb 100644
--- a/compat/time32/__xstat.c
+++ b/compat/time32/__xstat.c
@@ -3,22 +3,22 @@
struct stat32;
-int __fxstat64(int ver, int fd, struct stat32 *buf)
+int __fxstat(int ver, int fd, struct stat32 *buf)
{
return __fstat_time32(fd, buf);
}
-int __fxstatat64(int ver, int fd, const char *path, struct stat32 *buf, int flag)
+int __fxstatat(int ver, int fd, const char *path, struct stat32 *buf, int flag)
{
return __fstatat_time32(fd, path, buf, flag);
}
-int __lxstat64(int ver, const char *path, struct stat32 *buf)
+int __lxstat(int ver, const char *path, struct stat32 *buf)
{
return __lstat_time32(path, buf);
}
-int __xstat64(int ver, const char *path, struct stat32 *buf)
+int __xstat(int ver, const char *path, struct stat32 *buf)
{
return __stat_time32(path, buf);
}
diff --git a/compat/time32/aio_suspend_time32.c b/compat/time32/aio_suspend_time32.c
index ed5119bd..d99cb651 100644
--- a/compat/time32/aio_suspend_time32.c
+++ b/compat/time32/aio_suspend_time32.c
@@ -7,5 +7,3 @@ int __aio_suspend_time32(const struct aiocb *const cbs[], int cnt, const struct
return aio_suspend(cbs, cnt, ts32 ? (&(struct timespec){
.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
}
-
-weak_alias(aio_suspend, aio_suspend64);
diff --git a/compat/time32/fstat_time32.c b/compat/time32/fstat_time32.c
index 3e084398..e5d52022 100644
--- a/compat/time32/fstat_time32.c
+++ b/compat/time32/fstat_time32.c
@@ -13,5 +13,3 @@ int __fstat_time32(int fd, struct stat32 *restrict st32)
if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
return r;
}
-
-weak_alias(fstat, fstat64);
diff --git a/compat/time32/fstatat_time32.c b/compat/time32/fstatat_time32.c
index 85dcb008..31d42e63 100644
--- a/compat/time32/fstatat_time32.c
+++ b/compat/time32/fstatat_time32.c
@@ -13,5 +13,3 @@ int __fstatat_time32(int fd, const char *restrict path, struct stat32 *restrict
if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
return r;
}
-
-weak_alias(fstatat, fstatat64);
diff --git a/compat/time32/lstat_time32.c b/compat/time32/lstat_time32.c
index c1257a14..28cb5a0b 100644
--- a/compat/time32/lstat_time32.c
+++ b/compat/time32/lstat_time32.c
@@ -13,5 +13,3 @@ int __lstat_time32(const char *restrict path, struct stat32 *restrict st32)
if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
return r;
}
-
-weak_alias(lstat, lstat64);
diff --git a/compat/time32/stat_time32.c b/compat/time32/stat_time32.c
index 8c6121da..b154b0f9 100644
--- a/compat/time32/stat_time32.c
+++ b/compat/time32/stat_time32.c
@@ -13,5 +13,3 @@ int __stat_time32(const char *restrict path, struct stat32 *restrict st32)
if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
return r;
}
-
-weak_alias(stat, stat64);
diff --git a/configure b/configure
index 6f5453f5..853bf05e 100755
--- a/configure
+++ b/configure
@@ -354,6 +354,14 @@ tryflag CFLAGS_C99FSE -fexcess-precision=standard \
tryflag CFLAGS_C99FSE -frounding-math
#
+# Semantically we want to insist that our sources follow the
+# C rules for type-based aliasing, but most if not all real-world
+# compilers are known or suspected to have critical bugs in their
+# type-based aliasing analysis. See for example GCC bug 107107.
+#
+tryflag CFLAGS_C99FSE -fno-strict-aliasing
+
+#
# We may use the may_alias attribute if __GNUC__ is defined, so
# if the compiler defines __GNUC__ but does not provide it,
# it must be defined away as part of the CFLAGS.
diff --git a/include/aio.h b/include/aio.h
index 453c41b7..a938fcad 100644
--- a/include/aio.h
+++ b/include/aio.h
@@ -49,7 +49,7 @@ int aio_fsync(int, struct aiocb *);
int lio_listio(int, struct aiocb *__restrict const *__restrict, int, struct sigevent *__restrict);
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define aiocb64 aiocb
#define aio_read64 aio_read
#define aio_write64 aio_write
diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h
index 581925a4..9c1327a1 100644
--- a/include/arpa/nameser.h
+++ b/include/arpa/nameser.h
@@ -188,6 +188,36 @@ typedef enum __ns_type {
ns_t_sink = 40,
ns_t_opt = 41,
ns_t_apl = 42,
+ ns_t_ds = 43,
+ ns_t_sshfp = 44,
+ ns_t_ipseckey = 45,
+ ns_t_rrsig = 46,
+ ns_t_nsec = 47,
+ ns_t_dnskey = 48,
+ ns_t_dhcid = 49,
+ ns_t_nsec3 = 50,
+ ns_t_nsec3param = 51,
+ ns_t_tlsa = 52,
+ ns_t_smimea = 53,
+ ns_t_hip = 55,
+ ns_t_ninfo = 56,
+ ns_t_rkey = 57,
+ ns_t_talink = 58,
+ ns_t_cds = 59,
+ ns_t_cdnskey = 60,
+ ns_t_openpgpkey = 61,
+ ns_t_csync = 62,
+ ns_t_spf = 99,
+ ns_t_uinfo = 100,
+ ns_t_uid = 101,
+ ns_t_gid = 102,
+ ns_t_unspec = 103,
+ ns_t_nid = 104,
+ ns_t_l32 = 105,
+ ns_t_l64 = 106,
+ ns_t_lp = 107,
+ ns_t_eui48 = 108,
+ ns_t_eui64 = 109,
ns_t_tkey = 249,
ns_t_tsig = 250,
ns_t_ixfr = 251,
@@ -196,6 +226,11 @@ typedef enum __ns_type {
ns_t_maila = 254,
ns_t_any = 255,
ns_t_zxfr = 256,
+ ns_t_uri = 256,
+ ns_t_caa = 257,
+ ns_t_avc = 258,
+ ns_t_ta = 32768,
+ ns_t_dlv = 32769,
ns_t_max = 65536
} ns_type;
@@ -430,12 +465,48 @@ typedef struct {
#define T_NAPTR ns_t_naptr
#define T_A6 ns_t_a6
#define T_DNAME ns_t_dname
+#define T_DS ns_t_ds
+#define T_SSHFP ns_t_sshfp
+#define T_IPSECKEY ns_t_ipseckey
+#define T_RRSIG ns_t_rrsig
+#define T_NSEC ns_t_nsec
+#define T_DNSKEY ns_t_dnskey
+#define T_DHCID ns_t_dhcid
+#define T_NSEC3 ns_t_nsec3
+#define T_NSEC3PARAM ns_t_nsec3param
+#define T_TLSA ns_t_tlsa
+#define T_SMIMEA ns_t_smimea
+#define T_HIP ns_t_hip
+#define T_NINFO ns_t_ninfo
+#define T_RKEY ns_t_rkey
+#define T_TALINK ns_t_talink
+#define T_CDS ns_t_cds
+#define T_CDNSKEY ns_t_cdnskey
+#define T_OPENPGPKEY ns_t_openpgpkey
+#define T_CSYNC ns_t_csync
+#define T_SPF ns_t_spf
+#define T_UINFO ns_t_uinfo
+#define T_UID ns_t_uid
+#define T_GID ns_t_gid
+#define T_UNSPEC ns_t_unspec
+#define T_NID ns_t_nid
+#define T_L32 ns_t_l32
+#define T_L64 ns_t_l64
+#define T_LP ns_t_lp
+#define T_EUI48 ns_t_eui48
+#define T_EUI64 ns_t_eui64
+#define T_TKEY ns_t_tkey
#define T_TSIG ns_t_tsig
#define T_IXFR ns_t_ixfr
#define T_AXFR ns_t_axfr
#define T_MAILB ns_t_mailb
#define T_MAILA ns_t_maila
#define T_ANY ns_t_any
+#define T_URI ns_t_uri
+#define T_CAA ns_t_caa
+#define T_AVC ns_t_avc
+#define T_TA ns_t_ta
+#define T_DLV ns_t_dlv
#define C_IN ns_c_in
#define C_CHAOS ns_c_chaos
diff --git a/include/dirent.h b/include/dirent.h
index 650ecf64..2d8fffb2 100644
--- a/include/dirent.h
+++ b/include/dirent.h
@@ -56,7 +56,7 @@ int getdents(int, struct dirent *, size_t);
int versionsort(const struct dirent **, const struct dirent **);
#endif
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define dirent64 dirent
#define readdir64 readdir
#define readdir64_r readdir_r
diff --git a/include/elf.h b/include/elf.h
index 9e980a29..23f2c4bc 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -437,6 +437,7 @@ typedef struct {
} Elf64_Chdr;
#define ELFCOMPRESS_ZLIB 1
+#define ELFCOMPRESS_ZSTD 2
#define ELFCOMPRESS_LOOS 0x60000000
#define ELFCOMPRESS_HIOS 0x6fffffff
#define ELFCOMPRESS_LOPROC 0x70000000
diff --git a/include/fcntl.h b/include/fcntl.h
index b664cdc4..515f255d 100644
--- a/include/fcntl.h
+++ b/include/fcntl.h
@@ -195,7 +195,7 @@ ssize_t tee(int, int, size_t, unsigned);
#define loff_t off_t
#endif
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define F_GETLK64 F_GETLK
#define F_SETLK64 F_SETLK
#define F_SETLKW64 F_SETLKW
diff --git a/include/ftw.h b/include/ftw.h
index b15c062a..d0445e8a 100644
--- a/include/ftw.h
+++ b/include/ftw.h
@@ -29,7 +29,7 @@ struct FTW {
int ftw(const char *, int (*)(const char *, const struct stat *, int), int);
int nftw(const char *, int (*)(const char *, const struct stat *, int, struct FTW *), int, int);
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define ftw64 ftw
#define nftw64 nftw
#endif
diff --git a/include/glob.h b/include/glob.h
index 4a562a20..fed06745 100644
--- a/include/glob.h
+++ b/include/glob.h
@@ -39,7 +39,7 @@ void globfree(glob_t *);
#define GLOB_NOMATCH 3
#define GLOB_NOSYS 4
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define glob64 glob
#define globfree64 globfree
#define glob64_t glob_t
diff --git a/include/netdb.h b/include/netdb.h
index d096c781..3af065e2 100644
--- a/include/netdb.h
+++ b/include/netdb.h
@@ -44,6 +44,7 @@ struct addrinfo {
#define EAI_NONAME -2
#define EAI_AGAIN -3
#define EAI_FAIL -4
+#define EAI_NODATA -5
#define EAI_FAMILY -6
#define EAI_SOCKTYPE -7
#define EAI_SERVICE -8
diff --git a/include/sched.h b/include/sched.h
index fda4b484..204c34f5 100644
--- a/include/sched.h
+++ b/include/sched.h
@@ -124,7 +124,7 @@ __CPU_op_func_S(XOR, ^)
#define CPU_ALLOC(n) ((cpu_set_t *)calloc(1,CPU_ALLOC_SIZE(n)))
#define CPU_FREE(set) free(set)
-#define CPU_SETSIZE 128
+#define CPU_SETSIZE 1024
#define CPU_SET(i, set) CPU_SET_S(i,sizeof(cpu_set_t),set)
#define CPU_CLR(i, set) CPU_CLR_S(i,sizeof(cpu_set_t),set)
diff --git a/include/stdio.h b/include/stdio.h
index d1ed01f0..cb858618 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -205,7 +205,7 @@ typedef struct _IO_cookie_io_functions_t {
FILE *fopencookie(void *, const char *, cookie_io_functions_t);
#endif
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define tmpfile64 tmpfile
#define fopen64 fopen
#define freopen64 freopen
diff --git a/include/stdlib.h b/include/stdlib.h
index b507ca33..475190bf 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -95,7 +95,7 @@ size_t __ctype_get_mb_cur_max(void);
#define WTERMSIG(s) ((s) & 0x7f)
#define WSTOPSIG(s) WEXITSTATUS(s)
#define WIFEXITED(s) (!WTERMSIG(s))
-#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001)>>8) > 0x7f00)
+#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001U)>>8) > 0x7f00)
#define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu)
int posix_memalign (void **, size_t, size_t);
@@ -163,7 +163,7 @@ double strtod_l(const char *__restrict, char **__restrict, struct __locale_struc
long double strtold_l(const char *__restrict, char **__restrict, struct __locale_struct *);
#endif
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define mkstemp64 mkstemp
#define mkostemp64 mkostemp
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
diff --git a/include/string.h b/include/string.h
index 43ad0942..db73d2a9 100644
--- a/include/string.h
+++ b/include/string.h
@@ -73,6 +73,7 @@ char *strsignal(int);
char *strerror_l (int, locale_t);
int strcoll_l (const char *, const char *, locale_t);
size_t strxfrm_l (char *__restrict, const char *__restrict, size_t, locale_t);
+void *memmem(const void *, size_t, const void *, size_t);
#endif
#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
@@ -92,7 +93,6 @@ void explicit_bzero (void *, size_t);
int strverscmp (const char *, const char *);
char *strchrnul(const char *, int);
char *strcasestr(const char *, const char *);
-void *memmem(const void *, size_t, const void *, size_t);
void *memrchr(const void *, int, size_t);
void *mempcpy(void *, const void *, size_t);
#ifndef __cplusplus
diff --git a/include/sys/mman.h b/include/sys/mman.h
index 80a3baae..3d5d0f9c 100644
--- a/include/sys/mman.h
+++ b/include/sys/mman.h
@@ -141,7 +141,7 @@ int mincore (void *, size_t, unsigned char *);
int shm_open (const char *, int, mode_t);
int shm_unlink (const char *);
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define mmap64 mmap
#define off64_t off_t
#endif
diff --git a/include/sys/resource.h b/include/sys/resource.h
index 3068328d..e8bfbe1f 100644
--- a/include/sys/resource.h
+++ b/include/sys/resource.h
@@ -95,7 +95,7 @@ int prlimit(pid_t, int, const struct rlimit *, struct rlimit *);
#define RLIM_NLIMITS RLIMIT_NLIMITS
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define RLIM64_INFINITY RLIM_INFINITY
#define RLIM64_SAVED_CUR RLIM_SAVED_CUR
#define RLIM64_SAVED_MAX RLIM_SAVED_MAX
diff --git a/include/sys/sendfile.h b/include/sys/sendfile.h
index e7570d8e..253a041b 100644
--- a/include/sys/sendfile.h
+++ b/include/sys/sendfile.h
@@ -10,7 +10,7 @@ extern "C" {
ssize_t sendfile(int, int, off_t *, size_t);
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define sendfile64 sendfile
#define off64_t off_t
#endif
diff --git a/include/sys/stat.h b/include/sys/stat.h
index 10d446c4..e6d0049c 100644
--- a/include/sys/stat.h
+++ b/include/sys/stat.h
@@ -98,7 +98,7 @@ int lchmod(const char *, mode_t);
#define S_IEXEC S_IXUSR
#endif
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define stat64 stat
#define fstat64 fstat
#define lstat64 lstat
diff --git a/include/sys/statfs.h b/include/sys/statfs.h
index 6f4c6230..7a2e11cd 100644
--- a/include/sys/statfs.h
+++ b/include/sys/statfs.h
@@ -18,7 +18,7 @@ typedef struct __fsid_t {
int statfs (const char *, struct statfs *);
int fstatfs (int, struct statfs *);
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define statfs64 statfs
#define fstatfs64 fstatfs
#define fsblkcnt64_t fsblkcnt_t
diff --git a/include/sys/statvfs.h b/include/sys/statvfs.h
index 793490b6..57a6b806 100644
--- a/include/sys/statvfs.h
+++ b/include/sys/statvfs.h
@@ -42,7 +42,7 @@ int fstatvfs (int, struct statvfs *);
#define ST_NODIRATIME 2048
#define ST_RELATIME 4096
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define statvfs64 statvfs
#define fstatvfs64 fstatvfs
#define fsblkcnt64_t fsblkcnt_t
diff --git a/include/sys/types.h b/include/sys/types.h
index 0c35541d..3363374f 100644
--- a/include/sys/types.h
+++ b/include/sys/types.h
@@ -71,7 +71,7 @@ typedef unsigned long long u_quad_t;
#include <sys/select.h>
#endif
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define blkcnt64_t blkcnt_t
#define fsblkcnt64_t fsblkcnt_t
#define fsfilcnt64_t fsfilcnt_t
diff --git a/include/sys/uio.h b/include/sys/uio.h
index 00f73a2f..90e5939e 100644
--- a/include/sys/uio.h
+++ b/include/sys/uio.h
@@ -29,7 +29,7 @@ ssize_t writev (int, const struct iovec *, int);
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
ssize_t preadv (int, const struct iovec *, int, off_t);
ssize_t pwritev (int, const struct iovec *, int, off_t);
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define preadv64 preadv
#define pwritev64 pwritev
#define off64_t off_t
diff --git a/include/sys/wait.h b/include/sys/wait.h
index d4b1f2e1..8ced671b 100644
--- a/include/sys/wait.h
+++ b/include/sys/wait.h
@@ -50,7 +50,7 @@ pid_t wait4 (pid_t, int *, int, struct rusage *);
#define WSTOPSIG(s) WEXITSTATUS(s)
#define WCOREDUMP(s) ((s) & 0x80)
#define WIFEXITED(s) (!WTERMSIG(s))
-#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001)>>8) > 0x7f00)
+#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001U)>>8) > 0x7f00)
#define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu)
#define WIFCONTINUED(s) ((s) == 0xffff)
diff --git a/include/unistd.h b/include/unistd.h
index 0e8149e4..5bc7f798 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -198,7 +198,7 @@ ssize_t copy_file_range(int, off_t *, int, off_t *, size_t, unsigned);
pid_t gettid(void);
#endif
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
#define lseek64 lseek
#define pread64 pread
#define pwrite64 pwrite
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index d055bd26..746f9ebc 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -21,9 +21,15 @@
#include <sys/membarrier.h>
#include "pthread_impl.h"
#include "fork_impl.h"
-#include "libc.h"
#include "dynlink.h"
+static size_t ldso_page_size;
+#ifndef PAGE_SIZE
+#define PAGE_SIZE ldso_page_size
+#endif
+
+#include "libc.h"
+
#define STRINGIFY(x) __STRINGIFY(x)
#define __STRINGIFY(x) #x
@@ -343,6 +349,40 @@ static struct symdef find_sym(struct dso *dso, const char *s, int need_def)
return find_sym2(dso, s, need_def, 0);
}
+static struct symdef get_lfs64(const char *name)
+{
+ const char *p;
+ static const char lfs64_list[] =
+ "aio_cancel\0aio_error\0aio_fsync\0aio_read\0aio_return\0"
+ "aio_suspend\0aio_write\0alphasort\0creat\0fallocate\0"
+ "fgetpos\0fopen\0freopen\0fseeko\0fsetpos\0fstat\0"
+ "fstatat\0fstatfs\0fstatvfs\0ftello\0ftruncate\0ftw\0"
+ "getdents\0getrlimit\0glob\0globfree\0lio_listio\0"
+ "lockf\0lseek\0lstat\0mkostemp\0mkostemps\0mkstemp\0"
+ "mkstemps\0mmap\0nftw\0open\0openat\0posix_fadvise\0"
+ "posix_fallocate\0pread\0preadv\0prlimit\0pwrite\0"
+ "pwritev\0readdir\0scandir\0sendfile\0setrlimit\0"
+ "stat\0statfs\0statvfs\0tmpfile\0truncate\0versionsort\0"
+ "__fxstat\0__fxstatat\0__lxstat\0__xstat\0";
+ size_t l;
+ char buf[16];
+ for (l=0; name[l]; l++) {
+ if (l >= sizeof buf) goto nomatch;
+ buf[l] = name[l];
+ }
+ if (!strcmp(name, "readdir64_r"))
+ return find_sym(&ldso, "readdir_r", 1);
+ if (l<2 || name[l-2]!='6' || name[l-1]!='4')
+ goto nomatch;
+ buf[l-=2] = 0;
+ for (p=lfs64_list; *p; p++) {
+ if (!strcmp(buf, p)) return find_sym(&ldso, buf, 1);
+ while (*p) p++;
+ }
+nomatch:
+ return (struct symdef){ 0 };
+}
+
static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride)
{
unsigned char *base = dso->base;
@@ -396,6 +436,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
def = (sym->st_info>>4) == STB_LOCAL
? (struct symdef){ .dso = dso, .sym = sym }
: find_sym(ctx, name, type==REL_PLT);
+ if (!def.sym) def = get_lfs64(name);
if (!def.sym && (sym->st_shndx != SHN_UNDEF
|| sym->st_info>>4 != STB_WEAK)) {
if (dso->lazy && (type==REL_PLT || type==REL_GOT)) {
@@ -524,6 +565,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
static void do_relr_relocs(struct dso *dso, size_t *relr, size_t relr_size)
{
+ if (dso == &ldso) return; /* self-relocation was done in _dlstart */
unsigned char *base = dso->base;
size_t *reloc_addr;
for (; relr_size; relr++, relr_size-=sizeof(size_t))
@@ -1739,6 +1781,7 @@ hidden void __dls2(unsigned char *base, size_t *sp)
ldso.phentsize = ehdr->e_phentsize;
ldso.elfmachine = ehdr->e_machine;
ldso.elfclass = ehdr->e_ident[EI_CLASS];
+ search_vec(auxv, &ldso_page_size, AT_PAGESZ);
kernel_mapped_dso(&ldso);
decode_dyn(&ldso);
@@ -2001,6 +2044,10 @@ void __dls3(size_t *sp, size_t *auxv)
size_t *ptr = (size_t *) app.dynv[i+1];
*ptr = (size_t)&debug;
}
+ if (app.dynv[i]==DT_DEBUG_INDIRECT_REL) {
+ size_t *ptr = (size_t *)((size_t)&app.dynv[i] + app.dynv[i+1]);
+ *ptr = (size_t)&debug;
+ }
}
/* This must be done before final relocations, since it calls
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/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/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/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/internal/dynlink.h b/src/internal/dynlink.h
index 830354eb..06f41d09 100644
--- a/src/internal/dynlink.h
+++ b/src/internal/dynlink.h
@@ -92,6 +92,10 @@ 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 37
diff --git a/src/internal/fork_impl.h b/src/internal/fork_impl.h
index 5892c13b..354e733b 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,4 @@ extern hidden volatile int *const __vmlock_lockptr;
hidden void __malloc_atfork(int);
hidden void __ldso_atfork(int);
+hidden void __pthread_key_atfork(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/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/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/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/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/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/wait4.c b/src/linux/wait4.c
index 83650e34..ff2e3e66 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)
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/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/misc/getopt.c b/src/misc/getopt.c
index f8df7aea..fa66f0a3 100644
--- a/src/misc/getopt.c
+++ b/src/misc/getopt.c
@@ -87,7 +87,8 @@ int __posix_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/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/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/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/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..7f83e791 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;
@@ -15,18 +15,18 @@ int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, c
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 || *p>193 || (*p==193 && p[1]>254))
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 || *p>193 || (*p==193 && p[1]>254))
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/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 c9f3acc4..a5eb67fe 100644
--- a/src/network/gethostbyname2_r.c
+++ b/src/network/gethostbyname2_r.c
@@ -23,6 +23,9 @@ int gethostbyname2_r(const char *name, int af,
case EAI_NONAME:
*err = HOST_NOT_FOUND;
return 0;
+ case EAI_NODATA:
+ *err = NO_DATA;
+ return 0;
case EAI_AGAIN:
*err = TRY_AGAIN;
return EAGAIN;
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..7abe0fa9 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;
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_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 bec6ba22..4281482e 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 768
+
+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] = {
@@ -154,6 +159,7 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static
0, 0, 0, qbuf[nq], sizeof *qbuf);
if (qlens[nq] == -1)
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_msend.c b/src/network/res_msend.c
index 9adaea13..86c2fcf4 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)
@@ -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);
@@ -81,22 +133,9 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,
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);
- 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;
@@ -110,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++)
@@ -133,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;
@@ -176,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..fb0fdc2c 100644
--- a/src/process/_Fork.c
+++ b/src/process/_Fork.c
@@ -14,7 +14,6 @@ pid_t _Fork(void)
pid_t ret;
sigset_t set;
__block_all_sigs(&set);
- __aio_atfork(-1);
LOCK(__abort_lock);
#ifdef SYS_fork
ret = __syscall(SYS_fork);
@@ -32,7 +31,7 @@ pid_t _Fork(void)
if (libc.need_locks) libc.need_locks = -1;
}
UNLOCK(__abort_lock);
- __aio_atfork(!ret);
+ if (!ret) __aio_atfork(1);
__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/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/regex/glob.c b/src/regex/glob.c
index 9de080ed..a4906446 100644
--- a/src/regex/glob.c
+++ b/src/regex/glob.c
@@ -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/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/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/signal/mips/restore.s b/src/signal/mips/restore.s
deleted file mode 100644
index b6dadce0..00000000
--- a/src/signal/mips/restore.s
+++ /dev/null
@@ -1,15 +0,0 @@
-.set noreorder
-
-.global __restore_rt
-.hidden __restore_rt
-.type __restore_rt,@function
-__restore_rt:
- li $2, 4193
- syscall
-
-.global __restore
-.hidden __restore
-.type __restore,@function
-__restore:
- li $2, 4119
- syscall
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/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/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/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..04506375 100644
--- a/src/stat/fstatat.c
+++ b/src/stat/fstatat.c
@@ -151,7 +151,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..bfbb5fee 100644
--- a/src/stat/statvfs.c
+++ b/src/stat/statvfs.c
@@ -56,8 +56,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/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 96bfbb42..1641a4c5 100644
--- a/src/stdio/freopen.c
+++ b/src/stdio/freopen.c
@@ -51,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/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..a712d80f 100644
--- a/src/stdio/vfprintf.c
+++ b/src/stdio/vfprintf.c
@@ -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)
@@ -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;
@@ -672,7 +677,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 +693,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..53697701 100644
--- a/src/stdio/vfwprintf.c
+++ b/src/stdio/vfwprintf.c
@@ -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/vswprintf.c b/src/stdio/vswprintf.c
index 7f98c5c9..fc223cf2 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--;
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/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 2d3a98ea..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;
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/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..5c2517f2 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) __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/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/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/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/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..869b69f0 100644
--- a/src/unistd/pwrite.c
+++ b/src/unistd/pwrite.c
@@ -5,5 +5,3 @@ ssize_t pwrite(int fd, const void *buf, size_t size, off_t ofs)
{
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..becf9deb 100644
--- a/src/unistd/pwritev.c
+++ b/src/unistd/pwritev.c
@@ -8,5 +8,3 @@ ssize_t pwritev(int fd, const struct iovec *iov, int count, off_t ofs)
return syscall_cp(SYS_pwritev, fd, iov, count,
(long)(ofs), (long)(ofs>>32));
}
-
-weak_alias(pwritev, pwritev64);
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);