10216 lines
350 KiB
Diff
10216 lines
350 KiB
Diff
diff --git a/Makeconfig b/Makeconfig
|
||
index ba70321af1..9dd058e04b 100644
|
||
--- a/Makeconfig
|
||
+++ b/Makeconfig
|
||
@@ -43,6 +43,22 @@ else
|
||
$(error objdir must be defined by the build-directory Makefile)
|
||
endif
|
||
|
||
+# Did we request 'make -s' run? "yes" or "no".
|
||
+# Starting from make-4.4 MAKEFLAGS now contains long
|
||
+# options like '--shuffle'. To detect presence of 's'
|
||
+# we pick first word with short options. Long options
|
||
+# are guaranteed to come after whitespace. We use '-'
|
||
+# prefix to always have a word before long options
|
||
+# even if no short options were passed.
|
||
+# Typical MAKEFLAGS values to watch for:
|
||
+# "rs --shuffle=42" (silent)
|
||
+# " --shuffle" (not silent)
|
||
+ifeq ($(findstring s, $(firstword -$(MAKEFLAGS))),)
|
||
+silent-make := no
|
||
+else
|
||
+silent-make := yes
|
||
+endif
|
||
+
|
||
# Root of the sysdeps tree.
|
||
sysdep_dir := $(..)sysdeps
|
||
export sysdep_dir := $(sysdep_dir)
|
||
@@ -868,7 +884,7 @@ endif
|
||
# Use 64 bit time_t support for installed programs
|
||
installed-modules = nonlib nscd lddlibc4 ldconfig locale_programs \
|
||
iconvprogs libnss_files libnss_compat libnss_db libnss_hesiod \
|
||
- libutil libpcprofile libSegFault
|
||
+ libutil libpcprofile libSegFault libnsl
|
||
+extra-time-flags = $(if $(filter $(installed-modules),\
|
||
$(in-module)),-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64)
|
||
|
||
@@ -917,7 +933,7 @@ endif
|
||
# umpteen zillion filenames along with it (we use `...' instead)
|
||
# but we don't want this echoing done when the user has said
|
||
# he doesn't want to see commands echoed by using -s.
|
||
-ifneq "$(findstring s,$(MAKEFLAGS))" "" # if -s
|
||
+ifeq ($(silent-make),yes) # if -s
|
||
+cmdecho := echo >/dev/null
|
||
else # not -s
|
||
+cmdecho := echo
|
||
diff --git a/Makerules b/Makerules
|
||
index d1e139d03c..09c0cf8357 100644
|
||
--- a/Makerules
|
||
+++ b/Makerules
|
||
@@ -794,7 +794,7 @@ endif
|
||
# Maximize efficiency by minimizing the number of rules.
|
||
.SUFFIXES: # Clear the suffix list. We don't use suffix rules.
|
||
# Don't define any builtin rules.
|
||
-MAKEFLAGS := $(MAKEFLAGS)r
|
||
+MAKEFLAGS := $(MAKEFLAGS) -r
|
||
|
||
# Generic rule for making directories.
|
||
%/:
|
||
@@ -811,7 +811,7 @@ MAKEFLAGS := $(MAKEFLAGS)r
|
||
.PRECIOUS: $(foreach l,$(libtypes),$(patsubst %,$(common-objpfx)$l,c))
|
||
|
||
# Use the verbose option of ar and tar when not running silently.
|
||
-ifeq "$(findstring s,$(MAKEFLAGS))" "" # if not -s
|
||
+ifeq ($(silent-make),no) # if not -s
|
||
verbose := v
|
||
else # -s
|
||
verbose :=
|
||
diff --git a/NEWS b/NEWS
|
||
index f61e521fc8..82e868d73b 100644
|
||
--- a/NEWS
|
||
+++ b/NEWS
|
||
@@ -5,6 +5,66 @@ See the end for copying conditions.
|
||
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
|
||
using `glibc' in the "product" field.
|
||
|
||
+Version 2.36.1
|
||
+
|
||
+Major new features:
|
||
+
|
||
+* The getent tool now supports the --no-addrconfig option. The output of
|
||
+ getent with --no-addrconfig may contain addresses of families not
|
||
+ configured on the current host i.e. as-if you had not passed
|
||
+ AI_ADDRCONFIG to getaddrinfo calls.
|
||
+
|
||
+Security related changes:
|
||
+
|
||
+ CVE-2022-39046: When the syslog function is passed a crafted input
|
||
+ string larger than 1024 bytes, it reads uninitialized memory from the
|
||
+ heap and prints it to the target log file, potentially revealing a
|
||
+ portion of the contents of the heap.
|
||
+
|
||
+The following bugs are resolved with this release:
|
||
+
|
||
+ [12154] Do not fail DNS resolution for CNAMEs which are not host names
|
||
+ [20975] Deferred cancellation triggers in __check_pf and looses lock leading to deadlock
|
||
+ [24816] Fix tst-nss-files-hosts-long on single-stack hosts
|
||
+ [27576] gmon: improve mcount overflow handling
|
||
+ [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning
|
||
+ [29444] gmon: Fix allocated buffer overflow (bug 29444)
|
||
+ [29864] libc: __libc_start_main() should obtain program headers
|
||
+ address (_dl_phdr) from the auxv, not the ELF header.
|
||
+ [29305] Conserve NSS buffer space during DNS packet parsing
|
||
+ [29402] nscd: nscd: No such file or directory
|
||
+ [29415] nscd: Fix netlink cache invalidation if epoll is used
|
||
+ [28937] New DSO dependency sorter does not put new map first if in a cycle
|
||
+ [29446] _dlopen now ignores dl_caller argument in static mode
|
||
+ [29485] Linux: Terminate subprocess on late failure in tst-pidfd
|
||
+ [29490] alpha: New __brk_call implementation is broken
|
||
+ [29463] math/test-float128-y1 fails on x86_64
|
||
+ [29488] test-ibm128-llround fails on ppc64el when built with gcc-12 and -O2
|
||
+ or higher
|
||
+ [29528] elf: Call __libc_early_init for reused namespaces
|
||
+ [29537] libc: [2.34 regression]: Alignment issue on m68k when using
|
||
+ [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are
|
||
+ [29576] build: librtld.os: in function `_dl_start_profile':
|
||
+ (.text+0x9444): undefined reference to `strcpy'
|
||
+ [29583] Use 64-bit interfaces in gconv_parseconfdir
|
||
+ [29600] Do not completely clear reused namespace in dlmopen
|
||
+ [29607] nscd repeatably crashes calling __strlen_avx2 when hosts cache is
|
||
+ enabled
|
||
+ [29638] libc: stdlib: arc4random fallback is never used
|
||
+ [29657] libc: Incorrect struct stat for 64-bit time on linux/generic
|
||
+ platforms
|
||
+ [29730] broken y2038 support in fstatat on MIPS N64
|
||
+ [29771] Restore IPC_64 support in sysvipc *ctl functions
|
||
+ [29776] elf/tst-tlsopt-powerpc fails when compiled with -mcpu=power10
|
||
+ [29951] time: Set daylight to 1 for matching DST/offset change
|
||
+ [30053] time: strftime %s returns -1 after 2038 on 32 bits systems
|
||
+ [30101] gmon: fix memory corruption issues
|
||
+ [30151] gshadow: Matching sgetsgent, sgetsgent_r ERANGE handling
|
||
+ [30163] posix: Fix system blocks SIGCHLD erroneously
|
||
+ [30305] x86_64: Fix asm constraints in feraiseexcept
|
||
+ [30477] libc: [RISCV]: time64 does not work on riscv32
|
||
+ [30515] _dl_find_object incorrectly returns 1 during early startup
|
||
+
|
||
Version 2.36
|
||
|
||
Major new features:
|
||
diff --git a/bits/socket.h b/bits/socket.h
|
||
index 2b99dea33b..aac8c49b00 100644
|
||
--- a/bits/socket.h
|
||
+++ b/bits/socket.h
|
||
@@ -245,6 +245,12 @@ struct cmsghdr
|
||
+ CMSG_ALIGN (sizeof (struct cmsghdr)))
|
||
#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
|
||
|
||
+/* Given a length, return the additional padding necessary such that
|
||
+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
|
||
+#define __CMSG_PADDING(len) ((sizeof (size_t) \
|
||
+ - ((len) & (sizeof (size_t) - 1))) \
|
||
+ & (sizeof (size_t) - 1))
|
||
+
|
||
extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||
struct cmsghdr *__cmsg) __THROW;
|
||
#ifdef __USE_EXTERN_INLINES
|
||
@@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||
_EXTERN_INLINE struct cmsghdr *
|
||
__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
|
||
{
|
||
+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
|
||
+ __mhdr->msg_controllen because the user is required to obtain the first
|
||
+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
|
||
+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
|
||
+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
|
||
+ pointer arithmetic until we check its value. */
|
||
+
|
||
+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
|
||
+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
|
||
+
|
||
+ size_t __size_needed = sizeof (struct cmsghdr)
|
||
+ + __CMSG_PADDING (__cmsg->cmsg_len);
|
||
+
|
||
+ /* The current header is malformed, too small to be a full header. */
|
||
if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
|
||
- /* The kernel header does this so there may be a reason. */
|
||
return (struct cmsghdr *) 0;
|
||
|
||
+ /* There isn't enough space between __cmsg and the end of the buffer to
|
||
+ hold the current cmsg *and* the next one. */
|
||
+ if (((size_t)
|
||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
|
||
+ < __size_needed)
|
||
+ || ((size_t)
|
||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
|
||
+ - __size_needed)
|
||
+ < __cmsg->cmsg_len))
|
||
+
|
||
+ return (struct cmsghdr *) 0;
|
||
+
|
||
+ /* Now, we trust cmsg_len and can use it to find the next header. */
|
||
__cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
|
||
+ CMSG_ALIGN (__cmsg->cmsg_len));
|
||
- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
|
||
- + __mhdr->msg_controllen)
|
||
- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
|
||
- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
|
||
- /* No more entries. */
|
||
- return (struct cmsghdr *) 0;
|
||
return __cmsg;
|
||
}
|
||
#endif /* Use `extern inline'. */
|
||
diff --git a/csu/libc-start.c b/csu/libc-start.c
|
||
index 543560f36c..bfeee6d851 100644
|
||
--- a/csu/libc-start.c
|
||
+++ b/csu/libc-start.c
|
||
@@ -262,28 +262,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
|
||
}
|
||
# endif
|
||
_dl_aux_init (auxvec);
|
||
- if (GL(dl_phdr) == NULL)
|
||
# endif
|
||
- {
|
||
- /* Starting from binutils-2.23, the linker will define the
|
||
- magic symbol __ehdr_start to point to our own ELF header
|
||
- if it is visible in a segment that also includes the phdrs.
|
||
- So we can set up _dl_phdr and _dl_phnum even without any
|
||
- information from auxv. */
|
||
-
|
||
- extern const ElfW(Ehdr) __ehdr_start
|
||
-# if BUILD_PIE_DEFAULT
|
||
- __attribute__ ((visibility ("hidden")));
|
||
-# else
|
||
- __attribute__ ((weak, visibility ("hidden")));
|
||
- if (&__ehdr_start != NULL)
|
||
-# endif
|
||
- {
|
||
- assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr));
|
||
- GL(dl_phdr) = (const void *) &__ehdr_start + __ehdr_start.e_phoff;
|
||
- GL(dl_phnum) = __ehdr_start.e_phnum;
|
||
- }
|
||
- }
|
||
|
||
__tunables_init (__environ);
|
||
|
||
diff --git a/csu/libc-tls.c b/csu/libc-tls.c
|
||
index 0a216c5502..7fdf7cd7a8 100644
|
||
--- a/csu/libc-tls.c
|
||
+++ b/csu/libc-tls.c
|
||
@@ -118,19 +118,18 @@ __libc_setup_tls (void)
|
||
__tls_pre_init_tp ();
|
||
|
||
/* Look through the TLS segment if there is any. */
|
||
- if (_dl_phdr != NULL)
|
||
- for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr)
|
||
- if (phdr->p_type == PT_TLS)
|
||
- {
|
||
- /* Remember the values we need. */
|
||
- memsz = phdr->p_memsz;
|
||
- filesz = phdr->p_filesz;
|
||
- initimage = (void *) phdr->p_vaddr + main_map->l_addr;
|
||
- align = phdr->p_align;
|
||
- if (phdr->p_align > max_align)
|
||
- max_align = phdr->p_align;
|
||
- break;
|
||
- }
|
||
+ for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr)
|
||
+ if (phdr->p_type == PT_TLS)
|
||
+ {
|
||
+ /* Remember the values we need. */
|
||
+ memsz = phdr->p_memsz;
|
||
+ filesz = phdr->p_filesz;
|
||
+ initimage = (void *) phdr->p_vaddr + main_map->l_addr;
|
||
+ align = phdr->p_align;
|
||
+ if (phdr->p_align > max_align)
|
||
+ max_align = phdr->p_align;
|
||
+ break;
|
||
+ }
|
||
|
||
/* Calculate the size of the static TLS surplus, with 0 auditors. */
|
||
_dl_tls_static_surplus_init (0);
|
||
diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c
|
||
index 2696dde4b1..9b07b4e132 100644
|
||
--- a/dlfcn/dlopen.c
|
||
+++ b/dlfcn/dlopen.c
|
||
@@ -90,7 +90,7 @@ compat_symbol (libdl, ___dlopen, dlopen, GLIBC_2_1);
|
||
void *
|
||
__dlopen (const char *file, int mode, void *dl_caller)
|
||
{
|
||
- return dlopen_implementation (file, mode, RETURN_ADDRESS (0));
|
||
+ return dlopen_implementation (file, mode, dl_caller);
|
||
}
|
||
|
||
void *
|
||
diff --git a/elf/Makefile b/elf/Makefile
|
||
index fd77d0c7c8..48788fcdb8 100644
|
||
--- a/elf/Makefile
|
||
+++ b/elf/Makefile
|
||
@@ -374,6 +374,8 @@ tests += \
|
||
tst-align \
|
||
tst-align2 \
|
||
tst-align3 \
|
||
+ tst-audit-tlsdesc \
|
||
+ tst-audit-tlsdesc-dlopen \
|
||
tst-audit1 \
|
||
tst-audit2 \
|
||
tst-audit8 \
|
||
@@ -408,6 +410,7 @@ tests += \
|
||
tst-dlmopen4 \
|
||
tst-dlmopen-dlerror \
|
||
tst-dlmopen-gethostbyname \
|
||
+ tst-dlmopen-twice \
|
||
tst-dlopenfail \
|
||
tst-dlopenfail-2 \
|
||
tst-dlopenrpath \
|
||
@@ -631,6 +634,7 @@ ifeq ($(run-built-tests),yes)
|
||
tests-special += \
|
||
$(objpfx)noload-mem.out \
|
||
$(objpfx)tst-ldconfig-X.out \
|
||
+ $(objpfx)tst-ldconfig-p.out \
|
||
$(objpfx)tst-leaks1-mem.out \
|
||
$(objpfx)tst-rtld-help.out \
|
||
# tests-special
|
||
@@ -765,6 +769,8 @@ modules-names += \
|
||
tst-alignmod3 \
|
||
tst-array2dep \
|
||
tst-array5dep \
|
||
+ tst-audit-tlsdesc-mod1 \
|
||
+ tst-audit-tlsdesc-mod2 \
|
||
tst-audit11mod1 \
|
||
tst-audit11mod2 \
|
||
tst-audit12mod1 \
|
||
@@ -798,6 +804,7 @@ modules-names += \
|
||
tst-auditmanymod7 \
|
||
tst-auditmanymod8 \
|
||
tst-auditmanymod9 \
|
||
+ tst-auditmod-tlsdesc \
|
||
tst-auditmod1 \
|
||
tst-auditmod9a \
|
||
tst-auditmod9b \
|
||
@@ -834,6 +841,8 @@ modules-names += \
|
||
tst-dlmopen1mod \
|
||
tst-dlmopen-dlerror-mod \
|
||
tst-dlmopen-gethostbyname-mod \
|
||
+ tst-dlmopen-twice-mod1 \
|
||
+ tst-dlmopen-twice-mod2 \
|
||
tst-dlopenfaillinkmod \
|
||
tst-dlopenfailmod1 \
|
||
tst-dlopenfailmod2 \
|
||
@@ -990,23 +999,8 @@ modules-names += tst-gnu2-tls1mod
|
||
$(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so
|
||
tst-gnu2-tls1mod.so-no-z-defs = yes
|
||
CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2
|
||
+endif # $(have-mtls-dialect-gnu2)
|
||
|
||
-tests += tst-audit-tlsdesc tst-audit-tlsdesc-dlopen
|
||
-modules-names += tst-audit-tlsdesc-mod1 tst-audit-tlsdesc-mod2 tst-auditmod-tlsdesc
|
||
-$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||
- $(objpfx)tst-audit-tlsdesc-mod2.so \
|
||
- $(shared-thread-library)
|
||
-CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2
|
||
-CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2
|
||
-$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library)
|
||
-$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||
- $(objpfx)tst-audit-tlsdesc-mod2.so
|
||
-$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so
|
||
-$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||
-tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||
-$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||
-tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||
-endif
|
||
ifeq (yes,$(have-protected-data))
|
||
modules-names += tst-protected1moda tst-protected1modb
|
||
tests += tst-protected1a tst-protected1b
|
||
@@ -2410,6 +2404,11 @@ $(objpfx)tst-ldconfig-X.out : tst-ldconfig-X.sh $(objpfx)ldconfig
|
||
'$(run-program-env)' > $@; \
|
||
$(evaluate-test)
|
||
|
||
+$(objpfx)tst-ldconfig-p.out : tst-ldconfig-p.sh $(objpfx)ldconfig
|
||
+ $(SHELL) $< '$(common-objpfx)' '$(test-wrapper-env)' \
|
||
+ '$(run-program-env)' > $@; \
|
||
+ $(evaluate-test)
|
||
+
|
||
# Test static linking of all the libraries we can possibly link
|
||
# together. Note that in some configurations this may be less than the
|
||
# complete list of libraries we build but we try to maxmimize this list.
|
||
@@ -2967,3 +2966,25 @@ $(objpfx)tst-tls-allocation-failure-static-patched.out: \
|
||
grep -q '^Fatal glibc error: Cannot allocate TLS block$$' $@ \
|
||
&& grep -q '^status: 127$$' $@; \
|
||
$(evaluate-test)
|
||
+
|
||
+$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||
+ $(objpfx)tst-audit-tlsdesc-mod2.so \
|
||
+ $(shared-thread-library)
|
||
+ifeq (yes,$(have-mtls-dialect-gnu2))
|
||
+# The test is valid for all TLS types, but we want to exercise GNU2
|
||
+# TLS if possible.
|
||
+CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2
|
||
+CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2
|
||
+endif
|
||
+$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library)
|
||
+$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||
+ $(objpfx)tst-audit-tlsdesc-mod2.so
|
||
+$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so
|
||
+$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||
+tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||
+$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||
+tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||
+
|
||
+$(objpfx)tst-dlmopen-twice.out: \
|
||
+ $(objpfx)tst-dlmopen-twice-mod1.so \
|
||
+ $(objpfx)tst-dlmopen-twice-mod2.so
|
||
diff --git a/elf/dl-cache.c b/elf/dl-cache.c
|
||
index 8bbf110d02..b97c17b3a9 100644
|
||
--- a/elf/dl-cache.c
|
||
+++ b/elf/dl-cache.c
|
||
@@ -509,8 +509,9 @@ _dl_load_cache_lookup (const char *name)
|
||
we are accessing. Therefore we must make the copy of the
|
||
mapping data without using malloc. */
|
||
char *temp;
|
||
- temp = alloca (strlen (best) + 1);
|
||
- strcpy (temp, best);
|
||
+ size_t best_len = strlen (best) + 1;
|
||
+ temp = alloca (best_len);
|
||
+ memcpy (temp, best, best_len);
|
||
return __strdup (temp);
|
||
}
|
||
|
||
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
|
||
index 4d5831b6f4..2e5b456c11 100644
|
||
--- a/elf/dl-find_object.c
|
||
+++ b/elf/dl-find_object.c
|
||
@@ -46,7 +46,7 @@ _dl_find_object_slow (void *pc, struct dl_find_object *result)
|
||
struct dl_find_object_internal internal;
|
||
_dl_find_object_from_map (l, &internal);
|
||
_dl_find_object_to_external (&internal, result);
|
||
- return 1;
|
||
+ return 0;
|
||
}
|
||
|
||
/* Object not found. */
|
||
diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c
|
||
index 6f161f6ad5..92eb53790e 100644
|
||
--- a/elf/dl-hwcaps.c
|
||
+++ b/elf/dl-hwcaps.c
|
||
@@ -193,7 +193,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
|
||
/* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix
|
||
and a "/" suffix once stored in the result. */
|
||
hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1;
|
||
- size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1)
|
||
+ size_t hwcaps_sz = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1)
|
||
+ hwcaps_counts.total_length);
|
||
|
||
/* Count the number of bits set in the masked value. */
|
||
@@ -229,11 +229,12 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
|
||
assert (m == cnt);
|
||
|
||
/* Determine the total size of all strings together. */
|
||
+ size_t total;
|
||
if (cnt == 1)
|
||
- total += temp[0].len + 1;
|
||
+ total = temp[0].len + 1;
|
||
else
|
||
{
|
||
- total += temp[0].len + temp[cnt - 1].len + 2;
|
||
+ total = temp[0].len + temp[cnt - 1].len + 2;
|
||
if (cnt > 2)
|
||
{
|
||
total <<= 1;
|
||
@@ -255,6 +256,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
|
||
/* This is the overall result, including both glibc-hwcaps
|
||
subdirectories and the legacy hwcaps subdirectories using the
|
||
power set construction. */
|
||
+ total += hwcaps_sz;
|
||
struct r_strlenpair *overall_result
|
||
= malloc (*sz * sizeof (*result) + total);
|
||
if (overall_result == NULL)
|
||
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
|
||
index 4c86dc694e..67fb2e31e2 100644
|
||
--- a/elf/dl-lookup.c
|
||
+++ b/elf/dl-lookup.c
|
||
@@ -854,6 +854,23 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
|
||
if (__glibc_unlikely (current_value.m->l_used == 0))
|
||
current_value.m->l_used = 1;
|
||
|
||
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS))
|
||
+ {
|
||
+ const char *reference_name = undef_map->l_name;
|
||
+
|
||
+ _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'",
|
||
+ DSO_FILENAME (reference_name),
|
||
+ undef_map->l_ns,
|
||
+ DSO_FILENAME (current_value.m->l_name),
|
||
+ current_value.m->l_ns,
|
||
+ protected ? "protected" : "normal", undef_name);
|
||
+ if (version)
|
||
+ _dl_debug_printf_c (" [%s]\n", version->name);
|
||
+ else
|
||
+ _dl_debug_printf_c ("\n");
|
||
+ }
|
||
+
|
||
+
|
||
*ref = current_value.s;
|
||
return LOOKUP_VALUE (current_value.m);
|
||
}
|
||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||
index a23e65926b..e7db5e9642 100644
|
||
--- a/elf/dl-open.c
|
||
+++ b/elf/dl-open.c
|
||
@@ -850,6 +850,7 @@ no more namespaces available for dlmopen()"));
|
||
++GL(dl_nns);
|
||
}
|
||
|
||
+ GL(dl_ns)[nsid].libc_map = NULL;
|
||
_dl_debug_update (nsid)->r_state = RT_CONSISTENT;
|
||
}
|
||
/* Never allow loading a DSO in a namespace which is empty. Such
|
||
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
|
||
index 96638d7ed1..3e2a6a584e 100644
|
||
--- a/elf/dl-sort-maps.c
|
||
+++ b/elf/dl-sort-maps.c
|
||
@@ -27,12 +27,12 @@
|
||
If FOR_FINI is true, this is called for finishing an object. */
|
||
static void
|
||
_dl_sort_maps_original (struct link_map **maps, unsigned int nmaps,
|
||
- unsigned int skip, bool for_fini)
|
||
+ bool force_first, bool for_fini)
|
||
{
|
||
/* Allows caller to do the common optimization of skipping the first map,
|
||
usually the main binary. */
|
||
- maps += skip;
|
||
- nmaps -= skip;
|
||
+ maps += force_first;
|
||
+ nmaps -= force_first;
|
||
|
||
/* A list of one element need not be sorted. */
|
||
if (nmaps <= 1)
|
||
@@ -182,8 +182,9 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map,
|
||
|
||
static void
|
||
_dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||
- unsigned int skip __attribute__ ((unused)), bool for_fini)
|
||
+ bool force_first, bool for_fini)
|
||
{
|
||
+ struct link_map *first_map = maps[0];
|
||
for (int i = nmaps - 1; i >= 0; i--)
|
||
maps[i]->l_visited = 0;
|
||
|
||
@@ -208,14 +209,6 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||
Adjusting the order so that maps[0] is last traversed naturally avoids
|
||
this problem.
|
||
|
||
- Further, the old "optimization" of skipping the main object at maps[0]
|
||
- from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general
|
||
- no longer valid, since traversing along object dependency-links
|
||
- may "find" the main object even when it is not included in the initial
|
||
- order (e.g. a dlopen()'ed shared object can have circular dependencies
|
||
- linked back to itself). In such a case, traversing N-1 objects will
|
||
- create a N-object result, and raise problems.
|
||
-
|
||
To summarize, just passing in the full list, and iterating from back
|
||
to front makes things much more straightforward. */
|
||
|
||
@@ -274,6 +267,27 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||
}
|
||
|
||
memcpy (maps, rpo, sizeof (struct link_map *) * nmaps);
|
||
+
|
||
+ /* Skipping the first object at maps[0] is not valid in general,
|
||
+ since traversing along object dependency-links may "find" that
|
||
+ first object even when it is not included in the initial order
|
||
+ (e.g., a dlopen'ed shared object can have circular dependencies
|
||
+ linked back to itself). In such a case, traversing N-1 objects
|
||
+ will create a N-object result, and raise problems. Instead,
|
||
+ force the object back into first place after sorting. This naive
|
||
+ approach may introduce further dependency ordering violations
|
||
+ compared to rotating the cycle until the first map is again in
|
||
+ the first position, but as there is a cycle, at least one
|
||
+ violation is already present. */
|
||
+ if (force_first && maps[0] != first_map)
|
||
+ {
|
||
+ int i;
|
||
+ for (i = 0; maps[i] != first_map; ++i)
|
||
+ ;
|
||
+ assert (i < nmaps);
|
||
+ memmove (&maps[1], maps, i * sizeof (maps[0]));
|
||
+ maps[0] = first_map;
|
||
+ }
|
||
}
|
||
|
||
void
|
||
@@ -286,7 +300,7 @@ _dl_sort_maps_init (void)
|
||
|
||
void
|
||
_dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||
- unsigned int skip, bool for_fini)
|
||
+ bool force_first, bool for_fini)
|
||
{
|
||
/* It can be tempting to use a static function pointer to store and call
|
||
the current selected sorting algorithm routine, but experimentation
|
||
@@ -296,9 +310,9 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||
input cases. A simple if-case with direct function calls appears to
|
||
be the fastest. */
|
||
if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
|
||
- _dl_sort_maps_original (maps, nmaps, skip, for_fini);
|
||
+ _dl_sort_maps_original (maps, nmaps, force_first, for_fini);
|
||
else
|
||
- _dl_sort_maps_dfs (maps, nmaps, skip, for_fini);
|
||
+ _dl_sort_maps_dfs (maps, nmaps, force_first, for_fini);
|
||
}
|
||
|
||
#endif /* HAVE_TUNABLES. */
|
||
diff --git a/elf/dl-support.c b/elf/dl-support.c
|
||
index 4af0b5b2ce..f45b630ba5 100644
|
||
--- a/elf/dl-support.c
|
||
+++ b/elf/dl-support.c
|
||
@@ -255,6 +255,25 @@ _dl_aux_init (ElfW(auxv_t) *av)
|
||
for (int i = 0; i < array_length (auxv_values); ++i)
|
||
auxv_values[i] = 0;
|
||
_dl_parse_auxv (av, auxv_values);
|
||
+
|
||
+ _dl_phdr = (void*) auxv_values[AT_PHDR];
|
||
+ _dl_phnum = auxv_values[AT_PHNUM];
|
||
+
|
||
+ if (_dl_phdr == NULL)
|
||
+ {
|
||
+ /* Starting from binutils-2.23, the linker will define the
|
||
+ magic symbol __ehdr_start to point to our own ELF header
|
||
+ if it is visible in a segment that also includes the phdrs.
|
||
+ So we can set up _dl_phdr and _dl_phnum even without any
|
||
+ information from auxv. */
|
||
+
|
||
+ extern const ElfW(Ehdr) __ehdr_start attribute_hidden;
|
||
+ assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr));
|
||
+ _dl_phdr = (const void *) &__ehdr_start + __ehdr_start.e_phoff;
|
||
+ _dl_phnum = __ehdr_start.e_phnum;
|
||
+ }
|
||
+
|
||
+ assert (_dl_phdr != NULL);
|
||
}
|
||
#endif
|
||
|
||
@@ -323,20 +342,19 @@ _dl_non_dynamic_init (void)
|
||
if (_dl_platform != NULL)
|
||
_dl_platformlen = strlen (_dl_platform);
|
||
|
||
- if (_dl_phdr != NULL)
|
||
- for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph)
|
||
- switch (ph->p_type)
|
||
- {
|
||
- /* Check if the stack is nonexecutable. */
|
||
- case PT_GNU_STACK:
|
||
- _dl_stack_flags = ph->p_flags;
|
||
- break;
|
||
-
|
||
- case PT_GNU_RELRO:
|
||
- _dl_main_map.l_relro_addr = ph->p_vaddr;
|
||
- _dl_main_map.l_relro_size = ph->p_memsz;
|
||
- break;
|
||
- }
|
||
+ for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph)
|
||
+ switch (ph->p_type)
|
||
+ {
|
||
+ /* Check if the stack is nonexecutable. */
|
||
+ case PT_GNU_STACK:
|
||
+ _dl_stack_flags = ph->p_flags;
|
||
+ break;
|
||
+
|
||
+ case PT_GNU_RELRO:
|
||
+ _dl_main_map.l_relro_addr = ph->p_vaddr;
|
||
+ _dl_main_map.l_relro_size = ph->p_memsz;
|
||
+ break;
|
||
+ }
|
||
|
||
call_function_static_weak (_dl_find_object_init);
|
||
|
||
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
|
||
index e6a56b3070..9fa3b484cf 100644
|
||
--- a/elf/dl-tunables.list
|
||
+++ b/elf/dl-tunables.list
|
||
@@ -169,4 +169,17 @@ glibc {
|
||
default: 2
|
||
}
|
||
}
|
||
+
|
||
+ gmon {
|
||
+ minarcs {
|
||
+ type: INT_32
|
||
+ minval: 50
|
||
+ default: 50
|
||
+ }
|
||
+ maxarcs {
|
||
+ type: INT_32
|
||
+ minval: 50
|
||
+ default: 1048576
|
||
+ }
|
||
+ }
|
||
}
|
||
diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def
|
||
index 5f7f18ef27..4bf9052db1 100644
|
||
--- a/elf/dso-sort-tests-1.def
|
||
+++ b/elf/dso-sort-tests-1.def
|
||
@@ -64,3 +64,10 @@ output: b>a>{}<a<b
|
||
tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c
|
||
output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
|
||
output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<g<f<a<b<c<d<e];}
|
||
+
|
||
+# Test that even in the presence of dependency loops involving dlopen'ed
|
||
+# object, that object is initialized last (and not unloaded prematurely).
|
||
+# Final destructor order is indeterminate due to the cycle.
|
||
+tst-bz28937: {+a;+b;-b;+c;%c};a->a1;a->a2;a2->a;b->b1;c->a1;c=>a1
|
||
+output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a<a2<c<a1
|
||
+output(glibc.rtld.dynamic_sort=2): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a2<a<c<a1
|
||
diff --git a/elf/elf.h b/elf/elf.h
|
||
index 02a1b3f52f..014393f3cc 100644
|
||
--- a/elf/elf.h
|
||
+++ b/elf/elf.h
|
||
@@ -4085,8 +4085,11 @@ enum
|
||
#define R_NDS32_TLS_DESC 119
|
||
|
||
/* LoongArch ELF Flags */
|
||
-#define EF_LARCH_ABI 0x07
|
||
-#define EF_LARCH_ABI_LP64D 0x03
|
||
+#define EF_LARCH_ABI_MODIFIER_MASK 0x07
|
||
+#define EF_LARCH_ABI_SOFT_FLOAT 0x01
|
||
+#define EF_LARCH_ABI_SINGLE_FLOAT 0x02
|
||
+#define EF_LARCH_ABI_DOUBLE_FLOAT 0x03
|
||
+#define EF_LARCH_OBJABI_V1 0x40
|
||
|
||
/* LoongArch specific dynamic relocations */
|
||
#define R_LARCH_NONE 0
|
||
diff --git a/elf/rtld-Rules b/elf/rtld-Rules
|
||
index ca00dd1fe2..3c5e273f2b 100644
|
||
--- a/elf/rtld-Rules
|
||
+++ b/elf/rtld-Rules
|
||
@@ -52,7 +52,7 @@ $(objpfx)rtld-libc.a: $(foreach dir,$(rtld-subdirs),\
|
||
mv -f $@T $@
|
||
|
||
# Use the verbose option of ar and tar when not running silently.
|
||
-ifeq "$(findstring s,$(MAKEFLAGS))" "" # if not -s
|
||
+ifeq ($(silent-make),no) # if not -s
|
||
verbose := v
|
||
else # -s
|
||
verbose :=
|
||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||
index cbbaf4a331..3e771a93d8 100644
|
||
--- a/elf/rtld.c
|
||
+++ b/elf/rtld.c
|
||
@@ -2122,6 +2122,12 @@ dl_main (const ElfW(Phdr) *phdr,
|
||
if (l->l_faked)
|
||
/* The library was not found. */
|
||
_dl_printf ("\t%s => not found\n", l->l_libname->name);
|
||
+ else if (strcmp (l->l_libname->name, l->l_name) == 0)
|
||
+ /* Print vDSO like libraries without duplicate name. Some
|
||
+ consumers depend of this format. */
|
||
+ _dl_printf ("\t%s (0x%0*Zx)\n", l->l_libname->name,
|
||
+ (int) sizeof l->l_map_start * 2,
|
||
+ (size_t) l->l_map_start);
|
||
else
|
||
_dl_printf ("\t%s => %s (0x%0*Zx)\n",
|
||
DSO_FILENAME (l->l_libname->name),
|
||
diff --git a/elf/tst-auditmod28.c b/elf/tst-auditmod28.c
|
||
index db7ba95abe..9e0a122c38 100644
|
||
--- a/elf/tst-auditmod28.c
|
||
+++ b/elf/tst-auditmod28.c
|
||
@@ -71,6 +71,17 @@ la_version (unsigned int current)
|
||
TEST_VERIFY (dladdr1 (&_exit, &info, &extra_info, RTLD_DL_LINKMAP) != 0);
|
||
TEST_VERIFY (extra_info == handle);
|
||
|
||
+ /* Check _dl_find_object. */
|
||
+ struct dl_find_object dlfo;
|
||
+ TEST_COMPARE (_dl_find_object (__builtin_return_address (0), &dlfo), 0);
|
||
+ /* "ld.so" is seen with --enable-hardcoded-path-in-tests. */
|
||
+ if (strcmp (basename (dlfo.dlfo_link_map->l_name), "ld.so") != 0)
|
||
+ TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LD_SO);
|
||
+ TEST_COMPARE (_dl_find_object (dlsym (handle, "environ"), &dlfo), 0);
|
||
+ TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LIBC_SO);
|
||
+ TEST_COMPARE (_dl_find_object ((void *) 1, &dlfo), -1);
|
||
+ TEST_COMPARE (_dl_find_object ((void *) -1, &dlfo), -1);
|
||
+
|
||
/* Verify that dlmopen creates a new namespace. */
|
||
void *dlmopen_handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
|
||
TEST_VERIFY (dlmopen_handle != handle);
|
||
diff --git a/elf/tst-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c
|
||
new file mode 100644
|
||
index 0000000000..0eaf04948c
|
||
--- /dev/null
|
||
+++ b/elf/tst-dlmopen-twice-mod1.c
|
||
@@ -0,0 +1,37 @@
|
||
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 1.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <stdio.h>
|
||
+
|
||
+static void __attribute__ ((constructor))
|
||
+init (void)
|
||
+{
|
||
+ puts ("info: tst-dlmopen-twice-mod1.so loaded");
|
||
+ fflush (stdout);
|
||
+}
|
||
+
|
||
+static void __attribute__ ((destructor))
|
||
+fini (void)
|
||
+{
|
||
+ puts ("info: tst-dlmopen-twice-mod1.so about to be unloaded");
|
||
+ fflush (stdout);
|
||
+}
|
||
+
|
||
+/* Large allocation. The second module does not have this, so it
|
||
+ should load libc at a different address. */
|
||
+char large_allocate[16 * 1024 * 1024];
|
||
diff --git a/elf/tst-dlmopen-twice-mod2.c b/elf/tst-dlmopen-twice-mod2.c
|
||
new file mode 100644
|
||
index 0000000000..40c6c01f96
|
||
--- /dev/null
|
||
+++ b/elf/tst-dlmopen-twice-mod2.c
|
||
@@ -0,0 +1,50 @@
|
||
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 2.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <ctype.h>
|
||
+#include <stdio.h>
|
||
+
|
||
+static void __attribute__ ((constructor))
|
||
+init (void)
|
||
+{
|
||
+ puts ("info: tst-dlmopen-twice-mod2.so loaded");
|
||
+ fflush (stdout);
|
||
+}
|
||
+
|
||
+static void __attribute__ ((destructor))
|
||
+fini (void)
|
||
+{
|
||
+ puts ("info: tst-dlmopen-twice-mod2.so about to be unloaded");
|
||
+ fflush (stdout);
|
||
+}
|
||
+
|
||
+int
|
||
+run_check (void)
|
||
+{
|
||
+ puts ("info: about to call isalpha");
|
||
+ fflush (stdout);
|
||
+
|
||
+ volatile char ch = 'a';
|
||
+ if (!isalpha (ch))
|
||
+ {
|
||
+ puts ("error: isalpha ('a') is not true");
|
||
+ fflush (stdout);
|
||
+ return 1;
|
||
+ }
|
||
+ return 0;
|
||
+}
|
||
diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c
|
||
new file mode 100644
|
||
index 0000000000..70c71fe19c
|
||
--- /dev/null
|
||
+++ b/elf/tst-dlmopen-twice.c
|
||
@@ -0,0 +1,54 @@
|
||
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Main.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <stdio.h>
|
||
+#include <support/check.h>
|
||
+#include <support/xdlfcn.h>
|
||
+
|
||
+/* Run the test multiple times, to check finding a new namespace while
|
||
+ another namespace is already in use. This used to trigger bug 29600. */
|
||
+static void
|
||
+recurse (int depth)
|
||
+{
|
||
+ if (depth == 0)
|
||
+ return;
|
||
+
|
||
+ printf ("info: running at depth %d\n", depth);
|
||
+ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so",
|
||
+ RTLD_NOW);
|
||
+ xdlclose (handle);
|
||
+ handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW);
|
||
+ int (*run_check) (void) = xdlsym (handle, "run_check");
|
||
+ TEST_COMPARE (run_check (), 0);
|
||
+ recurse (depth - 1);
|
||
+ xdlclose (handle);
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ /* First run the test without nesting. */
|
||
+ recurse (1);
|
||
+
|
||
+ /* Then with nesting. The constant needs to be less than the
|
||
+ internal DL_NNS namespace constant. */
|
||
+ recurse (10);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/elf/tst-ldconfig-p.sh b/elf/tst-ldconfig-p.sh
|
||
new file mode 100644
|
||
index 0000000000..ec937bf4ec
|
||
--- /dev/null
|
||
+++ b/elf/tst-ldconfig-p.sh
|
||
@@ -0,0 +1,77 @@
|
||
+#!/bin/sh
|
||
+# Test that ldconfig -p prints something useful.
|
||
+# Copyright (C) 2023 Free Software Foundation, Inc.
|
||
+# This file is part of the GNU C Library.
|
||
+
|
||
+# The GNU C Library is free software; you can redistribute it and/or
|
||
+# modify it under the terms of the GNU Lesser General Public
|
||
+# License as published by the Free Software Foundation; either
|
||
+# version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+# The GNU C Library is distributed in the hope that it will be useful,
|
||
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+# Lesser General Public License for more details.
|
||
+
|
||
+# You should have received a copy of the GNU Lesser General Public
|
||
+# License along with the GNU C Library; if not, see
|
||
+# <https://www.gnu.org/licenses/>.
|
||
+
|
||
+# Check that the newly built ldconfig -p can dump the system
|
||
+# /etc/ld.so.cache file. This should always work even if the ABIs are
|
||
+# not compatible, except in a cross-endian build (that presumably
|
||
+# involves emulation when running ldconfig).
|
||
+
|
||
+common_objpfx=$1
|
||
+test_wrapper_env=$2
|
||
+run_program_env=$3
|
||
+
|
||
+if ! test -r /etc/ld.so.cache; then
|
||
+ echo "warning: /etc/ld.so.cache does not exist, test skipped"
|
||
+ exit 77
|
||
+fi
|
||
+
|
||
+testout="${common_objpfx}elf/tst-ldconfig-p.out"
|
||
+# Truncate file.
|
||
+: > "$testout"
|
||
+
|
||
+${test_wrapper_env} \
|
||
+${run_program_env} \
|
||
+${common_objpfx}elf/ldconfig -p \
|
||
+ $testroot/lib >>"$testout" 2>>"$testout"
|
||
+status=$?
|
||
+echo "info: ldconfig exit status: $status" >>"$testout"
|
||
+
|
||
+errors=0
|
||
+case $status in
|
||
+ (0)
|
||
+ if head -n 1 "$testout" | \
|
||
+ grep -q "libs found in cache \`/etc/ld.so.cache'\$" ; then
|
||
+ echo "info: initial string found" >>"$testout"
|
||
+ else
|
||
+ echo "error: initial string not found" >>"$testout"
|
||
+ errors=1
|
||
+ fi
|
||
+ if grep -q "^ libc\.so\..* => " "$testout"; then
|
||
+ echo "info: libc.so.* string found" >>"$testout"
|
||
+ else
|
||
+ echo "error: libc.so.* string not found" >>"$testout"
|
||
+ errors=1
|
||
+ fi
|
||
+ ;;
|
||
+ (1)
|
||
+ if head -n 1 "$testout" | \
|
||
+ grep -q ": Cache file has wrong endianness\.$" ; then
|
||
+ echo "info: cache file has wrong endianess" >> "$testout"
|
||
+ else
|
||
+ echo "error: unexpected ldconfig error message" >> "$testout"
|
||
+ errors=1
|
||
+ fi
|
||
+ ;;
|
||
+ (*)
|
||
+ echo "error: unexpected exit status" >> "$testout"
|
||
+ errors=1
|
||
+ ;;
|
||
+esac
|
||
+
|
||
+exit $errors
|
||
diff --git a/gmon/Makefile b/gmon/Makefile
|
||
index 552b7d7751..fbe2b0ba5c 100644
|
||
--- a/gmon/Makefile
|
||
+++ b/gmon/Makefile
|
||
@@ -1,4 +1,5 @@
|
||
-# Copyright (C) 1995-2022 Free Software Foundation, Inc.
|
||
+# Copyright (C) 1995-2023 Free Software Foundation, Inc.
|
||
+# Copyright The GNU Toolchain Authors.
|
||
# This file is part of the GNU C Library.
|
||
|
||
# The GNU C Library is free software; you can redistribute it and/or
|
||
@@ -25,7 +26,7 @@ include ../Makeconfig
|
||
headers := sys/gmon.h sys/gmon_out.h sys/profil.h
|
||
routines := gmon mcount profil sprofil prof-freq
|
||
|
||
-tests = tst-sprofil tst-gmon
|
||
+tests = tst-sprofil tst-gmon tst-mcleanup
|
||
ifeq ($(build-profile),yes)
|
||
tests += tst-profile-static
|
||
tests-static += tst-profile-static
|
||
@@ -56,6 +57,14 @@ ifeq ($(run-built-tests),yes)
|
||
tests-special += $(objpfx)tst-gmon-gprof.out
|
||
endif
|
||
|
||
+CFLAGS-tst-mcleanup.c := -fno-omit-frame-pointer -pg
|
||
+tst-mcleanup-no-pie = yes
|
||
+CRT-tst-mcleanup := $(csu-objpfx)g$(start-installed-name)
|
||
+tst-mcleanup-ENV := GMON_OUT_PREFIX=$(objpfx)tst-mcleanup.data
|
||
+ifeq ($(run-built-tests),yes)
|
||
+tests-special += $(objpfx)tst-mcleanup.out
|
||
+endif
|
||
+
|
||
CFLAGS-tst-gmon-static.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg
|
||
CRT-tst-gmon-static := $(csu-objpfx)g$(static-start-installed-name)
|
||
tst-gmon-static-no-pie = yes
|
||
@@ -103,6 +112,18 @@ $(objpfx)tst-gmon.out: clean-tst-gmon-data
|
||
clean-tst-gmon-data:
|
||
rm -f $(objpfx)tst-gmon.data.*
|
||
|
||
+$(objpfx)tst-mcount-overflow.o: clean-tst-mcount-overflow-data
|
||
+clean-tst-mcount-overflow-data:
|
||
+ rm -f $(objpfx)tst-mcount-overflow.data.*
|
||
+
|
||
+$(objpfx)tst-mcount-overflow-check.out: tst-mcount-overflow-check.sh $(objpfx)tst-mcount-overflow.out
|
||
+ $(SHELL) $< $(objpfx)tst-mcount-overflow > $@; \
|
||
+ $(evaluate-test)
|
||
+
|
||
+$(objpfx)tst-mcleanup.out: clean-tst-mcleanup-data
|
||
+clean-tst-mcleanup-data:
|
||
+ rm -f $(objpfx)tst-mcleanup.data.*
|
||
+
|
||
$(objpfx)tst-gmon-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon.out
|
||
$(SHELL) $< $(GPROF) $(objpfx)tst-gmon $(objpfx)tst-gmon.data.* > $@; \
|
||
$(evaluate-test)
|
||
diff --git a/gmon/gmon.c b/gmon/gmon.c
|
||
index dee64803ad..97be1f72ca 100644
|
||
--- a/gmon/gmon.c
|
||
+++ b/gmon/gmon.c
|
||
@@ -97,11 +97,8 @@ __moncontrol (int mode)
|
||
{
|
||
struct gmonparam *p = &_gmonparam;
|
||
|
||
- /* Don't change the state if we ran into an error. */
|
||
- if (p->state == GMON_PROF_ERROR)
|
||
- return;
|
||
-
|
||
- if (mode)
|
||
+ /* Treat start request as stop if error or gmon not initialized. */
|
||
+ if (mode && p->state != GMON_PROF_ERROR && p->tos != NULL)
|
||
{
|
||
/* start */
|
||
__profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
|
||
@@ -111,7 +108,9 @@ __moncontrol (int mode)
|
||
{
|
||
/* stop */
|
||
__profil(NULL, 0, 0, 0);
|
||
- p->state = GMON_PROF_OFF;
|
||
+ /* Don't change the state if we ran into an error. */
|
||
+ if (p->state != GMON_PROF_ERROR)
|
||
+ p->state = GMON_PROF_OFF;
|
||
}
|
||
}
|
||
libc_hidden_def (__moncontrol)
|
||
@@ -124,6 +123,19 @@ __monstartup (u_long lowpc, u_long highpc)
|
||
int o;
|
||
char *cp;
|
||
struct gmonparam *p = &_gmonparam;
|
||
+ long int minarcs, maxarcs;
|
||
+
|
||
+ /* No tunables, we use hardcoded defaults */
|
||
+ minarcs = MINARCS;
|
||
+ maxarcs = MAXARCS;
|
||
+
|
||
+ /*
|
||
+ * If we are incorrectly called twice in a row (without an
|
||
+ * intervening call to _mcleanup), ignore the second call to
|
||
+ * prevent leaking memory.
|
||
+ */
|
||
+ if (p->tos != NULL)
|
||
+ return;
|
||
|
||
/*
|
||
* round lowpc and highpc to multiples of the density we're using
|
||
@@ -132,6 +144,8 @@ __monstartup (u_long lowpc, u_long highpc)
|
||
p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
|
||
p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
|
||
p->textsize = p->highpc - p->lowpc;
|
||
+ /* This looks like a typo, but it's here to align the p->froms
|
||
+ section. */
|
||
p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms));
|
||
p->hashfraction = HASHFRACTION;
|
||
p->log_hashfraction = -1;
|
||
@@ -142,12 +156,12 @@ __monstartup (u_long lowpc, u_long highpc)
|
||
instead of integer division. Precompute shift amount. */
|
||
p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1;
|
||
}
|
||
- p->fromssize = p->textsize / HASHFRACTION;
|
||
+ p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms));
|
||
p->tolimit = p->textsize * ARCDENSITY / 100;
|
||
- if (p->tolimit < MINARCS)
|
||
- p->tolimit = MINARCS;
|
||
- else if (p->tolimit > MAXARCS)
|
||
- p->tolimit = MAXARCS;
|
||
+ if (p->tolimit < minarcs)
|
||
+ p->tolimit = minarcs;
|
||
+ else if (p->tolimit > maxarcs)
|
||
+ p->tolimit = maxarcs;
|
||
p->tossize = p->tolimit * sizeof(struct tostruct);
|
||
|
||
cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
|
||
@@ -440,9 +454,14 @@ _mcleanup (void)
|
||
{
|
||
__moncontrol (0);
|
||
|
||
- if (_gmonparam.state != GMON_PROF_ERROR)
|
||
+ if (_gmonparam.state != GMON_PROF_ERROR && _gmonparam.tos != NULL)
|
||
write_gmon ();
|
||
|
||
/* free the memory. */
|
||
free (_gmonparam.tos);
|
||
+
|
||
+ /* reset buffer to initial state for safety */
|
||
+ memset(&_gmonparam, 0, sizeof _gmonparam);
|
||
+ /* somewhat confusingly, ON=0, OFF=3 */
|
||
+ _gmonparam.state = GMON_PROF_OFF;
|
||
}
|
||
diff --git a/gmon/mcount.c b/gmon/mcount.c
|
||
index 9d4a1a50fa..f7180fdb83 100644
|
||
--- a/gmon/mcount.c
|
||
+++ b/gmon/mcount.c
|
||
@@ -41,6 +41,10 @@ static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93";
|
||
|
||
#include <atomic.h>
|
||
|
||
+#include <not-cancel.h>
|
||
+#include <unistd.h>
|
||
+#define ERR(s) __write_nocancel (STDERR_FILENO, s, sizeof (s) - 1)
|
||
+
|
||
/*
|
||
* mcount is called on entry to each function compiled with the profiling
|
||
* switch set. _mcount(), which is declared in a machine-dependent way
|
||
@@ -170,6 +174,7 @@ done:
|
||
return;
|
||
overflow:
|
||
p->state = GMON_PROF_ERROR;
|
||
+ ERR("mcount: call graph buffer size limit exceeded, gmon.out will not be generated\n");
|
||
return;
|
||
}
|
||
|
||
diff --git a/gmon/sys/gmon.h b/gmon/sys/gmon.h
|
||
index b4cc3b043a..af0582a371 100644
|
||
--- a/gmon/sys/gmon.h
|
||
+++ b/gmon/sys/gmon.h
|
||
@@ -111,6 +111,8 @@ extern struct __bb *__bb_head;
|
||
* Always allocate at least this many tostructs. This
|
||
* hides the inadequacy of the ARCDENSITY heuristic, at least
|
||
* for small programs.
|
||
+ *
|
||
+ * Value can be overridden at runtime by glibc.gmon.minarcs tunable.
|
||
*/
|
||
#define MINARCS 50
|
||
|
||
@@ -124,8 +126,8 @@ extern struct __bb *__bb_head;
|
||
* Used to be max representable value of ARCINDEX minus 2, but now
|
||
* that ARCINDEX is a long, that's too large; we don't really want
|
||
* to allow a 48 gigabyte table.
|
||
- * The old value of 1<<16 wasn't high enough in practice for large C++
|
||
- * programs; will 1<<20 be adequate for long? FIXME
|
||
+ *
|
||
+ * Value can be overridden at runtime by glibc.gmon.maxarcs tunable.
|
||
*/
|
||
#define MAXARCS (1 << 20)
|
||
|
||
diff --git a/gmon/tst-mcleanup.c b/gmon/tst-mcleanup.c
|
||
new file mode 100644
|
||
index 0000000000..b259653ec8
|
||
--- /dev/null
|
||
+++ b/gmon/tst-mcleanup.c
|
||
@@ -0,0 +1,31 @@
|
||
+/* Test program for repeated invocation of _mcleanup
|
||
+ Copyright The GNU Toolchain Authors.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+/* Intentionally calls _mcleanup() twice: once manually, it will be
|
||
+ called again as an atexit handler. This is incorrect use of the API,
|
||
+ but the point of the test is to make sure we don't crash when the
|
||
+ API is misused in this way. */
|
||
+
|
||
+#include <sys/gmon.h>
|
||
+
|
||
+int
|
||
+main (void)
|
||
+{
|
||
+ _mcleanup();
|
||
+ return 0;
|
||
+}
|
||
diff --git a/gmon/tst-mcount-overflow-check.sh b/gmon/tst-mcount-overflow-check.sh
|
||
new file mode 100644
|
||
index 0000000000..27eb5538fd
|
||
--- /dev/null
|
||
+++ b/gmon/tst-mcount-overflow-check.sh
|
||
@@ -0,0 +1,45 @@
|
||
+#!/bin/sh
|
||
+# Test expected messages generated when mcount overflows
|
||
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
|
||
+# Copyright The GNU Toolchain Authors.
|
||
+# This file is part of the GNU C Library.
|
||
+
|
||
+# The GNU C Library is free software; you can redistribute it and/or
|
||
+# modify it under the terms of the GNU Lesser General Public
|
||
+# License as published by the Free Software Foundation; either
|
||
+# version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+# The GNU C Library is distributed in the hope that it will be useful,
|
||
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+# Lesser General Public License for more details.
|
||
+
|
||
+# You should have received a copy of the GNU Lesser General Public
|
||
+# License along with the GNU C Library; if not, see
|
||
+# <https://www.gnu.org/licenses/>.
|
||
+
|
||
+LC_ALL=C
|
||
+export LC_ALL
|
||
+set -e
|
||
+exec 2>&1
|
||
+
|
||
+program="$1"
|
||
+
|
||
+check_msg() {
|
||
+ if ! grep -q "$1" "$program.out"; then
|
||
+ echo "FAIL: expected message not in output: $1"
|
||
+ exit 1
|
||
+ fi
|
||
+}
|
||
+
|
||
+check_msg 'monstartup: maxarcs < minarcs, setting maxarcs = minarcs'
|
||
+check_msg 'mcount: call graph buffer size limit exceeded, gmon.out will not be generated'
|
||
+
|
||
+for data_file in $1.data.*; do
|
||
+ if [ -f "$data_file" ]; then
|
||
+ echo "FAIL: expected no data files, but found $data_file"
|
||
+ exit 1
|
||
+ fi
|
||
+done
|
||
+
|
||
+echo PASS
|
||
diff --git a/gmon/tst-mcount-overflow.c b/gmon/tst-mcount-overflow.c
|
||
new file mode 100644
|
||
index 0000000000..06cc93ef87
|
||
--- /dev/null
|
||
+++ b/gmon/tst-mcount-overflow.c
|
||
@@ -0,0 +1,72 @@
|
||
+/* Test program to trigger mcount overflow in profiling collection.
|
||
+ Copyright (C) 2017-2023 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+/* Program with sufficiently complex, yet pointless, call graph
|
||
+ that it will trigger an mcount overflow, when you set the
|
||
+ minarcs/maxarcs tunables to very low values. */
|
||
+
|
||
+#define PREVENT_TAIL_CALL asm volatile ("")
|
||
+
|
||
+/* Calls REP(n) macro 16 times, for n=0..15.
|
||
+ * You need to define REP(n) before using this.
|
||
+ */
|
||
+#define REPS \
|
||
+ REP(0) REP(1) REP(2) REP(3) REP(4) REP(5) REP(6) REP(7) \
|
||
+ REP(8) REP(9) REP(10) REP(11) REP(12) REP(13) REP(14) REP(15)
|
||
+
|
||
+/* Defines 16 leaf functions named f1_0 to f1_15 */
|
||
+#define REP(n) \
|
||
+ __attribute__ ((noinline, noclone, weak)) void f1_##n (void) {};
|
||
+REPS
|
||
+#undef REP
|
||
+
|
||
+/* Calls all 16 leaf functions f1_* in succession */
|
||
+__attribute__ ((noinline, noclone, weak)) void
|
||
+f2 (void)
|
||
+{
|
||
+# define REP(n) f1_##n();
|
||
+ REPS
|
||
+# undef REP
|
||
+ PREVENT_TAIL_CALL;
|
||
+}
|
||
+
|
||
+/* Defines 16 functions named f2_0 to f2_15, which all just call f2 */
|
||
+#define REP(n) \
|
||
+ __attribute__ ((noinline, noclone, weak)) void \
|
||
+ f2_##n (void) { f2(); PREVENT_TAIL_CALL; };
|
||
+REPS
|
||
+#undef REP
|
||
+
|
||
+__attribute__ ((noinline, noclone, weak)) void
|
||
+f3 (int count)
|
||
+{
|
||
+ for (int i = 0; i < count; ++i)
|
||
+ {
|
||
+ /* Calls f1_0(), f2_0(), f1_1(), f2_1(), f3_0(), etc */
|
||
+# define REP(n) f1_##n(); f2_##n();
|
||
+ REPS
|
||
+# undef REP
|
||
+ }
|
||
+}
|
||
+
|
||
+int
|
||
+main (void)
|
||
+{
|
||
+ f3 (1000);
|
||
+ return 0;
|
||
+}
|
||
diff --git a/gshadow/Makefile b/gshadow/Makefile
|
||
index eff303f538..5b3fa7e387 100644
|
||
--- a/gshadow/Makefile
|
||
+++ b/gshadow/Makefile
|
||
@@ -26,7 +26,7 @@ headers = gshadow.h
|
||
routines = getsgent getsgnam sgetsgent fgetsgent putsgent \
|
||
getsgent_r getsgnam_r sgetsgent_r fgetsgent_r
|
||
|
||
-tests = tst-gshadow tst-putsgent tst-fgetsgent_r
|
||
+tests = tst-gshadow tst-putsgent tst-fgetsgent_r tst-sgetsgent
|
||
|
||
CFLAGS-getsgent_r.c += -fexceptions
|
||
CFLAGS-getsgent.c += -fexceptions
|
||
diff --git a/gshadow/sgetsgent_r.c b/gshadow/sgetsgent_r.c
|
||
index 28c826c9b5..a767a643d4 100644
|
||
--- a/gshadow/sgetsgent_r.c
|
||
+++ b/gshadow/sgetsgent_r.c
|
||
@@ -61,7 +61,10 @@ __sgetsgent_r (const char *string, struct sgrp *resbuf, char *buffer,
|
||
buffer[buflen - 1] = '\0';
|
||
sp = strncpy (buffer, string, buflen);
|
||
if (buffer[buflen - 1] != '\0')
|
||
- return ERANGE;
|
||
+ {
|
||
+ __set_errno (ERANGE);
|
||
+ return ERANGE;
|
||
+ }
|
||
}
|
||
else
|
||
sp = (char *) string;
|
||
diff --git a/gshadow/tst-sgetsgent.c b/gshadow/tst-sgetsgent.c
|
||
new file mode 100644
|
||
index 0000000000..0370c10fd0
|
||
--- /dev/null
|
||
+++ b/gshadow/tst-sgetsgent.c
|
||
@@ -0,0 +1,69 @@
|
||
+/* Test large input for sgetsgent (bug 30151).
|
||
+ Copyright (C) 2023 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <gshadow.h>
|
||
+#include <stddef.h>
|
||
+#include <support/check.h>
|
||
+#include <support/support.h>
|
||
+#include <support/xmemstream.h>
|
||
+#include <stdlib.h>
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ /* Create a shadow group with 1000 members. */
|
||
+ struct xmemstream mem;
|
||
+ xopen_memstream (&mem);
|
||
+ const char *passwd = "k+zD0nucwfxAo3sw1NXUj6K5vt5M16+X0TVGdE1uFvq5R8V7efJ";
|
||
+ fprintf (mem.out, "group-name:%s::m0", passwd);
|
||
+ for (int i = 1; i < 1000; ++i)
|
||
+ fprintf (mem.out, ",m%d", i);
|
||
+ xfclose_memstream (&mem);
|
||
+
|
||
+ /* Call sgetsgent. */
|
||
+ char *input = mem.buffer;
|
||
+ struct sgrp *e = sgetsgent (input);
|
||
+ TEST_VERIFY_EXIT (e != NULL);
|
||
+ TEST_COMPARE_STRING (e->sg_namp, "group-name");
|
||
+ TEST_COMPARE_STRING (e->sg_passwd, passwd);
|
||
+ /* No administrators. */
|
||
+ TEST_COMPARE_STRING (e->sg_adm[0], NULL);
|
||
+ /* Check the members list. */
|
||
+ for (int i = 0; i < 1000; ++i)
|
||
+ {
|
||
+ char *member = xasprintf ("m%d", i);
|
||
+ TEST_COMPARE_STRING (e->sg_mem[i], member);
|
||
+ free (member);
|
||
+ }
|
||
+ TEST_COMPARE_STRING (e->sg_mem[1000], NULL);
|
||
+
|
||
+ /* Check that putsgent brings back the input string. */
|
||
+ xopen_memstream (&mem);
|
||
+ TEST_COMPARE (putsgent (e, mem.out), 0);
|
||
+ xfclose_memstream (&mem);
|
||
+ /* Compare without the trailing '\n' that putsgent added. */
|
||
+ TEST_COMPARE (mem.buffer[mem.length - 1], '\n');
|
||
+ mem.buffer[mem.length - 1] = '\0';
|
||
+ TEST_COMPARE_STRING (mem.buffer, input);
|
||
+
|
||
+ free (mem.buffer);
|
||
+ free (input);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
|
||
index debb96b322..b72933b526 100644
|
||
--- a/iconv/gconv_parseconfdir.h
|
||
+++ b/iconv/gconv_parseconfdir.h
|
||
@@ -29,14 +29,14 @@
|
||
# define isspace(__c) __isspace_l ((__c), _nl_C_locobj_ptr)
|
||
# define asprintf __asprintf
|
||
# define opendir __opendir
|
||
-# define readdir __readdir
|
||
+# define readdir64 __readdir64
|
||
# define closedir __closedir
|
||
# define mempcpy __mempcpy
|
||
-# define struct_stat struct __stat64_t64
|
||
-# define lstat __lstat64_time64
|
||
+# define struct_stat64 struct __stat64_t64
|
||
+# define lstat64 __lstat64_time64
|
||
# define feof_unlocked __feof_unlocked
|
||
#else
|
||
-# define struct_stat struct stat
|
||
+# define struct_stat64 struct stat64
|
||
#endif
|
||
|
||
/* Name of the file containing the module information in the directories
|
||
@@ -148,8 +148,8 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
|
||
DIR *confdir = opendir (buf);
|
||
if (confdir != NULL)
|
||
{
|
||
- struct dirent *ent;
|
||
- while ((ent = readdir (confdir)) != NULL)
|
||
+ struct dirent64 *ent;
|
||
+ while ((ent = readdir64 (confdir)) != NULL)
|
||
{
|
||
if (ent->d_type != DT_REG && ent->d_type != DT_UNKNOWN)
|
||
continue;
|
||
@@ -161,12 +161,12 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
|
||
&& strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
|
||
{
|
||
char *conf;
|
||
- struct_stat st;
|
||
+ struct_stat64 st;
|
||
if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
|
||
continue;
|
||
|
||
if (ent->d_type != DT_UNKNOWN
|
||
- || (lstat (conf, &st) != -1 && S_ISREG (st.st_mode)))
|
||
+ || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode)))
|
||
found |= read_conf_file (conf, dir, dir_len);
|
||
|
||
free (conf);
|
||
diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h
|
||
index 53f1dbc7c3..c27e7886b7 100644
|
||
--- a/include/arpa/nameser.h
|
||
+++ b/include/arpa/nameser.h
|
||
@@ -55,6 +55,12 @@ int __ns_name_ntop (const unsigned char *, char *, size_t) __THROW;
|
||
int __ns_name_unpack (const unsigned char *, const unsigned char *,
|
||
const unsigned char *, unsigned char *, size_t) __THROW;
|
||
|
||
+/* Like ns_samename, but for uncompressed binary names. Return true
|
||
+ if the two arguments compare are equal as case-insensitive domain
|
||
+ names. */
|
||
+_Bool __ns_samebinaryname (const unsigned char *, const unsigned char *)
|
||
+ attribute_hidden;
|
||
+
|
||
#define ns_msg_getflag(handle, flag) \
|
||
(((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift)
|
||
|
||
@@ -89,5 +95,105 @@ libc_hidden_proto (__ns_name_unpack)
|
||
extern __typeof (ns_samename) __libc_ns_samename;
|
||
libc_hidden_proto (__libc_ns_samename)
|
||
|
||
+/* Packet parser helper functions. */
|
||
+
|
||
+/* Verify that P points to an uncompressed domain name in wire format.
|
||
+ On success, return the length of the encoded name, including the
|
||
+ terminating null byte. On failure, return -1 and set errno. EOM
|
||
+ must point one past the last byte in the packet. */
|
||
+int __ns_name_length_uncompressed (const unsigned char *p,
|
||
+ const unsigned char *eom) attribute_hidden;
|
||
+
|
||
+/* Iterator over the resource records in a DNS packet. */
|
||
+struct ns_rr_cursor
|
||
+{
|
||
+ /* These members are not changed after initialization. */
|
||
+ const unsigned char *begin; /* First byte of packet. */
|
||
+ const unsigned char *end; /* One past the last byte of the packet. */
|
||
+ const unsigned char *first_rr; /* First resource record (or packet end). */
|
||
+
|
||
+ /* Advanced towards the end while reading the packet. */
|
||
+ const unsigned char *current;
|
||
+};
|
||
+
|
||
+/* Returns the RCODE field from the DNS header. */
|
||
+static inline int
|
||
+ns_rr_cursor_rcode (const struct ns_rr_cursor *c)
|
||
+{
|
||
+ return c->begin[3] & 0x0f; /* Lower 4 bits at offset 3. */
|
||
+}
|
||
+
|
||
+/* Returns the length of the answer section according to the DNS header. */
|
||
+static inline int
|
||
+ns_rr_cursor_ancount (const struct ns_rr_cursor *c)
|
||
+{
|
||
+ return c->begin[6] * 256 + c->begin[7]; /* 16 bits at offset 6. */
|
||
+}
|
||
+
|
||
+/* Returns the length of the authority (name server) section according
|
||
+ to the DNS header. */
|
||
+static inline int
|
||
+ns_rr_cursor_nscount (const struct ns_rr_cursor *c)
|
||
+{
|
||
+ return c->begin[8] * 256 + c->begin[9]; /* 16 bits at offset 8. */
|
||
+}
|
||
+
|
||
+/* Returns the length of the additional data section according to the
|
||
+ DNS header. */
|
||
+static inline int
|
||
+ns_rr_cursor_adcount (const struct ns_rr_cursor *c)
|
||
+{
|
||
+ return c->begin[10] * 256 + c->begin[11]; /* 16 bits at offset 10. */
|
||
+}
|
||
+
|
||
+/* Returns a pointer to the uncompressed question name in wire
|
||
+ format. */
|
||
+static inline const unsigned char *
|
||
+ns_rr_cursor_qname (const struct ns_rr_cursor *c)
|
||
+{
|
||
+ return c->begin + 12; /* QNAME starts right after the header. */
|
||
+}
|
||
+
|
||
+/* Returns the question type of the first and only question. */
|
||
+static inline const int
|
||
+ns_rr_cursor_qtype (const struct ns_rr_cursor *c)
|
||
+{
|
||
+ /* 16 bits 4 bytes back from the first RR header start. */
|
||
+ return c->first_rr[-4] * 256 + c->first_rr[-3];
|
||
+}
|
||
+
|
||
+/* Returns the clss of the first and only question (usally C_IN). */
|
||
+static inline const int
|
||
+ns_rr_cursor_qclass (const struct ns_rr_cursor *c)
|
||
+{
|
||
+ /* 16 bits 2 bytes back from the first RR header start. */
|
||
+ return c->first_rr[-2] * 256 + c->first_rr[-1];
|
||
+}
|
||
+
|
||
+/* Initializes *C to cover the packet [BUF, BUF+LEN). Returns false
|
||
+ if LEN is less than sizeof (*HD), if the packet does not contain a
|
||
+ full (uncompressed) question, or if the question count is not 1. */
|
||
+_Bool __ns_rr_cursor_init (struct ns_rr_cursor *c,
|
||
+ const unsigned char *buf, size_t len)
|
||
+ attribute_hidden;
|
||
+
|
||
+/* Like ns_rr, but the record owner name is not decoded into text format. */
|
||
+struct ns_rr_wire
|
||
+{
|
||
+ unsigned char rname[NS_MAXCDNAME]; /* Owner name of the record. */
|
||
+ uint16_t rtype; /* Resource record type (T_*). */
|
||
+ uint16_t rclass; /* Resource record class (C_*). */
|
||
+ uint32_t ttl; /* Time-to-live field. */
|
||
+ const unsigned char *rdata; /* Start of resource record data. */
|
||
+ uint16_t rdlength; /* Length of the data at rdata, in bytes. */
|
||
+};
|
||
+
|
||
+/* Attempts to parse the record at C into *RR. On success, return
|
||
+ true, and C is advanced past the record, and RR->rdata points to
|
||
+ the record data. On failure, errno is set to EMSGSIZE, and false
|
||
+ is returned. */
|
||
+_Bool __ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr)
|
||
+ attribute_hidden;
|
||
+
|
||
# endif /* !_ISOMAC */
|
||
#endif
|
||
diff --git a/include/bits/wchar2-decl.h b/include/bits/wchar2-decl.h
|
||
new file mode 100644
|
||
index 0000000000..00b1b93342
|
||
--- /dev/null
|
||
+++ b/include/bits/wchar2-decl.h
|
||
@@ -0,0 +1 @@
|
||
+#include <wcsmbs/bits/wchar2-decl.h>
|
||
diff --git a/include/resolv.h b/include/resolv.h
|
||
index 3590b6f496..4dbbac3800 100644
|
||
--- a/include/resolv.h
|
||
+++ b/include/resolv.h
|
||
@@ -70,5 +70,8 @@ libc_hidden_proto (__libc_res_nameinquery)
|
||
extern __typeof (__res_queriesmatch) __libc_res_queriesmatch;
|
||
libc_hidden_proto (__libc_res_queriesmatch)
|
||
|
||
+/* Variant of res_hnok which operates on binary (but uncompressed) names. */
|
||
+bool __res_binary_hnok (const unsigned char *dn) attribute_hidden;
|
||
+
|
||
# endif /* _RESOLV_H_ && !_ISOMAC */
|
||
#endif
|
||
diff --git a/io/Makefile b/io/Makefile
|
||
index b1710407d0..fb363c612c 100644
|
||
--- a/io/Makefile
|
||
+++ b/io/Makefile
|
||
@@ -80,7 +80,8 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \
|
||
tst-utimensat \
|
||
tst-closefrom \
|
||
tst-close_range \
|
||
- tst-ftw-bz28126
|
||
+ tst-ftw-bz28126 \
|
||
+ tst-fcntl-lock
|
||
|
||
tests-time64 := \
|
||
tst-fcntl-time64 \
|
||
diff --git a/io/tst-fcntl-lock.c b/io/tst-fcntl-lock.c
|
||
new file mode 100644
|
||
index 0000000000..357c4b7b56
|
||
--- /dev/null
|
||
+++ b/io/tst-fcntl-lock.c
|
||
@@ -0,0 +1,97 @@
|
||
+/* Test for advisory record locking.
|
||
+ Copyright (C) 2023 Free Software Foundation, Inc.
|
||
+
|
||
+ This program is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU General Public License
|
||
+ as published by the Free Software Foundation; either version 2
|
||
+ of the License, or (at your option) any later version.
|
||
+
|
||
+ This program is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ GNU General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU General Public License
|
||
+ along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||
+*/
|
||
+
|
||
+#include <fcntl.h>
|
||
+#include <errno.h>
|
||
+#include <unistd.h>
|
||
+
|
||
+/* This is essentially the POSIX lockf. */
|
||
+
|
||
+static int
|
||
+fcntl_lockf (int fd, int cmd, off_t len)
|
||
+{
|
||
+ struct flock fl = {
|
||
+ .l_type = F_WRLCK,
|
||
+ .l_whence = SEEK_CUR,
|
||
+ .l_len = len
|
||
+ };
|
||
+
|
||
+ switch (cmd)
|
||
+ {
|
||
+ case F_TEST:
|
||
+ fl.l_type = F_RDLCK;
|
||
+ if (fcntl (fd, F_GETLK, &fl) < 0)
|
||
+ return -1;
|
||
+ if (fl.l_type == F_UNLCK || fl.l_pid == getpid ())
|
||
+ return 0;
|
||
+ errno = EACCES;
|
||
+ return -1;
|
||
+
|
||
+ case F_ULOCK:
|
||
+ fl.l_type = F_UNLCK;
|
||
+ return fcntl (fd, F_SETLK, &fl);
|
||
+
|
||
+ case F_LOCK:
|
||
+ return fcntl (fd, F_SETLKW, &fl);
|
||
+
|
||
+ case F_TLOCK:
|
||
+ return fcntl (fd, F_SETLK, &fl);
|
||
+ }
|
||
+
|
||
+ errno = EINVAL;
|
||
+ return -1;
|
||
+}
|
||
+
|
||
+static int
|
||
+fcntl64_lockf (int fd, int cmd, off64_t len64)
|
||
+ {
|
||
+ struct flock64 fl64 = {
|
||
+ .l_type = F_WRLCK,
|
||
+ .l_whence = SEEK_CUR,
|
||
+ .l_len = len64
|
||
+ };
|
||
+
|
||
+ switch (cmd)
|
||
+ {
|
||
+ case F_TEST:
|
||
+ fl64.l_type = F_RDLCK;
|
||
+ if (fcntl64 (fd, F_GETLK64, &fl64) < 0)
|
||
+ return -1;
|
||
+ if (fl64.l_type == F_UNLCK || fl64.l_pid == getpid ())
|
||
+ return 0;
|
||
+ errno = EACCES;
|
||
+ return -1;
|
||
+
|
||
+ case F_ULOCK:
|
||
+ fl64.l_type = F_UNLCK;
|
||
+ return fcntl64 (fd, F_SETLK64, &fl64);
|
||
+
|
||
+ case F_LOCK:
|
||
+ return fcntl64 (fd, F_SETLKW64, &fl64);
|
||
+
|
||
+ case F_TLOCK:
|
||
+ return fcntl64 (fd, F_SETLK64, &fl64);
|
||
+ }
|
||
+
|
||
+ errno = EINVAL;
|
||
+ return -1;
|
||
+}
|
||
+
|
||
+#define TST_LOCKFD "tst-fcntl-lock."
|
||
+#define LOCKF fcntl_lockf
|
||
+#define LOCKF64 fcntl64_lockf
|
||
+#include "tst-lockf.c"
|
||
diff --git a/io/tst-lockf.c b/io/tst-lockf.c
|
||
index be92f33fd1..5e41dc19df 100644
|
||
--- a/io/tst-lockf.c
|
||
+++ b/io/tst-lockf.c
|
||
@@ -24,13 +24,23 @@
|
||
#include <support/capture_subprocess.h>
|
||
#include <support/check.h>
|
||
|
||
+#ifndef TST_LOCKFD
|
||
+# define TST_LOCKFD "tst-lockfd."
|
||
+#endif
|
||
+#ifndef LOCKF
|
||
+# define LOCKF lockf
|
||
+#endif
|
||
+#ifndef LOCKF64
|
||
+# define LOCKF64 lockf64
|
||
+#endif
|
||
+
|
||
static char *temp_filename;
|
||
static int temp_fd;
|
||
|
||
static void
|
||
do_prepare (int argc, char **argv)
|
||
{
|
||
- temp_fd = create_temp_file ("tst-lockfd.", &temp_filename);
|
||
+ temp_fd = create_temp_file (TST_LOCKFD, &temp_filename);
|
||
TEST_VERIFY_EXIT (temp_fd != -1);
|
||
}
|
||
#define PREPARE do_prepare
|
||
@@ -40,22 +50,22 @@ do_test_child_lockf (void *closure)
|
||
{
|
||
/* Check if parent has [0, 1024) locked. */
|
||
TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0);
|
||
- TEST_COMPARE (lockf (temp_fd, F_TLOCK, 1024), -1);
|
||
+ TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), -1);
|
||
TEST_COMPARE (errno, EAGAIN);
|
||
- TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), -1);
|
||
+ TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1);
|
||
TEST_COMPARE (errno, EACCES);
|
||
/* Also Check if parent has last 1024 bytes locked. */
|
||
TEST_COMPARE (lseek (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024);
|
||
- TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), -1);
|
||
+ TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1);
|
||
|
||
/* And try to lock [1024, 2048). */
|
||
TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024);
|
||
- TEST_COMPARE (lockf (temp_fd, F_LOCK, 1024), 0);
|
||
+ TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0);
|
||
|
||
/* Check if non-LFS interface cap access to 32-bif off_t. */
|
||
TEST_COMPARE (lseek64 (temp_fd, (off64_t)INT32_MAX, SEEK_SET),
|
||
(off64_t)INT32_MAX);
|
||
- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), 0);
|
||
+ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0);
|
||
}
|
||
|
||
static void
|
||
@@ -63,32 +73,32 @@ do_test_child_lockf64 (void *closure)
|
||
{
|
||
/* Check if parent has [0, 1024) locked. */
|
||
TEST_COMPARE (lseek64 (temp_fd, 0, SEEK_SET), 0);
|
||
- TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), -1);
|
||
+ TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1);
|
||
TEST_COMPARE (errno, EAGAIN);
|
||
- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1);
|
||
+ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1);
|
||
TEST_COMPARE (errno, EACCES);
|
||
/* Also Check if parent has last 1024 bytes locked. */
|
||
TEST_COMPARE (lseek64 (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024);
|
||
- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1);
|
||
+ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1);
|
||
|
||
/* And try to lock [1024, 2048). */
|
||
TEST_COMPARE (lseek64 (temp_fd, 1024, SEEK_SET), 1024);
|
||
- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0);
|
||
+ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0);
|
||
|
||
/* And also [INT32_MAX, INT32_MAX+1024). */
|
||
{
|
||
off64_t off = (off64_t)INT32_MAX;
|
||
TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off);
|
||
- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0);
|
||
+ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0);
|
||
}
|
||
|
||
/* Check if [INT32_MAX+1024, INT64_MAX) is locked. */
|
||
{
|
||
off64_t off = (off64_t)INT32_MAX+1024;
|
||
TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off);
|
||
- TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), -1);
|
||
+ TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1);
|
||
TEST_COMPARE (errno, EAGAIN);
|
||
- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1);
|
||
+ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1);
|
||
TEST_COMPARE (errno, EACCES);
|
||
}
|
||
}
|
||
@@ -97,38 +107,38 @@ static int
|
||
do_test (void)
|
||
{
|
||
/* Basic tests to check if a lock can be obtained and checked. */
|
||
- TEST_COMPARE (lockf (temp_fd, F_LOCK, 1024), 0);
|
||
- TEST_COMPARE (lockf (temp_fd, F_LOCK, INT32_MAX), 0);
|
||
- TEST_COMPARE (lockf (temp_fd, F_TLOCK, 1024), 0);
|
||
- TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), 0);
|
||
+ TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0);
|
||
+ TEST_COMPARE (LOCKF (temp_fd, F_LOCK, INT32_MAX), 0);
|
||
+ TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), 0);
|
||
+ TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), 0);
|
||
TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024);
|
||
- TEST_COMPARE (lockf (temp_fd, F_ULOCK, 1024), 0);
|
||
+ TEST_COMPARE (LOCKF (temp_fd, F_ULOCK, 1024), 0);
|
||
/* Parent process should have ([0, 1024), [2048, INT32_MAX)) ranges locked. */
|
||
|
||
{
|
||
struct support_capture_subprocess result;
|
||
result = support_capture_subprocess (do_test_child_lockf, NULL);
|
||
- support_capture_subprocess_check (&result, "lockf", 0, sc_allow_none);
|
||
+ support_capture_subprocess_check (&result, "LOCKF", 0, sc_allow_none);
|
||
}
|
||
|
||
if (sizeof (off_t) != sizeof (off64_t))
|
||
{
|
||
/* Check if previously locked regions with LFS symbol. */
|
||
TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0);
|
||
- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0);
|
||
- TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), 0);
|
||
- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), 0);
|
||
+ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0);
|
||
+ TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), 0);
|
||
+ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0);
|
||
/* Lock region [INT32_MAX+1024, INT64_MAX). */
|
||
off64_t off = (off64_t)INT32_MAX + 1024;
|
||
TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off);
|
||
- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0);
|
||
+ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0);
|
||
/* Parent process should have ([0, 1024), [2048, INT32_MAX),
|
||
[INT32_MAX+1024, INT64_MAX)) ranges locked. */
|
||
|
||
{
|
||
struct support_capture_subprocess result;
|
||
result = support_capture_subprocess (do_test_child_lockf64, NULL);
|
||
- support_capture_subprocess_check (&result, "lockf", 0, sc_allow_none);
|
||
+ support_capture_subprocess_check (&result, "LOCKF", 0, sc_allow_none);
|
||
}
|
||
}
|
||
|
||
diff --git a/locale/weight.h b/locale/weight.h
|
||
index 8be2d220f8..4a4d5aa6b2 100644
|
||
--- a/locale/weight.h
|
||
+++ b/locale/weight.h
|
||
@@ -27,7 +27,14 @@ findidx (const int32_t *table,
|
||
const unsigned char *extra,
|
||
const unsigned char **cpp, size_t len)
|
||
{
|
||
+ /* With GCC 8 when compiling with -Os the compiler warns that
|
||
+ seq1.back_us and seq2.back_us might be used uninitialized.
|
||
+ This uninitialized use is impossible for the same reason
|
||
+ as described in comments in locale/weightwc.h. */
|
||
+ DIAG_PUSH_NEEDS_COMMENT;
|
||
+ DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized");
|
||
int32_t i = table[*(*cpp)++];
|
||
+ DIAG_POP_NEEDS_COMMENT;
|
||
const unsigned char *cp;
|
||
const unsigned char *usrc;
|
||
|
||
diff --git a/misc/bits/syslog.h b/misc/bits/syslog.h
|
||
index fd30dd3114..916d2b6f12 100644
|
||
--- a/misc/bits/syslog.h
|
||
+++ b/misc/bits/syslog.h
|
||
@@ -24,6 +24,20 @@
|
||
extern void __syslog_chk (int __pri, int __flag, const char *__fmt, ...)
|
||
__attribute__ ((__format__ (__printf__, 3, 4)));
|
||
|
||
+#ifdef __USE_MISC
|
||
+extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt,
|
||
+ __gnuc_va_list __ap)
|
||
+ __attribute__ ((__format__ (__printf__, 3, 0)));
|
||
+#endif
|
||
+
|
||
+#include <bits/floatn.h>
|
||
+#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
|
||
+# include <bits/syslog-ldbl.h>
|
||
+#endif
|
||
+
|
||
+/* The following functions must be used only after applying all asm
|
||
+ redirections, e.g. long double asm redirections. */
|
||
+
|
||
#ifdef __va_arg_pack
|
||
__fortify_function void
|
||
syslog (int __pri, const char *__fmt, ...)
|
||
@@ -37,10 +51,6 @@ syslog (int __pri, const char *__fmt, ...)
|
||
|
||
|
||
#ifdef __USE_MISC
|
||
-extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt,
|
||
- __gnuc_va_list __ap)
|
||
- __attribute__ ((__format__ (__printf__, 3, 0)));
|
||
-
|
||
__fortify_function void
|
||
vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap)
|
||
{
|
||
diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
|
||
index f525f67547..294e633335 100644
|
||
--- a/misc/sys/cdefs.h
|
||
+++ b/misc/sys/cdefs.h
|
||
@@ -152,6 +152,7 @@
|
||
# define __glibc_objsize(__o) __bos (__o)
|
||
#endif
|
||
|
||
+#if __USE_FORTIFY_LEVEL > 0
|
||
/* Compile time conditions to choose between the regular, _chk and _chk_warn
|
||
variants. These conditions should get evaluated to constant and optimized
|
||
away. */
|
||
@@ -187,7 +188,7 @@
|
||
? __ ## f ## _alias (__VA_ARGS__) \
|
||
: (__glibc_unsafe_len (__l, __s, __osz) \
|
||
? __ ## f ## _chk_warn (__VA_ARGS__, __osz) \
|
||
- : __ ## f ## _chk (__VA_ARGS__, __osz))) \
|
||
+ : __ ## f ## _chk (__VA_ARGS__, __osz)))
|
||
|
||
/* Fortify function f, where object size argument passed to f is the number of
|
||
elements and not total size. */
|
||
@@ -197,7 +198,8 @@
|
||
? __ ## f ## _alias (__VA_ARGS__) \
|
||
: (__glibc_unsafe_len (__l, __s, __osz) \
|
||
? __ ## f ## _chk_warn (__VA_ARGS__, (__osz) / (__s)) \
|
||
- : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) \
|
||
+ : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s))))
|
||
+#endif
|
||
|
||
#if __GNUC_PREREQ (4,3)
|
||
# define __warnattr(msg) __attribute__((__warning__ (msg)))
|
||
diff --git a/misc/sys/syslog.h b/misc/sys/syslog.h
|
||
index d933fea104..3888153ed2 100644
|
||
--- a/misc/sys/syslog.h
|
||
+++ b/misc/sys/syslog.h
|
||
@@ -205,11 +205,11 @@ extern void vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap)
|
||
/* Define some macros helping to catch buffer overflows. */
|
||
#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
|
||
# include <bits/syslog.h>
|
||
-#endif
|
||
-
|
||
-#include <bits/floatn.h>
|
||
-#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
|
||
-# include <bits/syslog-ldbl.h>
|
||
+#else
|
||
+# include <bits/floatn.h>
|
||
+# if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
|
||
+# include <bits/syslog-ldbl.h>
|
||
+# endif
|
||
#endif
|
||
|
||
__END_DECLS
|
||
diff --git a/misc/syslog.c b/misc/syslog.c
|
||
index 554089bfc4..f67d4b58a4 100644
|
||
--- a/misc/syslog.c
|
||
+++ b/misc/syslog.c
|
||
@@ -167,7 +167,7 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
|
||
_nl_C_locobj_ptr);
|
||
|
||
#define SYSLOG_HEADER(__pri, __timestamp, __msgoff, pid) \
|
||
- "<%d>%s %n%s%s%.0d%s: ", \
|
||
+ "<%d>%s%n%s%s%.0d%s: ", \
|
||
__pri, __timestamp, __msgoff, \
|
||
LogTag == NULL ? __progname : LogTag, \
|
||
"[" + (pid == 0), pid, "]" + (pid == 0)
|
||
@@ -193,28 +193,32 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
|
||
int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc,
|
||
mode_flags);
|
||
if (0 <= vl && vl < sizeof bufs - l)
|
||
- {
|
||
- buf = bufs;
|
||
- bufsize = l + vl;
|
||
- }
|
||
+ buf = bufs;
|
||
+ bufsize = l + vl;
|
||
|
||
va_end (apc);
|
||
}
|
||
|
||
if (buf == NULL)
|
||
{
|
||
- buf = malloc (l * sizeof (char));
|
||
+ buf = malloc ((bufsize + 1) * sizeof (char));
|
||
if (buf != NULL)
|
||
{
|
||
/* Tell the cancellation handler to free this buffer. */
|
||
clarg.buf = buf;
|
||
|
||
if (has_ts)
|
||
- __snprintf (bufs, sizeof bufs,
|
||
+ __snprintf (buf, l + 1,
|
||
SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
|
||
else
|
||
- __snprintf (bufs, sizeof bufs,
|
||
+ __snprintf (buf, l + 1,
|
||
SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
|
||
+
|
||
+ va_list apc;
|
||
+ va_copy (apc, ap);
|
||
+ __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc,
|
||
+ mode_flags);
|
||
+ va_end (apc);
|
||
}
|
||
else
|
||
{
|
||
diff --git a/misc/tst-syslog.c b/misc/tst-syslog.c
|
||
index e550d15796..3560b518a2 100644
|
||
--- a/misc/tst-syslog.c
|
||
+++ b/misc/tst-syslog.c
|
||
@@ -68,21 +68,19 @@ static const int priorities[] =
|
||
LOG_DEBUG
|
||
};
|
||
|
||
-enum
|
||
- {
|
||
- ident_length = 64,
|
||
- msg_length = 64
|
||
- };
|
||
+#define IDENT_LENGTH 64
|
||
+#define MSG_LENGTH 1024
|
||
|
||
#define SYSLOG_MSG_BASE "syslog_message"
|
||
#define OPENLOG_IDENT "openlog_ident"
|
||
+static char large_message[MSG_LENGTH];
|
||
|
||
struct msg_t
|
||
{
|
||
int priority;
|
||
int facility;
|
||
- char ident[ident_length];
|
||
- char msg[msg_length];
|
||
+ char ident[IDENT_LENGTH];
|
||
+ char msg[MSG_LENGTH];
|
||
pid_t pid;
|
||
};
|
||
|
||
@@ -147,6 +145,37 @@ check_syslog_message (const struct msg_t *msg, int msgnum, int options,
|
||
return true;
|
||
}
|
||
|
||
+static void
|
||
+send_syslog_large (int options)
|
||
+{
|
||
+ int facility = LOG_USER;
|
||
+ int priority = LOG_INFO;
|
||
+
|
||
+ syslog (facility | priority, "%s %d %d", large_message, facility,
|
||
+ priority);
|
||
+}
|
||
+
|
||
+static void
|
||
+send_vsyslog_large (int options)
|
||
+{
|
||
+ int facility = LOG_USER;
|
||
+ int priority = LOG_INFO;
|
||
+
|
||
+ call_vsyslog (facility | priority, "%s %d %d", large_message, facility,
|
||
+ priority);
|
||
+}
|
||
+
|
||
+static bool
|
||
+check_syslog_message_large (const struct msg_t *msg, int msgnum, int options,
|
||
+ pid_t pid)
|
||
+{
|
||
+ TEST_COMPARE (msg->facility, LOG_USER);
|
||
+ TEST_COMPARE (msg->priority, LOG_INFO);
|
||
+ TEST_COMPARE_STRING (msg->msg, large_message);
|
||
+
|
||
+ return false;
|
||
+}
|
||
+
|
||
static void
|
||
send_openlog (int options)
|
||
{
|
||
@@ -179,6 +208,17 @@ send_openlog (int options)
|
||
closelog ();
|
||
}
|
||
|
||
+static void
|
||
+send_openlog_large (int options)
|
||
+{
|
||
+ /* Define a non-default IDENT and a not default facility. */
|
||
+ openlog (OPENLOG_IDENT, options, LOG_LOCAL0);
|
||
+
|
||
+ syslog (LOG_INFO, "%s %d %d", large_message, LOG_LOCAL0, LOG_INFO);
|
||
+
|
||
+ closelog ();
|
||
+}
|
||
+
|
||
static bool
|
||
check_openlog_message (const struct msg_t *msg, int msgnum,
|
||
int options, pid_t pid)
|
||
@@ -189,7 +229,7 @@ check_openlog_message (const struct msg_t *msg, int msgnum,
|
||
int expected_priority = priorities[msgnum % array_length (priorities)];
|
||
TEST_COMPARE (msg->priority, expected_priority);
|
||
|
||
- char expected_ident[ident_length];
|
||
+ char expected_ident[IDENT_LENGTH];
|
||
snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:",
|
||
OPENLOG_IDENT,
|
||
options & LOG_PID ? "[" : "",
|
||
@@ -211,17 +251,43 @@ check_openlog_message (const struct msg_t *msg, int msgnum,
|
||
return true;
|
||
}
|
||
|
||
+static bool
|
||
+check_openlog_message_large (const struct msg_t *msg, int msgnum,
|
||
+ int options, pid_t pid)
|
||
+{
|
||
+ char expected_ident[IDENT_LENGTH];
|
||
+ snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:",
|
||
+ OPENLOG_IDENT,
|
||
+ options & LOG_PID ? "[" : "",
|
||
+ options & LOG_PID ? pid : 0,
|
||
+ options & LOG_PID ? "]" : "");
|
||
+
|
||
+ TEST_COMPARE_STRING (msg->ident, expected_ident);
|
||
+ TEST_COMPARE_STRING (msg->msg, large_message);
|
||
+ TEST_COMPARE (msg->priority, LOG_INFO);
|
||
+ TEST_COMPARE (msg->facility, LOG_LOCAL0);
|
||
+
|
||
+ return false;
|
||
+}
|
||
+
|
||
static struct msg_t
|
||
parse_syslog_msg (const char *msg)
|
||
{
|
||
struct msg_t r = { .pid = -1 };
|
||
int number;
|
||
+ int wsb, wsa;
|
||
+
|
||
+#define STRINPUT(size) XSTRINPUT(size)
|
||
+#define XSTRINPUT(size) "%" # size "s"
|
||
|
||
/* The message in the form:
|
||
- <179>Apr 8 14:51:19 tst-syslog: syslog message 176 3 */
|
||
- int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d %32s %64s %*d %*d",
|
||
- &number, r.ident, r.msg);
|
||
+ <179>Apr 8 14:51:19 tst-syslog: message 176 3 */
|
||
+ int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d%n %n" STRINPUT(IDENT_LENGTH)
|
||
+ " " STRINPUT(MSG_LENGTH) " %*d %*d",
|
||
+ &number, &wsb, &wsa, r.ident, r.msg);
|
||
TEST_COMPARE (n, 3);
|
||
+ /* It should only one space between timestamp and message. */
|
||
+ TEST_COMPARE (wsa - wsb, 1);
|
||
|
||
r.facility = number & LOG_FACMASK;
|
||
r.priority = number & LOG_PRIMASK;
|
||
@@ -246,7 +312,7 @@ parse_syslog_console (const char *msg)
|
||
|
||
/* The message in the form:
|
||
openlog_ident: syslog_message 128 0 */
|
||
- int n = sscanf (msg, "%32s %64s %d %d",
|
||
+ int n = sscanf (msg, STRINPUT(IDENT_LENGTH) " " STRINPUT(MSG_LENGTH) " %d %d",
|
||
r.ident, r.msg, &facility, &priority);
|
||
TEST_COMPARE (n, 4);
|
||
|
||
@@ -281,7 +347,7 @@ check_syslog_udp (void (*syslog_send)(int), int options,
|
||
int msgnum = 0;
|
||
while (1)
|
||
{
|
||
- char buf[512];
|
||
+ char buf[2048];
|
||
size_t l = xrecvfrom (server_udp, buf, sizeof (buf), 0,
|
||
(struct sockaddr *) &addr, &addrlen);
|
||
buf[l] = '\0';
|
||
@@ -325,7 +391,7 @@ check_syslog_tcp (void (*syslog_send)(int), int options,
|
||
|
||
int client_tcp = xaccept (server_tcp, NULL, NULL);
|
||
|
||
- char buf[512], *rb = buf;
|
||
+ char buf[2048], *rb = buf;
|
||
size_t rbl = sizeof (buf);
|
||
size_t prl = 0; /* Track the size of the partial record. */
|
||
int msgnum = 0;
|
||
@@ -393,20 +459,34 @@ check_syslog_console_read (FILE *fp)
|
||
}
|
||
|
||
static void
|
||
-check_syslog_console (void)
|
||
+check_syslog_console_read_large (FILE *fp)
|
||
+{
|
||
+ char buf[2048];
|
||
+ TEST_VERIFY (fgets (buf, sizeof (buf), fp) != NULL);
|
||
+ struct msg_t msg = parse_syslog_console (buf);
|
||
+
|
||
+ TEST_COMPARE_STRING (msg.ident, OPENLOG_IDENT ":");
|
||
+ TEST_COMPARE_STRING (msg.msg, large_message);
|
||
+ TEST_COMPARE (msg.priority, LOG_INFO);
|
||
+ TEST_COMPARE (msg.facility, LOG_LOCAL0);
|
||
+}
|
||
+
|
||
+static void
|
||
+check_syslog_console (void (*syslog_send)(int),
|
||
+ void (*syslog_check)(FILE *fp))
|
||
{
|
||
xmkfifo (_PATH_CONSOLE, 0666);
|
||
|
||
pid_t sender_pid = xfork ();
|
||
if (sender_pid == 0)
|
||
{
|
||
- send_openlog (LOG_CONS);
|
||
+ syslog_send (LOG_CONS);
|
||
_exit (0);
|
||
}
|
||
|
||
{
|
||
FILE *fp = xfopen (_PATH_CONSOLE, "r+");
|
||
- check_syslog_console_read (fp);
|
||
+ syslog_check (fp);
|
||
xfclose (fp);
|
||
}
|
||
|
||
@@ -425,16 +505,28 @@ send_openlog_callback (void *clousure)
|
||
}
|
||
|
||
static void
|
||
-check_syslog_perror (void)
|
||
+send_openlog_callback_large (void *clousure)
|
||
+{
|
||
+ int options = *(int *) clousure;
|
||
+ send_openlog_large (options);
|
||
+}
|
||
+
|
||
+static void
|
||
+check_syslog_perror (bool large)
|
||
{
|
||
struct support_capture_subprocess result;
|
||
- result = support_capture_subprocess (send_openlog_callback,
|
||
+ result = support_capture_subprocess (large
|
||
+ ? send_openlog_callback_large
|
||
+ : send_openlog_callback,
|
||
&(int){LOG_PERROR});
|
||
|
||
FILE *mfp = fmemopen (result.err.buffer, result.err.length, "r");
|
||
if (mfp == NULL)
|
||
FAIL_EXIT1 ("fmemopen: %m");
|
||
- check_syslog_console_read (mfp);
|
||
+ if (large)
|
||
+ check_syslog_console_read_large (mfp);
|
||
+ else
|
||
+ check_syslog_console_read (mfp);
|
||
xfclose (mfp);
|
||
|
||
support_capture_subprocess_check (&result, "tst-openlog-child", 0,
|
||
@@ -462,10 +554,31 @@ do_test (void)
|
||
check_syslog_tcp (send_openlog, LOG_PID, check_openlog_message);
|
||
|
||
/* Check the LOG_CONS option. */
|
||
- check_syslog_console ();
|
||
+ check_syslog_console (send_openlog, check_syslog_console_read);
|
||
|
||
/* Check the LOG_PERROR option. */
|
||
- check_syslog_perror ();
|
||
+ check_syslog_perror (false);
|
||
+
|
||
+ /* Similar tests as before, but with a large message to trigger the
|
||
+ syslog path that uses dynamically allocated memory. */
|
||
+ memset (large_message, 'a', sizeof large_message - 1);
|
||
+ large_message[sizeof large_message - 1] = '\0';
|
||
+
|
||
+ check_syslog_udp (send_syslog_large, 0, check_syslog_message_large);
|
||
+ check_syslog_tcp (send_syslog_large, 0, check_syslog_message_large);
|
||
+
|
||
+ check_syslog_udp (send_vsyslog_large, 0, check_syslog_message_large);
|
||
+ check_syslog_tcp (send_vsyslog_large, 0, check_syslog_message_large);
|
||
+
|
||
+ check_syslog_udp (send_openlog_large, 0, check_openlog_message_large);
|
||
+ check_syslog_tcp (send_openlog_large, 0, check_openlog_message_large);
|
||
+
|
||
+ check_syslog_udp (send_openlog_large, LOG_PID, check_openlog_message_large);
|
||
+ check_syslog_tcp (send_openlog_large, LOG_PID, check_openlog_message_large);
|
||
+
|
||
+ check_syslog_console (send_openlog_large, check_syslog_console_read_large);
|
||
+
|
||
+ check_syslog_perror (true);
|
||
|
||
return 0;
|
||
}
|
||
diff --git a/nis/nis_call.c b/nis/nis_call.c
|
||
index 90187e30b1..5b9dd50151 100644
|
||
--- a/nis/nis_call.c
|
||
+++ b/nis/nis_call.c
|
||
@@ -574,7 +574,7 @@ static struct nis_server_cache
|
||
unsigned int size;
|
||
unsigned int server_used;
|
||
unsigned int current_ep;
|
||
- __time64_t expires;
|
||
+ time_t expires;
|
||
char name[];
|
||
} *nis_server_cache[16];
|
||
static time_t nis_cold_start_mtime;
|
||
@@ -583,7 +583,7 @@ __libc_lock_define_initialized (static, nis_server_cache_lock)
|
||
static directory_obj *
|
||
nis_server_cache_search (const_nis_name name, int search_parent,
|
||
unsigned int *server_used, unsigned int *current_ep,
|
||
- struct __timespec64 *now)
|
||
+ struct timespec *now)
|
||
{
|
||
directory_obj *ret = NULL;
|
||
int i;
|
||
@@ -641,7 +641,7 @@ nis_server_cache_search (const_nis_name name, int search_parent,
|
||
static void
|
||
nis_server_cache_add (const_nis_name name, int search_parent,
|
||
directory_obj *dir, unsigned int server_used,
|
||
- unsigned int current_ep, struct __timespec64 *now)
|
||
+ unsigned int current_ep, struct timespec *now)
|
||
{
|
||
struct nis_server_cache **loc;
|
||
struct nis_server_cache *new;
|
||
@@ -707,7 +707,7 @@ __nisfind_server (const_nis_name name, int search_parent,
|
||
nis_error result = NIS_SUCCESS;
|
||
nis_error status;
|
||
directory_obj *obj;
|
||
- struct __timespec64 ts;
|
||
+ struct timespec ts;
|
||
unsigned int server_used = ~0;
|
||
unsigned int current_ep = ~0;
|
||
|
||
@@ -717,7 +717,7 @@ __nisfind_server (const_nis_name name, int search_parent,
|
||
if (*dir != NULL)
|
||
return NIS_SUCCESS;
|
||
|
||
- __clock_gettime64 (CLOCK_REALTIME, &ts);
|
||
+ clock_gettime (CLOCK_REALTIME, &ts);
|
||
|
||
if ((flags & NO_CACHE) == 0)
|
||
*dir = nis_server_cache_search (name, search_parent, &server_used,
|
||
diff --git a/nscd/aicache.c b/nscd/aicache.c
|
||
index 51e793199f..e0baed170b 100644
|
||
--- a/nscd/aicache.c
|
||
+++ b/nscd/aicache.c
|
||
@@ -110,11 +110,10 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
|
||
"gethostbyname4_r");
|
||
if (fct4 != NULL)
|
||
{
|
||
- struct gaih_addrtuple atmem;
|
||
struct gaih_addrtuple *at;
|
||
while (1)
|
||
{
|
||
- at = &atmem;
|
||
+ at = NULL;
|
||
rc6 = 0;
|
||
herrno = 0;
|
||
status[1] = DL_CALL_FCT (fct4, (key, &at,
|
||
@@ -137,7 +136,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
|
||
goto next_nip;
|
||
|
||
/* We found the data. Count the addresses and the size. */
|
||
- for (const struct gaih_addrtuple *at2 = at = &atmem; at2 != NULL;
|
||
+ for (const struct gaih_addrtuple *at2 = at; at2 != NULL;
|
||
at2 = at2->next)
|
||
{
|
||
++naddrs;
|
||
diff --git a/nscd/connections.c b/nscd/connections.c
|
||
index 61d1674eb4..531d2e83df 100644
|
||
--- a/nscd/connections.c
|
||
+++ b/nscd/connections.c
|
||
@@ -2284,7 +2284,8 @@ main_loop_epoll (int efd)
|
||
sizeof (buf))) != -1)
|
||
;
|
||
|
||
- __bump_nl_timestamp ();
|
||
+ dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP]
|
||
+ = __bump_nl_timestamp ();
|
||
}
|
||
# endif
|
||
else
|
||
diff --git a/nscd/nscd.h b/nscd/nscd.h
|
||
index 368091aef8..f15321585b 100644
|
||
--- a/nscd/nscd.h
|
||
+++ b/nscd/nscd.h
|
||
@@ -65,7 +65,7 @@ typedef enum
|
||
struct traced_file
|
||
{
|
||
/* Tracks the last modified time of the traced file. */
|
||
- time_t mtime;
|
||
+ __time64_t mtime;
|
||
/* Support multiple registered files per database. */
|
||
struct traced_file *next;
|
||
int call_res_init;
|
||
diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c
|
||
index 9becb62033..31c64275f0 100644
|
||
--- a/nscd/nscd_gethst_r.c
|
||
+++ b/nscd/nscd_gethst_r.c
|
||
@@ -112,7 +112,7 @@ __nscd_get_nl_timestamp (void)
|
||
if (map == NULL
|
||
|| (map != NO_MAPPING
|
||
&& map->head->nscd_certainly_running == 0
|
||
- && map->head->timestamp + MAPPING_TIMEOUT < time_now ()))
|
||
+ && map->head->timestamp + MAPPING_TIMEOUT < time64_now ()))
|
||
map = __nscd_get_mapping (GETFDHST, "hosts", &__hst_map_handle.mapped);
|
||
|
||
if (map == NO_MAPPING)
|
||
diff --git a/nss/getent.c b/nss/getent.c
|
||
index 8178b4b470..d2d2524b0c 100644
|
||
--- a/nss/getent.c
|
||
+++ b/nss/getent.c
|
||
@@ -58,6 +58,8 @@ static const struct argp_option args_options[] =
|
||
{
|
||
{ "service", 's', N_("CONFIG"), 0, N_("Service configuration to be used") },
|
||
{ "no-idn", 'i', NULL, 0, N_("disable IDN encoding") },
|
||
+ { "no-addrconfig", 'A', NULL, 0,
|
||
+ N_("do not filter out unsupported IPv4/IPv6 addresses (with ahosts*)") },
|
||
{ NULL, 0, NULL, 0, NULL },
|
||
};
|
||
|
||
@@ -79,6 +81,9 @@ static struct argp argp =
|
||
/* Additional getaddrinfo flags for IDN encoding. */
|
||
static int idn_flags = AI_IDN | AI_CANONIDN;
|
||
|
||
+/* Set to 0 by --no-addrconfig. */
|
||
+static int addrconfig_flags = AI_ADDRCONFIG;
|
||
+
|
||
/* Print the version information. */
|
||
static void
|
||
print_version (FILE *stream, struct argp_state *state)
|
||
@@ -346,7 +351,7 @@ ahosts_keys_int (int af, int xflags, int number, char *key[])
|
||
|
||
struct addrinfo hint;
|
||
memset (&hint, '\0', sizeof (hint));
|
||
- hint.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME
|
||
+ hint.ai_flags = (AI_V4MAPPED | addrconfig_flags | AI_CANONNAME
|
||
| idn_flags | xflags);
|
||
hint.ai_family = af;
|
||
|
||
@@ -905,6 +910,10 @@ parse_option (int key, char *arg, struct argp_state *state)
|
||
idn_flags = 0;
|
||
break;
|
||
|
||
+ case 'A':
|
||
+ addrconfig_flags = 0;
|
||
+ break;
|
||
+
|
||
default:
|
||
return ARGP_ERR_UNKNOWN;
|
||
}
|
||
diff --git a/nss/tst-nss-files-hosts-long.c b/nss/tst-nss-files-hosts-long.c
|
||
index 3942cf5fca..a7697e3143 100644
|
||
--- a/nss/tst-nss-files-hosts-long.c
|
||
+++ b/nss/tst-nss-files-hosts-long.c
|
||
@@ -28,14 +28,15 @@ do_test (void)
|
||
{
|
||
int ret;
|
||
|
||
- /* Run getent to fetch the IPv4 address for host test4.
|
||
- This forces /etc/hosts to be parsed. */
|
||
- ret = system("getent ahostsv4 test4");
|
||
+ /* Run getent to fetch the IPv4 address for host test4. This forces
|
||
+ /etc/hosts to be parsed. Use --no-addrconfig to return addresses
|
||
+ even in an IPv6-only environment. */
|
||
+ ret = system("getent --no-addrconfig ahostsv4 test4");
|
||
if (ret != 0)
|
||
FAIL_EXIT1("ahostsv4 failed");
|
||
|
||
/* Likewise for IPv6. */
|
||
- ret = system("getent ahostsv6 test6");
|
||
+ ret = system("getent --no-addrconfig ahostsv6 test6");
|
||
if (ret != 0)
|
||
FAIL_EXIT1("ahostsv6 failed");
|
||
|
||
diff --git a/nss/tst-reload1.c b/nss/tst-reload1.c
|
||
index fdc5bdd65b..bc32bb132a 100644
|
||
--- a/nss/tst-reload1.c
|
||
+++ b/nss/tst-reload1.c
|
||
@@ -43,12 +43,12 @@ static struct passwd pwd_table_1[] = {
|
||
|
||
static const char *hostaddr_5[] =
|
||
{
|
||
- "ABCD", "abcd", "1234", NULL
|
||
+ "ABCd", "ABCD", "ABC4", NULL
|
||
};
|
||
|
||
static const char *hostaddr_15[] =
|
||
{
|
||
- "4321", "ghij", NULL
|
||
+ "4321", "4322", NULL
|
||
};
|
||
|
||
static const char *hostaddr_25[] =
|
||
@@ -86,12 +86,12 @@ static const char *hostaddr_6[] =
|
||
|
||
static const char *hostaddr_16[] =
|
||
{
|
||
- "7890", "a1b2", NULL
|
||
+ "7890", "7891", NULL
|
||
};
|
||
|
||
static const char *hostaddr_26[] =
|
||
{
|
||
- "qwer", "tyui", NULL
|
||
+ "qwer", "qweR", NULL
|
||
};
|
||
|
||
static struct hostent host_table_2[] = {
|
||
diff --git a/resolv/Makefile b/resolv/Makefile
|
||
index 5b15321f9b..f8a92c6cff 100644
|
||
--- a/resolv/Makefile
|
||
+++ b/resolv/Makefile
|
||
@@ -40,12 +40,16 @@ routines := \
|
||
inet_pton \
|
||
ns_makecanon \
|
||
ns_name_compress \
|
||
+ ns_name_length_uncompressed \
|
||
ns_name_ntop \
|
||
ns_name_pack \
|
||
ns_name_pton \
|
||
ns_name_skip \
|
||
ns_name_uncompress \
|
||
ns_name_unpack \
|
||
+ ns_rr_cursor_init \
|
||
+ ns_rr_cursor_next \
|
||
+ ns_samebinaryname \
|
||
ns_samename \
|
||
nsap_addr \
|
||
nss_dns_functions \
|
||
@@ -89,9 +93,12 @@ tests += \
|
||
tst-ns_name_pton \
|
||
tst-res_hconf_reorder \
|
||
tst-res_hnok \
|
||
+ tst-resolv-aliases \
|
||
tst-resolv-basic \
|
||
tst-resolv-binary \
|
||
+ tst-resolv-byaddr \
|
||
tst-resolv-edns \
|
||
+ tst-resolv-invalid-cname \
|
||
tst-resolv-network \
|
||
tst-resolv-noaaaa \
|
||
tst-resolv-nondecimal \
|
||
@@ -104,6 +111,18 @@ tests += \
|
||
tests-internal += tst-resolv-txnid-collision
|
||
tests-static += tst-resolv-txnid-collision
|
||
|
||
+# Likewise for __ns_samebinaryname.
|
||
+tests-internal += tst-ns_samebinaryname
|
||
+tests-static += tst-ns_samebinaryname
|
||
+
|
||
+# Likewise for __ns_name_length_uncompressed.
|
||
+tests-internal += tst-ns_name_length_uncompressed
|
||
+tests-static += tst-ns_name_length_uncompressed
|
||
+
|
||
+# Likewise for struct ns_rr_cursor and its functions.
|
||
+tests-internal += tst-ns_rr_cursor
|
||
+tests-static += tst-ns_rr_cursor
|
||
+
|
||
# These tests need libdl.
|
||
ifeq (yes,$(build-shared))
|
||
tests += \
|
||
@@ -258,8 +277,10 @@ $(objpfx)tst-resolv-ai_idn.out: $(gen-locales)
|
||
$(objpfx)tst-resolv-ai_idn-latin1.out: $(gen-locales)
|
||
$(objpfx)tst-resolv-ai_idn-nolibidn2.out: \
|
||
$(gen-locales) $(objpfx)tst-no-libidn2.so
|
||
+$(objpfx)tst-resolv-aliases: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library)
|
||
+$(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-res_init: $(objpfx)libresolv.so
|
||
@@ -267,6 +288,8 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \
|
||
$(shared-thread-library)
|
||
$(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \
|
||
$(shared-thread-library)
|
||
+$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \
|
||
+ $(shared-thread-library)
|
||
$(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
|
||
diff --git a/resolv/README b/resolv/README
|
||
index 514e9bb617..2146bc3b27 100644
|
||
--- a/resolv/README
|
||
+++ b/resolv/README
|
||
@@ -146,6 +146,3 @@ res_libc.c is home-brewn, although parts of it are taken from res_data.c.
|
||
|
||
res_hconf.c and res_hconf.h were contributed by David Mosberger, and
|
||
do not come from BIND.
|
||
-
|
||
-The files gethnamaddr.c, mapv4v6addr.h and mapv4v6hostent.h are
|
||
-leftovers from BIND 4.9.7.
|
||
diff --git a/resolv/mapv4v6addr.h b/resolv/mapv4v6addr.h
|
||
deleted file mode 100644
|
||
index 7f85f7d5e3..0000000000
|
||
--- a/resolv/mapv4v6addr.h
|
||
+++ /dev/null
|
||
@@ -1,69 +0,0 @@
|
||
-/*
|
||
- * ++Copyright++ 1985, 1988, 1993
|
||
- * -
|
||
- * Copyright (c) 1985, 1988, 1993
|
||
- * The Regents of the University of California. All rights reserved.
|
||
- *
|
||
- * Redistribution and use in source and binary forms, with or without
|
||
- * modification, are permitted provided that the following conditions
|
||
- * are met:
|
||
- * 1. Redistributions of source code must retain the above copyright
|
||
- * notice, this list of conditions and the following disclaimer.
|
||
- * 2. Redistributions in binary form must reproduce the above copyright
|
||
- * notice, this list of conditions and the following disclaimer in the
|
||
- * documentation and/or other materials provided with the distribution.
|
||
- * 4. Neither the name of the University nor the names of its contributors
|
||
- * may be used to endorse or promote products derived from this software
|
||
- * without specific prior written permission.
|
||
- *
|
||
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
- * SUCH DAMAGE.
|
||
- * -
|
||
- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
|
||
- *
|
||
- * Permission to use, copy, modify, and distribute this software for any
|
||
- * purpose with or without fee is hereby granted, provided that the above
|
||
- * copyright notice and this permission notice appear in all copies, and that
|
||
- * the name of Digital Equipment Corporation not be used in advertising or
|
||
- * publicity pertaining to distribution of the document or software without
|
||
- * specific, written prior permission.
|
||
- *
|
||
- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
||
- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
||
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
||
- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||
- * SOFTWARE.
|
||
- * -
|
||
- * --Copyright--
|
||
- */
|
||
-
|
||
-#include <string.h>
|
||
-#include <arpa/nameser.h>
|
||
-
|
||
-static void
|
||
-map_v4v6_address (const char *src, char *dst)
|
||
-{
|
||
- u_char *p = (u_char *) dst;
|
||
- int i;
|
||
-
|
||
- /* Move the IPv4 part to the right position. */
|
||
- memcpy (dst + 12, src, INADDRSZ);
|
||
-
|
||
- /* Mark this ipv6 addr as a mapped ipv4. */
|
||
- for (i = 0; i < 10; i++)
|
||
- *p++ = 0x00;
|
||
- *p++ = 0xff;
|
||
- *p = 0xff;
|
||
-}
|
||
diff --git a/resolv/mapv4v6hostent.h b/resolv/mapv4v6hostent.h
|
||
deleted file mode 100644
|
||
index c11038adf3..0000000000
|
||
--- a/resolv/mapv4v6hostent.h
|
||
+++ /dev/null
|
||
@@ -1,84 +0,0 @@
|
||
-/*
|
||
- * ++Copyright++ 1985, 1988, 1993
|
||
- * -
|
||
- * Copyright (c) 1985, 1988, 1993
|
||
- * The Regents of the University of California. All rights reserved.
|
||
- *
|
||
- * Redistribution and use in source and binary forms, with or without
|
||
- * modification, are permitted provided that the following conditions
|
||
- * are met:
|
||
- * 1. Redistributions of source code must retain the above copyright
|
||
- * notice, this list of conditions and the following disclaimer.
|
||
- * 2. Redistributions in binary form must reproduce the above copyright
|
||
- * notice, this list of conditions and the following disclaimer in the
|
||
- * documentation and/or other materials provided with the distribution.
|
||
- * 4. Neither the name of the University nor the names of its contributors
|
||
- * may be used to endorse or promote products derived from this software
|
||
- * without specific prior written permission.
|
||
- *
|
||
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
- * SUCH DAMAGE.
|
||
- * -
|
||
- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
|
||
- *
|
||
- * Permission to use, copy, modify, and distribute this software for any
|
||
- * purpose with or without fee is hereby granted, provided that the above
|
||
- * copyright notice and this permission notice appear in all copies, and that
|
||
- * the name of Digital Equipment Corporation not be used in advertising or
|
||
- * publicity pertaining to distribution of the document or software without
|
||
- * specific, written prior permission.
|
||
- *
|
||
- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
||
- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
||
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
||
- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||
- * SOFTWARE.
|
||
- * -
|
||
- * --Copyright--
|
||
- */
|
||
-
|
||
-#include <arpa/nameser.h>
|
||
-#include <sys/socket.h>
|
||
-
|
||
-typedef union {
|
||
- int32_t al;
|
||
- char ac;
|
||
-} align;
|
||
-
|
||
-static int
|
||
-map_v4v6_hostent (struct hostent *hp, char **bpp, int *lenp)
|
||
-{
|
||
- char **ap;
|
||
-
|
||
- if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
|
||
- return 0;
|
||
- hp->h_addrtype = AF_INET6;
|
||
- hp->h_length = IN6ADDRSZ;
|
||
- for (ap = hp->h_addr_list; *ap; ap++)
|
||
- {
|
||
- int i = sizeof (align) - ((u_long) *bpp % sizeof (align));
|
||
-
|
||
- if (*lenp < (i + IN6ADDRSZ))
|
||
- /* Out of memory. */
|
||
- return 1;
|
||
- *bpp += i;
|
||
- *lenp -= i;
|
||
- map_v4v6_address (*ap, *bpp);
|
||
- *ap = *bpp;
|
||
- *bpp += IN6ADDRSZ;
|
||
- *lenp -= IN6ADDRSZ;
|
||
- }
|
||
- return 0;
|
||
-}
|
||
diff --git a/resolv/ns_name_length_uncompressed.c b/resolv/ns_name_length_uncompressed.c
|
||
new file mode 100644
|
||
index 0000000000..51296b47ef
|
||
--- /dev/null
|
||
+++ b/resolv/ns_name_length_uncompressed.c
|
||
@@ -0,0 +1,72 @@
|
||
+/* Skip over an uncompressed name in wire format.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <arpa/nameser.h>
|
||
+#include <errno.h>
|
||
+#include <stdbool.h>
|
||
+
|
||
+int
|
||
+__ns_name_length_uncompressed (const unsigned char *p,
|
||
+ const unsigned char *eom)
|
||
+{
|
||
+ const unsigned char *start = p;
|
||
+
|
||
+ while (true)
|
||
+ {
|
||
+ if (p == eom)
|
||
+ {
|
||
+ /* Truncated packet: no room for label length. */
|
||
+ __set_errno (EMSGSIZE);
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ unsigned char b = *p;
|
||
+ ++p;
|
||
+ if (b == 0)
|
||
+ {
|
||
+ /* Root label. */
|
||
+ size_t length = p - start;
|
||
+ if (length > NS_MAXCDNAME)
|
||
+ {
|
||
+ /* Domain name too long. */
|
||
+ __set_errno (EMSGSIZE);
|
||
+ return -1;
|
||
+ }
|
||
+ return length;
|
||
+ }
|
||
+
|
||
+ if (b <= 63)
|
||
+ {
|
||
+ /* Regular label. */
|
||
+ if (b <= eom - p)
|
||
+ p += b;
|
||
+ else
|
||
+ {
|
||
+ /* Truncated packet: label incomplete. */
|
||
+ __set_errno (EMSGSIZE);
|
||
+ return -1;
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* Compression reference or corrupted label length. */
|
||
+ __set_errno (EMSGSIZE);
|
||
+ return -1;
|
||
+ }
|
||
+ }
|
||
+}
|
||
diff --git a/resolv/ns_rr_cursor_init.c b/resolv/ns_rr_cursor_init.c
|
||
new file mode 100644
|
||
index 0000000000..6ee80b30e9
|
||
--- /dev/null
|
||
+++ b/resolv/ns_rr_cursor_init.c
|
||
@@ -0,0 +1,62 @@
|
||
+/* Initialize a simple DNS packet parser.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <arpa/nameser.h>
|
||
+#include <errno.h>
|
||
+#include <stdbool.h>
|
||
+#include <string.h>
|
||
+
|
||
+bool
|
||
+__ns_rr_cursor_init (struct ns_rr_cursor *c,
|
||
+ const unsigned char *buf, size_t len)
|
||
+{
|
||
+ c->begin = buf;
|
||
+ c->end = buf + len;
|
||
+
|
||
+ /* Check for header size and 16-bit question count value (it must be 1). */
|
||
+ if (len < 12 || buf[4] != 0 || buf[5] != 1)
|
||
+ {
|
||
+ __set_errno (EMSGSIZE);
|
||
+ c->current = c->end;
|
||
+ return false;
|
||
+ }
|
||
+ c->current = buf + 12;
|
||
+
|
||
+ int consumed = __ns_name_length_uncompressed (c->current, c->end);
|
||
+ if (consumed < 0)
|
||
+ {
|
||
+ __set_errno (EMSGSIZE);
|
||
+ c->current = c->end;
|
||
+ c->first_rr = NULL;
|
||
+ return false;
|
||
+ }
|
||
+ c->current += consumed;
|
||
+
|
||
+ /* Ensure there is room for question type and class. */
|
||
+ if (c->end - c->current < 4)
|
||
+ {
|
||
+ __set_errno (EMSGSIZE);
|
||
+ c->current = c->end;
|
||
+ c->first_rr = NULL;
|
||
+ return false;
|
||
+ }
|
||
+ c->current += 4;
|
||
+ c->first_rr = c->current;
|
||
+
|
||
+ return true;
|
||
+}
|
||
diff --git a/resolv/ns_rr_cursor_next.c b/resolv/ns_rr_cursor_next.c
|
||
new file mode 100644
|
||
index 0000000000..33652fc5da
|
||
--- /dev/null
|
||
+++ b/resolv/ns_rr_cursor_next.c
|
||
@@ -0,0 +1,74 @@
|
||
+/* Simple DNS record parser without textual name decoding.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <arpa/nameser.h>
|
||
+#include <errno.h>
|
||
+#include <stdbool.h>
|
||
+#include <string.h>
|
||
+
|
||
+bool
|
||
+__ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr)
|
||
+{
|
||
+ rr->rdata = NULL;
|
||
+
|
||
+ /* Extract the record owner name. */
|
||
+ int consumed = __ns_name_unpack (c->begin, c->end, c->current,
|
||
+ rr->rname, sizeof (rr->rname));
|
||
+ if (consumed < 0)
|
||
+ {
|
||
+ memset (rr, 0, sizeof (*rr));
|
||
+ __set_errno (EMSGSIZE);
|
||
+ return false;
|
||
+ }
|
||
+ c->current += consumed;
|
||
+
|
||
+ /* Extract the metadata. */
|
||
+ struct
|
||
+ {
|
||
+ uint16_t rtype;
|
||
+ uint16_t rclass;
|
||
+ uint32_t ttl;
|
||
+ uint16_t rdlength;
|
||
+ } __attribute__ ((packed)) metadata;
|
||
+ _Static_assert (sizeof (metadata) == 10, "sizeof metadata");
|
||
+ if (c->end - c->current < sizeof (metadata))
|
||
+ {
|
||
+ memset (rr, 0, sizeof (*rr));
|
||
+ __set_errno (EMSGSIZE);
|
||
+ return false;
|
||
+ }
|
||
+ memcpy (&metadata, c->current, sizeof (metadata));
|
||
+ c->current += sizeof (metadata);
|
||
+ /* Endianess conversion. */
|
||
+ rr->rtype = ntohs (metadata.rtype);
|
||
+ rr->rclass = ntohs (metadata.rclass);
|
||
+ rr->ttl = ntohl (metadata.ttl);
|
||
+ rr->rdlength = ntohs (metadata.rdlength);
|
||
+
|
||
+ /* Extract record data. */
|
||
+ if (c->end - c->current < rr->rdlength)
|
||
+ {
|
||
+ memset (rr, 0, sizeof (*rr));
|
||
+ __set_errno (EMSGSIZE);
|
||
+ return false;
|
||
+ }
|
||
+ rr->rdata = c->current;
|
||
+ c->current += rr->rdlength;
|
||
+
|
||
+ return true;
|
||
+}
|
||
diff --git a/resolv/ns_samebinaryname.c b/resolv/ns_samebinaryname.c
|
||
new file mode 100644
|
||
index 0000000000..9a47d8e97a
|
||
--- /dev/null
|
||
+++ b/resolv/ns_samebinaryname.c
|
||
@@ -0,0 +1,55 @@
|
||
+/* Compare two binary domain names for quality.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <arpa/nameser.h>
|
||
+#include <stdbool.h>
|
||
+
|
||
+/* Convert ASCII letters to upper case. */
|
||
+static inline int
|
||
+ascii_toupper (unsigned char ch)
|
||
+{
|
||
+ if (ch >= 'a' && ch <= 'z')
|
||
+ return ch - 'a' + 'A';
|
||
+ else
|
||
+ return ch;
|
||
+}
|
||
+
|
||
+bool
|
||
+__ns_samebinaryname (const unsigned char *a, const unsigned char *b)
|
||
+{
|
||
+ while (*a != 0 && *b != 0)
|
||
+ {
|
||
+ if (*a != *b)
|
||
+ /* Different label length. */
|
||
+ return false;
|
||
+ int labellen = *a;
|
||
+ ++a;
|
||
+ ++b;
|
||
+ for (int i = 0; i < labellen; ++i)
|
||
+ {
|
||
+ if (*a != *b && ascii_toupper (*a) != ascii_toupper (*b))
|
||
+ /* Different character in label. */
|
||
+ return false;
|
||
+ ++a;
|
||
+ ++b;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Match if both names are at the root label. */
|
||
+ return *a == 0 && *b == 0;
|
||
+}
|
||
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
|
||
index 544cffbecd..9fa81f23c8 100644
|
||
--- a/resolv/nss_dns/dns-host.c
|
||
+++ b/resolv/nss_dns/dns-host.c
|
||
@@ -69,6 +69,7 @@
|
||
* --Copyright--
|
||
*/
|
||
|
||
+#include <alloc_buffer.h>
|
||
#include <assert.h>
|
||
#include <ctype.h>
|
||
#include <errno.h>
|
||
@@ -86,10 +87,6 @@
|
||
#include <resolv/resolv-internal.h>
|
||
#include <resolv/resolv_context.h>
|
||
|
||
-/* Get implementations of some internal functions. */
|
||
-#include <resolv/mapv4v6addr.h>
|
||
-#include <resolv/mapv4v6hostent.h>
|
||
-
|
||
#define RESOLVSORT
|
||
|
||
#if PACKETSZ > 65536
|
||
@@ -103,32 +100,36 @@
|
||
#endif
|
||
#define MAXHOSTNAMELEN 256
|
||
|
||
-/* We need this time later. */
|
||
-typedef union querybuf
|
||
-{
|
||
- HEADER hdr;
|
||
- u_char buf[MAXPACKET];
|
||
-} querybuf;
|
||
-
|
||
-static enum nss_status getanswer_r (struct resolv_context *ctx,
|
||
- const querybuf *answer, int anslen,
|
||
- const char *qname, int qtype,
|
||
- struct hostent *result, char *buffer,
|
||
- size_t buflen, int *errnop, int *h_errnop,
|
||
- int map, int32_t *ttlp, char **canonp);
|
||
-
|
||
-static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
|
||
- const querybuf *answer2, int anslen2,
|
||
- const char *qname,
|
||
+/* For historic reasons, pointers to IP addresses are char *, so use a
|
||
+ single list type for addresses and host names. */
|
||
+#define DYNARRAY_STRUCT ptrlist
|
||
+#define DYNARRAY_ELEMENT char *
|
||
+#define DYNARRAY_PREFIX ptrlist_
|
||
+#include <malloc/dynarray-skeleton.c>
|
||
+
|
||
+static enum nss_status getanswer_r (unsigned char *packet, size_t packetlen,
|
||
+ uint16_t qtype, struct alloc_buffer *abuf,
|
||
+ struct ptrlist *addresses,
|
||
+ struct ptrlist *aliases,
|
||
+ int *errnop, int *h_errnop, int32_t *ttlp);
|
||
+static void addrsort (struct resolv_context *ctx, char **ap, int num);
|
||
+static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen,
|
||
+ struct alloc_buffer *abuf,
|
||
+ char **hnamep, int *errnop,
|
||
+ int *h_errnop, int32_t *ttlp);
|
||
+
|
||
+static enum nss_status gaih_getanswer (unsigned char *packet1,
|
||
+ size_t packet1len,
|
||
+ unsigned char *packet2,
|
||
+ size_t packet2len,
|
||
+ struct alloc_buffer *abuf,
|
||
struct gaih_addrtuple **pat,
|
||
- char *buffer, size_t buflen,
|
||
int *errnop, int *h_errnop,
|
||
int32_t *ttlp);
|
||
-static enum nss_status gaih_getanswer_noaaaa (const querybuf *answer1,
|
||
- int anslen1,
|
||
- const char *qname,
|
||
+static enum nss_status gaih_getanswer_noaaaa (unsigned char *packet,
|
||
+ size_t packetlen,
|
||
+ struct alloc_buffer *abuf,
|
||
struct gaih_addrtuple **pat,
|
||
- char *buffer, size_t buflen,
|
||
int *errnop, int *h_errnop,
|
||
int32_t *ttlp);
|
||
|
||
@@ -183,16 +184,9 @@ gethostbyname3_context (struct resolv_context *ctx,
|
||
char *buffer, size_t buflen, int *errnop,
|
||
int *h_errnop, int32_t *ttlp, char **canonp)
|
||
{
|
||
- union
|
||
- {
|
||
- querybuf *buf;
|
||
- u_char *ptr;
|
||
- } host_buffer;
|
||
- querybuf *orig_host_buffer;
|
||
char tmp[NS_MAXDNAME];
|
||
int size, type, n;
|
||
const char *cp;
|
||
- int map = 0;
|
||
int olderr = errno;
|
||
enum nss_status status;
|
||
|
||
@@ -223,10 +217,12 @@ gethostbyname3_context (struct resolv_context *ctx,
|
||
&& (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL)
|
||
name = cp;
|
||
|
||
- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
|
||
+ unsigned char dns_packet_buffer[1024];
|
||
+ unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
|
||
|
||
- n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf,
|
||
- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
|
||
+ n = __res_context_search (ctx, name, C_IN, type,
|
||
+ dns_packet_buffer, sizeof (dns_packet_buffer),
|
||
+ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL);
|
||
if (n < 0)
|
||
{
|
||
switch (errno)
|
||
@@ -253,34 +249,79 @@ gethostbyname3_context (struct resolv_context *ctx,
|
||
*errnop = EAGAIN;
|
||
else
|
||
__set_errno (olderr);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
|
||
|
||
- /* If we are looking for an IPv6 address and mapping is enabled
|
||
- by having the RES_USE_INET6 bit in _res.options set, we try
|
||
- another lookup. */
|
||
- if (af == AF_INET6 && res_use_inet6 ())
|
||
- n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf,
|
||
- host_buffer.buf != orig_host_buffer
|
||
- ? MAXPACKET : 1024, &host_buffer.ptr,
|
||
- NULL, NULL, NULL, NULL);
|
||
+ struct ptrlist addresses;
|
||
+ ptrlist_init (&addresses);
|
||
+ struct ptrlist aliases;
|
||
+ ptrlist_init (&aliases);
|
||
|
||
- if (n < 0)
|
||
+ status = getanswer_r (alt_dns_packet_buffer, n, type,
|
||
+ &abuf, &addresses, &aliases,
|
||
+ errnop, h_errnop, ttlp);
|
||
+ if (status == NSS_STATUS_SUCCESS)
|
||
{
|
||
- if (host_buffer.buf != orig_host_buffer)
|
||
- free (host_buffer.buf);
|
||
- return status;
|
||
- }
|
||
+ if (ptrlist_has_failed (&addresses)
|
||
+ || ptrlist_has_failed (&aliases))
|
||
+ {
|
||
+ /* malloc failure. Do not retry using the ERANGE protocol. */
|
||
+ *errnop = ENOMEM;
|
||
+ *h_errnop = NETDB_INTERNAL;
|
||
+ status = NSS_STATUS_UNAVAIL;
|
||
+ }
|
||
|
||
- map = 1;
|
||
+ /* Reserve the address and alias arrays in the result
|
||
+ buffer. Both are NULL-terminated, but the first element
|
||
+ of the alias array is stored in h_name, so no extra space
|
||
+ for the NULL terminator is needed there. */
|
||
+ result->h_addr_list
|
||
+ = alloc_buffer_alloc_array (&abuf, char *,
|
||
+ ptrlist_size (&addresses) + 1);
|
||
+ result->h_aliases
|
||
+ = alloc_buffer_alloc_array (&abuf, char *,
|
||
+ ptrlist_size (&aliases));
|
||
+ if (alloc_buffer_has_failed (&abuf))
|
||
+ {
|
||
+ /* Retry using the ERANGE protocol. */
|
||
+ *errnop = ERANGE;
|
||
+ *h_errnop = NETDB_INTERNAL;
|
||
+ status = NSS_STATUS_TRYAGAIN;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* Copy the address list and NULL-terminate it. */
|
||
+ memcpy (result->h_addr_list, ptrlist_begin (&addresses),
|
||
+ ptrlist_size (&addresses) * sizeof (char *));
|
||
+ result->h_addr_list[ptrlist_size (&addresses)] = NULL;
|
||
+
|
||
+ /* Sort the address list if requested. */
|
||
+ if (type == T_A && __resolv_context_sort_count (ctx) > 0)
|
||
+ addrsort (ctx, result->h_addr_list, ptrlist_size (&addresses));
|
||
|
||
- result->h_addrtype = AF_INET;
|
||
- result->h_length = INADDRSZ;
|
||
+ /* Copy the aliases, excluding the last one. */
|
||
+ memcpy (result->h_aliases, ptrlist_begin (&aliases),
|
||
+ (ptrlist_size (&aliases) - 1) * sizeof (char *));
|
||
+ result->h_aliases[ptrlist_size (&aliases) - 1] = NULL;
|
||
+
|
||
+ /* The last alias goes into h_name. */
|
||
+ assert (ptrlist_size (&aliases) >= 1);
|
||
+ result->h_name = ptrlist_end (&aliases)[-1];
|
||
+
|
||
+ /* This is also the canonical name. */
|
||
+ if (canonp != NULL)
|
||
+ *canonp = result->h_name;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ptrlist_free (&aliases);
|
||
+ ptrlist_free (&addresses);
|
||
}
|
||
|
||
- status = getanswer_r
|
||
- (ctx, host_buffer.buf, n, name, type, result, buffer, buflen,
|
||
- errnop, h_errnop, map, ttlp, canonp);
|
||
- if (host_buffer.buf != orig_host_buffer)
|
||
- free (host_buffer.buf);
|
||
+ if (alt_dns_packet_buffer != dns_packet_buffer)
|
||
+ free (alt_dns_packet_buffer);
|
||
return status;
|
||
}
|
||
|
||
@@ -324,13 +365,8 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
|
||
*h_errnop = NETDB_INTERNAL;
|
||
return NSS_STATUS_UNAVAIL;
|
||
}
|
||
- status = NSS_STATUS_NOTFOUND;
|
||
- if (res_use_inet6 ())
|
||
- status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer,
|
||
- buflen, errnop, h_errnop, NULL, NULL);
|
||
- if (status == NSS_STATUS_NOTFOUND)
|
||
- status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
|
||
- buflen, errnop, h_errnop, NULL, NULL);
|
||
+ status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
|
||
+ buflen, errnop, h_errnop, NULL, NULL);
|
||
__resolv_context_put (ctx);
|
||
return status;
|
||
}
|
||
@@ -365,17 +401,13 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
|
||
name = cp;
|
||
}
|
||
|
||
- union
|
||
- {
|
||
- querybuf *buf;
|
||
- u_char *ptr;
|
||
- } host_buffer;
|
||
- querybuf *orig_host_buffer;
|
||
- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
|
||
+ unsigned char dns_packet_buffer[2048];
|
||
+ unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
|
||
u_char *ans2p = NULL;
|
||
int nans2p = 0;
|
||
int resplen2 = 0;
|
||
int ans2p_malloced = 0;
|
||
+ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
|
||
|
||
|
||
int olderr = errno;
|
||
@@ -384,22 +416,21 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
|
||
if ((ctx->resp->options & RES_NOAAAA) == 0)
|
||
{
|
||
n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
|
||
- host_buffer.buf->buf, 2048, &host_buffer.ptr,
|
||
- &ans2p, &nans2p, &resplen2, &ans2p_malloced);
|
||
+ dns_packet_buffer, sizeof (dns_packet_buffer),
|
||
+ &alt_dns_packet_buffer, &ans2p, &nans2p,
|
||
+ &resplen2, &ans2p_malloced);
|
||
if (n >= 0)
|
||
- status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
|
||
- resplen2, name, pat, buffer, buflen,
|
||
- errnop, herrnop, ttlp);
|
||
+ status = gaih_getanswer (alt_dns_packet_buffer, n, ans2p, resplen2,
|
||
+ &abuf, pat, errnop, herrnop, ttlp);
|
||
}
|
||
else
|
||
{
|
||
n = __res_context_search (ctx, name, C_IN, T_A,
|
||
- host_buffer.buf->buf, 2048, NULL,
|
||
- NULL, NULL, NULL, NULL);
|
||
+ dns_packet_buffer, sizeof (dns_packet_buffer),
|
||
+ NULL, NULL, NULL, NULL, NULL);
|
||
if (n >= 0)
|
||
- status = gaih_getanswer_noaaaa (host_buffer.buf, n,
|
||
- name, pat, buffer, buflen,
|
||
- errnop, herrnop, ttlp);
|
||
+ status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n,
|
||
+ &abuf, pat, errnop, herrnop, ttlp);
|
||
}
|
||
if (n < 0)
|
||
{
|
||
@@ -430,12 +461,20 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
|
||
__set_errno (olderr);
|
||
}
|
||
|
||
+ /* Implement the buffer resizing protocol. */
|
||
+ if (alloc_buffer_has_failed (&abuf))
|
||
+ {
|
||
+ *errnop = ERANGE;
|
||
+ *herrnop = NETDB_INTERNAL;
|
||
+ status = NSS_STATUS_TRYAGAIN;
|
||
+ }
|
||
+
|
||
/* Check whether ans2p was separately allocated. */
|
||
if (ans2p_malloced)
|
||
free (ans2p);
|
||
|
||
- if (host_buffer.buf != orig_host_buffer)
|
||
- free (host_buffer.buf);
|
||
+ if (alt_dns_packet_buffer != dns_packet_buffer)
|
||
+ free (alt_dns_packet_buffer);
|
||
|
||
__resolv_context_put (ctx);
|
||
return status;
|
||
@@ -451,36 +490,21 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
|
||
static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
|
||
static const u_char v6local[] = { 0,0, 0,1 };
|
||
const u_char *uaddr = (const u_char *)addr;
|
||
- struct host_data
|
||
- {
|
||
- char *aliases[MAX_NR_ALIASES];
|
||
- unsigned char host_addr[16]; /* IPv4 or IPv6 */
|
||
- char *h_addr_ptrs[MAX_NR_ADDRS + 1];
|
||
- char linebuffer[0];
|
||
- } *host_data = (struct host_data *) buffer;
|
||
- union
|
||
- {
|
||
- querybuf *buf;
|
||
- u_char *ptr;
|
||
- } host_buffer;
|
||
- querybuf *orig_host_buffer;
|
||
char qbuf[MAXDNAME+1], *qp = NULL;
|
||
size_t size;
|
||
int n, status;
|
||
int olderr = errno;
|
||
|
||
- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
|
||
- buffer += pad;
|
||
- buflen = buflen > pad ? buflen - pad : 0;
|
||
-
|
||
- if (__glibc_unlikely (buflen < sizeof (struct host_data)))
|
||
- {
|
||
- *errnop = ERANGE;
|
||
- *h_errnop = NETDB_INTERNAL;
|
||
- return NSS_STATUS_TRYAGAIN;
|
||
- }
|
||
-
|
||
- host_data = (struct host_data *) buffer;
|
||
+ /* Prepare the allocation buffer. Store the pointer array first, to
|
||
+ benefit from buffer alignment. */
|
||
+ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
|
||
+ char **address_array = alloc_buffer_alloc_array (&abuf, char *, 2);
|
||
+ if (address_array == NULL)
|
||
+ {
|
||
+ *errnop = ERANGE;
|
||
+ *h_errnop = NETDB_INTERNAL;
|
||
+ return NSS_STATUS_TRYAGAIN;
|
||
+ }
|
||
|
||
struct resolv_context *ctx = __resolv_context_get ();
|
||
if (ctx == NULL)
|
||
@@ -524,8 +548,6 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
|
||
return NSS_STATUS_UNAVAIL;
|
||
}
|
||
|
||
- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
|
||
-
|
||
switch (af)
|
||
{
|
||
case AF_INET:
|
||
@@ -549,36 +571,52 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
|
||
break;
|
||
}
|
||
|
||
- n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
|
||
- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
|
||
+ unsigned char dns_packet_buffer[1024];
|
||
+ unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
|
||
+ n = __res_context_query (ctx, qbuf, C_IN, T_PTR,
|
||
+ dns_packet_buffer, sizeof (dns_packet_buffer),
|
||
+ &alt_dns_packet_buffer,
|
||
+ NULL, NULL, NULL, NULL);
|
||
if (n < 0)
|
||
{
|
||
*h_errnop = h_errno;
|
||
__set_errno (olderr);
|
||
- if (host_buffer.buf != orig_host_buffer)
|
||
- free (host_buffer.buf);
|
||
+ if (alt_dns_packet_buffer != dns_packet_buffer)
|
||
+ free (alt_dns_packet_buffer);
|
||
__resolv_context_put (ctx);
|
||
return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
|
||
}
|
||
|
||
- status = getanswer_r
|
||
- (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
|
||
- errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
|
||
- if (host_buffer.buf != orig_host_buffer)
|
||
- free (host_buffer.buf);
|
||
+ status = getanswer_ptr (alt_dns_packet_buffer, n,
|
||
+ &abuf, &result->h_name, errnop, h_errnop, ttlp);
|
||
+
|
||
+ if (alt_dns_packet_buffer != dns_packet_buffer)
|
||
+ free (alt_dns_packet_buffer);
|
||
+ __resolv_context_put (ctx);
|
||
+
|
||
if (status != NSS_STATUS_SUCCESS)
|
||
- {
|
||
- __resolv_context_put (ctx);
|
||
- return status;
|
||
- }
|
||
+ return status;
|
||
|
||
+ /* result->h_name has already been set by getanswer_ptr. */
|
||
result->h_addrtype = af;
|
||
result->h_length = len;
|
||
- memcpy (host_data->host_addr, addr, len);
|
||
- host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
|
||
- host_data->h_addr_ptrs[1] = NULL;
|
||
+ /* Increase the alignment to 4, in case there are applications out
|
||
+ there that expect at least this level of address alignment. */
|
||
+ address_array[0] = (char *) alloc_buffer_next (&abuf, uint32_t);
|
||
+ alloc_buffer_copy_bytes (&abuf, uaddr, len);
|
||
+ address_array[1] = NULL;
|
||
+
|
||
+ /* This check also covers allocation failure in getanswer_ptr. */
|
||
+ if (alloc_buffer_has_failed (&abuf))
|
||
+ {
|
||
+ *errnop = ERANGE;
|
||
+ *h_errnop = NETDB_INTERNAL;
|
||
+ return NSS_STATUS_TRYAGAIN;
|
||
+ }
|
||
+ result->h_addr_list = address_array;
|
||
+ result->h_aliases = &address_array[1]; /* Points to NULL. */
|
||
+
|
||
*h_errnop = NETDB_SUCCESS;
|
||
- __resolv_context_put (ctx);
|
||
return NSS_STATUS_SUCCESS;
|
||
}
|
||
libc_hidden_def (_nss_dns_gethostbyaddr2_r)
|
||
@@ -640,650 +678,362 @@ addrsort (struct resolv_context *ctx, char **ap, int num)
|
||
break;
|
||
}
|
||
|
||
-static enum nss_status
|
||
-getanswer_r (struct resolv_context *ctx,
|
||
- const querybuf *answer, int anslen, const char *qname, int qtype,
|
||
- struct hostent *result, char *buffer, size_t buflen,
|
||
- int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp)
|
||
+/* Convert the uncompressed, binary domain name CDNAME into its
|
||
+ textual representation and add it to the end of ALIASES, allocating
|
||
+ space for a copy of the name from ABUF. Skip adding the name if it
|
||
+ is not a valid host name, and return false in that case, otherwise
|
||
+ true. */
|
||
+static bool
|
||
+getanswer_r_store_alias (const unsigned char *cdname,
|
||
+ struct alloc_buffer *abuf,
|
||
+ struct ptrlist *aliases)
|
||
{
|
||
- struct host_data
|
||
- {
|
||
- char *aliases[MAX_NR_ALIASES];
|
||
- unsigned char host_addr[16]; /* IPv4 or IPv6 */
|
||
- char *h_addr_ptrs[0];
|
||
- } *host_data;
|
||
- int linebuflen;
|
||
- const HEADER *hp;
|
||
- const u_char *end_of_message, *cp;
|
||
- int n, ancount, qdcount;
|
||
- int haveanswer, had_error;
|
||
- char *bp, **ap, **hap;
|
||
- char tbuf[MAXDNAME];
|
||
- const char *tname;
|
||
- int (*name_ok) (const char *);
|
||
- u_char packtmp[NS_MAXCDNAME];
|
||
- int have_to_map = 0;
|
||
- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
|
||
- buffer += pad;
|
||
- buflen = buflen > pad ? buflen - pad : 0;
|
||
- if (__glibc_unlikely (buflen < sizeof (struct host_data)))
|
||
- {
|
||
- /* The buffer is too small. */
|
||
- too_small:
|
||
- *errnop = ERANGE;
|
||
- *h_errnop = NETDB_INTERNAL;
|
||
- return NSS_STATUS_TRYAGAIN;
|
||
- }
|
||
- host_data = (struct host_data *) buffer;
|
||
- linebuflen = buflen - sizeof (struct host_data);
|
||
- if (buflen - sizeof (struct host_data) != linebuflen)
|
||
- linebuflen = INT_MAX;
|
||
-
|
||
- tname = qname;
|
||
- result->h_name = NULL;
|
||
- end_of_message = answer->buf + anslen;
|
||
- switch (qtype)
|
||
- {
|
||
- case T_A:
|
||
- case T_AAAA:
|
||
- name_ok = __libc_res_hnok;
|
||
- break;
|
||
- case T_PTR:
|
||
- name_ok = __libc_res_dnok;
|
||
- break;
|
||
- default:
|
||
- *errnop = ENOENT;
|
||
- return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */
|
||
- }
|
||
+ /* Filter out domain names that are not host names. */
|
||
+ if (!__res_binary_hnok (cdname))
|
||
+ return false;
|
||
+
|
||
+ /* Note: Not NS_MAXCDNAME, so that __ns_name_ntop implicitly checks
|
||
+ for length. */
|
||
+ char dname[MAXHOSTNAMELEN + 1];
|
||
+ if (__ns_name_ntop (cdname, dname, sizeof (dname)) < 0)
|
||
+ return false;
|
||
+ /* Do not report an error on allocation failure, instead store NULL
|
||
+ or do nothing. getanswer_r's caller will see NSS_STATUS_SUCCESS
|
||
+ and detect the memory allocation failure or buffer space
|
||
+ exhaustion, and report it accordingly. */
|
||
+ ptrlist_add (aliases, alloc_buffer_copy_string (abuf, dname));
|
||
+ return true;
|
||
+}
|
||
|
||
- /*
|
||
- * find first satisfactory answer
|
||
- */
|
||
- hp = &answer->hdr;
|
||
- ancount = ntohs (hp->ancount);
|
||
- qdcount = ntohs (hp->qdcount);
|
||
- cp = answer->buf + HFIXEDSZ;
|
||
- if (__glibc_unlikely (qdcount != 1))
|
||
+static enum nss_status __attribute__ ((noinline))
|
||
+getanswer_r (unsigned char *packet, size_t packetlen, uint16_t qtype,
|
||
+ struct alloc_buffer *abuf,
|
||
+ struct ptrlist *addresses, struct ptrlist *aliases,
|
||
+ int *errnop, int *h_errnop, int32_t *ttlp)
|
||
+{
|
||
+ struct ns_rr_cursor c;
|
||
+ if (!__ns_rr_cursor_init (&c, packet, packetlen))
|
||
{
|
||
+ /* This should not happen because __res_context_query already
|
||
+ perfroms response validation. */
|
||
*h_errnop = NO_RECOVERY;
|
||
return NSS_STATUS_UNAVAIL;
|
||
}
|
||
- if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen)
|
||
- goto too_small;
|
||
- bp = (char *) &host_data->h_addr_ptrs[ancount + 1];
|
||
- linebuflen -= (ancount + 1) * sizeof (char *);
|
||
-
|
||
- n = __ns_name_unpack (answer->buf, end_of_message, cp,
|
||
- packtmp, sizeof packtmp);
|
||
- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
|
||
- {
|
||
- if (__glibc_unlikely (errno == EMSGSIZE))
|
||
- goto too_small;
|
||
|
||
- n = -1;
|
||
- }
|
||
-
|
||
- if (__glibc_unlikely (n < 0))
|
||
+ /* Treat the QNAME just like an alias. Error out if it is not a
|
||
+ valid host name. */
|
||
+ if (ns_rr_cursor_rcode (&c) == NXDOMAIN
|
||
+ || !getanswer_r_store_alias (ns_rr_cursor_qname (&c), abuf, aliases))
|
||
{
|
||
- *errnop = errno;
|
||
- *h_errnop = NO_RECOVERY;
|
||
- return NSS_STATUS_UNAVAIL;
|
||
- }
|
||
- if (__glibc_unlikely (name_ok (bp) == 0))
|
||
- {
|
||
- errno = EBADMSG;
|
||
- *errnop = EBADMSG;
|
||
- *h_errnop = NO_RECOVERY;
|
||
- return NSS_STATUS_UNAVAIL;
|
||
+ if (ttlp != NULL)
|
||
+ /* No negative caching. */
|
||
+ *ttlp = 0;
|
||
+ *h_errnop = HOST_NOT_FOUND;
|
||
+ *errnop = ENOENT;
|
||
+ return NSS_STATUS_NOTFOUND;
|
||
}
|
||
- cp += n + QFIXEDSZ;
|
||
|
||
- if (qtype == T_A || qtype == T_AAAA)
|
||
+ int ancount = ns_rr_cursor_ancount (&c);
|
||
+ const unsigned char *expected_name = ns_rr_cursor_qname (&c);
|
||
+ /* expected_name may be updated to point into this buffer. */
|
||
+ unsigned char name_buffer[NS_MAXCDNAME];
|
||
+
|
||
+ for (; ancount > 0; --ancount)
|
||
{
|
||
- /* res_send() has already verified that the query name is the
|
||
- * same as the one we sent; this just gets the expanded name
|
||
- * (i.e., with the succeeding search-domain tacked on).
|
||
- */
|
||
- n = strlen (bp) + 1; /* for the \0 */
|
||
- if (n >= MAXHOSTNAMELEN)
|
||
+ struct ns_rr_wire rr;
|
||
+ if (!__ns_rr_cursor_next (&c, &rr))
|
||
{
|
||
*h_errnop = NO_RECOVERY;
|
||
- *errnop = ENOENT;
|
||
- return NSS_STATUS_TRYAGAIN;
|
||
+ return NSS_STATUS_UNAVAIL;
|
||
}
|
||
- result->h_name = bp;
|
||
- bp += n;
|
||
- linebuflen -= n;
|
||
- if (linebuflen < 0)
|
||
- goto too_small;
|
||
- /* The qname can be abbreviated, but h_name is now absolute. */
|
||
- qname = result->h_name;
|
||
- }
|
||
|
||
- ap = host_data->aliases;
|
||
- *ap = NULL;
|
||
- result->h_aliases = host_data->aliases;
|
||
- hap = host_data->h_addr_ptrs;
|
||
- *hap = NULL;
|
||
- result->h_addr_list = host_data->h_addr_ptrs;
|
||
- haveanswer = 0;
|
||
- had_error = 0;
|
||
+ /* Skip over records with the wrong class. */
|
||
+ if (rr.rclass != C_IN)
|
||
+ continue;
|
||
|
||
- while (ancount-- > 0 && cp < end_of_message && had_error == 0)
|
||
- {
|
||
- int type, class;
|
||
+ /* Update TTL for recognized record types. */
|
||
+ if ((rr.rtype == T_CNAME || rr.rtype == qtype)
|
||
+ && ttlp != NULL && *ttlp > rr.ttl)
|
||
+ *ttlp = rr.ttl;
|
||
|
||
- n = __ns_name_unpack (answer->buf, end_of_message, cp,
|
||
- packtmp, sizeof packtmp);
|
||
- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
|
||
+ if (rr.rtype == T_CNAME)
|
||
{
|
||
- if (__glibc_unlikely (errno == EMSGSIZE))
|
||
- goto too_small;
|
||
-
|
||
- n = -1;
|
||
+ /* NB: No check for owner name match, based on historic
|
||
+ precedent. Record the CNAME target as the new expected
|
||
+ name. */
|
||
+ int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
|
||
+ name_buffer, sizeof (name_buffer));
|
||
+ if (n < 0)
|
||
+ {
|
||
+ *h_errnop = NO_RECOVERY;
|
||
+ return NSS_STATUS_UNAVAIL;
|
||
+ }
|
||
+ /* And store the new name as an alias. */
|
||
+ getanswer_r_store_alias (name_buffer, abuf, aliases);
|
||
+ expected_name = name_buffer;
|
||
}
|
||
-
|
||
- if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0))
|
||
+ else if (rr.rtype == qtype
|
||
+ && __ns_samebinaryname (rr.rname, expected_name)
|
||
+ && rr.rdlength == rrtype_to_rdata_length (qtype))
|
||
{
|
||
- ++had_error;
|
||
- continue;
|
||
+ /* Make a copy of the address and store it. Increase the
|
||
+ alignment to 4, in case there are applications out there
|
||
+ that expect at least this level of address alignment. */
|
||
+ ptrlist_add (addresses, (char *) alloc_buffer_next (abuf, uint32_t));
|
||
+ alloc_buffer_copy_bytes (abuf, rr.rdata, rr.rdlength);
|
||
}
|
||
- cp += n; /* name */
|
||
+ }
|
||
|
||
- if (__glibc_unlikely (cp + 10 > end_of_message))
|
||
- {
|
||
- ++had_error;
|
||
- continue;
|
||
- }
|
||
+ if (ptrlist_size (addresses) == 0)
|
||
+ {
|
||
+ /* No address record found. */
|
||
+ if (ttlp != NULL)
|
||
+ /* No caching of negative responses. */
|
||
+ *ttlp = 0;
|
||
|
||
- NS_GET16 (type, cp);
|
||
- NS_GET16 (class, cp);
|
||
- int32_t ttl;
|
||
- NS_GET32 (ttl, cp);
|
||
- NS_GET16 (n, cp); /* RDATA length. */
|
||
+ *h_errnop = NO_RECOVERY;
|
||
+ *errnop = ENOENT;
|
||
+ return NSS_STATUS_TRYAGAIN;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ *h_errnop = NETDB_SUCCESS;
|
||
+ return NSS_STATUS_SUCCESS;
|
||
+ }
|
||
+}
|
||
|
||
- if (end_of_message - cp < n)
|
||
- {
|
||
- /* RDATA extends beyond the end of the packet. */
|
||
- ++had_error;
|
||
- continue;
|
||
- }
|
||
+static enum nss_status
|
||
+getanswer_ptr (unsigned char *packet, size_t packetlen,
|
||
+ struct alloc_buffer *abuf, char **hnamep,
|
||
+ int *errnop, int *h_errnop, int32_t *ttlp)
|
||
+{
|
||
+ struct ns_rr_cursor c;
|
||
+ if (!__ns_rr_cursor_init (&c, packet, packetlen))
|
||
+ {
|
||
+ /* This should not happen because __res_context_query already
|
||
+ perfroms response validation. */
|
||
+ *h_errnop = NO_RECOVERY;
|
||
+ return NSS_STATUS_UNAVAIL;
|
||
+ }
|
||
+ int ancount = ns_rr_cursor_ancount (&c);
|
||
+ const unsigned char *expected_name = ns_rr_cursor_qname (&c);
|
||
+ /* expected_name may be updated to point into this buffer. */
|
||
+ unsigned char name_buffer[NS_MAXCDNAME];
|
||
|
||
- if (__glibc_unlikely (class != C_IN))
|
||
+ while (ancount > 0)
|
||
+ {
|
||
+ struct ns_rr_wire rr;
|
||
+ if (!__ns_rr_cursor_next (&c, &rr))
|
||
{
|
||
- /* XXX - debug? syslog? */
|
||
- cp += n;
|
||
- continue; /* XXX - had_error++ ? */
|
||
+ *h_errnop = NO_RECOVERY;
|
||
+ return NSS_STATUS_UNAVAIL;
|
||
}
|
||
|
||
- if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
|
||
- {
|
||
- /* A CNAME could also have a TTL entry. */
|
||
- if (ttlp != NULL && ttl < *ttlp)
|
||
- *ttlp = ttl;
|
||
-
|
||
- if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
|
||
- continue;
|
||
- n = __libc_dn_expand (answer->buf, end_of_message, cp,
|
||
- tbuf, sizeof tbuf);
|
||
- if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0))
|
||
- {
|
||
- ++had_error;
|
||
- continue;
|
||
- }
|
||
- cp += n;
|
||
- /* Store alias. */
|
||
- *ap++ = bp;
|
||
- n = strlen (bp) + 1; /* For the \0. */
|
||
- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
|
||
- {
|
||
- ++had_error;
|
||
- continue;
|
||
- }
|
||
- bp += n;
|
||
- linebuflen -= n;
|
||
- /* Get canonical name. */
|
||
- n = strlen (tbuf) + 1; /* For the \0. */
|
||
- if (__glibc_unlikely (n > linebuflen))
|
||
- goto too_small;
|
||
- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
|
||
- {
|
||
- ++had_error;
|
||
- continue;
|
||
- }
|
||
- result->h_name = bp;
|
||
- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
|
||
- linebuflen -= n;
|
||
- continue;
|
||
- }
|
||
+ /* Skip over records with the wrong class. */
|
||
+ if (rr.rclass != C_IN)
|
||
+ continue;
|
||
|
||
- if (qtype == T_PTR && type == T_CNAME)
|
||
- {
|
||
- /* A CNAME could also have a TTL entry. */
|
||
- if (ttlp != NULL && ttl < *ttlp)
|
||
- *ttlp = ttl;
|
||
+ /* Update TTL for known record types. */
|
||
+ if ((rr.rtype == T_CNAME || rr.rtype == T_PTR)
|
||
+ && ttlp != NULL && *ttlp > rr.ttl)
|
||
+ *ttlp = rr.ttl;
|
||
|
||
- n = __libc_dn_expand (answer->buf, end_of_message, cp,
|
||
- tbuf, sizeof tbuf);
|
||
- if (__glibc_unlikely (n < 0 || __libc_res_dnok (tbuf) == 0))
|
||
- {
|
||
- ++had_error;
|
||
- continue;
|
||
- }
|
||
- cp += n;
|
||
- /* Get canonical name. */
|
||
- n = strlen (tbuf) + 1; /* For the \0. */
|
||
- if (__glibc_unlikely (n > linebuflen))
|
||
- goto too_small;
|
||
- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
|
||
+ if (rr.rtype == T_CNAME)
|
||
+ {
|
||
+ /* NB: No check for owner name match, based on historic
|
||
+ precedent. Record the CNAME target as the new expected
|
||
+ name. */
|
||
+ int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
|
||
+ name_buffer, sizeof (name_buffer));
|
||
+ if (n < 0)
|
||
{
|
||
- ++had_error;
|
||
- continue;
|
||
+ *h_errnop = NO_RECOVERY;
|
||
+ return NSS_STATUS_UNAVAIL;
|
||
}
|
||
- tname = bp;
|
||
- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
|
||
- linebuflen -= n;
|
||
- continue;
|
||
+ expected_name = name_buffer;
|
||
}
|
||
-
|
||
- if (type == T_A && qtype == T_AAAA && map)
|
||
- have_to_map = 1;
|
||
- else if (__glibc_unlikely (type != qtype))
|
||
+ else if (rr.rtype == T_PTR
|
||
+ && __ns_samebinaryname (rr.rname, expected_name))
|
||
{
|
||
- cp += n;
|
||
- continue; /* XXX - had_error++ ? */
|
||
- }
|
||
-
|
||
- switch (type)
|
||
- {
|
||
- case T_PTR:
|
||
- if (__glibc_unlikely (__strcasecmp (tname, bp) != 0))
|
||
+ /* Decompress the target of the PTR record. This is the
|
||
+ host name we are looking for. We can only use it if it
|
||
+ is syntactically valid. Historically, only one host name
|
||
+ is returned here. If the recursive resolver performs DNS
|
||
+ record rotation, the returned host name is essentially
|
||
+ random, which is why multiple PTR records are rarely
|
||
+ used. Use MAXHOSTNAMELEN instead of NS_MAXCDNAME for
|
||
+ additional length checking. */
|
||
+ char hname[MAXHOSTNAMELEN + 1];
|
||
+ if (__ns_name_unpack (c.begin, c.end, rr.rdata,
|
||
+ name_buffer, sizeof (name_buffer)) < 0
|
||
+ || !__res_binary_hnok (expected_name)
|
||
+ || __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0)
|
||
{
|
||
- cp += n;
|
||
- continue; /* XXX - had_error++ ? */
|
||
+ *h_errnop = NO_RECOVERY;
|
||
+ return NSS_STATUS_UNAVAIL;
|
||
}
|
||
-
|
||
- n = __ns_name_unpack (answer->buf, end_of_message, cp,
|
||
- packtmp, sizeof packtmp);
|
||
- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
|
||
- {
|
||
- if (__glibc_unlikely (errno == EMSGSIZE))
|
||
- goto too_small;
|
||
-
|
||
- n = -1;
|
||
- }
|
||
-
|
||
- if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0))
|
||
- {
|
||
- ++had_error;
|
||
- break;
|
||
- }
|
||
- if (ttlp != NULL && ttl < *ttlp)
|
||
- *ttlp = ttl;
|
||
- /* bind would put multiple PTR records as aliases, but we don't do
|
||
- that. */
|
||
- result->h_name = bp;
|
||
- *h_errnop = NETDB_SUCCESS;
|
||
+ /* Successful allocation is checked by the caller. */
|
||
+ *hnamep = alloc_buffer_copy_string (abuf, hname);
|
||
return NSS_STATUS_SUCCESS;
|
||
- case T_A:
|
||
- case T_AAAA:
|
||
- if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0))
|
||
- {
|
||
- cp += n;
|
||
- continue; /* XXX - had_error++ ? */
|
||
- }
|
||
-
|
||
- /* Stop parsing at a record whose length is incorrect. */
|
||
- if (n != rrtype_to_rdata_length (type))
|
||
- {
|
||
- ++had_error;
|
||
- break;
|
||
- }
|
||
-
|
||
- /* Skip records of the wrong type. */
|
||
- if (n != result->h_length)
|
||
- {
|
||
- cp += n;
|
||
- continue;
|
||
- }
|
||
- if (!haveanswer)
|
||
- {
|
||
- int nn;
|
||
-
|
||
- /* We compose a single hostent out of the entire chain of
|
||
- entries, so the TTL of the hostent is essentially the lowest
|
||
- TTL in the chain. */
|
||
- if (ttlp != NULL && ttl < *ttlp)
|
||
- *ttlp = ttl;
|
||
- if (canonp != NULL)
|
||
- *canonp = bp;
|
||
- result->h_name = bp;
|
||
- nn = strlen (bp) + 1; /* for the \0 */
|
||
- bp += nn;
|
||
- linebuflen -= nn;
|
||
- }
|
||
-
|
||
- /* Provide sufficient alignment for both address
|
||
- families. */
|
||
- enum { align = 4 };
|
||
- _Static_assert ((align % __alignof__ (struct in_addr)) == 0,
|
||
- "struct in_addr alignment");
|
||
- _Static_assert ((align % __alignof__ (struct in6_addr)) == 0,
|
||
- "struct in6_addr alignment");
|
||
- {
|
||
- char *new_bp = PTR_ALIGN_UP (bp, align);
|
||
- linebuflen -= new_bp - bp;
|
||
- bp = new_bp;
|
||
- }
|
||
-
|
||
- if (__glibc_unlikely (n > linebuflen))
|
||
- goto too_small;
|
||
- bp = __mempcpy (*hap++ = bp, cp, n);
|
||
- cp += n;
|
||
- linebuflen -= n;
|
||
- break;
|
||
- default:
|
||
- abort ();
|
||
}
|
||
- if (had_error == 0)
|
||
- ++haveanswer;
|
||
}
|
||
|
||
- if (haveanswer > 0)
|
||
- {
|
||
- *ap = NULL;
|
||
- *hap = NULL;
|
||
- /*
|
||
- * Note: we sort even if host can take only one address
|
||
- * in its return structures - should give it the "best"
|
||
- * address in that case, not some random one
|
||
- */
|
||
- if (haveanswer > 1 && qtype == T_A
|
||
- && __resolv_context_sort_count (ctx) > 0)
|
||
- addrsort (ctx, host_data->h_addr_ptrs, haveanswer);
|
||
-
|
||
- if (result->h_name == NULL)
|
||
- {
|
||
- n = strlen (qname) + 1; /* For the \0. */
|
||
- if (n > linebuflen)
|
||
- goto too_small;
|
||
- if (n >= MAXHOSTNAMELEN)
|
||
- goto no_recovery;
|
||
- result->h_name = bp;
|
||
- bp = __mempcpy (bp, qname, n); /* Cannot overflow. */
|
||
- linebuflen -= n;
|
||
- }
|
||
+ /* No PTR record found. */
|
||
+ if (ttlp != NULL)
|
||
+ /* No caching of negative responses. */
|
||
+ *ttlp = 0;
|
||
|
||
- if (have_to_map)
|
||
- if (map_v4v6_hostent (result, &bp, &linebuflen))
|
||
- goto too_small;
|
||
- *h_errnop = NETDB_SUCCESS;
|
||
- return NSS_STATUS_SUCCESS;
|
||
- }
|
||
- no_recovery:
|
||
*h_errnop = NO_RECOVERY;
|
||
*errnop = ENOENT;
|
||
- /* Special case here: if the resolver sent a result but it only
|
||
- contains a CNAME while we are looking for a T_A or T_AAAA record,
|
||
- we fail with NOTFOUND instead of TRYAGAIN. */
|
||
- return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
|
||
- ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
|
||
+ return NSS_STATUS_TRYAGAIN;
|
||
}
|
||
|
||
-
|
||
+/* Parses DNS data found in PACKETLEN bytes at PACKET in struct
|
||
+ gaih_addrtuple address tuples. The new address tuples are linked
|
||
+ from **TAILP, with backing store allocated from ABUF, and *TAILP is
|
||
+ updated to point where the next tuple pointer should be stored. If
|
||
+ TTLP is not null, *TTLP is updated to reflect the minimum TTL. If
|
||
+ STORE_CANON is true, the canonical name is stored as part of the
|
||
+ first address tuple being written. */
|
||
static enum nss_status
|
||
-gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
|
||
- struct gaih_addrtuple ***patp,
|
||
- char **bufferp, size_t *buflenp,
|
||
- int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
|
||
+gaih_getanswer_slice (unsigned char *packet, size_t packetlen,
|
||
+ struct alloc_buffer *abuf,
|
||
+ struct gaih_addrtuple ***tailp,
|
||
+ int *errnop, int *h_errnop, int32_t *ttlp,
|
||
+ bool store_canon)
|
||
{
|
||
- char *buffer = *bufferp;
|
||
- size_t buflen = *buflenp;
|
||
-
|
||
- struct gaih_addrtuple **pat = *patp;
|
||
- const HEADER *hp = &answer->hdr;
|
||
- int ancount = ntohs (hp->ancount);
|
||
- int qdcount = ntohs (hp->qdcount);
|
||
- const u_char *cp = answer->buf + HFIXEDSZ;
|
||
- const u_char *end_of_message = answer->buf + anslen;
|
||
- if (__glibc_unlikely (qdcount != 1))
|
||
- {
|
||
- *h_errnop = NO_RECOVERY;
|
||
- return NSS_STATUS_UNAVAIL;
|
||
- }
|
||
-
|
||
- u_char packtmp[NS_MAXCDNAME];
|
||
- int n = __ns_name_unpack (answer->buf, end_of_message, cp,
|
||
- packtmp, sizeof packtmp);
|
||
- /* We unpack the name to check it for validity. But we do not need
|
||
- it later. */
|
||
- if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
|
||
- {
|
||
- if (__glibc_unlikely (errno == EMSGSIZE))
|
||
- {
|
||
- too_small:
|
||
- *errnop = ERANGE;
|
||
- *h_errnop = NETDB_INTERNAL;
|
||
- return NSS_STATUS_TRYAGAIN;
|
||
- }
|
||
-
|
||
- n = -1;
|
||
- }
|
||
-
|
||
- if (__glibc_unlikely (n < 0))
|
||
+ struct ns_rr_cursor c;
|
||
+ if (!__ns_rr_cursor_init (&c, packet, packetlen))
|
||
{
|
||
- *errnop = errno;
|
||
+ /* This should not happen because __res_context_query already
|
||
+ perfroms response validation. */
|
||
*h_errnop = NO_RECOVERY;
|
||
return NSS_STATUS_UNAVAIL;
|
||
}
|
||
- if (__glibc_unlikely (__libc_res_hnok (buffer) == 0))
|
||
- {
|
||
- errno = EBADMSG;
|
||
- *errnop = EBADMSG;
|
||
- *h_errnop = NO_RECOVERY;
|
||
- return NSS_STATUS_UNAVAIL;
|
||
- }
|
||
- cp += n + QFIXEDSZ;
|
||
-
|
||
- int haveanswer = 0;
|
||
- int had_error = 0;
|
||
- char *canon = NULL;
|
||
- char *h_name = NULL;
|
||
- int h_namelen = 0;
|
||
-
|
||
- if (ancount == 0)
|
||
+ bool haveanswer = false; /* Set to true if at least one address. */
|
||
+ uint16_t qtype = ns_rr_cursor_qtype (&c);
|
||
+ int ancount = ns_rr_cursor_ancount (&c);
|
||
+ const unsigned char *expected_name = ns_rr_cursor_qname (&c);
|
||
+ /* expected_name may be updated to point into this buffer. */
|
||
+ unsigned char name_buffer[NS_MAXCDNAME];
|
||
+
|
||
+ /* This is a pointer to a possibly-compressed name in the packet.
|
||
+ Eventually it is equivalent to the canonical name. If needed, it
|
||
+ is uncompressed and translated to text form when the first
|
||
+ address tuple is encountered. */
|
||
+ const unsigned char *compressed_alias_name = expected_name;
|
||
+
|
||
+ if (ancount == 0 || !__res_binary_hnok (compressed_alias_name))
|
||
{
|
||
*h_errnop = HOST_NOT_FOUND;
|
||
return NSS_STATUS_NOTFOUND;
|
||
}
|
||
|
||
- while (ancount-- > 0 && cp < end_of_message && had_error == 0)
|
||
+ for (; ancount > -0; --ancount)
|
||
{
|
||
- n = __ns_name_unpack (answer->buf, end_of_message, cp,
|
||
- packtmp, sizeof packtmp);
|
||
- if (n != -1 &&
|
||
- (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
|
||
+ struct ns_rr_wire rr;
|
||
+ if (!__ns_rr_cursor_next (&c, &rr))
|
||
{
|
||
- if (__glibc_unlikely (errno == EMSGSIZE))
|
||
- goto too_small;
|
||
-
|
||
- n = -1;
|
||
- }
|
||
- if (__glibc_unlikely (n < 0 || __libc_res_hnok (buffer) == 0))
|
||
- {
|
||
- ++had_error;
|
||
- continue;
|
||
- }
|
||
- if (*firstp && canon == NULL)
|
||
- {
|
||
- h_name = buffer;
|
||
- buffer += h_namelen;
|
||
- buflen -= h_namelen;
|
||
- }
|
||
-
|
||
- cp += n; /* name */
|
||
-
|
||
- if (__glibc_unlikely (cp + 10 > end_of_message))
|
||
- {
|
||
- ++had_error;
|
||
- continue;
|
||
+ *h_errnop = NO_RECOVERY;
|
||
+ return NSS_STATUS_UNAVAIL;
|
||
}
|
||
|
||
- uint16_t type;
|
||
- NS_GET16 (type, cp);
|
||
- uint16_t class;
|
||
- NS_GET16 (class, cp);
|
||
- int32_t ttl;
|
||
- NS_GET32 (ttl, cp);
|
||
- NS_GET16 (n, cp); /* RDATA length. */
|
||
+ /* Update TTL for known record types. */
|
||
+ if ((rr.rtype == T_CNAME || rr.rtype == qtype)
|
||
+ && ttlp != NULL && *ttlp > rr.ttl)
|
||
+ *ttlp = rr.ttl;
|
||
|
||
- if (end_of_message - cp < n)
|
||
+ if (rr.rtype == T_CNAME)
|
||
{
|
||
- /* RDATA extends beyond the end of the packet. */
|
||
- ++had_error;
|
||
- continue;
|
||
- }
|
||
-
|
||
- if (class != C_IN)
|
||
- {
|
||
- cp += n;
|
||
- continue;
|
||
- }
|
||
-
|
||
- if (type == T_CNAME)
|
||
- {
|
||
- char tbuf[MAXDNAME];
|
||
-
|
||
- /* A CNAME could also have a TTL entry. */
|
||
- if (ttlp != NULL && ttl < *ttlp)
|
||
- *ttlp = ttl;
|
||
-
|
||
- n = __libc_dn_expand (answer->buf, end_of_message, cp,
|
||
- tbuf, sizeof tbuf);
|
||
- if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0))
|
||
+ /* NB: No check for owner name match, based on historic
|
||
+ precedent. Record the CNAME target as the new expected
|
||
+ name. */
|
||
+ int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
|
||
+ name_buffer, sizeof (name_buffer));
|
||
+ if (n < 0)
|
||
{
|
||
- ++had_error;
|
||
- continue;
|
||
- }
|
||
- cp += n;
|
||
-
|
||
- if (*firstp)
|
||
- {
|
||
- /* Reclaim buffer space. */
|
||
- if (h_name + h_namelen == buffer)
|
||
- {
|
||
- buffer = h_name;
|
||
- buflen += h_namelen;
|
||
- }
|
||
-
|
||
- n = strlen (tbuf) + 1;
|
||
- if (__glibc_unlikely (n > buflen))
|
||
- goto too_small;
|
||
- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
|
||
- {
|
||
- ++had_error;
|
||
- continue;
|
||
- }
|
||
-
|
||
- canon = buffer;
|
||
- buffer = __mempcpy (buffer, tbuf, n);
|
||
- buflen -= n;
|
||
- h_namelen = 0;
|
||
+ *h_errnop = NO_RECOVERY;
|
||
+ return NSS_STATUS_UNAVAIL;
|
||
}
|
||
- continue;
|
||
+ expected_name = name_buffer;
|
||
+ if (store_canon && __res_binary_hnok (name_buffer))
|
||
+ /* This name can be used as a canonical name. Do not
|
||
+ translate to text form here to conserve buffer space.
|
||
+ Point to the compressed name because name_buffer can be
|
||
+ overwritten with an unusable name later. */
|
||
+ compressed_alias_name = rr.rdata;
|
||
}
|
||
-
|
||
- /* Stop parsing if we encounter a record with incorrect RDATA
|
||
- length. */
|
||
- if (type == T_A || type == T_AAAA)
|
||
+ else if (rr.rtype == qtype
|
||
+ && __ns_samebinaryname (rr.rname, expected_name)
|
||
+ && rr.rdlength == rrtype_to_rdata_length (qtype))
|
||
{
|
||
- if (n != rrtype_to_rdata_length (type))
|
||
+ struct gaih_addrtuple *ntup
|
||
+ = alloc_buffer_alloc (abuf, struct gaih_addrtuple);
|
||
+ /* Delay error reporting to the callers (they implement the
|
||
+ ERANGE buffer resizing handshake). */
|
||
+ if (ntup != NULL)
|
||
{
|
||
- ++had_error;
|
||
- continue;
|
||
+ ntup->next = NULL;
|
||
+ if (store_canon && compressed_alias_name != NULL)
|
||
+ {
|
||
+ /* This assumes that all the CNAME records come
|
||
+ first. Use MAXHOSTNAMELEN instead of
|
||
+ NS_MAXCDNAME for additional length checking.
|
||
+ However, these checks are not expected to fail
|
||
+ because all size NS_MAXCDNAME names should into
|
||
+ the hname buffer because no escaping is
|
||
+ needed. */
|
||
+ char unsigned nbuf[NS_MAXCDNAME];
|
||
+ char hname[MAXHOSTNAMELEN + 1];
|
||
+ if (__ns_name_unpack (c.begin, c.end,
|
||
+ compressed_alias_name,
|
||
+ nbuf, sizeof (nbuf)) >= 0
|
||
+ && __ns_name_ntop (nbuf, hname, sizeof (hname)) >= 0)
|
||
+ /* Space checking is performed by the callers. */
|
||
+ ntup->name = alloc_buffer_copy_string (abuf, hname);
|
||
+ store_canon = false;
|
||
+ }
|
||
+ else
|
||
+ ntup->name = NULL;
|
||
+ if (rr.rdlength == 4)
|
||
+ ntup->family = AF_INET;
|
||
+ else
|
||
+ ntup->family = AF_INET6;
|
||
+ memcpy (ntup->addr, rr.rdata, rr.rdlength);
|
||
+ ntup->scopeid = 0;
|
||
+
|
||
+ /* Link in the new tuple, and update the tail pointer to
|
||
+ point to its next field. */
|
||
+ **tailp = ntup;
|
||
+ *tailp = &ntup->next;
|
||
+
|
||
+ haveanswer = true;
|
||
}
|
||
}
|
||
- else
|
||
- {
|
||
- /* Skip unknown records. */
|
||
- cp += n;
|
||
- continue;
|
||
- }
|
||
-
|
||
- assert (type == T_A || type == T_AAAA);
|
||
- if (*pat == NULL)
|
||
- {
|
||
- uintptr_t pad = (-(uintptr_t) buffer
|
||
- % __alignof__ (struct gaih_addrtuple));
|
||
- buffer += pad;
|
||
- buflen = buflen > pad ? buflen - pad : 0;
|
||
-
|
||
- if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple)))
|
||
- goto too_small;
|
||
-
|
||
- *pat = (struct gaih_addrtuple *) buffer;
|
||
- buffer += sizeof (struct gaih_addrtuple);
|
||
- buflen -= sizeof (struct gaih_addrtuple);
|
||
- }
|
||
-
|
||
- (*pat)->name = NULL;
|
||
- (*pat)->next = NULL;
|
||
-
|
||
- if (*firstp)
|
||
- {
|
||
- /* We compose a single hostent out of the entire chain of
|
||
- entries, so the TTL of the hostent is essentially the lowest
|
||
- TTL in the chain. */
|
||
- if (ttlp != NULL && ttl < *ttlp)
|
||
- *ttlp = ttl;
|
||
-
|
||
- (*pat)->name = canon ?: h_name;
|
||
-
|
||
- *firstp = 0;
|
||
- }
|
||
-
|
||
- (*pat)->family = type == T_A ? AF_INET : AF_INET6;
|
||
- memcpy ((*pat)->addr, cp, n);
|
||
- cp += n;
|
||
- (*pat)->scopeid = 0;
|
||
-
|
||
- pat = &((*pat)->next);
|
||
-
|
||
- haveanswer = 1;
|
||
}
|
||
|
||
if (haveanswer)
|
||
{
|
||
- *patp = pat;
|
||
- *bufferp = buffer;
|
||
- *buflenp = buflen;
|
||
-
|
||
*h_errnop = NETDB_SUCCESS;
|
||
return NSS_STATUS_SUCCESS;
|
||
}
|
||
-
|
||
- /* Special case here: if the resolver sent a result but it only
|
||
- contains a CNAME while we are looking for a T_A or T_AAAA record,
|
||
- we fail with NOTFOUND instead of TRYAGAIN. */
|
||
- if (canon != NULL)
|
||
+ else
|
||
{
|
||
+ /* Special case here: if the resolver sent a result but it only
|
||
+ contains a CNAME while we are looking for a T_A or T_AAAA
|
||
+ record, we fail with NOTFOUND. */
|
||
*h_errnop = HOST_NOT_FOUND;
|
||
return NSS_STATUS_NOTFOUND;
|
||
}
|
||
-
|
||
- *h_errnop = NETDB_INTERNAL;
|
||
- return NSS_STATUS_TRYAGAIN;
|
||
}
|
||
|
||
|
||
static enum nss_status
|
||
-gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
|
||
- int anslen2, const char *qname,
|
||
- struct gaih_addrtuple **pat, char *buffer, size_t buflen,
|
||
+gaih_getanswer (unsigned char *packet1, size_t packet1len,
|
||
+ unsigned char *packet2, size_t packet2len,
|
||
+ struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
|
||
int *errnop, int *h_errnop, int32_t *ttlp)
|
||
{
|
||
- int first = 1;
|
||
-
|
||
enum nss_status status = NSS_STATUS_NOTFOUND;
|
||
|
||
/* Combining the NSS status of two distinct queries requires some
|
||
@@ -1295,7 +1045,10 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
|
||
between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
|
||
A recoverable TRYAGAIN is almost always due to buffer size issues
|
||
and returns ERANGE in errno and the caller is expected to retry
|
||
- with a larger buffer.
|
||
+ with a larger buffer. (The caller, _nss_dns_gethostbyname4_r,
|
||
+ ignores the return status if it detects that the result buffer
|
||
+ has been exhausted and generates a TRYAGAIN failure with an
|
||
+ ERANGE code.)
|
||
|
||
Lastly, you may be tempted to make significant changes to the
|
||
conditions in this code to bring about symmetry between responses.
|
||
@@ -1375,36 +1128,30 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
|
||
is a recoverable error we now return TRYAGIN even if the first
|
||
response was SUCCESS. */
|
||
|
||
- if (anslen1 > 0)
|
||
- status = gaih_getanswer_slice(answer1, anslen1, qname,
|
||
- &pat, &buffer, &buflen,
|
||
- errnop, h_errnop, ttlp,
|
||
- &first);
|
||
-
|
||
- if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
|
||
- || (status == NSS_STATUS_TRYAGAIN
|
||
- /* We want to look at the second answer in case of an
|
||
- NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e.
|
||
- *h_errnop is NO_RECOVERY. If not, and if the failure was due to
|
||
- an insufficient buffer (ERANGE), then we need to drop the results
|
||
- and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can
|
||
- repeat the query with a larger buffer. */
|
||
- && (*errnop != ERANGE || *h_errnop == NO_RECOVERY)))
|
||
- && answer2 != NULL && anslen2 > 0)
|
||
+ if (packet1len > 0)
|
||
{
|
||
- enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
|
||
- &pat, &buffer, &buflen,
|
||
- errnop, h_errnop, ttlp,
|
||
- &first);
|
||
+ status = gaih_getanswer_slice (packet1, packet1len,
|
||
+ abuf, &pat, errnop, h_errnop, ttlp, true);
|
||
+ if (alloc_buffer_has_failed (abuf))
|
||
+ /* Do not try parsing the second packet if a larger result
|
||
+ buffer is needed. The caller implements the resizing
|
||
+ protocol because *abuf has been exhausted. */
|
||
+ return NSS_STATUS_TRYAGAIN; /* Ignored by the caller. */
|
||
+ }
|
||
+
|
||
+ if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
|
||
+ && packet2 != NULL && packet2len > 0)
|
||
+ {
|
||
+ enum nss_status status2
|
||
+ = gaih_getanswer_slice (packet2, packet2len,
|
||
+ abuf, &pat, errnop, h_errnop, ttlp,
|
||
+ /* Success means that data with a
|
||
+ canonical name has already been
|
||
+ stored. Do not store the name again. */
|
||
+ status != NSS_STATUS_SUCCESS);
|
||
/* Use the second response status in some cases. */
|
||
if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
|
||
status = status2;
|
||
- /* Do not return a truncated second response (unless it was
|
||
- unavoidable e.g. unrecoverable TRYAGAIN). */
|
||
- if (status == NSS_STATUS_SUCCESS
|
||
- && (status2 == NSS_STATUS_TRYAGAIN
|
||
- && *errnop == ERANGE && *h_errnop != NO_RECOVERY))
|
||
- status = NSS_STATUS_TRYAGAIN;
|
||
}
|
||
|
||
return status;
|
||
@@ -1412,18 +1159,13 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
|
||
|
||
/* Variant of gaih_getanswer without a second (AAAA) response. */
|
||
static enum nss_status
|
||
-gaih_getanswer_noaaaa (const querybuf *answer1, int anslen1, const char *qname,
|
||
- struct gaih_addrtuple **pat,
|
||
- char *buffer, size_t buflen,
|
||
+gaih_getanswer_noaaaa (unsigned char *packet, size_t packetlen,
|
||
+ struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
|
||
int *errnop, int *h_errnop, int32_t *ttlp)
|
||
{
|
||
- int first = 1;
|
||
-
|
||
enum nss_status status = NSS_STATUS_NOTFOUND;
|
||
- if (anslen1 > 0)
|
||
- status = gaih_getanswer_slice (answer1, anslen1, qname,
|
||
- &pat, &buffer, &buflen,
|
||
- errnop, h_errnop, ttlp,
|
||
- &first);
|
||
+ if (packetlen > 0)
|
||
+ status = gaih_getanswer_slice (packet, packetlen,
|
||
+ abuf, &pat, errnop, h_errnop, ttlp, true);
|
||
return status;
|
||
}
|
||
diff --git a/resolv/res-name-checking.c b/resolv/res-name-checking.c
|
||
index 07a412d8ff..213edceaf3 100644
|
||
--- a/resolv/res-name-checking.c
|
||
+++ b/resolv/res-name-checking.c
|
||
@@ -138,6 +138,12 @@ binary_leading_dash (const unsigned char *dn)
|
||
return dn[0] > 0 && dn[1] == '-';
|
||
}
|
||
|
||
+bool
|
||
+__res_binary_hnok (const unsigned char *dn)
|
||
+{
|
||
+ return !binary_leading_dash (dn) && binary_hnok (dn);
|
||
+}
|
||
+
|
||
/* Return 1 if res_hnok is a valid host name. Labels must only
|
||
contain [0-9a-zA-Z_-] characters, and the name must not start with
|
||
a '-'. The latter is to avoid confusion with program options. */
|
||
@@ -145,11 +151,9 @@ int
|
||
___res_hnok (const char *dn)
|
||
{
|
||
unsigned char buf[NS_MAXCDNAME];
|
||
- if (!printable_string (dn)
|
||
- || __ns_name_pton (dn, buf, sizeof (buf)) < 0
|
||
- || binary_leading_dash (buf))
|
||
- return 0;
|
||
- return binary_hnok (buf);
|
||
+ return (printable_string (dn)
|
||
+ && __ns_name_pton (dn, buf, sizeof (buf)) >= 0
|
||
+ && __res_binary_hnok (buf));
|
||
}
|
||
versioned_symbol (libc, ___res_hnok, res_hnok, GLIBC_2_34);
|
||
versioned_symbol (libc, ___res_hnok, __libc_res_hnok, GLIBC_PRIVATE);
|
||
diff --git a/resolv/tst-ns_name_length_uncompressed.c b/resolv/tst-ns_name_length_uncompressed.c
|
||
new file mode 100644
|
||
index 0000000000..c4a2904db7
|
||
--- /dev/null
|
||
+++ b/resolv/tst-ns_name_length_uncompressed.c
|
||
@@ -0,0 +1,135 @@
|
||
+/* Test __ns_name_length_uncompressed.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <arpa/nameser.h>
|
||
+#include <array_length.h>
|
||
+#include <errno.h>
|
||
+#include <stdio.h>
|
||
+#include <support/check.h>
|
||
+#include <support/next_to_fault.h>
|
||
+
|
||
+/* Reference implementation based on other building blocks. */
|
||
+static int
|
||
+reference_length (const unsigned char *p, const unsigned char *eom)
|
||
+{
|
||
+ unsigned char buf[NS_MAXCDNAME];
|
||
+ int n = __ns_name_unpack (p, eom, p, buf, sizeof (buf));
|
||
+ if (n < 0)
|
||
+ return n;
|
||
+ const unsigned char *q = buf;
|
||
+ if (__ns_name_skip (&q, array_end (buf)) < 0)
|
||
+ return -1;
|
||
+ if (q - buf != n)
|
||
+ /* Compressed name. */
|
||
+ return -1;
|
||
+ return n;
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ {
|
||
+ unsigned char buf[] = { 3, 'w', 'w', 'w', 0, 0, 0 };
|
||
+ TEST_COMPARE (reference_length (buf, array_end (buf)), sizeof (buf) - 2);
|
||
+ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)),
|
||
+ sizeof (buf) - 2);
|
||
+ TEST_COMPARE (reference_length (array_end (buf) - 1, array_end (buf)), 1);
|
||
+ TEST_COMPARE (__ns_name_length_uncompressed (array_end (buf) - 1,
|
||
+ array_end (buf)), 1);
|
||
+ buf[4] = 0xc0; /* Forward compression reference. */
|
||
+ buf[5] = 0x06;
|
||
+ TEST_COMPARE (reference_length (buf, array_end (buf)), -1);
|
||
+ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), -1);
|
||
+ }
|
||
+
|
||
+ struct support_next_to_fault ntf = support_next_to_fault_allocate (300);
|
||
+
|
||
+ /* Buffer region with all possible bytes at start and end. */
|
||
+ for (int length = 1; length <= 300; ++length)
|
||
+ {
|
||
+ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length;
|
||
+ unsigned char *start = end - length;
|
||
+ memset (start, 'X', length);
|
||
+ for (int first = 0; first <= 255; ++first)
|
||
+ {
|
||
+ *start = first;
|
||
+ for (int last = 0; last <= 255; ++last)
|
||
+ {
|
||
+ start[length - 1] = last;
|
||
+ TEST_COMPARE (reference_length (start, end),
|
||
+ __ns_name_length_uncompressed (start, end));
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Poor man's fuzz testing: patch two bytes. */
|
||
+ {
|
||
+ unsigned char ref[] =
|
||
+ {
|
||
+ 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'n', 'e', 't', 0, 0, 0
|
||
+ };
|
||
+ TEST_COMPARE (reference_length (ref, array_end (ref)), 13);
|
||
+ TEST_COMPARE (__ns_name_length_uncompressed (ref, array_end (ref)), 13);
|
||
+
|
||
+ int good = 0;
|
||
+ int bad = 0;
|
||
+ for (int length = 1; length <= sizeof (ref); ++length)
|
||
+ {
|
||
+ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length;
|
||
+ unsigned char *start = end - length;
|
||
+ memcpy (start, ref, length);
|
||
+
|
||
+ for (int patch1_pos = 0; patch1_pos < length; ++patch1_pos)
|
||
+ {
|
||
+ for (int patch1_value = 0; patch1_value <= 255; ++patch1_value)
|
||
+ {
|
||
+ start[patch1_pos] = patch1_value;
|
||
+ for (int patch2_pos = 0; patch2_pos < length; ++patch2_pos)
|
||
+ {
|
||
+ for (int patch2_value = 0; patch2_value <= 255;
|
||
+ ++patch2_value)
|
||
+ {
|
||
+ start[patch2_pos] = patch2_value;
|
||
+ int expected = reference_length (start, end);
|
||
+ errno = EINVAL;
|
||
+ int actual
|
||
+ = __ns_name_length_uncompressed (start, end);
|
||
+ if (actual > 0)
|
||
+ ++good;
|
||
+ else
|
||
+ {
|
||
+ TEST_COMPARE (errno, EMSGSIZE);
|
||
+ ++bad;
|
||
+ }
|
||
+ TEST_COMPARE (expected, actual);
|
||
+ }
|
||
+ start[patch2_pos] = ref[patch2_pos];
|
||
+ }
|
||
+ }
|
||
+ start[patch1_pos] = ref[patch1_pos];
|
||
+ }
|
||
+ }
|
||
+ printf ("info: patched inputs with success: %d\n", good);
|
||
+ printf ("info: patched inputs with failure: %d\n", bad);
|
||
+ }
|
||
+
|
||
+ support_next_to_fault_free (&ntf);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/resolv/tst-ns_rr_cursor.c b/resolv/tst-ns_rr_cursor.c
|
||
new file mode 100644
|
||
index 0000000000..c3c0908905
|
||
--- /dev/null
|
||
+++ b/resolv/tst-ns_rr_cursor.c
|
||
@@ -0,0 +1,227 @@
|
||
+/* Tests for resource record parsing.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <arpa/nameser.h>
|
||
+#include <string.h>
|
||
+#include <support/check.h>
|
||
+#include <support/next_to_fault.h>
|
||
+
|
||
+/* Reference packet for packet parsing. */
|
||
+static const unsigned char valid_packet[] =
|
||
+ { 0x11, 0x12, 0x13, 0x14,
|
||
+ 0x00, 0x01, /* Question count. */
|
||
+ 0x00, 0x02, /* Answer count. */
|
||
+ 0x21, 0x22, 0x23, 0x24, /* Other counts (not actually in packet). */
|
||
+ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0,
|
||
+ 0x00, 0x1c, /* Question type: AAAA. */
|
||
+ 0x00, 0x01, /* Question class: IN. */
|
||
+ 0xc0, 0x0c, /* Compression reference to QNAME. */
|
||
+ 0x00, 0x1c, /* Record type: AAAA. */
|
||
+ 0x00, 0x01, /* Record class: IN. */
|
||
+ 0x12, 0x34, 0x56, 0x78, /* Record TTL. */
|
||
+ 0x00, 0x10, /* Record data length (16 bytes). */
|
||
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* IPv6 address. */
|
||
+ 0xc0, 0x0c, /* Compression reference to QNAME. */
|
||
+ 0x00, 0x1c, /* Record type: AAAA. */
|
||
+ 0x00, 0x01, /* Record class: IN. */
|
||
+ 0x11, 0x33, 0x55, 0x77, /* Record TTL. */
|
||
+ 0x00, 0x10, /* Record data length (16 bytes). */
|
||
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* IPv6 address. */
|
||
+ };
|
||
+
|
||
+/* Special offsets in valid_packet. */
|
||
+enum
|
||
+ {
|
||
+ offset_of_first_record = 29,
|
||
+ offset_of_second_record = 57,
|
||
+ };
|
||
+
|
||
+/* Check that parsing valid_packet succeeds. */
|
||
+static void
|
||
+test_valid (void)
|
||
+{
|
||
+ struct ns_rr_cursor c;
|
||
+ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, valid_packet,
|
||
+ sizeof (valid_packet)));
|
||
+ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
|
||
+ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
|
||
+ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
|
||
+ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
|
||
+ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
|
||
+ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
|
||
+ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
|
||
+ TEST_COMPARE (c.current - valid_packet, offset_of_first_record);
|
||
+
|
||
+ struct ns_rr_wire r;
|
||
+ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
|
||
+ TEST_COMPARE (r.rtype, T_AAAA);
|
||
+ TEST_COMPARE (r.rclass, C_IN);
|
||
+ TEST_COMPARE (r.ttl, 0x12345678);
|
||
+ TEST_COMPARE_BLOB (r.rdata, r.rdlength,
|
||
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
|
||
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16);
|
||
+ TEST_COMPARE (c.current - valid_packet, offset_of_second_record);
|
||
+ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
|
||
+ TEST_COMPARE (r.rtype, T_AAAA);
|
||
+ TEST_COMPARE (r.rclass, C_IN);
|
||
+ TEST_COMPARE (r.ttl, 0x11335577);
|
||
+ TEST_COMPARE_BLOB (r.rdata, r.rdlength,
|
||
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
|
||
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf", 16);
|
||
+ TEST_VERIFY (c.current == c.end);
|
||
+}
|
||
+
|
||
+/* Check that trying to parse a packet with a compressed QNAME fails. */
|
||
+static void
|
||
+test_compressed_qname (void)
|
||
+{
|
||
+ static const unsigned char packet[] =
|
||
+ { 0x11, 0x12, 0x13, 0x14,
|
||
+ 0x00, 0x01, /* Question count. */
|
||
+ 0x00, 0x00, /* Answer count. */
|
||
+ 0x00, 0x00, 0x00, 0x00, /* Other counts. */
|
||
+ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
|
||
+ 0x00, 0x01, /* Question type: A. */
|
||
+ 0x00, 0x01, /* Question class: IN. */
|
||
+ };
|
||
+
|
||
+ struct ns_rr_cursor c;
|
||
+ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet)));
|
||
+}
|
||
+
|
||
+/* Check that trying to parse a packet with two questions fails. */
|
||
+static void
|
||
+test_two_questions (void)
|
||
+{
|
||
+ static const unsigned char packet[] =
|
||
+ { 0x11, 0x12, 0x13, 0x14,
|
||
+ 0x00, 0x02, /* Question count. */
|
||
+ 0x00, 0x00, /* Answer count. */
|
||
+ 0x00, 0x00, 0x00, 0x00, /* Other counts. */
|
||
+ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
|
||
+ 0x00, 0x01, /* Question type: A. */
|
||
+ 0x00, 0x01, /* Question class: IN. */
|
||
+ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
|
||
+ 0x00, 0x1c, /* Question type: AAAA. */
|
||
+ 0x00, 0x01, /* Question class: IN. */
|
||
+ };
|
||
+
|
||
+ struct ns_rr_cursor c;
|
||
+ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet)));
|
||
+}
|
||
+
|
||
+/* Used to check that parsing truncated packets does not over-read. */
|
||
+static struct support_next_to_fault ntf;
|
||
+
|
||
+/* Truncated packet in the second resource record. */
|
||
+static void
|
||
+test_truncated_one_rr (size_t length)
|
||
+{
|
||
+ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
|
||
+ unsigned char *start = end - length;
|
||
+
|
||
+ /* Produce the truncated packet. */
|
||
+ memcpy (start, valid_packet, length);
|
||
+
|
||
+ struct ns_rr_cursor c;
|
||
+ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length));
|
||
+ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
|
||
+ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
|
||
+ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
|
||
+ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
|
||
+ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
|
||
+ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
|
||
+ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
|
||
+ TEST_COMPARE (c.current - start, offset_of_first_record);
|
||
+
|
||
+ struct ns_rr_wire r;
|
||
+ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
|
||
+ TEST_COMPARE (r.rtype, T_AAAA);
|
||
+ TEST_COMPARE (r.rclass, C_IN);
|
||
+ TEST_COMPARE (r.ttl, 0x12345678);
|
||
+ TEST_COMPARE_BLOB (r.rdata, r.rdlength,
|
||
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
|
||
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16);
|
||
+ TEST_COMPARE (c.current - start, offset_of_second_record);
|
||
+ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r));
|
||
+}
|
||
+
|
||
+/* Truncated packet in the first resource record. */
|
||
+static void
|
||
+test_truncated_no_rr (size_t length)
|
||
+{
|
||
+ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
|
||
+ unsigned char *start = end - length;
|
||
+
|
||
+ /* Produce the truncated packet. */
|
||
+ memcpy (start, valid_packet, length);
|
||
+
|
||
+ struct ns_rr_cursor c;
|
||
+ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length));
|
||
+ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
|
||
+ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
|
||
+ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
|
||
+ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
|
||
+ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
|
||
+ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
|
||
+ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
|
||
+ TEST_COMPARE (c.current - start, offset_of_first_record);
|
||
+
|
||
+ struct ns_rr_wire r;
|
||
+ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r));
|
||
+}
|
||
+
|
||
+/* Truncated packet before first resource record. */
|
||
+static void
|
||
+test_truncated_before_rr (size_t length)
|
||
+{
|
||
+ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
|
||
+ unsigned char *start = end - length;
|
||
+
|
||
+ /* Produce the truncated packet. */
|
||
+ memcpy (start, valid_packet, length);
|
||
+
|
||
+ struct ns_rr_cursor c;
|
||
+ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, start, length));
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ ntf = support_next_to_fault_allocate (sizeof (valid_packet));
|
||
+
|
||
+ test_valid ();
|
||
+ test_compressed_qname ();
|
||
+ test_two_questions ();
|
||
+
|
||
+ for (int length = offset_of_second_record; length < sizeof (valid_packet);
|
||
+ ++length)
|
||
+ test_truncated_one_rr (length);
|
||
+ for (int length = offset_of_first_record; length < offset_of_second_record;
|
||
+ ++length)
|
||
+ test_truncated_no_rr (length);
|
||
+ for (int length = 0; length < offset_of_first_record; ++length)
|
||
+ test_truncated_before_rr (length);
|
||
+
|
||
+ support_next_to_fault_free (&ntf);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/resolv/tst-ns_samebinaryname.c b/resolv/tst-ns_samebinaryname.c
|
||
new file mode 100644
|
||
index 0000000000..b06ac610b4
|
||
--- /dev/null
|
||
+++ b/resolv/tst-ns_samebinaryname.c
|
||
@@ -0,0 +1,62 @@
|
||
+/* Test the __ns_samebinaryname function.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <arpa/nameser.h>
|
||
+#include <array_length.h>
|
||
+#include <stdbool.h>
|
||
+#include <stdio.h>
|
||
+#include <support/check.h>
|
||
+
|
||
+/* First character denotes the comparison group: All names with the
|
||
+ same first character are expected to compare equal. */
|
||
+static const char *const cases[] =
|
||
+ {
|
||
+ " ",
|
||
+ "1\001a", "1\001A",
|
||
+ "2\002ab", "2\002aB", "2\002Ab", "2\002AB",
|
||
+ "3\001a\002ab", "3\001A\002ab",
|
||
+ "w\003www\007example\003com", "w\003Www\007Example\003Com",
|
||
+ "w\003WWW\007EXAMPLE\003COM",
|
||
+ "W\003WWW", "W\003www",
|
||
+ };
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ for (int i = 0; i < array_length (cases); ++i)
|
||
+ for (int j = 0; j < array_length (cases); ++j)
|
||
+ {
|
||
+ unsigned char *a = (unsigned char *) &cases[i][1];
|
||
+ unsigned char *b = (unsigned char *) &cases[j][1];
|
||
+ bool actual = __ns_samebinaryname (a, b);
|
||
+ bool expected = cases[i][0] == cases[j][0];
|
||
+ if (actual != expected)
|
||
+ {
|
||
+ char a1[NS_MAXDNAME];
|
||
+ TEST_VERIFY (ns_name_ntop (a, a1, sizeof (a1)) > 0);
|
||
+ char b1[NS_MAXDNAME];
|
||
+ TEST_VERIFY (ns_name_ntop (b, b1, sizeof (b1)) > 0);
|
||
+ printf ("error: \"%s\" \"%s\": expected %s\n",
|
||
+ a1, b1, expected ? "equal" : "unqueal");
|
||
+ support_record_failure ();
|
||
+ }
|
||
+ }
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/resolv/tst-resolv-aliases.c b/resolv/tst-resolv-aliases.c
|
||
new file mode 100644
|
||
index 0000000000..b212823aa0
|
||
--- /dev/null
|
||
+++ b/resolv/tst-resolv-aliases.c
|
||
@@ -0,0 +1,254 @@
|
||
+/* Test alias handling (mainly for gethostbyname).
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <array_length.h>
|
||
+#include <arpa/inet.h>
|
||
+#include <netdb.h>
|
||
+#include <stdbool.h>
|
||
+#include <stdio.h>
|
||
+#include <stdlib.h>
|
||
+#include <string.h>
|
||
+#include <support/check.h>
|
||
+#include <support/check_nss.h>
|
||
+#include <support/resolv_test.h>
|
||
+#include <support/support.h>
|
||
+
|
||
+#include "tst-resolv-maybe_insert_sig.h"
|
||
+
|
||
+/* QNAME format:
|
||
+
|
||
+ aADDRESSES-cCNAMES.example.net
|
||
+
|
||
+ CNAMES is the length of the CNAME chain, ADDRESSES is the number of
|
||
+ addresses in the response. The special value 255 means that there
|
||
+ are no addresses, and the RCODE is NXDOMAIN. */
|
||
+static void
|
||
+response (const struct resolv_response_context *ctx,
|
||
+ struct resolv_response_builder *b,
|
||
+ const char *qname, uint16_t qclass, uint16_t qtype)
|
||
+{
|
||
+ TEST_COMPARE (qclass, C_IN);
|
||
+ if (qtype != T_A)
|
||
+ TEST_COMPARE (qtype, T_AAAA);
|
||
+
|
||
+ unsigned int addresses, cnames;
|
||
+ char *tail;
|
||
+ if (sscanf (qname, "a%u-c%u%ms", &addresses, &cnames, &tail) == 3)
|
||
+ {
|
||
+ if (strcmp (tail, ".example.com") == 0
|
||
+ || strcmp (tail, ".example.net.example.net") == 0
|
||
+ || strcmp (tail, ".example.net.example.com") == 0)
|
||
+ /* These only happen after NXDOMAIN. */
|
||
+ TEST_VERIFY (addresses == 255);
|
||
+ else if (strcmp (tail, ".example.net") != 0)
|
||
+ FAIL_EXIT1 ("invalid QNAME: %s", qname);
|
||
+ }
|
||
+ free (tail);
|
||
+
|
||
+ int rcode;
|
||
+ if (addresses == 255)
|
||
+ {
|
||
+ /* Special case: Use no addresses with NXDOMAIN response. */
|
||
+ rcode = ns_r_nxdomain;
|
||
+ addresses = 0;
|
||
+ }
|
||
+ else
|
||
+ rcode = 0;
|
||
+
|
||
+ struct resolv_response_flags flags = { .rcode = rcode };
|
||
+ resolv_response_init (b, flags);
|
||
+ resolv_response_add_question (b, qname, qclass, qtype);
|
||
+ resolv_response_section (b, ns_s_an);
|
||
+ maybe_insert_sig (b, qname);
|
||
+
|
||
+ /* Provide the requested number of CNAME records. */
|
||
+ char *previous_name = (char *) qname;
|
||
+ for (int unique = 0; unique < cnames; ++unique)
|
||
+ {
|
||
+ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60);
|
||
+ char *new_name = xasprintf ("%d.alias.example", unique);
|
||
+ resolv_response_add_name (b, new_name);
|
||
+ resolv_response_close_record (b);
|
||
+
|
||
+ maybe_insert_sig (b, qname);
|
||
+
|
||
+ if (previous_name != qname)
|
||
+ free (previous_name);
|
||
+ previous_name = new_name;
|
||
+ }
|
||
+
|
||
+ for (int unique = 0; unique < addresses; ++unique)
|
||
+ {
|
||
+ resolv_response_open_record (b, previous_name, qclass, qtype, 60);
|
||
+
|
||
+ if (qtype == T_A)
|
||
+ {
|
||
+ char ipv4[4] = {192, 0, 2, 1 + unique};
|
||
+ resolv_response_add_data (b, &ipv4, sizeof (ipv4));
|
||
+ }
|
||
+ else if (qtype == T_AAAA)
|
||
+ {
|
||
+ char ipv6[16] =
|
||
+ {
|
||
+ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||
+ 1 + unique
|
||
+ };
|
||
+ resolv_response_add_data (b, &ipv6, sizeof (ipv6));
|
||
+ }
|
||
+ resolv_response_close_record (b);
|
||
+ }
|
||
+
|
||
+ if (previous_name != qname)
|
||
+ free (previous_name);
|
||
+}
|
||
+
|
||
+static char *
|
||
+make_qname (bool do_search, int cnames, int addresses)
|
||
+{
|
||
+ return xasprintf ("a%d-c%d%s",
|
||
+ addresses, cnames, do_search ? "" : ".example.net");
|
||
+}
|
||
+
|
||
+static void
|
||
+check_cnames_failure (int af, bool do_search, int cnames, int addresses)
|
||
+{
|
||
+ char *qname = make_qname (do_search, cnames, addresses);
|
||
+
|
||
+ struct hostent *e;
|
||
+ if (af == AF_UNSPEC)
|
||
+ e = gethostbyname (qname);
|
||
+ else
|
||
+ e = gethostbyname2 (qname, af);
|
||
+
|
||
+ if (addresses == 0)
|
||
+ check_hostent (qname, e, "error: NO_RECOVERY\n");
|
||
+ else
|
||
+ check_hostent (qname, e, "error: HOST_NOT_FOUND\n");
|
||
+
|
||
+ free (qname);
|
||
+}
|
||
+
|
||
+static void
|
||
+check (int af, bool do_search, int cnames, int addresses)
|
||
+{
|
||
+ char *qname = make_qname (do_search, cnames, addresses);
|
||
+ char *fqdn = make_qname (false, cnames, addresses);
|
||
+
|
||
+ struct hostent *e;
|
||
+ if (af == AF_UNSPEC)
|
||
+ e = gethostbyname (qname);
|
||
+ else
|
||
+ e = gethostbyname2 (qname, af);
|
||
+ if (e == NULL)
|
||
+ FAIL_EXIT1 ("unexpected failure for %d, %d, %d", af, cnames, addresses);
|
||
+
|
||
+ if (af == AF_UNSPEC || af == AF_INET)
|
||
+ {
|
||
+ TEST_COMPARE (e->h_addrtype, AF_INET);
|
||
+ TEST_COMPARE (e->h_length, 4);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ TEST_COMPARE (e->h_addrtype, AF_INET6);
|
||
+ TEST_COMPARE (e->h_length, 16);
|
||
+ }
|
||
+
|
||
+ for (int i = 0; i < addresses; ++i)
|
||
+ {
|
||
+ char ipv4[4] = {192, 0, 2, 1 + i};
|
||
+ char ipv6[16] =
|
||
+ { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + i };
|
||
+ char *expected = e->h_addrtype == AF_INET ? ipv4 : ipv6;
|
||
+ TEST_COMPARE_BLOB (e->h_addr_list[i], e->h_length,
|
||
+ expected, e->h_length);
|
||
+ }
|
||
+ TEST_VERIFY (e->h_addr_list[addresses] == NULL);
|
||
+
|
||
+
|
||
+ if (cnames == 0)
|
||
+ {
|
||
+ /* QNAME is fully qualified. */
|
||
+ TEST_COMPARE_STRING (e->h_name, fqdn);
|
||
+ TEST_VERIFY (e->h_aliases[0] == NULL);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* Fully-qualified QNAME is demoted to an aliases. */
|
||
+ TEST_COMPARE_STRING (e->h_aliases[0], fqdn);
|
||
+
|
||
+ for (int i = 1; i <= cnames; ++i)
|
||
+ {
|
||
+ char *expected = xasprintf ("%d.alias.example", i - 1);
|
||
+ if (i == cnames)
|
||
+ TEST_COMPARE_STRING (e->h_name, expected);
|
||
+ else
|
||
+ TEST_COMPARE_STRING (e->h_aliases[i], expected);
|
||
+ free (expected);
|
||
+ }
|
||
+ TEST_VERIFY (e->h_aliases[cnames] == NULL);
|
||
+ }
|
||
+
|
||
+ free (fqdn);
|
||
+ free (qname);
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ struct resolv_test *obj = resolv_test_start
|
||
+ ((struct resolv_redirect_config)
|
||
+ {
|
||
+ .response_callback = response,
|
||
+ .search = { "example.net", "example.com" },
|
||
+ });
|
||
+
|
||
+ static const int families[] = { AF_UNSPEC, AF_INET, AF_INET6 };
|
||
+
|
||
+ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig)
|
||
+ {
|
||
+ insert_sig = do_insert_sig;
|
||
+
|
||
+ /* If do_search is true, a bare host name (for example, a1-c1)
|
||
+ is used. This exercises search path processing and FQDN
|
||
+ qualification. */
|
||
+ for (int do_search = 0; do_search < 2; ++do_search)
|
||
+ for (const int *paf = families; paf != array_end (families); ++paf)
|
||
+ {
|
||
+ for (int cnames = 0; cnames <= 100; ++cnames)
|
||
+ {
|
||
+ check_cnames_failure (*paf, do_search, cnames, 0);
|
||
+ /* Now with NXDOMAIN responses. */
|
||
+ check_cnames_failure (*paf, do_search, cnames, 255);
|
||
+ }
|
||
+
|
||
+ for (int cnames = 0; cnames <= 10; ++cnames)
|
||
+ for (int addresses = 1; addresses <= 10; ++addresses)
|
||
+ check (*paf, do_search, cnames, addresses);
|
||
+
|
||
+ /* The current implementation is limited to 47 aliases.
|
||
+ Addresses do not have such a limit. */
|
||
+ check (*paf, do_search, 47, 60);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ resolv_test_end (obj);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/resolv/tst-resolv-byaddr.c b/resolv/tst-resolv-byaddr.c
|
||
new file mode 100644
|
||
index 0000000000..6299e89837
|
||
--- /dev/null
|
||
+++ b/resolv/tst-resolv-byaddr.c
|
||
@@ -0,0 +1,326 @@
|
||
+/* Test reverse DNS lookup.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <arpa/inet.h>
|
||
+#include <errno.h>
|
||
+#include <netdb.h>
|
||
+#include <stdbool.h>
|
||
+#include <stdio.h>
|
||
+#include <stdlib.h>
|
||
+#include <string.h>
|
||
+#include <support/check.h>
|
||
+#include <support/check_nss.h>
|
||
+#include <support/next_to_fault.h>
|
||
+#include <support/resolv_test.h>
|
||
+#include <support/support.h>
|
||
+
|
||
+#include "tst-resolv-maybe_insert_sig.h"
|
||
+
|
||
+/* QNAME format:
|
||
+
|
||
+ ADDRESSES.CNAMES...(lots of 0s)...8.b.d.0.1.0.0.2.ip6.arpa.
|
||
+ CNAMES|ADDRESSES.2.0.192.in-addr-arpa.
|
||
+
|
||
+ For the IPv4 reverse lookup, the address count is in the lower
|
||
+ bits.
|
||
+
|
||
+ CNAMES is the length of the CNAME chain, ADDRESSES is the number of
|
||
+ addresses in the response. The special value 15 means that there
|
||
+ are no addresses, and the RCODE is NXDOMAIN. */
|
||
+static void
|
||
+response (const struct resolv_response_context *ctx,
|
||
+ struct resolv_response_builder *b,
|
||
+ const char *qname, uint16_t qclass, uint16_t qtype)
|
||
+{
|
||
+ TEST_COMPARE (qclass, C_IN);
|
||
+ TEST_COMPARE (qtype, T_PTR);
|
||
+
|
||
+ unsigned int addresses, cnames, bits;
|
||
+ char *tail;
|
||
+ if (strstr (qname, "ip6.arpa") != NULL
|
||
+ && sscanf (qname, "%x.%x.%ms", &addresses, &cnames, &tail) == 3)
|
||
+ TEST_COMPARE_STRING (tail, "\
|
||
+0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
|
||
+ else if (sscanf (qname, "%u.%ms", &bits, &tail) == 2)
|
||
+ {
|
||
+ TEST_COMPARE_STRING (tail, "2.0.192.in-addr.arpa");
|
||
+ addresses = bits & 0x0f;
|
||
+ cnames = bits >> 4;
|
||
+ }
|
||
+ else
|
||
+ FAIL_EXIT1 ("invalid QNAME: %s", qname);
|
||
+ free (tail);
|
||
+
|
||
+ int rcode;
|
||
+ if (addresses == 15)
|
||
+ {
|
||
+ /* Special case: Use no addresses with NXDOMAIN response. */
|
||
+ rcode = ns_r_nxdomain;
|
||
+ addresses = 0;
|
||
+ }
|
||
+ else
|
||
+ rcode = 0;
|
||
+
|
||
+ struct resolv_response_flags flags = { .rcode = rcode };
|
||
+ resolv_response_init (b, flags);
|
||
+ resolv_response_add_question (b, qname, qclass, qtype);
|
||
+ resolv_response_section (b, ns_s_an);
|
||
+ maybe_insert_sig (b, qname);
|
||
+
|
||
+ /* Provide the requested number of CNAME records. */
|
||
+ char *previous_name = (char *) qname;
|
||
+ for (int unique = 0; unique < cnames; ++unique)
|
||
+ {
|
||
+ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60);
|
||
+ char *new_name = xasprintf ("%d.alias.example", unique);
|
||
+ resolv_response_add_name (b, new_name);
|
||
+ resolv_response_close_record (b);
|
||
+
|
||
+ maybe_insert_sig (b, qname);
|
||
+
|
||
+ if (previous_name != qname)
|
||
+ free (previous_name);
|
||
+ previous_name = new_name;
|
||
+ }
|
||
+
|
||
+ for (int unique = 0; unique < addresses; ++unique)
|
||
+ {
|
||
+ resolv_response_open_record (b, previous_name, qclass, T_PTR, 60);
|
||
+ char *ptr = xasprintf ("unique-%d.cnames-%u.addresses-%u.example",
|
||
+ unique, cnames, addresses);
|
||
+ resolv_response_add_name (b, ptr);
|
||
+ free (ptr);
|
||
+ resolv_response_close_record (b);
|
||
+ }
|
||
+
|
||
+ if (previous_name != qname)
|
||
+ free (previous_name);
|
||
+}
|
||
+
|
||
+/* Used to check that gethostbyaddr_r does not write past the buffer
|
||
+ end. */
|
||
+static struct support_next_to_fault ntf;
|
||
+
|
||
+/* Perform a gethostbyaddr call and check the result. */
|
||
+static void
|
||
+check_gethostbyaddr (const char *address, const char *expected)
|
||
+{
|
||
+ unsigned char bytes[16];
|
||
+ unsigned int byteslen;
|
||
+ int family;
|
||
+ if (strchr (address, ':') != NULL)
|
||
+ {
|
||
+ family = AF_INET6;
|
||
+ byteslen = 16;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ family = AF_INET;
|
||
+ byteslen = 4;
|
||
+ }
|
||
+ TEST_COMPARE (inet_pton (family, address, bytes), 1);
|
||
+
|
||
+ struct hostent *e = gethostbyaddr (bytes, byteslen, family);
|
||
+ check_hostent (address, e, expected);
|
||
+
|
||
+ if (e == NULL)
|
||
+ return;
|
||
+
|
||
+ /* Try gethostbyaddr_r with increasing sizes until success. First
|
||
+ compute a reasonable minimum buffer size, to avoid many pointless
|
||
+ attempts. */
|
||
+ size_t minimum_size = strlen (e->h_name);
|
||
+ for (int i = 0; e->h_addr_list[i] != NULL; ++i)
|
||
+ minimum_size += e->h_length + sizeof (char *);
|
||
+ for (int i = 0; e->h_aliases[i] != NULL; ++i)
|
||
+ minimum_size += strlen (e->h_aliases[i]) + 1 + sizeof (char *);
|
||
+
|
||
+ /* Gradually increase the size until success. */
|
||
+ for (size_t size = minimum_size; size < ntf.length; ++size)
|
||
+ {
|
||
+ struct hostent result;
|
||
+ int herrno;
|
||
+ int ret = gethostbyaddr_r (bytes, byteslen, family, &result,
|
||
+ ntf.buffer + ntf.length - size, size,
|
||
+ &e, &herrno);
|
||
+ if (ret == ERANGE)
|
||
+ /* Retry with larger size. */
|
||
+ TEST_COMPARE (herrno, NETDB_INTERNAL);
|
||
+ else if (ret == 0)
|
||
+ {
|
||
+ TEST_VERIFY (size > minimum_size);
|
||
+ check_hostent (address, e, expected);
|
||
+ return;
|
||
+ }
|
||
+ else
|
||
+ FAIL_EXIT1 ("Unexpected gethostbyaddr_r failure: %d", ret);
|
||
+ }
|
||
+
|
||
+ FAIL_EXIT1 ("gethostbyaddr_r always failed for: %s", address);
|
||
+}
|
||
+
|
||
+/* Perform a getnameinfo call and check the result. */
|
||
+static void
|
||
+check_getnameinfo (const char *address, const char *expected)
|
||
+{
|
||
+ struct sockaddr_in sin = { };
|
||
+ struct sockaddr_in6 sin6 = { };
|
||
+ void *sa;
|
||
+ socklen_t salen;
|
||
+ if (strchr (address, ':') != NULL)
|
||
+ {
|
||
+ sin6.sin6_family = AF_INET6;
|
||
+ TEST_COMPARE (inet_pton (AF_INET6, address, &sin6.sin6_addr), 1);
|
||
+ sin6.sin6_port = htons (80);
|
||
+ sa = &sin6;
|
||
+ salen = sizeof (sin6);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ sin.sin_family = AF_INET;
|
||
+ TEST_COMPARE (inet_pton (AF_INET, address, &sin.sin_addr), 1);
|
||
+ sin.sin_port = htons (80);
|
||
+ sa = &sin;
|
||
+ salen = sizeof (sin);
|
||
+ }
|
||
+
|
||
+ char host[64];
|
||
+ char service[64];
|
||
+ int ret = getnameinfo (sa, salen, host,
|
||
+ sizeof (host), service, sizeof (service),
|
||
+ NI_NAMEREQD | NI_NUMERICSERV);
|
||
+ switch (ret)
|
||
+ {
|
||
+ case 0:
|
||
+ TEST_COMPARE_STRING (host, expected);
|
||
+ TEST_COMPARE_STRING (service, "80");
|
||
+ break;
|
||
+ case EAI_SYSTEM:
|
||
+ TEST_COMPARE_STRING (strerror (errno), expected);
|
||
+ break;
|
||
+ default:
|
||
+ TEST_COMPARE_STRING (gai_strerror (ret), expected);
|
||
+ }
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ /* Some reasonably upper bound for the maximum response size. */
|
||
+ ntf = support_next_to_fault_allocate (4096);
|
||
+
|
||
+ struct resolv_test *obj = resolv_test_start
|
||
+ ((struct resolv_redirect_config)
|
||
+ {
|
||
+ .response_callback = response
|
||
+ });
|
||
+
|
||
+ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig)
|
||
+ {
|
||
+ insert_sig = do_insert_sig;
|
||
+
|
||
+ /* No PTR record, RCODE=0. */
|
||
+ check_gethostbyaddr ("192.0.2.0", "error: NO_RECOVERY\n");
|
||
+ check_getnameinfo ("192.0.2.0", "Name or service not known");
|
||
+ check_gethostbyaddr ("192.0.2.16", "error: NO_RECOVERY\n");
|
||
+ check_getnameinfo ("192.0.2.16", "Name or service not known");
|
||
+ check_gethostbyaddr ("192.0.2.32", "error: NO_RECOVERY\n");
|
||
+ check_getnameinfo ("192.0.2.32", "Name or service not known");
|
||
+ check_gethostbyaddr ("2001:db8::", "error: NO_RECOVERY\n");
|
||
+ check_getnameinfo ("2001:db8::", "Name or service not known");
|
||
+ check_gethostbyaddr ("2001:db8::10", "error: NO_RECOVERY\n");
|
||
+ check_getnameinfo ("2001:db8::10", "Name or service not known");
|
||
+ check_gethostbyaddr ("2001:db8::20", "error: NO_RECOVERY\n");
|
||
+ check_getnameinfo ("2001:db8::20", "Name or service not known");
|
||
+
|
||
+ /* No PTR record, NXDOMAIN. */
|
||
+ check_gethostbyaddr ("192.0.2.15", "error: HOST_NOT_FOUND\n");
|
||
+ check_getnameinfo ("192.0.2.15", "Name or service not known");
|
||
+ check_gethostbyaddr ("192.0.2.31", "error: HOST_NOT_FOUND\n");
|
||
+ check_getnameinfo ("192.0.2.31", "Name or service not known");
|
||
+ check_gethostbyaddr ("192.0.2.47", "error: HOST_NOT_FOUND\n");
|
||
+ check_getnameinfo ("192.0.2.47", "Name or service not known");
|
||
+ check_gethostbyaddr ("2001:db8::f", "error: HOST_NOT_FOUND\n");
|
||
+ check_getnameinfo ("2001:db8::f", "Name or service not known");
|
||
+ check_gethostbyaddr ("2001:db8::1f", "error: HOST_NOT_FOUND\n");
|
||
+ check_getnameinfo ("2001:db8::1f", "Name or service not known");
|
||
+ check_gethostbyaddr ("2001:db8::2f", "error: HOST_NOT_FOUND\n");
|
||
+ check_getnameinfo ("2001:db8::2f", "Name or service not known");
|
||
+
|
||
+ /* Actual response data. Only the first PTR record is returned. */
|
||
+ check_gethostbyaddr ("192.0.2.1",
|
||
+ "name: unique-0.cnames-0.addresses-1.example\n"
|
||
+ "address: 192.0.2.1\n");
|
||
+ check_getnameinfo ("192.0.2.1",
|
||
+ "unique-0.cnames-0.addresses-1.example");
|
||
+ check_gethostbyaddr ("192.0.2.17",
|
||
+ "name: unique-0.cnames-1.addresses-1.example\n"
|
||
+ "address: 192.0.2.17\n");
|
||
+ check_getnameinfo ("192.0.2.17",
|
||
+ "unique-0.cnames-1.addresses-1.example");
|
||
+ check_gethostbyaddr ("192.0.2.18",
|
||
+ "name: unique-0.cnames-1.addresses-2.example\n"
|
||
+ "address: 192.0.2.18\n");
|
||
+ check_getnameinfo ("192.0.2.18",
|
||
+ "unique-0.cnames-1.addresses-2.example");
|
||
+ check_gethostbyaddr ("192.0.2.33",
|
||
+ "name: unique-0.cnames-2.addresses-1.example\n"
|
||
+ "address: 192.0.2.33\n");
|
||
+ check_getnameinfo ("192.0.2.33",
|
||
+ "unique-0.cnames-2.addresses-1.example");
|
||
+ check_gethostbyaddr ("192.0.2.34",
|
||
+ "name: unique-0.cnames-2.addresses-2.example\n"
|
||
+ "address: 192.0.2.34\n");
|
||
+ check_getnameinfo ("192.0.2.34",
|
||
+ "unique-0.cnames-2.addresses-2.example");
|
||
+
|
||
+ /* Same for IPv6 addresses. */
|
||
+ check_gethostbyaddr ("2001:db8::1",
|
||
+ "name: unique-0.cnames-0.addresses-1.example\n"
|
||
+ "address: 2001:db8::1\n");
|
||
+ check_getnameinfo ("2001:db8::1",
|
||
+ "unique-0.cnames-0.addresses-1.example");
|
||
+ check_gethostbyaddr ("2001:db8::11",
|
||
+ "name: unique-0.cnames-1.addresses-1.example\n"
|
||
+ "address: 2001:db8::11\n");
|
||
+ check_getnameinfo ("2001:db8::11",
|
||
+ "unique-0.cnames-1.addresses-1.example");
|
||
+ check_gethostbyaddr ("2001:db8::12",
|
||
+ "name: unique-0.cnames-1.addresses-2.example\n"
|
||
+ "address: 2001:db8::12\n");
|
||
+ check_getnameinfo ("2001:db8::12",
|
||
+ "unique-0.cnames-1.addresses-2.example");
|
||
+ check_gethostbyaddr ("2001:db8::21",
|
||
+ "name: unique-0.cnames-2.addresses-1.example\n"
|
||
+ "address: 2001:db8::21\n");
|
||
+ check_getnameinfo ("2001:db8::21",
|
||
+ "unique-0.cnames-2.addresses-1.example");
|
||
+ check_gethostbyaddr ("2001:db8::22",
|
||
+ "name: unique-0.cnames-2.addresses-2.example\n"
|
||
+ "address: 2001:db8::22\n");
|
||
+ check_getnameinfo ("2001:db8::22",
|
||
+ "unique-0.cnames-2.addresses-2.example");
|
||
+ }
|
||
+
|
||
+ resolv_test_end (obj);
|
||
+
|
||
+ support_next_to_fault_free (&ntf);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/resolv/tst-resolv-invalid-cname.c b/resolv/tst-resolv-invalid-cname.c
|
||
new file mode 100644
|
||
index 0000000000..63dac90e02
|
||
--- /dev/null
|
||
+++ b/resolv/tst-resolv-invalid-cname.c
|
||
@@ -0,0 +1,406 @@
|
||
+/* Test handling of CNAMEs with non-host domain names (bug 12154).
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <errno.h>
|
||
+#include <netdb.h>
|
||
+#include <resolv.h>
|
||
+#include <stdlib.h>
|
||
+#include <string.h>
|
||
+#include <support/check.h>
|
||
+#include <support/check_nss.h>
|
||
+#include <support/resolv_test.h>
|
||
+#include <support/support.h>
|
||
+#include <support/xmemstream.h>
|
||
+
|
||
+/* Query strings describe the CNAME chain in the response. They have
|
||
+ the format "bitsBITS.countCOUNT.example.", where BITS and COUNT are
|
||
+ replaced by unsigned decimal numbers. COUNT is the number of CNAME
|
||
+ records in the response. BITS has two bits for each CNAME record,
|
||
+ describing a special prefix that is added to that CNAME.
|
||
+
|
||
+ 0: No special leading label.
|
||
+ 1: Starting with "*.".
|
||
+ 2: Starting with "-x.".
|
||
+ 3: Starting with "star.*.".
|
||
+
|
||
+ The first CNAME in the response using the two least significant
|
||
+ bits.
|
||
+
|
||
+ For PTR queries, the QNAME format is different, it is either
|
||
+ COUNT.BITS.168.192.in-addr.arpa. (with BITS and COUNT still
|
||
+ decimal), or:
|
||
+
|
||
+COUNT.BITS0.BITS1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
|
||
+
|
||
+ where BITS and COUNT are hexadecimal. */
|
||
+
|
||
+static void
|
||
+response (const struct resolv_response_context *ctx,
|
||
+ struct resolv_response_builder *b,
|
||
+ const char *qname, uint16_t qclass, uint16_t qtype)
|
||
+{
|
||
+ TEST_COMPARE (qclass, C_IN);
|
||
+
|
||
+ /* The only other query type besides A is PTR. */
|
||
+ if (qtype != T_A && qtype != T_AAAA)
|
||
+ TEST_COMPARE (qtype, T_PTR);
|
||
+
|
||
+ unsigned int bits, bits1, count;
|
||
+ char *tail = NULL;
|
||
+ if (sscanf (qname, "bits%u.count%u.%ms", &bits, &count, &tail) == 3)
|
||
+ TEST_COMPARE_STRING (tail, "example");
|
||
+ else if (strstr (qname, "in-addr.arpa") != NULL
|
||
+ && sscanf (qname, "%u.%u.%ms", &bits, &count, &tail) == 3)
|
||
+ TEST_COMPARE_STRING (tail, "168.192.in-addr.arpa");
|
||
+ else if (sscanf (qname, "%x.%x.%x.%ms", &bits, &bits1, &count, &tail) == 4)
|
||
+ {
|
||
+ TEST_COMPARE_STRING (tail, "\
|
||
+0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
|
||
+ bits |= bits1 << 4;
|
||
+ }
|
||
+ else
|
||
+ FAIL_EXIT1 ("invalid QNAME: %s\n", qname);
|
||
+ free (tail);
|
||
+
|
||
+ struct resolv_response_flags flags = {};
|
||
+ resolv_response_init (b, flags);
|
||
+ resolv_response_add_question (b, qname, qclass, qtype);
|
||
+ resolv_response_section (b, ns_s_an);
|
||
+
|
||
+ /* Provide the requested number of CNAME records. */
|
||
+ char *previous_name = (char *) qname;
|
||
+ unsigned int original_bits = bits;
|
||
+ for (int unique = 0; unique < count; ++unique)
|
||
+ {
|
||
+ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60);
|
||
+
|
||
+ static const char bits_to_prefix[4][8] = { "", "*.", "-x.", "star.*." };
|
||
+ char *new_name = xasprintf ("%sunique%d.example",
|
||
+ bits_to_prefix[bits & 3], unique);
|
||
+ bits >>= 2;
|
||
+ resolv_response_add_name (b, new_name);
|
||
+ resolv_response_close_record (b);
|
||
+
|
||
+ if (previous_name != qname)
|
||
+ free (previous_name);
|
||
+ previous_name = new_name;
|
||
+ }
|
||
+
|
||
+ /* Actual answer record. */
|
||
+ resolv_response_open_record (b, previous_name, qclass, qtype, 60);
|
||
+ switch (qtype)
|
||
+ {
|
||
+ case T_A:
|
||
+ {
|
||
+ char ipv4[4] = {192, 168, count, original_bits};
|
||
+ resolv_response_add_data (b, &ipv4, sizeof (ipv4));
|
||
+ }
|
||
+ break;
|
||
+ case T_AAAA:
|
||
+ {
|
||
+ char ipv6[16] =
|
||
+ {
|
||
+ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||
+ count, original_bits
|
||
+ };
|
||
+ resolv_response_add_data (b, &ipv6, sizeof (ipv6));
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case T_PTR:
|
||
+ {
|
||
+ char *name = xasprintf ("bits%u.count%u.example",
|
||
+ original_bits, count);
|
||
+ resolv_response_add_name (b, name);
|
||
+ free (name);
|
||
+ }
|
||
+ break;
|
||
+ }
|
||
+ resolv_response_close_record (b);
|
||
+
|
||
+ if (previous_name != qname)
|
||
+ free (previous_name);
|
||
+}
|
||
+
|
||
+/* Controls which name resolution function is invoked. */
|
||
+enum test_mode
|
||
+ {
|
||
+ byname, /* gethostbyname. */
|
||
+ byname2, /* gethostbyname2. */
|
||
+ gai, /* getaddrinfo without AI_CANONNAME. */
|
||
+ gai_canon, /* getaddrinfo with AI_CANONNAME. */
|
||
+
|
||
+ test_mode_num /* Number of enum values. */
|
||
+ };
|
||
+
|
||
+static const char *
|
||
+test_mode_to_string (enum test_mode mode)
|
||
+{
|
||
+ switch (mode)
|
||
+ {
|
||
+ case byname:
|
||
+ return "byname";
|
||
+ case byname2:
|
||
+ return "byname2";
|
||
+ case gai:
|
||
+ return "gai";
|
||
+ case gai_canon:
|
||
+ return "gai_canon";
|
||
+ case test_mode_num:
|
||
+ break; /* Report error below. */
|
||
+ }
|
||
+ FAIL_EXIT1 ("invalid test_mode: %d", mode);
|
||
+}
|
||
+
|
||
+/* Append the name and aliases to OUT. */
|
||
+static void
|
||
+append_names (FILE *out, const char *qname, int bits, int count,
|
||
+ enum test_mode mode)
|
||
+{
|
||
+ /* Largest valid index which has a corresponding zero in bits
|
||
+ (meaning a syntactically valid CNAME). */
|
||
+ int last_valid_cname = -1;
|
||
+
|
||
+ for (int i = 0; i < count; ++i)
|
||
+ if ((bits & (3 << (i * 2))) == 0)
|
||
+ last_valid_cname = i;
|
||
+
|
||
+ if (mode != gai)
|
||
+ {
|
||
+ const char *label;
|
||
+ if (mode == gai_canon)
|
||
+ label = "canonname";
|
||
+ else
|
||
+ label = "name";
|
||
+ if (last_valid_cname >= 0)
|
||
+ fprintf (out, "%s: unique%d.example\n", label, last_valid_cname);
|
||
+ else
|
||
+ fprintf (out, "%s: %s\n", label, qname);
|
||
+ }
|
||
+
|
||
+ if (mode == byname || mode == byname2)
|
||
+ {
|
||
+ if (last_valid_cname >= 0)
|
||
+ fprintf (out, "alias: %s\n", qname);
|
||
+ for (int i = 0; i < count; ++i)
|
||
+ {
|
||
+ if ((bits & (3 << (i * 2))) == 0 && i != last_valid_cname)
|
||
+ fprintf (out, "alias: unique%d.example\n", i);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Append the address information to OUT. */
|
||
+static void
|
||
+append_addresses (FILE *out, int af, int bits, int count, enum test_mode mode)
|
||
+{
|
||
+ int last = count * 256 + bits;
|
||
+ if (mode == gai || mode == gai_canon)
|
||
+ {
|
||
+ if (af == AF_INET || af == AF_UNSPEC)
|
||
+ fprintf (out, "address: STREAM/TCP 192.168.%d.%d 80\n", count, bits);
|
||
+ if (af == AF_INET6 || af == AF_UNSPEC)
|
||
+ {
|
||
+ if (last == 0)
|
||
+ fprintf (out, "address: STREAM/TCP 2001:db8:: 80\n");
|
||
+ else
|
||
+ fprintf (out, "address: STREAM/TCP 2001:db8::%x 80\n", last);
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ TEST_VERIFY (af != AF_UNSPEC);
|
||
+ if (af == AF_INET)
|
||
+ fprintf (out, "address: 192.168.%d.%d\n", count, bits);
|
||
+ if (af == AF_INET6)
|
||
+ {
|
||
+ if (last == 0)
|
||
+ fprintf (out, "address: 2001:db8::\n");
|
||
+ else
|
||
+ fprintf (out, "address: 2001:db8::%x\n", last);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Perform one test using a forward lookup. */
|
||
+static void
|
||
+check_forward (int af, int bits, int count, enum test_mode mode)
|
||
+{
|
||
+ char *qname = xasprintf ("bits%d.count%d.example", bits, count);
|
||
+ char *label = xasprintf ("af=%d bits=%d count=%d mode=%s qname=%s",
|
||
+ af, bits, count, test_mode_to_string (mode), qname);
|
||
+
|
||
+ struct xmemstream expected;
|
||
+ xopen_memstream (&expected);
|
||
+ if (mode == gai_canon)
|
||
+ fprintf (expected.out, "flags: AI_CANONNAME\n");
|
||
+ append_names (expected.out, qname, bits, count, mode);
|
||
+ append_addresses (expected.out, af, bits, count, mode);
|
||
+ xfclose_memstream (&expected);
|
||
+
|
||
+ if (mode == gai || mode == gai_canon)
|
||
+ {
|
||
+ struct addrinfo *ai;
|
||
+ struct addrinfo hints =
|
||
+ {
|
||
+ .ai_family = af,
|
||
+ .ai_socktype = SOCK_STREAM,
|
||
+ };
|
||
+ if (mode == gai_canon)
|
||
+ hints.ai_flags |= AI_CANONNAME;
|
||
+ int ret = getaddrinfo (qname, "80", &hints, &ai);
|
||
+ check_addrinfo (label, ai, ret, expected.buffer);
|
||
+ if (ret == 0)
|
||
+ freeaddrinfo (ai);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ struct hostent *e;
|
||
+ if (mode == gai)
|
||
+ {
|
||
+ TEST_COMPARE (af, AF_INET);
|
||
+ e = gethostbyname (qname);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ if (af != AF_INET)
|
||
+ TEST_COMPARE (af, AF_INET6);
|
||
+ e = gethostbyname2 (qname, af);
|
||
+ }
|
||
+ check_hostent (label, e, expected.buffer);
|
||
+ }
|
||
+
|
||
+ free (expected.buffer);
|
||
+ free (label);
|
||
+ free (qname);
|
||
+}
|
||
+
|
||
+/* Perform one check using a reverse lookup. */
|
||
+
|
||
+static void
|
||
+check_reverse (int af, int bits, int count)
|
||
+{
|
||
+ TEST_VERIFY (af == AF_INET || af == AF_INET6);
|
||
+
|
||
+ char *label = xasprintf ("af=%d bits=%d count=%d", af, bits, count);
|
||
+ char *fqdn = xasprintf ("bits%d.count%d.example", bits, count);
|
||
+
|
||
+ struct xmemstream expected;
|
||
+ xopen_memstream (&expected);
|
||
+ fprintf (expected.out, "name: %s\n", fqdn);
|
||
+ append_addresses (expected.out, af, bits, count, byname);
|
||
+ xfclose_memstream (&expected);
|
||
+
|
||
+ char addr[16] = { 0 };
|
||
+ socklen_t addrlen;
|
||
+ if (af == AF_INET)
|
||
+ {
|
||
+ addr[0] = 192;
|
||
+ addr[1] = 168;
|
||
+ addr[2] = count;
|
||
+ addr[3] = bits;
|
||
+ addrlen = 4;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ addr[0] = 0x20;
|
||
+ addr[1] = 0x01;
|
||
+ addr[2] = 0x0d;
|
||
+ addr[3] = 0xb8;
|
||
+ addr[14] = count;
|
||
+ addr[15] = bits;
|
||
+ addrlen = 16;
|
||
+ }
|
||
+
|
||
+ struct hostent *e = gethostbyaddr (addr, addrlen, af);
|
||
+ check_hostent (label, e, expected.buffer);
|
||
+
|
||
+ /* getnameinfo check is different. There is no generic check_*
|
||
+ function for it. */
|
||
+ {
|
||
+ struct sockaddr_in sin = { };
|
||
+ struct sockaddr_in6 sin6 = { };
|
||
+ void *sa;
|
||
+ socklen_t salen;
|
||
+ if (af == AF_INET)
|
||
+ {
|
||
+ sin.sin_family = AF_INET;
|
||
+ memcpy (&sin.sin_addr, addr, addrlen);
|
||
+ sin.sin_port = htons (80);
|
||
+ sa = &sin;
|
||
+ salen = sizeof (sin);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ sin6.sin6_family = AF_INET6;
|
||
+ memcpy (&sin6.sin6_addr, addr, addrlen);
|
||
+ sin6.sin6_port = htons (80);
|
||
+ sa = &sin6;
|
||
+ salen = sizeof (sin6);
|
||
+ }
|
||
+
|
||
+ char host[64];
|
||
+ char service[64];
|
||
+ int ret = getnameinfo (sa, salen, host,
|
||
+ sizeof (host), service, sizeof (service),
|
||
+ NI_NAMEREQD | NI_NUMERICSERV);
|
||
+ TEST_COMPARE (ret, 0);
|
||
+ TEST_COMPARE_STRING (host, fqdn);
|
||
+ TEST_COMPARE_STRING (service, "80");
|
||
+ }
|
||
+
|
||
+ free (expected.buffer);
|
||
+ free (fqdn);
|
||
+ free (label);
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ struct resolv_test *obj = resolv_test_start
|
||
+ ((struct resolv_redirect_config)
|
||
+ {
|
||
+ .response_callback = response
|
||
+ });
|
||
+
|
||
+ for (int count = 0; count <= 3; ++count)
|
||
+ for (int bits = 0; bits <= 1 << (count * 2); ++bits)
|
||
+ {
|
||
+ if (count > 0 && bits == count)
|
||
+ /* The last bits value is only checked if count == 0. */
|
||
+ continue;
|
||
+
|
||
+ for (enum test_mode mode = 0; mode < test_mode_num; ++mode)
|
||
+ {
|
||
+ check_forward (AF_INET, bits, count, mode);
|
||
+ if (mode != byname)
|
||
+ check_forward (AF_INET6, bits, count, mode);
|
||
+ if (mode == gai || mode == gai_canon)
|
||
+ check_forward (AF_UNSPEC, bits, count, mode);
|
||
+ }
|
||
+
|
||
+ check_reverse (AF_INET, bits, count);
|
||
+ check_reverse (AF_INET6, bits, count);
|
||
+ }
|
||
+
|
||
+ resolv_test_end (obj);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/resolv/tst-resolv-maybe_insert_sig.h b/resolv/tst-resolv-maybe_insert_sig.h
|
||
new file mode 100644
|
||
index 0000000000..05725225af
|
||
--- /dev/null
|
||
+++ b/resolv/tst-resolv-maybe_insert_sig.h
|
||
@@ -0,0 +1,32 @@
|
||
+/* Code snippet for optionally inserting ignored SIG records in resolver tests.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+/* Set to true for an alternative pass that inserts (ignored) SIG
|
||
+ records. This does not alter the response, so this property is not
|
||
+ encoded in the QNAME. The variable needs to be volatile because
|
||
+ leaf attributes tell GCC that the response function is not
|
||
+ called. */
|
||
+static volatile bool insert_sig;
|
||
+
|
||
+static void
|
||
+maybe_insert_sig (struct resolv_response_builder *b, const char *owner)
|
||
+{
|
||
+ resolv_response_open_record (b, owner, C_IN, T_SIG, 60);
|
||
+ resolv_response_add_data (b, "", 1);
|
||
+ resolv_response_close_record (b);
|
||
+}
|
||
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
|
||
index 2dd6bfda18..b87cf2f809 100644
|
||
--- a/scripts/dso-ordering-test.py
|
||
+++ b/scripts/dso-ordering-test.py
|
||
@@ -707,13 +707,12 @@ def process_testcase(t):
|
||
"\t$(compile.c) $(OUTPUT_OPTION)\n")
|
||
makefile.write (rule)
|
||
|
||
- not_depended_objs = find_objs_not_depended_on(test_descr)
|
||
- if not_depended_objs:
|
||
- depstr = ""
|
||
- for dep in not_depended_objs:
|
||
- depstr += (" $(objpfx)" + test_subdir + "/"
|
||
- + test_name + "-" + dep + ".so")
|
||
- makefile.write("$(objpfx)%s.out:%s\n" % (base_test_name, depstr))
|
||
+ # Ensure that all shared objects are built before running the
|
||
+ # test, whether there link-time dependencies or not.
|
||
+ depobjs = ["$(objpfx){}/{}-{}.so".format(test_subdir, test_name, dep)
|
||
+ for dep in test_descr.objs]
|
||
+ makefile.write("$(objpfx){}.out: {}\n".format(
|
||
+ base_test_name, " ".join(depobjs)))
|
||
|
||
# Add main executable to test-srcs
|
||
makefile.write("test-srcs += %s/%s\n" % (test_subdir, test_name))
|
||
diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
|
||
index 43ab58ffe2..36d204c9b0 100644
|
||
--- a/scripts/glibcextract.py
|
||
+++ b/scripts/glibcextract.py
|
||
@@ -17,6 +17,7 @@
|
||
# License along with the GNU C Library; if not, see
|
||
# <https://www.gnu.org/licenses/>.
|
||
|
||
+import collections
|
||
import os.path
|
||
import re
|
||
import subprocess
|
||
@@ -173,3 +174,21 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None,
|
||
if not allow_extra_2:
|
||
ret = 1
|
||
return ret
|
||
+
|
||
+CompileResult = collections.namedtuple("CompileResult", "returncode output")
|
||
+
|
||
+def compile_c_snippet(snippet, cc, extra_cc_args=''):
|
||
+ """Compile and return whether the SNIPPET can be build with CC along
|
||
+ EXTRA_CC_ARGS compiler flags. Return a CompileResult with RETURNCODE
|
||
+ being 0 for success, or the failure value and the compiler output.
|
||
+ """
|
||
+ with tempfile.TemporaryDirectory() as temp_dir:
|
||
+ c_file_name = os.path.join(temp_dir, 'test.c')
|
||
+ obj_file_name = os.path.join(temp_dir, 'test.o')
|
||
+ with open(c_file_name, 'w') as c_file:
|
||
+ c_file.write(snippet + '\n')
|
||
+ cmd = cc.split() + extra_cc_args.split() + ['-c', '-o', obj_file_name,
|
||
+ c_file_name]
|
||
+ r = subprocess.run(cmd, check=False, stdout=subprocess.PIPE,
|
||
+ stderr=subprocess.STDOUT)
|
||
+ return CompileResult(r.returncode, r.stdout)
|
||
diff --git a/socket/Makefile b/socket/Makefile
|
||
index 156eec6c85..2bde78387f 100644
|
||
--- a/socket/Makefile
|
||
+++ b/socket/Makefile
|
||
@@ -34,6 +34,7 @@ routines := accept bind connect getpeername getsockname getsockopt \
|
||
tests := \
|
||
tst-accept4 \
|
||
tst-sockopt \
|
||
+ tst-cmsghdr \
|
||
# tests
|
||
|
||
tests-internal := \
|
||
diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c
|
||
new file mode 100644
|
||
index 0000000000..4c6898569b
|
||
--- /dev/null
|
||
+++ b/socket/tst-cmsghdr-skeleton.c
|
||
@@ -0,0 +1,92 @@
|
||
+/* Test ancillary data header creation.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+/* We use the preprocessor to generate the function/macro tests instead of
|
||
+ using indirection because having all the macro expansions alongside
|
||
+ each other lets the compiler warn us about suspicious pointer
|
||
+ arithmetic across subsequent CMSG_{FIRST,NXT}HDR expansions. */
|
||
+
|
||
+#include <stdint.h>
|
||
+
|
||
+#define RUN_TEST_CONCAT(suffix) run_test_##suffix
|
||
+#define RUN_TEST_FUNCNAME(suffix) RUN_TEST_CONCAT (suffix)
|
||
+
|
||
+static void
|
||
+RUN_TEST_FUNCNAME (CMSG_NXTHDR_IMPL) (void)
|
||
+{
|
||
+ struct msghdr m = {0};
|
||
+ struct cmsghdr *cmsg;
|
||
+ char cmsgbuf[3 * CMSG_SPACE (sizeof (PAYLOAD))] = {0};
|
||
+
|
||
+ m.msg_control = cmsgbuf;
|
||
+ m.msg_controllen = sizeof (cmsgbuf);
|
||
+
|
||
+ /* First header should point to the start of the buffer. */
|
||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||
+
|
||
+ /* If the first header length consumes the entire buffer, there is no
|
||
+ space remaining for additional headers. */
|
||
+ cmsg->cmsg_len = sizeof (cmsgbuf);
|
||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||
+ TEST_VERIFY_EXIT (cmsg == NULL);
|
||
+
|
||
+ /* The first header length is so big, using it would cause an overflow. */
|
||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||
+ cmsg->cmsg_len = SIZE_MAX;
|
||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||
+ TEST_VERIFY_EXIT (cmsg == NULL);
|
||
+
|
||
+ /* The first header leaves just enough space to hold another header. */
|
||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||
+ cmsg->cmsg_len = sizeof (cmsgbuf) - sizeof (struct cmsghdr);
|
||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||
+ TEST_VERIFY_EXIT (cmsg != NULL);
|
||
+
|
||
+ /* The first header leaves space but not enough for another header. */
|
||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||
+ cmsg->cmsg_len ++;
|
||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||
+ TEST_VERIFY_EXIT (cmsg == NULL);
|
||
+
|
||
+ /* The second header leaves just enough space to hold another header. */
|
||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||
+ cmsg->cmsg_len = CMSG_LEN (sizeof (PAYLOAD));
|
||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||
+ TEST_VERIFY_EXIT (cmsg != NULL);
|
||
+ cmsg->cmsg_len = sizeof (cmsgbuf)
|
||
+ - CMSG_SPACE (sizeof (PAYLOAD)) /* First header. */
|
||
+ - sizeof (struct cmsghdr);
|
||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||
+ TEST_VERIFY_EXIT (cmsg != NULL);
|
||
+
|
||
+ /* The second header leaves space but not enough for another header. */
|
||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||
+ TEST_VERIFY_EXIT (cmsg != NULL);
|
||
+ cmsg->cmsg_len ++;
|
||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||
+ TEST_VERIFY_EXIT (cmsg == NULL);
|
||
+
|
||
+ return;
|
||
+}
|
||
diff --git a/socket/tst-cmsghdr.c b/socket/tst-cmsghdr.c
|
||
new file mode 100644
|
||
index 0000000000..68c96d3c9d
|
||
--- /dev/null
|
||
+++ b/socket/tst-cmsghdr.c
|
||
@@ -0,0 +1,56 @@
|
||
+/* Test ancillary data header creation.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <sys/socket.h>
|
||
+#include <gnu/lib-names.h>
|
||
+#include <support/xdlfcn.h>
|
||
+#include <support/check.h>
|
||
+
|
||
+#define PAYLOAD "Hello, World!"
|
||
+
|
||
+/* CMSG_NXTHDR is a macro that calls an inline function defined in
|
||
+ bits/socket.h. In case the function cannot be inlined, libc.so carries
|
||
+ a copy. Both versions need to be tested. */
|
||
+
|
||
+#define CMSG_NXTHDR_IMPL CMSG_NXTHDR
|
||
+#include "tst-cmsghdr-skeleton.c"
|
||
+#undef CMSG_NXTHDR_IMPL
|
||
+
|
||
+static struct cmsghdr * (* cmsg_nxthdr) (struct msghdr *, struct cmsghdr *);
|
||
+
|
||
+#define CMSG_NXTHDR_IMPL cmsg_nxthdr
|
||
+#include "tst-cmsghdr-skeleton.c"
|
||
+#undef CMSG_NXTHDR_IMPL
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ static void *handle;
|
||
+
|
||
+ run_test_CMSG_NXTHDR ();
|
||
+
|
||
+ handle = xdlopen (LIBC_SO, RTLD_LAZY);
|
||
+ cmsg_nxthdr = (struct cmsghdr * (*) (struct msghdr *, struct cmsghdr *))
|
||
+ xdlsym (handle, "__cmsg_nxthdr");
|
||
+
|
||
+ run_test_cmsg_nxthdr ();
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/stdlib/Makefile b/stdlib/Makefile
|
||
index f7b25c1981..3d49c4941a 100644
|
||
--- a/stdlib/Makefile
|
||
+++ b/stdlib/Makefile
|
||
@@ -171,6 +171,7 @@ tests := \
|
||
test-a64l \
|
||
test-at_quick_exit-race \
|
||
test-atexit-race \
|
||
+ test-atexit-recursive \
|
||
test-bz22786 \
|
||
test-canon \
|
||
test-canon2 \
|
||
diff --git a/stdlib/arc4random.c b/stdlib/arc4random.c
|
||
index e417ef624d..960a38f295 100644
|
||
--- a/stdlib/arc4random.c
|
||
+++ b/stdlib/arc4random.c
|
||
@@ -34,7 +34,7 @@ void
|
||
__arc4random_buf (void *p, size_t n)
|
||
{
|
||
static int seen_initialized;
|
||
- size_t l;
|
||
+ ssize_t l;
|
||
int fd;
|
||
|
||
if (n == 0)
|
||
diff --git a/stdlib/exit.c b/stdlib/exit.c
|
||
index bc46109f3e..dc12e212bc 100644
|
||
--- a/stdlib/exit.c
|
||
+++ b/stdlib/exit.c
|
||
@@ -53,7 +53,10 @@ __run_exit_handlers (int status, struct exit_function_list **listp,
|
||
exit (). */
|
||
while (true)
|
||
{
|
||
- struct exit_function_list *cur = *listp;
|
||
+ struct exit_function_list *cur;
|
||
+
|
||
+ restart:
|
||
+ cur = *listp;
|
||
|
||
if (cur == NULL)
|
||
{
|
||
@@ -118,7 +121,7 @@ __run_exit_handlers (int status, struct exit_function_list **listp,
|
||
if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called))
|
||
/* The last exit function, or another thread, has registered
|
||
more exit functions. Start the loop over. */
|
||
- continue;
|
||
+ goto restart;
|
||
}
|
||
|
||
*listp = cur->next;
|
||
diff --git a/stdlib/longlong.h b/stdlib/longlong.h
|
||
index 9b89469ac2..d8f76a43b5 100644
|
||
--- a/stdlib/longlong.h
|
||
+++ b/stdlib/longlong.h
|
||
@@ -593,6 +593,18 @@ extern UDItype __umulsidi3 (USItype, USItype);
|
||
#define UMUL_TIME 14
|
||
#endif
|
||
|
||
+#ifdef __loongarch__
|
||
+# if W_TYPE_SIZE == 32
|
||
+# define count_leading_zeros(count, x) ((count) = __builtin_clz (x))
|
||
+# define count_trailing_zeros(count, x) ((count) = __builtin_ctz (x))
|
||
+# define COUNT_LEADING_ZEROS_0 32
|
||
+# elif W_TYPE_SIZE == 64
|
||
+# define count_leading_zeros(count, x) ((count) = __builtin_clzll (x))
|
||
+# define count_trailing_zeros(count, x) ((count) = __builtin_ctzll (x))
|
||
+# define COUNT_LEADING_ZEROS_0 64
|
||
+# endif
|
||
+#endif
|
||
+
|
||
#if defined (__M32R__) && W_TYPE_SIZE == 32
|
||
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
|
||
/* The cmp clears the condition bit. */ \
|
||
diff --git a/stdlib/test-atexit-recursive.c b/stdlib/test-atexit-recursive.c
|
||
new file mode 100644
|
||
index 0000000000..0596b9763b
|
||
--- /dev/null
|
||
+++ b/stdlib/test-atexit-recursive.c
|
||
@@ -0,0 +1,75 @@
|
||
+/* Support file for atexit/exit, etc. race tests (BZ #27749).
|
||
+ Copyright (C) 2023 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+/* Check that atexit handler registed from another handler still called. */
|
||
+
|
||
+#include <stdio.h>
|
||
+#include <stdlib.h>
|
||
+#include <support/check.h>
|
||
+#include <support/xunistd.h>
|
||
+#include <sys/wait.h>
|
||
+#include <unistd.h>
|
||
+
|
||
+static void
|
||
+atexit_cb (void)
|
||
+{
|
||
+}
|
||
+
|
||
+static void
|
||
+atexit_last (void)
|
||
+{
|
||
+ _exit (1);
|
||
+}
|
||
+
|
||
+static void
|
||
+atexit_recursive (void)
|
||
+{
|
||
+ atexit (&atexit_cb);
|
||
+ atexit (&atexit_last);
|
||
+}
|
||
+
|
||
+_Noreturn static void
|
||
+test_and_exit (int count)
|
||
+{
|
||
+ for (int i = 0; i < count; ++i)
|
||
+ atexit (&atexit_cb);
|
||
+ atexit (&atexit_recursive);
|
||
+ exit (0);
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ for (int i = 0; i < 100; ++i)
|
||
+ if (xfork () == 0)
|
||
+ test_and_exit (i);
|
||
+
|
||
+ for (int i = 0; i < 100; ++i)
|
||
+ {
|
||
+ int status;
|
||
+ xwaitpid (0, &status, 0);
|
||
+ if (!WIFEXITED (status))
|
||
+ FAIL_EXIT1 ("Failed iterations %d", i);
|
||
+ TEST_COMPARE (WEXITSTATUS (status), 1);
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#define TEST_FUNCTION do_test
|
||
+#include <support/test-driver.c>
|
||
diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c
|
||
index f7fa74b2a6..5e0c79475f 100644
|
||
--- a/stdlib/tst-system.c
|
||
+++ b/stdlib/tst-system.c
|
||
@@ -25,6 +25,7 @@
|
||
#include <support/check.h>
|
||
#include <support/temp_file.h>
|
||
#include <support/support.h>
|
||
+#include <support/xthread.h>
|
||
#include <support/xunistd.h>
|
||
|
||
static char *tmpdir;
|
||
@@ -71,6 +72,20 @@ call_system (void *closure)
|
||
}
|
||
}
|
||
|
||
+static void *
|
||
+sleep_and_check_sigchld (void *closure)
|
||
+{
|
||
+ double *seconds = (double *) closure;
|
||
+ char cmd[namemax];
|
||
+ sprintf (cmd, "sleep %lf" , *seconds);
|
||
+ TEST_COMPARE (system (cmd), 0);
|
||
+
|
||
+ sigset_t blocked = {0};
|
||
+ TEST_COMPARE (sigprocmask (SIG_BLOCK, NULL, &blocked), 0);
|
||
+ TEST_COMPARE (sigismember (&blocked, SIGCHLD), 0);
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
static int
|
||
do_test (void)
|
||
{
|
||
@@ -154,6 +169,17 @@ do_test (void)
|
||
xchmod (_PATH_BSHELL, st.st_mode);
|
||
}
|
||
|
||
+ {
|
||
+ pthread_t long_sleep_thread = xpthread_create (NULL,
|
||
+ sleep_and_check_sigchld,
|
||
+ &(double) { 0.2 });
|
||
+ pthread_t short_sleep_thread = xpthread_create (NULL,
|
||
+ sleep_and_check_sigchld,
|
||
+ &(double) { 0.1 });
|
||
+ xpthread_join (short_sleep_thread);
|
||
+ xpthread_join (long_sleep_thread);
|
||
+ }
|
||
+
|
||
TEST_COMPARE (system (""), 0);
|
||
|
||
return 0;
|
||
diff --git a/string/test-strnlen.c b/string/test-strnlen.c
|
||
index 4a9375112a..5cbaf4b734 100644
|
||
--- a/string/test-strnlen.c
|
||
+++ b/string/test-strnlen.c
|
||
@@ -73,7 +73,7 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char)
|
||
{
|
||
size_t i;
|
||
|
||
- align &= 63;
|
||
+ align &= (getpagesize () / sizeof (CHAR) - 1);
|
||
if ((align + len) * sizeof (CHAR) >= page_size)
|
||
return;
|
||
|
||
@@ -90,38 +90,50 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char)
|
||
static void
|
||
do_overflow_tests (void)
|
||
{
|
||
- size_t i, j, len;
|
||
+ size_t i, j, al_idx, repeats, len;
|
||
const size_t one = 1;
|
||
uintptr_t buf_addr = (uintptr_t) buf1;
|
||
+ const size_t alignments[] = { 0, 1, 7, 9, 31, 33, 63, 65, 95, 97, 127, 129 };
|
||
|
||
- for (i = 0; i < 750; ++i)
|
||
+ for (al_idx = 0; al_idx < sizeof (alignments) / sizeof (alignments[0]);
|
||
+ al_idx++)
|
||
{
|
||
- do_test (1, i, SIZE_MAX, BIG_CHAR);
|
||
-
|
||
- do_test (0, i, SIZE_MAX - i, BIG_CHAR);
|
||
- do_test (0, i, i - buf_addr, BIG_CHAR);
|
||
- do_test (0, i, -buf_addr - i, BIG_CHAR);
|
||
- do_test (0, i, SIZE_MAX - buf_addr - i, BIG_CHAR);
|
||
- do_test (0, i, SIZE_MAX - buf_addr + i, BIG_CHAR);
|
||
-
|
||
- len = 0;
|
||
- for (j = 8 * sizeof(size_t) - 1; j ; --j)
|
||
- {
|
||
- len |= one << j;
|
||
- do_test (0, i, len - i, BIG_CHAR);
|
||
- do_test (0, i, len + i, BIG_CHAR);
|
||
- do_test (0, i, len - buf_addr - i, BIG_CHAR);
|
||
- do_test (0, i, len - buf_addr + i, BIG_CHAR);
|
||
-
|
||
- do_test (0, i, ~len - i, BIG_CHAR);
|
||
- do_test (0, i, ~len + i, BIG_CHAR);
|
||
- do_test (0, i, ~len - buf_addr - i, BIG_CHAR);
|
||
- do_test (0, i, ~len - buf_addr + i, BIG_CHAR);
|
||
-
|
||
- do_test (0, i, -buf_addr, BIG_CHAR);
|
||
- do_test (0, i, j - buf_addr, BIG_CHAR);
|
||
- do_test (0, i, -buf_addr - j, BIG_CHAR);
|
||
- }
|
||
+ for (repeats = 0; repeats < 2; ++repeats)
|
||
+ {
|
||
+ size_t align = repeats ? (getpagesize () - alignments[al_idx])
|
||
+ : alignments[al_idx];
|
||
+ align /= sizeof (CHAR);
|
||
+ for (i = 0; i < 750; ++i)
|
||
+ {
|
||
+ do_test (align, i, SIZE_MAX, BIG_CHAR);
|
||
+
|
||
+ do_test (align, i, SIZE_MAX - i, BIG_CHAR);
|
||
+ do_test (align, i, i - buf_addr, BIG_CHAR);
|
||
+ do_test (align, i, -buf_addr - i, BIG_CHAR);
|
||
+ do_test (align, i, SIZE_MAX - buf_addr - i, BIG_CHAR);
|
||
+ do_test (align, i, SIZE_MAX - buf_addr + i, BIG_CHAR);
|
||
+
|
||
+ len = 0;
|
||
+ for (j = 8 * sizeof (size_t) - 1; j; --j)
|
||
+ {
|
||
+ len |= one << j;
|
||
+ do_test (align, i, len, BIG_CHAR);
|
||
+ do_test (align, i, len - i, BIG_CHAR);
|
||
+ do_test (align, i, len + i, BIG_CHAR);
|
||
+ do_test (align, i, len - buf_addr - i, BIG_CHAR);
|
||
+ do_test (align, i, len - buf_addr + i, BIG_CHAR);
|
||
+
|
||
+ do_test (align, i, ~len - i, BIG_CHAR);
|
||
+ do_test (align, i, ~len + i, BIG_CHAR);
|
||
+ do_test (align, i, ~len - buf_addr - i, BIG_CHAR);
|
||
+ do_test (align, i, ~len - buf_addr + i, BIG_CHAR);
|
||
+
|
||
+ do_test (align, i, -buf_addr, BIG_CHAR);
|
||
+ do_test (align, i, j - buf_addr, BIG_CHAR);
|
||
+ do_test (align, i, -buf_addr - j, BIG_CHAR);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
}
|
||
}
|
||
|
||
diff --git a/sunrpc/netname.c b/sunrpc/netname.c
|
||
index bf7f0b81c4..c1d1c43e50 100644
|
||
--- a/sunrpc/netname.c
|
||
+++ b/sunrpc/netname.c
|
||
@@ -20,6 +20,7 @@
|
||
#include <string.h>
|
||
#include <rpc/rpc.h>
|
||
#include <shlib-compat.h>
|
||
+#include <libc-diag.h>
|
||
|
||
#include "nsswitch.h"
|
||
|
||
@@ -48,7 +49,12 @@ user2netname (char netname[MAXNETNAMELEN + 1], const uid_t uid,
|
||
if ((strlen (dfltdom) + OPSYS_LEN + 3 + MAXIPRINT) > (size_t) MAXNETNAMELEN)
|
||
return 0;
|
||
|
||
+ /* GCC with -Os warns that sprint might overflow while handling dfltdom,
|
||
+ however the above test does check if an overflow would happen. */
|
||
+ DIAG_PUSH_NEEDS_COMMENT;
|
||
+ DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wformat-overflow");
|
||
sprintf (netname, "%s.%d@%s", OPSYS, uid, dfltdom);
|
||
+ DIAG_POP_NEEDS_COMMENT;
|
||
i = strlen (netname);
|
||
if (netname[i - 1] == '.')
|
||
netname[i - 1] = '\0';
|
||
diff --git a/support/Makefile b/support/Makefile
|
||
index 9b50eac117..2b661a7eb8 100644
|
||
--- a/support/Makefile
|
||
+++ b/support/Makefile
|
||
@@ -32,6 +32,8 @@ libsupport-routines = \
|
||
check_hostent \
|
||
check_netent \
|
||
delayed_exit \
|
||
+ dtotimespec \
|
||
+ dtotimespec-time64 \
|
||
ignore_stderr \
|
||
next_to_fault \
|
||
oom_error \
|
||
diff --git a/support/dtotimespec-time64.c b/support/dtotimespec-time64.c
|
||
new file mode 100644
|
||
index 0000000000..b3d5e351e3
|
||
--- /dev/null
|
||
+++ b/support/dtotimespec-time64.c
|
||
@@ -0,0 +1,27 @@
|
||
+/* Convert double to timespec. 64-bit time support.
|
||
+ Copyright (C) 2011-2023 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library and is also part of gnulib.
|
||
+ Patches to this file should be submitted to both projects.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <time.h>
|
||
+
|
||
+#if __TIMESIZE != 64
|
||
+# define timespec __timespec64
|
||
+# define time_t __time64_t
|
||
+# define dtotimespec dtotimespec_time64
|
||
+# include "dtotimespec.c"
|
||
+#endif
|
||
diff --git a/support/dtotimespec.c b/support/dtotimespec.c
|
||
new file mode 100644
|
||
index 0000000000..cde5b4d74c
|
||
--- /dev/null
|
||
+++ b/support/dtotimespec.c
|
||
@@ -0,0 +1,50 @@
|
||
+/* Convert double to timespec.
|
||
+ Copyright (C) 2011-2023 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library and is also part of gnulib.
|
||
+ Patches to this file should be submitted to both projects.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+/* Convert the double value SEC to a struct timespec. Round toward
|
||
+ positive infinity. On overflow, return an extremal value. */
|
||
+
|
||
+#include <support/timespec.h>
|
||
+#include <intprops.h>
|
||
+
|
||
+struct timespec
|
||
+dtotimespec (double sec)
|
||
+{
|
||
+ if (sec <= TYPE_MINIMUM (time_t))
|
||
+ return make_timespec (TYPE_MINIMUM (time_t), 0);
|
||
+ else if (sec >= 1.0 + TYPE_MAXIMUM (time_t))
|
||
+ return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1);
|
||
+ else
|
||
+ {
|
||
+ time_t s = sec;
|
||
+ double frac = TIMESPEC_HZ * (sec - s);
|
||
+ long ns = frac;
|
||
+ ns += ns < frac;
|
||
+ s += ns / TIMESPEC_HZ;
|
||
+ ns %= TIMESPEC_HZ;
|
||
+
|
||
+ if (ns < 0)
|
||
+ {
|
||
+ s--;
|
||
+ ns += TIMESPEC_HZ;
|
||
+ }
|
||
+
|
||
+ return make_timespec (s, ns);
|
||
+ }
|
||
+}
|
||
diff --git a/support/shell-container.c b/support/shell-container.c
|
||
index 1c73666f0a..6698061b9b 100644
|
||
--- a/support/shell-container.c
|
||
+++ b/support/shell-container.c
|
||
@@ -39,6 +39,7 @@
|
||
#include <error.h>
|
||
|
||
#include <support/support.h>
|
||
+#include <support/timespec.h>
|
||
|
||
/* Design considerations
|
||
|
||
@@ -171,6 +172,32 @@ kill_func (char **argv)
|
||
return 0;
|
||
}
|
||
|
||
+/* Emulate the "/bin/sleep" command. No suffix support. Options are
|
||
+ ignored. */
|
||
+static int
|
||
+sleep_func (char **argv)
|
||
+{
|
||
+ if (argv[0] == NULL)
|
||
+ {
|
||
+ fprintf (stderr, "sleep: missing operand\n");
|
||
+ return 1;
|
||
+ }
|
||
+ char *endptr = NULL;
|
||
+ double sec = strtod (argv[0], &endptr);
|
||
+ if (endptr == argv[0] || errno == ERANGE || sec < 0)
|
||
+ {
|
||
+ fprintf (stderr, "sleep: invalid time interval '%s'\n", argv[0]);
|
||
+ return 1;
|
||
+ }
|
||
+ struct timespec ts = dtotimespec (sec);
|
||
+ if (nanosleep (&ts, NULL) < 0)
|
||
+ {
|
||
+ fprintf (stderr, "sleep: failed to nanosleep: %s\n", strerror (errno));
|
||
+ return 1;
|
||
+ }
|
||
+ return 0;
|
||
+}
|
||
+
|
||
/* This is a list of all the built-in commands we understand. */
|
||
static struct {
|
||
const char *name;
|
||
@@ -181,6 +208,7 @@ static struct {
|
||
{ "cp", copy_func },
|
||
{ "exit", exit_func },
|
||
{ "kill", kill_func },
|
||
+ { "sleep", sleep_func },
|
||
{ NULL, NULL }
|
||
};
|
||
|
||
diff --git a/support/timespec.h b/support/timespec.h
|
||
index 4d2ac2737d..1bba3a6837 100644
|
||
--- a/support/timespec.h
|
||
+++ b/support/timespec.h
|
||
@@ -57,6 +57,8 @@ int support_timespec_check_in_range (struct timespec expected,
|
||
struct timespec observed,
|
||
double lower_bound, double upper_bound);
|
||
|
||
+struct timespec dtotimespec (double sec) __attribute__((const));
|
||
+
|
||
#else
|
||
struct timespec __REDIRECT (timespec_add, (struct timespec, struct timespec),
|
||
timespec_add_time64);
|
||
@@ -82,6 +84,8 @@ int __REDIRECT (support_timespec_check_in_range, (struct timespec expected,
|
||
double lower_bound,
|
||
double upper_bound),
|
||
support_timespec_check_in_range_time64);
|
||
+
|
||
+struct timespec __REDIRECT (dtotimespec, (double sec), dtotimespec_time64);
|
||
#endif
|
||
|
||
/* Check that the timespec on the left represents a time before the
|
||
diff --git a/sysdeps/aarch64/dl-trampoline.S b/sysdeps/aarch64/dl-trampoline.S
|
||
index 909b208578..d66f0b9c45 100644
|
||
--- a/sysdeps/aarch64/dl-trampoline.S
|
||
+++ b/sysdeps/aarch64/dl-trampoline.S
|
||
@@ -298,12 +298,11 @@ _dl_runtime_profile:
|
||
stp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1]
|
||
stp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2]
|
||
stp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3]
|
||
- str x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4]
|
||
stp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0]
|
||
stp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1]
|
||
stp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2]
|
||
stp q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3]
|
||
- str xzr, [X29, #OFFSET_RV + DL_OFFSET_RG_VPCS]
|
||
+ str xzr, [X29, #OFFSET_RV + DL_OFFSET_RV_VPCS]
|
||
|
||
/* Setup call to pltexit */
|
||
ldp x0, x1, [x29, #OFFSET_SAVED_CALL_X0]
|
||
@@ -315,7 +314,6 @@ _dl_runtime_profile:
|
||
ldp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1]
|
||
ldp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2]
|
||
ldp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3]
|
||
- ldr x8, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*4]
|
||
ldp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0]
|
||
ldp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1]
|
||
ldp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2]
|
||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||
index 050a3032de..6b256b8388 100644
|
||
--- a/sysdeps/generic/ldsodefs.h
|
||
+++ b/sysdeps/generic/ldsodefs.h
|
||
@@ -1048,9 +1048,11 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv,
|
||
initializer functions have completed. */
|
||
extern void _dl_fini (void) attribute_hidden;
|
||
|
||
-/* Sort array MAPS according to dependencies of the contained objects. */
|
||
+/* Sort array MAPS according to dependencies of the contained objects.
|
||
+ If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies
|
||
+ say otherwise. */
|
||
extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||
- unsigned int skip, bool for_fini) attribute_hidden;
|
||
+ bool force_first, bool for_fini) attribute_hidden;
|
||
|
||
/* The dynamic linker calls this function before and having changing
|
||
any shared object mappings. The `r_state' member of `struct r_debug'
|
||
diff --git a/sysdeps/generic/libc-lock-arch.h b/sysdeps/generic/libc-lock-arch.h
|
||
new file mode 100644
|
||
index 0000000000..4713b30a8a
|
||
--- /dev/null
|
||
+++ b/sysdeps/generic/libc-lock-arch.h
|
||
@@ -0,0 +1,25 @@
|
||
+/* Private libc-internal arch-specific definitions. Generic version.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public License as
|
||
+ published by the Free Software Foundation; either version 2.1 of the
|
||
+ License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; see the file COPYING.LIB. If
|
||
+ not, see <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#ifndef _LIBC_LOCK_ARCH_H
|
||
+#define _LIBC_LOCK_ARCH_H
|
||
+
|
||
+/* The default definition uses the natural alignment from the lock type. */
|
||
+#define __LIBC_LOCK_ALIGNMENT
|
||
+
|
||
+#endif
|
||
diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h
|
||
index c865713be1..1d51948566 100644
|
||
--- a/sysdeps/hppa/dl-machine.h
|
||
+++ b/sysdeps/hppa/dl-machine.h
|
||
@@ -347,6 +347,16 @@ elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
|
||
its return value is the user program's entry point. */
|
||
|
||
#define RTLD_START \
|
||
+/* Set up dp for any non-PIC lib constructors that may be called. */ \
|
||
+static struct link_map * __attribute__((used)) \
|
||
+set_dp (struct link_map *map) \
|
||
+{ \
|
||
+ register Elf32_Addr dp asm ("%r27"); \
|
||
+ dp = D_PTR (map, l_info[DT_PLTGOT]); \
|
||
+ asm volatile ("" : : "r" (dp)); \
|
||
+ return map; \
|
||
+} \
|
||
+ \
|
||
asm ( \
|
||
" .text\n" \
|
||
" .globl _start\n" \
|
||
@@ -426,6 +436,13 @@ asm ( \
|
||
direct loader invocation. Thus, argc and argv must be \
|
||
reloaded from from _dl_argc and _dl_argv. */ \
|
||
\
|
||
+ /* Load main_map from _rtld_local and setup dp. */ \
|
||
+" addil LT'_rtld_local,%r19\n" \
|
||
+" ldw RT'_rtld_local(%r1),%r26\n" \
|
||
+" bl set_dp, %r2\n" \
|
||
+" ldw 0(%r26),%r26\n" \
|
||
+" copy %ret0,%r26\n" \
|
||
+ \
|
||
/* Load argc from _dl_argc. */ \
|
||
" addil LT'_dl_argc,%r19\n" \
|
||
" ldw RT'_dl_argc(%r1),%r20\n" \
|
||
@@ -438,13 +455,10 @@ asm ( \
|
||
" ldw 0(%r20),%r24\n" \
|
||
" stw %r24,-44(%sp)\n" \
|
||
\
|
||
- /* Call _dl_init(main_map, argc, argv, envp). */ \
|
||
-" addil LT'_rtld_local,%r19\n" \
|
||
-" ldw RT'_rtld_local(%r1),%r26\n" \
|
||
-" ldw 0(%r26),%r26\n" \
|
||
- \
|
||
/* envp = argv + argc + 1 */ \
|
||
" sh2add %r25,%r24,%r23\n" \
|
||
+ \
|
||
+ /* Call _dl_init(main_map, argc, argv, envp). */ \
|
||
" bl _dl_init,%r2\n" \
|
||
" ldo 4(%r23),%r23\n" /* delay slot */ \
|
||
\
|
||
diff --git a/sysdeps/ieee754/ldbl-128/e_j1l.c b/sysdeps/ieee754/ldbl-128/e_j1l.c
|
||
index 54c457681a..9a9c5c6f00 100644
|
||
--- a/sysdeps/ieee754/ldbl-128/e_j1l.c
|
||
+++ b/sysdeps/ieee754/ldbl-128/e_j1l.c
|
||
@@ -869,10 +869,13 @@ __ieee754_y1l (_Float128 x)
|
||
{
|
||
/* 0 <= x <= 2 */
|
||
SET_RESTORE_ROUNDL (FE_TONEAREST);
|
||
+ xx = math_opt_barrier (xx);
|
||
+ x = math_opt_barrier (x);
|
||
z = xx * xx;
|
||
p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D);
|
||
p = -TWOOPI / xx + p;
|
||
p = TWOOPI * __ieee754_logl (x) * __ieee754_j1l (x) + p;
|
||
+ math_force_eval (p);
|
||
return p;
|
||
}
|
||
|
||
diff --git a/sysdeps/ieee754/ldbl-128ibm/e_j1l.c b/sysdeps/ieee754/ldbl-128ibm/e_j1l.c
|
||
index f85ba94466..0a5fe68342 100644
|
||
--- a/sysdeps/ieee754/ldbl-128ibm/e_j1l.c
|
||
+++ b/sysdeps/ieee754/ldbl-128ibm/e_j1l.c
|
||
@@ -792,10 +792,13 @@ __ieee754_y1l (long double x)
|
||
{
|
||
/* 0 <= x <= 2 */
|
||
SET_RESTORE_ROUNDL (FE_TONEAREST);
|
||
+ xx = math_opt_barrier (xx);
|
||
+ x = math_opt_barrier (x);
|
||
z = xx * xx;
|
||
p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D);
|
||
p = -TWOOPI / xx + p;
|
||
p = TWOOPI * __ieee754_logl (x) * __ieee754_j1l (x) + p;
|
||
+ math_force_eval (p);
|
||
return p;
|
||
}
|
||
|
||
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c
|
||
index d85154e73a..d8c0de1faf 100644
|
||
--- a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c
|
||
+++ b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c
|
||
@@ -66,38 +66,35 @@ __llroundl (long double x)
|
||
/* Peg at max/min values, assuming that the above conversions do so.
|
||
Strictly speaking, we can return anything for values that overflow,
|
||
but this is more useful. */
|
||
- res = hi + lo;
|
||
-
|
||
- /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi). */
|
||
- if (__glibc_unlikely (((~(hi ^ lo) & (res ^ hi)) < 0)))
|
||
+ if (__glibc_unlikely (__builtin_add_overflow (hi, lo, &res)))
|
||
goto overflow;
|
||
|
||
xh -= lo;
|
||
ldbl_canonicalize (&xh, &xl);
|
||
|
||
- hi = res;
|
||
if (xh > 0.5)
|
||
{
|
||
- res += 1;
|
||
+ if (__glibc_unlikely (__builtin_add_overflow (res, 1, &res)))
|
||
+ goto overflow;
|
||
}
|
||
else if (xh == 0.5)
|
||
{
|
||
if (xl > 0.0 || (xl == 0.0 && res >= 0))
|
||
- res += 1;
|
||
+ if (__glibc_unlikely (__builtin_add_overflow (res, 1, &res)))
|
||
+ goto overflow;
|
||
}
|
||
else if (-xh > 0.5)
|
||
{
|
||
- res -= 1;
|
||
+ if (__glibc_unlikely (__builtin_add_overflow (res, -1, &res)))
|
||
+ goto overflow;
|
||
}
|
||
else if (-xh == 0.5)
|
||
{
|
||
if (xl < 0.0 || (xl == 0.0 && res <= 0))
|
||
- res -= 1;
|
||
+ if (__glibc_unlikely (__builtin_add_overflow (res, -1, &res)))
|
||
+ goto overflow;
|
||
}
|
||
|
||
- if (__glibc_unlikely (((~(hi ^ (res - hi)) & (res ^ hi)) < 0)))
|
||
- goto overflow;
|
||
-
|
||
return res;
|
||
}
|
||
else
|
||
diff --git a/sysdeps/mach/hurd/bits/socket.h b/sysdeps/mach/hurd/bits/socket.h
|
||
index 5b35ea81ec..70fce4fb27 100644
|
||
--- a/sysdeps/mach/hurd/bits/socket.h
|
||
+++ b/sysdeps/mach/hurd/bits/socket.h
|
||
@@ -249,6 +249,12 @@ struct cmsghdr
|
||
+ CMSG_ALIGN (sizeof (struct cmsghdr)))
|
||
#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
|
||
|
||
+/* Given a length, return the additional padding necessary such that
|
||
+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
|
||
+#define __CMSG_PADDING(len) ((sizeof (size_t) \
|
||
+ - ((len) & (sizeof (size_t) - 1))) \
|
||
+ & (sizeof (size_t) - 1))
|
||
+
|
||
extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||
struct cmsghdr *__cmsg) __THROW;
|
||
#ifdef __USE_EXTERN_INLINES
|
||
@@ -258,18 +264,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||
_EXTERN_INLINE struct cmsghdr *
|
||
__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
|
||
{
|
||
+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
|
||
+ __mhdr->msg_controllen because the user is required to obtain the first
|
||
+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
|
||
+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
|
||
+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
|
||
+ pointer arithmetic until we check its value. */
|
||
+
|
||
+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
|
||
+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
|
||
+
|
||
+ size_t __size_needed = sizeof (struct cmsghdr)
|
||
+ + __CMSG_PADDING (__cmsg->cmsg_len);
|
||
+
|
||
+ /* The current header is malformed, too small to be a full header. */
|
||
if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
|
||
- /* The kernel header does this so there may be a reason. */
|
||
return (struct cmsghdr *) 0;
|
||
|
||
+ /* There isn't enough space between __cmsg and the end of the buffer to
|
||
+ hold the current cmsg *and* the next one. */
|
||
+ if (((size_t)
|
||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
|
||
+ < __size_needed)
|
||
+ || ((size_t)
|
||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
|
||
+ - __size_needed)
|
||
+ < __cmsg->cmsg_len))
|
||
+
|
||
+ return (struct cmsghdr *) 0;
|
||
+
|
||
+ /* Now, we trust cmsg_len and can use it to find the next header. */
|
||
__cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
|
||
+ CMSG_ALIGN (__cmsg->cmsg_len));
|
||
- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
|
||
- + __mhdr->msg_controllen)
|
||
- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
|
||
- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
|
||
- /* No more entries. */
|
||
- return (struct cmsghdr *) 0;
|
||
return __cmsg;
|
||
}
|
||
#endif /* Use `extern inline'. */
|
||
diff --git a/sysdeps/nptl/libc-lock.h b/sysdeps/nptl/libc-lock.h
|
||
index 5af476c48b..63b3f3d75c 100644
|
||
--- a/sysdeps/nptl/libc-lock.h
|
||
+++ b/sysdeps/nptl/libc-lock.h
|
||
@@ -22,6 +22,7 @@
|
||
#include <pthread.h>
|
||
#define __need_NULL
|
||
#include <stddef.h>
|
||
+#include <libc-lock-arch.h>
|
||
|
||
|
||
/* Mutex type. */
|
||
@@ -29,7 +30,12 @@
|
||
# if (!IS_IN (libc) && !IS_IN (libpthread)) || !defined _LIBC
|
||
typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t;
|
||
# else
|
||
-typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t;
|
||
+typedef struct
|
||
+{
|
||
+ int lock __LIBC_LOCK_ALIGNMENT;
|
||
+ int cnt;
|
||
+ void *owner;
|
||
+} __libc_lock_recursive_t;
|
||
# endif
|
||
#else
|
||
typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t;
|
||
diff --git a/sysdeps/nptl/libc-lockP.h b/sysdeps/nptl/libc-lockP.h
|
||
index d3a6837fd2..425f514c5c 100644
|
||
--- a/sysdeps/nptl/libc-lockP.h
|
||
+++ b/sysdeps/nptl/libc-lockP.h
|
||
@@ -32,9 +32,10 @@
|
||
ld.so might be used on old kernels with a different libc.so. */
|
||
#include <lowlevellock.h>
|
||
#include <tls.h>
|
||
+#include <libc-lock-arch.h>
|
||
|
||
/* Mutex type. */
|
||
-typedef int __libc_lock_t;
|
||
+typedef int __libc_lock_t __LIBC_LOCK_ALIGNMENT;
|
||
typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t;
|
||
typedef pthread_rwlock_t __libc_rwlock_t;
|
||
|
||
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
|
||
index bcff909b2f..5cda9bb072 100644
|
||
--- a/sysdeps/posix/getaddrinfo.c
|
||
+++ b/sysdeps/posix/getaddrinfo.c
|
||
@@ -540,11 +540,11 @@ get_nscd_addresses (const char *name, const struct addrinfo *req,
|
||
at[count].addr[2] = htonl (0xffff);
|
||
}
|
||
else if (req->ai_family == AF_UNSPEC
|
||
- || air->family[count] == req->ai_family)
|
||
+ || air->family[i] == req->ai_family)
|
||
{
|
||
- at[count].family = air->family[count];
|
||
+ at[count].family = air->family[i];
|
||
memcpy (at[count].addr, addrs, size);
|
||
- if (air->family[count] == AF_INET6)
|
||
+ if (air->family[i] == AF_INET6)
|
||
res->got_ipv6 = true;
|
||
}
|
||
at[count].next = at + count + 1;
|
||
diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c
|
||
index 8014f63355..20c9420dd4 100644
|
||
--- a/sysdeps/posix/system.c
|
||
+++ b/sysdeps/posix/system.c
|
||
@@ -179,16 +179,16 @@ do_system (const char *line)
|
||
as if the shell had terminated using _exit(127). */
|
||
status = W_EXITCODE (127, 0);
|
||
|
||
+ /* sigaction can not fail with SIGINT/SIGQUIT used with old
|
||
+ disposition. Same applies for sigprocmask. */
|
||
DO_LOCK ();
|
||
if (SUB_REF () == 0)
|
||
{
|
||
- /* sigaction can not fail with SIGINT/SIGQUIT used with old
|
||
- disposition. Same applies for sigprocmask. */
|
||
__sigaction (SIGINT, &intr, NULL);
|
||
__sigaction (SIGQUIT, &quit, NULL);
|
||
- __sigprocmask (SIG_SETMASK, &omask, NULL);
|
||
}
|
||
DO_UNLOCK ();
|
||
+ __sigprocmask (SIG_SETMASK, &omask, NULL);
|
||
|
||
if (ret != 0)
|
||
__set_errno (ret);
|
||
diff --git a/sysdeps/powerpc/mod-tlsopt-powerpc.c b/sysdeps/powerpc/mod-tlsopt-powerpc.c
|
||
index 2a82e53baf..d941024963 100644
|
||
--- a/sysdeps/powerpc/mod-tlsopt-powerpc.c
|
||
+++ b/sysdeps/powerpc/mod-tlsopt-powerpc.c
|
||
@@ -22,7 +22,11 @@ tls_get_addr_opt_test (void)
|
||
tls_index *tls_arg;
|
||
#ifdef __powerpc64__
|
||
register unsigned long thread_pointer __asm__ ("r13");
|
||
- asm ("addi %0,2,foo@got@tlsgd" : "=r" (tls_arg));
|
||
+# ifdef __PCREL__
|
||
+ asm ("paddi %0,0,foo@got@tlsgd@pcrel,1" : "=b" (tls_arg));
|
||
+# else
|
||
+ asm ("addi %0,2,foo@got@tlsgd" : "=b" (tls_arg));
|
||
+# endif
|
||
#else
|
||
register unsigned long thread_pointer __asm__ ("r2");
|
||
asm ("bcl 20,31,1f\n1:\t"
|
||
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
|
||
index a139a16532..d5d9af4de2 100644
|
||
--- a/sysdeps/unix/sysv/linux/Makefile
|
||
+++ b/sysdeps/unix/sysv/linux/Makefile
|
||
@@ -265,6 +265,14 @@ $(objpfx)tst-mount-consts.out: ../sysdeps/unix/sysv/linux/tst-mount-consts.py
|
||
< /dev/null > $@ 2>&1; $(evaluate-test)
|
||
$(objpfx)tst-mount-consts.out: $(sysdeps-linux-python-deps)
|
||
|
||
+tests-special += $(objpfx)tst-mount-compile.out
|
||
+$(objpfx)tst-mount-compile.out: ../sysdeps/unix/sysv/linux/tst-mount-compile.py
|
||
+ $(sysdeps-linux-python) \
|
||
+ ../sysdeps/unix/sysv/linux/tst-mount-compile.py \
|
||
+ $(sysdeps-linux-python-cc) \
|
||
+ < /dev/null > $@ 2>&1; $(evaluate-test)
|
||
+$(objpfx)tst-mount-compile.out: $(sysdeps-linux-python-deps)
|
||
+
|
||
tst-rseq-disable-ENV = GLIBC_TUNABLES=glibc.pthread.rseq=0
|
||
|
||
endif # $(subdir) == misc
|
||
@@ -354,6 +362,8 @@ sysdep_headers += netinet/if_fddi.h netinet/if_tr.h \
|
||
netrom/netrom.h netpacket/packet.h netrose/rose.h \
|
||
neteconet/ec.h netiucv/iucv.h
|
||
sysdep_routines += netlink_assert_response
|
||
+
|
||
+CFLAGS-check_pf.c += -fexceptions
|
||
endif
|
||
|
||
# Don't compile the ctype glue code, since there is no old non-GNU C library.
|
||
diff --git a/sysdeps/unix/sysv/linux/alpha/brk_call.h b/sysdeps/unix/sysv/linux/alpha/brk_call.h
|
||
index b8088cf13f..0b851b6c86 100644
|
||
--- a/sysdeps/unix/sysv/linux/alpha/brk_call.h
|
||
+++ b/sysdeps/unix/sysv/linux/alpha/brk_call.h
|
||
@@ -21,8 +21,7 @@ __brk_call (void *addr)
|
||
{
|
||
unsigned long int result = INTERNAL_SYSCALL_CALL (brk, addr);
|
||
if (result == -ENOMEM)
|
||
- /* Mimic the default error reporting behavior. */
|
||
- return addr;
|
||
- else
|
||
- return (void *) result;
|
||
+ /* Mimic the generic error reporting behavior. */
|
||
+ result = INTERNAL_SYSCALL_CALL (brk, 0);
|
||
+ return (void *) result;
|
||
}
|
||
diff --git a/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h b/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h
|
||
new file mode 100644
|
||
index 0000000000..30ee6279d2
|
||
--- /dev/null
|
||
+++ b/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h
|
||
@@ -0,0 +1,139 @@
|
||
+/* Definition for struct stat. Linux/arm version.
|
||
+ Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library. If not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
|
||
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
|
||
+#endif
|
||
+
|
||
+#ifndef _BITS_STRUCT_STAT_H
|
||
+#define _BITS_STRUCT_STAT_H 1
|
||
+
|
||
+#include <bits/endian.h>
|
||
+#include <bits/wordsize.h>
|
||
+
|
||
+struct stat
|
||
+ {
|
||
+#ifdef __USE_TIME_BITS64
|
||
+# include <bits/struct_stat_time64_helper.h>
|
||
+#else
|
||
+ __dev_t st_dev; /* Device. */
|
||
+ unsigned short int __pad1;
|
||
+# ifndef __USE_FILE_OFFSET64
|
||
+ __ino_t st_ino; /* File serial number. */
|
||
+# else
|
||
+ __ino_t __st_ino; /* 32bit file serial number. */
|
||
+# endif
|
||
+ __mode_t st_mode; /* File mode. */
|
||
+ __nlink_t st_nlink; /* Link count. */
|
||
+ __uid_t st_uid; /* User ID of the file's owner. */
|
||
+ __gid_t st_gid; /* Group ID of the file's group.*/
|
||
+ __dev_t st_rdev; /* Device number, if device. */
|
||
+ unsigned short int __pad2;
|
||
+# ifndef __USE_FILE_OFFSET64
|
||
+ __off_t st_size; /* Size of file, in bytes. */
|
||
+# else
|
||
+ __off64_t st_size; /* Size of file, in bytes. */
|
||
+# endif
|
||
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
+
|
||
+# ifndef __USE_FILE_OFFSET64
|
||
+ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */
|
||
+# else
|
||
+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
|
||
+# endif
|
||
+# ifdef __USE_XOPEN2K8
|
||
+ /* Nanosecond resolution timestamps are stored in a format
|
||
+ equivalent to 'struct timespec'. This is the type used
|
||
+ whenever possible but the Unix namespace rules do not allow the
|
||
+ identifier 'timespec' to appear in the <sys/stat.h> header.
|
||
+ Therefore we have to handle the use of this header in strictly
|
||
+ standard-compliant sources special. */
|
||
+ struct timespec st_atim; /* Time of last access. */
|
||
+ struct timespec st_mtim; /* Time of last modification. */
|
||
+ struct timespec st_ctim; /* Time of last status change. */
|
||
+# define st_atime st_atim.tv_sec /* Backward compatibility. */
|
||
+# define st_mtime st_mtim.tv_sec
|
||
+# define st_ctime st_ctim.tv_sec
|
||
+# else
|
||
+ __time_t st_atime; /* Time of last access. */
|
||
+ unsigned long int st_atimensec; /* Nscecs of last access. */
|
||
+ __time_t st_mtime; /* Time of last modification. */
|
||
+ unsigned long int st_mtimensec; /* Nsecs of last modification. */
|
||
+ __time_t st_ctime; /* Time of last status change. */
|
||
+ unsigned long int st_ctimensec; /* Nsecs of last status change. */
|
||
+# endif
|
||
+# ifndef __USE_FILE_OFFSET64
|
||
+ unsigned long int __glibc_reserved4;
|
||
+ unsigned long int __glibc_reserved5;
|
||
+# else
|
||
+ __ino64_t st_ino; /* File serial number. */
|
||
+# endif
|
||
+#endif /* __USE_TIME_BITS64 */
|
||
+ };
|
||
+
|
||
+#ifdef __USE_LARGEFILE64
|
||
+struct stat64
|
||
+ {
|
||
+# ifdef __USE_TIME_BITS64
|
||
+# include <bits/struct_stat_time64_helper.h>
|
||
+# else
|
||
+ __dev_t st_dev; /* Device. */
|
||
+ unsigned int __pad1;
|
||
+
|
||
+ __ino_t __st_ino; /* 32bit file serial number. */
|
||
+ __mode_t st_mode; /* File mode. */
|
||
+ __nlink_t st_nlink; /* Link count. */
|
||
+ __uid_t st_uid; /* User ID of the file's owner. */
|
||
+ __gid_t st_gid; /* Group ID of the file's group.*/
|
||
+ __dev_t st_rdev; /* Device number, if device. */
|
||
+ unsigned int __pad2;
|
||
+ __off64_t st_size; /* Size of file, in bytes. */
|
||
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
+
|
||
+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
|
||
+# ifdef __USE_XOPEN2K8
|
||
+ /* Nanosecond resolution timestamps are stored in a format
|
||
+ equivalent to 'struct timespec'. This is the type used
|
||
+ whenever possible but the Unix namespace rules do not allow the
|
||
+ identifier 'timespec' to appear in the <sys/stat.h> header.
|
||
+ Therefore we have to handle the use of this header in strictly
|
||
+ standard-compliant sources special. */
|
||
+ struct timespec st_atim; /* Time of last access. */
|
||
+ struct timespec st_mtim; /* Time of last modification. */
|
||
+ struct timespec st_ctim; /* Time of last status change. */
|
||
+# else
|
||
+ __time_t st_atime; /* Time of last access. */
|
||
+ unsigned long int st_atimensec; /* Nscecs of last access. */
|
||
+ __time_t st_mtime; /* Time of last modification. */
|
||
+ unsigned long int st_mtimensec; /* Nsecs of last modification. */
|
||
+ __time_t st_ctime; /* Time of last status change. */
|
||
+ unsigned long int st_ctimensec; /* Nsecs of last status change. */
|
||
+# endif
|
||
+ __ino64_t st_ino; /* File serial number. */
|
||
+# endif /* __USE_TIME_BITS64 */
|
||
+ };
|
||
+#endif
|
||
+
|
||
+/* Tell code we have these members. */
|
||
+#define _STATBUF_ST_BLKSIZE
|
||
+#define _STATBUF_ST_RDEV
|
||
+/* Nanosecond resolution time values are supported. */
|
||
+#define _STATBUF_ST_NSEC
|
||
+
|
||
+
|
||
+#endif /* _BITS_STRUCT_STAT_H */
|
||
diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
|
||
index 33ff88ce59..bfc674235d 100644
|
||
--- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
|
||
+++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
|
||
@@ -101,7 +101,7 @@
|
||
#endif
|
||
|
||
#ifndef F_GETLK
|
||
-# ifndef __USE_FILE_OFFSET64
|
||
+# if !defined __USE_FILE_OFFSET64 && __TIMESIZE != 64
|
||
# define F_GETLK 5 /* Get record locking info. */
|
||
# define F_SETLK 6 /* Set record locking info (non-blocking). */
|
||
# define F_SETLKW 7 /* Set record locking info (blocking). */
|
||
diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h
|
||
index 4f1f810ea1..539b8d7716 100644
|
||
--- a/sysdeps/unix/sysv/linux/bits/socket.h
|
||
+++ b/sysdeps/unix/sysv/linux/bits/socket.h
|
||
@@ -307,6 +307,12 @@ struct cmsghdr
|
||
+ CMSG_ALIGN (sizeof (struct cmsghdr)))
|
||
#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
|
||
|
||
+/* Given a length, return the additional padding necessary such that
|
||
+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
|
||
+#define __CMSG_PADDING(len) ((sizeof (size_t) \
|
||
+ - ((len) & (sizeof (size_t) - 1))) \
|
||
+ & (sizeof (size_t) - 1))
|
||
+
|
||
extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||
struct cmsghdr *__cmsg) __THROW;
|
||
#ifdef __USE_EXTERN_INLINES
|
||
@@ -316,18 +322,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||
_EXTERN_INLINE struct cmsghdr *
|
||
__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
|
||
{
|
||
+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
|
||
+ __mhdr->msg_controllen because the user is required to obtain the first
|
||
+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
|
||
+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
|
||
+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
|
||
+ pointer arithmetic until we check its value. */
|
||
+
|
||
+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
|
||
+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
|
||
+
|
||
+ size_t __size_needed = sizeof (struct cmsghdr)
|
||
+ + __CMSG_PADDING (__cmsg->cmsg_len);
|
||
+
|
||
+ /* The current header is malformed, too small to be a full header. */
|
||
if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
|
||
- /* The kernel header does this so there may be a reason. */
|
||
return (struct cmsghdr *) 0;
|
||
|
||
+ /* There isn't enough space between __cmsg and the end of the buffer to
|
||
+ hold the current cmsg *and* the next one. */
|
||
+ if (((size_t)
|
||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
|
||
+ < __size_needed)
|
||
+ || ((size_t)
|
||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
|
||
+ - __size_needed)
|
||
+ < __cmsg->cmsg_len))
|
||
+
|
||
+ return (struct cmsghdr *) 0;
|
||
+
|
||
+ /* Now, we trust cmsg_len and can use it to find the next header. */
|
||
__cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
|
||
+ CMSG_ALIGN (__cmsg->cmsg_len));
|
||
- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
|
||
- + __mhdr->msg_controllen)
|
||
- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
|
||
- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
|
||
- /* No more entries. */
|
||
- return (struct cmsghdr *) 0;
|
||
return __cmsg;
|
||
}
|
||
#endif /* Use `extern inline'. */
|
||
diff --git a/sysdeps/unix/sysv/linux/bits/struct_stat.h b/sysdeps/unix/sysv/linux/bits/struct_stat.h
|
||
index 25bd6cb638..fb11a3fba4 100644
|
||
--- a/sysdeps/unix/sysv/linux/bits/struct_stat.h
|
||
+++ b/sysdeps/unix/sysv/linux/bits/struct_stat.h
|
||
@@ -26,37 +26,36 @@
|
||
#include <bits/endian.h>
|
||
#include <bits/wordsize.h>
|
||
|
||
-struct stat
|
||
- {
|
||
-#ifdef __USE_TIME_BITS64
|
||
-# include <bits/struct_stat_time64_helper.h>
|
||
-#else
|
||
- __dev_t st_dev; /* Device. */
|
||
- unsigned short int __pad1;
|
||
-# ifndef __USE_FILE_OFFSET64
|
||
- __ino_t st_ino; /* File serial number. */
|
||
-# else
|
||
- __ino_t __st_ino; /* 32bit file serial number. */
|
||
+#if defined __USE_FILE_OFFSET64
|
||
+# define __field64(type, type64, name) type64 name
|
||
+#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T
|
||
+# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T
|
||
+# error "ino_t and off_t must both be the same type"
|
||
# endif
|
||
- __mode_t st_mode; /* File mode. */
|
||
- __nlink_t st_nlink; /* Link count. */
|
||
- __uid_t st_uid; /* User ID of the file's owner. */
|
||
- __gid_t st_gid; /* Group ID of the file's group.*/
|
||
- __dev_t st_rdev; /* Device number, if device. */
|
||
- unsigned short int __pad2;
|
||
-# ifndef __USE_FILE_OFFSET64
|
||
- __off_t st_size; /* Size of file, in bytes. */
|
||
-# else
|
||
- __off64_t st_size; /* Size of file, in bytes. */
|
||
-# endif
|
||
- __blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
+# define __field64(type, type64, name) type name
|
||
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||
+# define __field64(type, type64, name) \
|
||
+ type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad
|
||
+#else
|
||
+# define __field64(type, type64, name) \
|
||
+ int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name
|
||
+#endif
|
||
|
||
-# ifndef __USE_FILE_OFFSET64
|
||
- __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */
|
||
-# else
|
||
- __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
|
||
-# endif
|
||
-# ifdef __USE_XOPEN2K8
|
||
+struct stat
|
||
+ {
|
||
+ __dev_t st_dev; /* Device. */
|
||
+ __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */
|
||
+ __mode_t st_mode; /* File mode. */
|
||
+ __nlink_t st_nlink; /* Link count. */
|
||
+ __uid_t st_uid; /* User ID of the file's owner. */
|
||
+ __gid_t st_gid; /* Group ID of the file's group.*/
|
||
+ __dev_t st_rdev; /* Device number, if device. */
|
||
+ __dev_t __pad1;
|
||
+ __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */
|
||
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
+ int __pad2;
|
||
+ __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */
|
||
+#ifdef __USE_XOPEN2K8
|
||
/* Nanosecond resolution timestamps are stored in a format
|
||
equivalent to 'struct timespec'. This is the type used
|
||
whenever possible but the Unix namespace rules do not allow the
|
||
@@ -66,47 +65,38 @@ struct stat
|
||
struct timespec st_atim; /* Time of last access. */
|
||
struct timespec st_mtim; /* Time of last modification. */
|
||
struct timespec st_ctim; /* Time of last status change. */
|
||
-# define st_atime st_atim.tv_sec /* Backward compatibility. */
|
||
-# define st_mtime st_mtim.tv_sec
|
||
-# define st_ctime st_ctim.tv_sec
|
||
-# else
|
||
+# define st_atime st_atim.tv_sec /* Backward compatibility. */
|
||
+# define st_mtime st_mtim.tv_sec
|
||
+# define st_ctime st_ctim.tv_sec
|
||
+#else
|
||
__time_t st_atime; /* Time of last access. */
|
||
unsigned long int st_atimensec; /* Nscecs of last access. */
|
||
__time_t st_mtime; /* Time of last modification. */
|
||
unsigned long int st_mtimensec; /* Nsecs of last modification. */
|
||
__time_t st_ctime; /* Time of last status change. */
|
||
unsigned long int st_ctimensec; /* Nsecs of last status change. */
|
||
-# endif
|
||
-# ifndef __USE_FILE_OFFSET64
|
||
- unsigned long int __glibc_reserved4;
|
||
- unsigned long int __glibc_reserved5;
|
||
-# else
|
||
- __ino64_t st_ino; /* File serial number. */
|
||
-# endif
|
||
-#endif /* __USE_TIME_BITS64 */
|
||
+#endif
|
||
+ int __glibc_reserved[2];
|
||
};
|
||
|
||
+#undef __field64
|
||
+
|
||
#ifdef __USE_LARGEFILE64
|
||
struct stat64
|
||
{
|
||
-# ifdef __USE_TIME_BITS64
|
||
-# include <bits/struct_stat_time64_helper.h>
|
||
-# else
|
||
- __dev_t st_dev; /* Device. */
|
||
- unsigned int __pad1;
|
||
-
|
||
- __ino_t __st_ino; /* 32bit file serial number. */
|
||
- __mode_t st_mode; /* File mode. */
|
||
- __nlink_t st_nlink; /* Link count. */
|
||
- __uid_t st_uid; /* User ID of the file's owner. */
|
||
- __gid_t st_gid; /* Group ID of the file's group.*/
|
||
- __dev_t st_rdev; /* Device number, if device. */
|
||
- unsigned int __pad2;
|
||
- __off64_t st_size; /* Size of file, in bytes. */
|
||
- __blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
-
|
||
- __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
|
||
-# ifdef __USE_XOPEN2K8
|
||
+ __dev_t st_dev; /* Device. */
|
||
+ __ino64_t st_ino; /* File serial number. */
|
||
+ __mode_t st_mode; /* File mode. */
|
||
+ __nlink_t st_nlink; /* Link count. */
|
||
+ __uid_t st_uid; /* User ID of the file's owner. */
|
||
+ __gid_t st_gid; /* Group ID of the file's group.*/
|
||
+ __dev_t st_rdev; /* Device number, if device. */
|
||
+ __dev_t __pad1;
|
||
+ __off64_t st_size; /* Size of file, in bytes. */
|
||
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
+ int __pad2;
|
||
+ __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */
|
||
+#ifdef __USE_XOPEN2K8
|
||
/* Nanosecond resolution timestamps are stored in a format
|
||
equivalent to 'struct timespec'. This is the type used
|
||
whenever possible but the Unix namespace rules do not allow the
|
||
@@ -116,16 +106,15 @@ struct stat64
|
||
struct timespec st_atim; /* Time of last access. */
|
||
struct timespec st_mtim; /* Time of last modification. */
|
||
struct timespec st_ctim; /* Time of last status change. */
|
||
-# else
|
||
+#else
|
||
__time_t st_atime; /* Time of last access. */
|
||
unsigned long int st_atimensec; /* Nscecs of last access. */
|
||
__time_t st_mtime; /* Time of last modification. */
|
||
unsigned long int st_mtimensec; /* Nsecs of last modification. */
|
||
__time_t st_ctime; /* Time of last status change. */
|
||
unsigned long int st_ctimensec; /* Nsecs of last status change. */
|
||
-# endif
|
||
- __ino64_t st_ino; /* File serial number. */
|
||
-# endif /* __USE_TIME_BITS64 */
|
||
+#endif
|
||
+ int __glibc_reserved[2];
|
||
};
|
||
#endif
|
||
|
||
@@ -135,5 +124,4 @@ struct stat64
|
||
/* Nanosecond resolution time values are supported. */
|
||
#define _STATBUF_ST_NSEC
|
||
|
||
-
|
||
#endif /* _BITS_STRUCT_STAT_H */
|
||
diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c
|
||
index fe73fe3ba8..ca20043408 100644
|
||
--- a/sysdeps/unix/sysv/linux/check_pf.c
|
||
+++ b/sysdeps/unix/sysv/linux/check_pf.c
|
||
@@ -292,6 +292,14 @@ make_request (int fd, pid_t pid)
|
||
return NULL;
|
||
}
|
||
|
||
+#ifdef __EXCEPTIONS
|
||
+static void
|
||
+cancel_handler (void *arg __attribute__((unused)))
|
||
+{
|
||
+ /* Release the lock. */
|
||
+ __libc_lock_unlock (lock);
|
||
+}
|
||
+#endif
|
||
|
||
void
|
||
attribute_hidden
|
||
@@ -304,6 +312,10 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6,
|
||
struct cached_data *olddata = NULL;
|
||
struct cached_data *data = NULL;
|
||
|
||
+#ifdef __EXCEPTIONS
|
||
+ /* Make sure that lock is released when the thread is cancelled. */
|
||
+ __libc_cleanup_push (cancel_handler, NULL);
|
||
+#endif
|
||
__libc_lock_lock (lock);
|
||
|
||
if (cache_valid_p ())
|
||
@@ -338,6 +350,9 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6,
|
||
}
|
||
}
|
||
|
||
+#ifdef __EXCEPTIONS
|
||
+ __libc_cleanup_pop (0);
|
||
+#endif
|
||
__libc_lock_unlock (lock);
|
||
|
||
if (data != NULL)
|
||
diff --git a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
|
||
index 15b7a3a925..24f72b797a 100644
|
||
--- a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
|
||
+++ b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
|
||
@@ -23,18 +23,38 @@
|
||
struct cmsghdr *
|
||
__cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg)
|
||
{
|
||
+ /* We may safely assume that cmsg lies between mhdr->msg_control and
|
||
+ mhdr->msg_controllen because the user is required to obtain the first
|
||
+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
|
||
+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
|
||
+ trust the value of cmsg->cmsg_len and therefore do not use it in any
|
||
+ pointer arithmetic until we check its value. */
|
||
+
|
||
+ unsigned char * msg_control_ptr = (unsigned char *) mhdr->msg_control;
|
||
+ unsigned char * cmsg_ptr = (unsigned char *) cmsg;
|
||
+
|
||
+ size_t size_needed = sizeof (struct cmsghdr)
|
||
+ + __CMSG_PADDING (cmsg->cmsg_len);
|
||
+
|
||
+ /* The current header is malformed, too small to be a full header. */
|
||
if ((size_t) cmsg->cmsg_len < sizeof (struct cmsghdr))
|
||
- /* The kernel header does this so there may be a reason. */
|
||
- return NULL;
|
||
+ return (struct cmsghdr *) 0;
|
||
+
|
||
+ /* There isn't enough space between cmsg and the end of the buffer to
|
||
+ hold the current cmsg *and* the next one. */
|
||
+ if (((size_t)
|
||
+ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr)
|
||
+ < size_needed)
|
||
+ || ((size_t)
|
||
+ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr
|
||
+ - size_needed)
|
||
+ < cmsg->cmsg_len))
|
||
+
|
||
+ return (struct cmsghdr *) 0;
|
||
|
||
+ /* Now, we trust cmsg_len and can use it to find the next header. */
|
||
cmsg = (struct cmsghdr *) ((unsigned char *) cmsg
|
||
+ CMSG_ALIGN (cmsg->cmsg_len));
|
||
- if ((unsigned char *) (cmsg + 1) > ((unsigned char *) mhdr->msg_control
|
||
- + mhdr->msg_controllen)
|
||
- || ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len)
|
||
- > ((unsigned char *) mhdr->msg_control + mhdr->msg_controllen)))
|
||
- /* No more entries. */
|
||
- return NULL;
|
||
return cmsg;
|
||
}
|
||
libc_hidden_def (__cmsg_nxthdr)
|
||
diff --git a/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h
|
||
similarity index 92%
|
||
rename from sysdeps/unix/sysv/linux/generic/bits/struct_stat.h
|
||
rename to sysdeps/unix/sysv/linux/csky/bits/struct_stat.h
|
||
index fb11a3fba4..f0ee455748 100644
|
||
--- a/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h
|
||
+++ b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h
|
||
@@ -1,4 +1,4 @@
|
||
-/* Definition for struct stat.
|
||
+/* Definition for struct stat. Linux/csky version.
|
||
Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||
This file is part of the GNU C Library.
|
||
|
||
@@ -43,6 +43,9 @@
|
||
|
||
struct stat
|
||
{
|
||
+#ifdef __USE_TIME_BITS64
|
||
+# include <bits/struct_stat_time64_helper.h>
|
||
+#else
|
||
__dev_t st_dev; /* Device. */
|
||
__field64(__ino_t, __ino64_t, st_ino); /* File serial number. */
|
||
__mode_t st_mode; /* File mode. */
|
||
@@ -55,7 +58,7 @@ struct stat
|
||
__blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
int __pad2;
|
||
__field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */
|
||
-#ifdef __USE_XOPEN2K8
|
||
+# ifdef __USE_XOPEN2K8
|
||
/* Nanosecond resolution timestamps are stored in a format
|
||
equivalent to 'struct timespec'. This is the type used
|
||
whenever possible but the Unix namespace rules do not allow the
|
||
@@ -65,18 +68,19 @@ struct stat
|
||
struct timespec st_atim; /* Time of last access. */
|
||
struct timespec st_mtim; /* Time of last modification. */
|
||
struct timespec st_ctim; /* Time of last status change. */
|
||
-# define st_atime st_atim.tv_sec /* Backward compatibility. */
|
||
-# define st_mtime st_mtim.tv_sec
|
||
-# define st_ctime st_ctim.tv_sec
|
||
-#else
|
||
+# define st_atime st_atim.tv_sec /* Backward compatibility. */
|
||
+# define st_mtime st_mtim.tv_sec
|
||
+# define st_ctime st_ctim.tv_sec
|
||
+# else
|
||
__time_t st_atime; /* Time of last access. */
|
||
unsigned long int st_atimensec; /* Nscecs of last access. */
|
||
__time_t st_mtime; /* Time of last modification. */
|
||
unsigned long int st_mtimensec; /* Nsecs of last modification. */
|
||
__time_t st_ctime; /* Time of last status change. */
|
||
unsigned long int st_ctimensec; /* Nsecs of last status change. */
|
||
-#endif
|
||
+# endif
|
||
int __glibc_reserved[2];
|
||
+#endif
|
||
};
|
||
|
||
#undef __field64
|
||
@@ -84,6 +88,9 @@ struct stat
|
||
#ifdef __USE_LARGEFILE64
|
||
struct stat64
|
||
{
|
||
+# ifdef __USE_TIME_BITS64
|
||
+# include <bits/struct_stat_time64_helper.h>
|
||
+# else
|
||
__dev_t st_dev; /* Device. */
|
||
__ino64_t st_ino; /* File serial number. */
|
||
__mode_t st_mode; /* File mode. */
|
||
@@ -96,7 +103,7 @@ struct stat64
|
||
__blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
int __pad2;
|
||
__blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */
|
||
-#ifdef __USE_XOPEN2K8
|
||
+# ifdef __USE_XOPEN2K8
|
||
/* Nanosecond resolution timestamps are stored in a format
|
||
equivalent to 'struct timespec'. This is the type used
|
||
whenever possible but the Unix namespace rules do not allow the
|
||
@@ -106,15 +113,16 @@ struct stat64
|
||
struct timespec st_atim; /* Time of last access. */
|
||
struct timespec st_mtim; /* Time of last modification. */
|
||
struct timespec st_ctim; /* Time of last status change. */
|
||
-#else
|
||
+# else
|
||
__time_t st_atime; /* Time of last access. */
|
||
unsigned long int st_atimensec; /* Nscecs of last access. */
|
||
__time_t st_mtime; /* Time of last modification. */
|
||
unsigned long int st_mtimensec; /* Nsecs of last modification. */
|
||
__time_t st_ctime; /* Time of last status change. */
|
||
unsigned long int st_ctimensec; /* Nsecs of last status change. */
|
||
-#endif
|
||
+# endif
|
||
int __glibc_reserved[2];
|
||
+# endif
|
||
};
|
||
#endif
|
||
|
||
diff --git a/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h b/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h
|
||
new file mode 100644
|
||
index 0000000000..38b6e13e68
|
||
--- /dev/null
|
||
+++ b/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h
|
||
@@ -0,0 +1,139 @@
|
||
+/* Definition for struct stat. Linux/hppa version.
|
||
+ Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library. If not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
|
||
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
|
||
+#endif
|
||
+
|
||
+#ifndef _BITS_STRUCT_STAT_H
|
||
+#define _BITS_STRUCT_STAT_H 1
|
||
+
|
||
+#include <bits/endian.h>
|
||
+#include <bits/wordsize.h>
|
||
+
|
||
+struct stat
|
||
+ {
|
||
+#ifdef __USE_TIME_BITS64
|
||
+# include <bits/struct_stat_time64_helper.h>
|
||
+#else
|
||
+ __dev_t st_dev; /* Device. */
|
||
+ unsigned short int __pad1;
|
||
+# ifndef __USE_FILE_OFFSET64
|
||
+ __ino_t st_ino; /* File serial number. */
|
||
+# else
|
||
+ __ino_t __st_ino; /* 32bit file serial number. */
|
||
+# endif
|
||
+ __mode_t st_mode; /* File mode. */
|
||
+ __nlink_t st_nlink; /* Link count. */
|
||
+ __uid_t st_uid; /* User ID of the file's owner. */
|
||
+ __gid_t st_gid; /* Group ID of the file's group.*/
|
||
+ __dev_t st_rdev; /* Device number, if device. */
|
||
+ unsigned short int __pad2;
|
||
+# ifndef __USE_FILE_OFFSET64
|
||
+ __off_t st_size; /* Size of file, in bytes. */
|
||
+# else
|
||
+ __off64_t st_size; /* Size of file, in bytes. */
|
||
+# endif
|
||
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
+
|
||
+# ifndef __USE_FILE_OFFSET64
|
||
+ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */
|
||
+# else
|
||
+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
|
||
+# endif
|
||
+# ifdef __USE_XOPEN2K8
|
||
+ /* Nanosecond resolution timestamps are stored in a format
|
||
+ equivalent to 'struct timespec'. This is the type used
|
||
+ whenever possible but the Unix namespace rules do not allow the
|
||
+ identifier 'timespec' to appear in the <sys/stat.h> header.
|
||
+ Therefore we have to handle the use of this header in strictly
|
||
+ standard-compliant sources special. */
|
||
+ struct timespec st_atim; /* Time of last access. */
|
||
+ struct timespec st_mtim; /* Time of last modification. */
|
||
+ struct timespec st_ctim; /* Time of last status change. */
|
||
+# define st_atime st_atim.tv_sec /* Backward compatibility. */
|
||
+# define st_mtime st_mtim.tv_sec
|
||
+# define st_ctime st_ctim.tv_sec
|
||
+# else
|
||
+ __time_t st_atime; /* Time of last access. */
|
||
+ unsigned long int st_atimensec; /* Nscecs of last access. */
|
||
+ __time_t st_mtime; /* Time of last modification. */
|
||
+ unsigned long int st_mtimensec; /* Nsecs of last modification. */
|
||
+ __time_t st_ctime; /* Time of last status change. */
|
||
+ unsigned long int st_ctimensec; /* Nsecs of last status change. */
|
||
+# endif
|
||
+# ifndef __USE_FILE_OFFSET64
|
||
+ unsigned long int __glibc_reserved4;
|
||
+ unsigned long int __glibc_reserved5;
|
||
+# else
|
||
+ __ino64_t st_ino; /* File serial number. */
|
||
+# endif
|
||
+#endif /* __USE_TIME_BITS64 */
|
||
+ };
|
||
+
|
||
+#ifdef __USE_LARGEFILE64
|
||
+struct stat64
|
||
+ {
|
||
+# ifdef __USE_TIME_BITS64
|
||
+# include <bits/struct_stat_time64_helper.h>
|
||
+# else
|
||
+ __dev_t st_dev; /* Device. */
|
||
+ unsigned int __pad1;
|
||
+
|
||
+ __ino_t __st_ino; /* 32bit file serial number. */
|
||
+ __mode_t st_mode; /* File mode. */
|
||
+ __nlink_t st_nlink; /* Link count. */
|
||
+ __uid_t st_uid; /* User ID of the file's owner. */
|
||
+ __gid_t st_gid; /* Group ID of the file's group.*/
|
||
+ __dev_t st_rdev; /* Device number, if device. */
|
||
+ unsigned int __pad2;
|
||
+ __off64_t st_size; /* Size of file, in bytes. */
|
||
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
+
|
||
+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
|
||
+# ifdef __USE_XOPEN2K8
|
||
+ /* Nanosecond resolution timestamps are stored in a format
|
||
+ equivalent to 'struct timespec'. This is the type used
|
||
+ whenever possible but the Unix namespace rules do not allow the
|
||
+ identifier 'timespec' to appear in the <sys/stat.h> header.
|
||
+ Therefore we have to handle the use of this header in strictly
|
||
+ standard-compliant sources special. */
|
||
+ struct timespec st_atim; /* Time of last access. */
|
||
+ struct timespec st_mtim; /* Time of last modification. */
|
||
+ struct timespec st_ctim; /* Time of last status change. */
|
||
+# else
|
||
+ __time_t st_atime; /* Time of last access. */
|
||
+ unsigned long int st_atimensec; /* Nscecs of last access. */
|
||
+ __time_t st_mtime; /* Time of last modification. */
|
||
+ unsigned long int st_mtimensec; /* Nsecs of last modification. */
|
||
+ __time_t st_ctime; /* Time of last status change. */
|
||
+ unsigned long int st_ctimensec; /* Nsecs of last status change. */
|
||
+# endif
|
||
+ __ino64_t st_ino; /* File serial number. */
|
||
+# endif /* __USE_TIME_BITS64 */
|
||
+ };
|
||
+#endif
|
||
+
|
||
+/* Tell code we have these members. */
|
||
+#define _STATBUF_ST_BLKSIZE
|
||
+#define _STATBUF_ST_RDEV
|
||
+/* Nanosecond resolution time values are supported. */
|
||
+#define _STATBUF_ST_NSEC
|
||
+
|
||
+
|
||
+#endif /* _BITS_STRUCT_STAT_H */
|
||
diff --git a/sysdeps/unix/sysv/linux/hppa/kernel-features.h b/sysdeps/unix/sysv/linux/hppa/kernel-features.h
|
||
index 0cd21ef0fa..079612e4aa 100644
|
||
--- a/sysdeps/unix/sysv/linux/hppa/kernel-features.h
|
||
+++ b/sysdeps/unix/sysv/linux/hppa/kernel-features.h
|
||
@@ -30,3 +30,6 @@
|
||
|
||
#undef __ASSUME_CLONE_DEFAULT
|
||
#define __ASSUME_CLONE_BACKWARDS 1
|
||
+
|
||
+/* QEMU does not support set_robust_list. */
|
||
+#undef __ASSUME_SET_ROBUST_LIST
|
||
diff --git a/sysdeps/unix/sysv/linux/ipc_priv.h b/sysdeps/unix/sysv/linux/ipc_priv.h
|
||
index 87893a6757..2f50c31a8e 100644
|
||
--- a/sysdeps/unix/sysv/linux/ipc_priv.h
|
||
+++ b/sysdeps/unix/sysv/linux/ipc_priv.h
|
||
@@ -63,4 +63,10 @@ struct __old_ipc_perm
|
||
# define __IPC_TIME64 0
|
||
#endif
|
||
|
||
+#if __IPC_TIME64 || defined __ASSUME_SYSVIPC_BROKEN_MODE_T
|
||
+# define IPC_CTL_NEED_TRANSLATION 1
|
||
+#else
|
||
+# define IPC_CTL_NEED_TRANSLATION 0
|
||
+#endif
|
||
+
|
||
#include <ipc_ops.h>
|
||
diff --git a/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h
|
||
new file mode 100644
|
||
index 0000000000..1844bbaf6f
|
||
--- /dev/null
|
||
+++ b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h
|
||
@@ -0,0 +1,25 @@
|
||
+/* Private libc-internal arch-specific definitions. m68k version.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public License as
|
||
+ published by the Free Software Foundation; either version 2.1 of the
|
||
+ License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; see the file COPYING.LIB. If
|
||
+ not, see <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#ifndef _LIBC_LOCK_ARCH_H
|
||
+#define _LIBC_LOCK_ARCH_H
|
||
+
|
||
+/* Linux enforces 4-bytes alignment on futex inputs. */
|
||
+#define __LIBC_LOCK_ALIGNMENT __attribute__ ((__aligned__ (4)))
|
||
+
|
||
+#endif
|
||
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c
|
||
new file mode 100644
|
||
index 0000000000..fe6c3a0dda
|
||
--- /dev/null
|
||
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c
|
||
@@ -0,0 +1,51 @@
|
||
+/* Get file status. Linux/MIPSn64 version.
|
||
+ Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <sys/stat.h>
|
||
+#include <sysdep.h>
|
||
+
|
||
+/* Different than other ABIs, mips64 has different layouts for non-LFS
|
||
+ and LFS struct stat. */
|
||
+int
|
||
+__fstatat (int fd, const char *file, struct stat *buf, int flag)
|
||
+{
|
||
+ struct __stat64_t64 st64;
|
||
+ int r = __fstatat64_time64 (fd, file, &st64, flag);
|
||
+ if (r == 0)
|
||
+ {
|
||
+ /* Clear internal pad and reserved fields. */
|
||
+ memset (buf, 0, sizeof (*buf));
|
||
+
|
||
+ buf->st_dev = st64.st_dev;
|
||
+ buf->st_ino = st64.st_ino;
|
||
+ buf->st_mode = st64.st_mode;
|
||
+ buf->st_nlink = st64.st_nlink;
|
||
+ buf->st_uid = st64.st_uid;
|
||
+ buf->st_gid = st64.st_gid;
|
||
+ buf->st_rdev = st64.st_rdev;
|
||
+ buf->st_size = st64.st_size;
|
||
+ buf->st_blksize = st64.st_blksize;
|
||
+ buf->st_blocks = st64.st_blocks;
|
||
+ buf->st_atim = st64.st_atim;
|
||
+ buf->st_mtim = st64.st_mtim;
|
||
+ buf->st_ctim = st64.st_ctim;
|
||
+ }
|
||
+ return r;
|
||
+}
|
||
+
|
||
+weak_alias (__fstatat, fstatat)
|
||
diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c
|
||
index e824ebb095..2072205252 100644
|
||
--- a/sysdeps/unix/sysv/linux/msgctl.c
|
||
+++ b/sysdeps/unix/sysv/linux/msgctl.c
|
||
@@ -85,11 +85,19 @@ msgctl_syscall (int msqid, int cmd, msgctl_arg_t *buf)
|
||
int
|
||
__msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
|
||
{
|
||
-#if __IPC_TIME64
|
||
+#if IPC_CTL_NEED_TRANSLATION
|
||
+# if __IPC_TIME64
|
||
struct kernel_msqid64_ds ksemid, *arg = NULL;
|
||
-#else
|
||
+# else
|
||
msgctl_arg_t *arg;
|
||
-#endif
|
||
+# endif
|
||
+
|
||
+ /* Some applications pass the __IPC_64 flag in cmd, to invoke
|
||
+ previously unsupported commands back when there was no EINVAL
|
||
+ error checking in glibc. Mask the flag for the switch statements
|
||
+ below. msgctl_syscall adds back the __IPC_64 flag for the actual
|
||
+ system call. */
|
||
+ cmd &= ~__IPC_64;
|
||
|
||
switch (cmd)
|
||
{
|
||
@@ -101,19 +109,19 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
|
||
case IPC_STAT:
|
||
case MSG_STAT:
|
||
case MSG_STAT_ANY:
|
||
-#if __IPC_TIME64
|
||
+# if __IPC_TIME64
|
||
if (buf != NULL)
|
||
{
|
||
msqid64_to_kmsqid64 (buf, &ksemid);
|
||
arg = &ksemid;
|
||
}
|
||
-# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
|
||
+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
|
||
if (cmd == IPC_SET)
|
||
arg->msg_perm.mode *= 0x10000U;
|
||
-# endif
|
||
-#else
|
||
+# endif
|
||
+# else
|
||
arg = buf;
|
||
-#endif
|
||
+# endif
|
||
break;
|
||
|
||
case IPC_INFO:
|
||
@@ -137,21 +145,25 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
|
||
case IPC_STAT:
|
||
case MSG_STAT:
|
||
case MSG_STAT_ANY:
|
||
-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
|
||
+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
|
||
arg->msg_perm.mode >>= 16;
|
||
-#else
|
||
+# else
|
||
/* Old Linux kernel versions might not clear the mode padding. */
|
||
if (sizeof ((struct msqid_ds){0}.msg_perm.mode)
|
||
!= sizeof (__kernel_mode_t))
|
||
arg->msg_perm.mode &= 0xFFFF;
|
||
-#endif
|
||
+# endif
|
||
|
||
-#if __IPC_TIME64
|
||
+# if __IPC_TIME64
|
||
kmsqid64_to_msqid64 (arg, buf);
|
||
-#endif
|
||
+# endif
|
||
}
|
||
|
||
return ret;
|
||
+
|
||
+#else /* !IPC_CTL_NEED_TRANSLATION */
|
||
+ return msgctl_syscall (msqid, cmd, buf);
|
||
+#endif
|
||
}
|
||
#if __TIMESIZE != 64
|
||
libc_hidden_def (__msgctl64)
|
||
diff --git a/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h b/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h
|
||
new file mode 100644
|
||
index 0000000000..e00e71173e
|
||
--- /dev/null
|
||
+++ b/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h
|
||
@@ -0,0 +1,135 @@
|
||
+/* Definition for struct stat. Linux/nios2 version.
|
||
+ Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library. If not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
|
||
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
|
||
+#endif
|
||
+
|
||
+#ifndef _BITS_STRUCT_STAT_H
|
||
+#define _BITS_STRUCT_STAT_H 1
|
||
+
|
||
+#include <bits/endian.h>
|
||
+#include <bits/wordsize.h>
|
||
+
|
||
+#if defined __USE_FILE_OFFSET64
|
||
+# define __field64(type, type64, name) type64 name
|
||
+#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T
|
||
+# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T
|
||
+# error "ino_t and off_t must both be the same type"
|
||
+# endif
|
||
+# define __field64(type, type64, name) type name
|
||
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||
+# define __field64(type, type64, name) \
|
||
+ type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad
|
||
+#else
|
||
+# define __field64(type, type64, name) \
|
||
+ int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name
|
||
+#endif
|
||
+
|
||
+struct stat
|
||
+ {
|
||
+#ifdef __USE_TIME_BITS64
|
||
+# include <bits/struct_stat_time64_helper.h>
|
||
+#else
|
||
+ __dev_t st_dev; /* Device. */
|
||
+ __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */
|
||
+ __mode_t st_mode; /* File mode. */
|
||
+ __nlink_t st_nlink; /* Link count. */
|
||
+ __uid_t st_uid; /* User ID of the file's owner. */
|
||
+ __gid_t st_gid; /* Group ID of the file's group.*/
|
||
+ __dev_t st_rdev; /* Device number, if device. */
|
||
+ __dev_t __pad1;
|
||
+ __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */
|
||
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
+ int __pad2;
|
||
+ __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */
|
||
+# ifdef __USE_XOPEN2K8
|
||
+ /* Nanosecond resolution timestamps are stored in a format
|
||
+ equivalent to 'struct timespec'. This is the type used
|
||
+ whenever possible but the Unix namespace rules do not allow the
|
||
+ identifier 'timespec' to appear in the <sys/stat.h> header.
|
||
+ Therefore we have to handle the use of this header in strictly
|
||
+ standard-compliant sources special. */
|
||
+ struct timespec st_atim; /* Time of last access. */
|
||
+ struct timespec st_mtim; /* Time of last modification. */
|
||
+ struct timespec st_ctim; /* Time of last status change. */
|
||
+# define st_atime st_atim.tv_sec /* Backward compatibility. */
|
||
+# define st_mtime st_mtim.tv_sec
|
||
+# define st_ctime st_ctim.tv_sec
|
||
+# else
|
||
+ __time_t st_atime; /* Time of last access. */
|
||
+ unsigned long int st_atimensec; /* Nscecs of last access. */
|
||
+ __time_t st_mtime; /* Time of last modification. */
|
||
+ unsigned long int st_mtimensec; /* Nsecs of last modification. */
|
||
+ __time_t st_ctime; /* Time of last status change. */
|
||
+ unsigned long int st_ctimensec; /* Nsecs of last status change. */
|
||
+# endif
|
||
+ int __glibc_reserved[2];
|
||
+#endif
|
||
+ };
|
||
+
|
||
+#undef __field64
|
||
+
|
||
+#ifdef __USE_LARGEFILE64
|
||
+struct stat64
|
||
+ {
|
||
+# ifdef __USE_TIME_BITS64
|
||
+# include <bits/struct_stat_time64_helper.h>
|
||
+# else
|
||
+ __dev_t st_dev; /* Device. */
|
||
+ __ino64_t st_ino; /* File serial number. */
|
||
+ __mode_t st_mode; /* File mode. */
|
||
+ __nlink_t st_nlink; /* Link count. */
|
||
+ __uid_t st_uid; /* User ID of the file's owner. */
|
||
+ __gid_t st_gid; /* Group ID of the file's group.*/
|
||
+ __dev_t st_rdev; /* Device number, if device. */
|
||
+ __dev_t __pad1;
|
||
+ __off64_t st_size; /* Size of file, in bytes. */
|
||
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
+ int __pad2;
|
||
+ __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */
|
||
+# ifdef __USE_XOPEN2K8
|
||
+ /* Nanosecond resolution timestamps are stored in a format
|
||
+ equivalent to 'struct timespec'. This is the type used
|
||
+ whenever possible but the Unix namespace rules do not allow the
|
||
+ identifier 'timespec' to appear in the <sys/stat.h> header.
|
||
+ Therefore we have to handle the use of this header in strictly
|
||
+ standard-compliant sources special. */
|
||
+ struct timespec st_atim; /* Time of last access. */
|
||
+ struct timespec st_mtim; /* Time of last modification. */
|
||
+ struct timespec st_ctim; /* Time of last status change. */
|
||
+# else
|
||
+ __time_t st_atime; /* Time of last access. */
|
||
+ unsigned long int st_atimensec; /* Nscecs of last access. */
|
||
+ __time_t st_mtime; /* Time of last modification. */
|
||
+ unsigned long int st_mtimensec; /* Nsecs of last modification. */
|
||
+ __time_t st_ctime; /* Time of last status change. */
|
||
+ unsigned long int st_ctimensec; /* Nsecs of last status change. */
|
||
+# endif
|
||
+ int __glibc_reserved[2];
|
||
+# endif
|
||
+ };
|
||
+#endif
|
||
+
|
||
+/* Tell code we have these members. */
|
||
+#define _STATBUF_ST_BLKSIZE
|
||
+#define _STATBUF_ST_RDEV
|
||
+/* Nanosecond resolution time values are supported. */
|
||
+#define _STATBUF_ST_NSEC
|
||
+
|
||
+#endif /* _BITS_STRUCT_STAT_H */
|
||
diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h
|
||
index a263d294b1..cf35c8bfc9 100644
|
||
--- a/sysdeps/unix/sysv/linux/not-cancel.h
|
||
+++ b/sysdeps/unix/sysv/linux/not-cancel.h
|
||
@@ -68,7 +68,7 @@ __writev_nocancel_nostatus (int fd, const struct iovec *iov, int iovcnt)
|
||
INTERNAL_SYSCALL_CALL (writev, fd, iov, iovcnt);
|
||
}
|
||
|
||
-static inline int
|
||
+static inline ssize_t
|
||
__getrandom_nocancel (void *buf, size_t buflen, unsigned int flags)
|
||
{
|
||
return INLINE_SYSCALL_CALL (getrandom, buf, buflen, flags);
|
||
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h
|
||
index d7cf158b33..49c8fac0fb 100644
|
||
--- a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h
|
||
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h
|
||
@@ -33,6 +33,12 @@
|
||
# define __O_LARGEFILE 0200000
|
||
#endif
|
||
|
||
+#if __WORDSIZE == 64
|
||
+# define F_GETLK 5
|
||
+# define F_SETLK 6
|
||
+# define F_SETLKW 7
|
||
+#endif
|
||
+
|
||
struct flock
|
||
{
|
||
short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */
|
||
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
|
||
index bf4be80f8d..202520ee25 100644
|
||
--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
|
||
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
|
||
@@ -122,6 +122,7 @@
|
||
#define __NR_mbind 235
|
||
#define __NR_membarrier 283
|
||
#define __NR_memfd_create 279
|
||
+#define __NR_memfd_secret 447
|
||
#define __NR_migrate_pages 238
|
||
#define __NR_mincore 232
|
||
#define __NR_mkdirat 34
|
||
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
|
||
index d656aedcc2..4e65f337d4 100644
|
||
--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
|
||
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
|
||
@@ -127,6 +127,7 @@
|
||
#define __NR_mbind 235
|
||
#define __NR_membarrier 283
|
||
#define __NR_memfd_create 279
|
||
+#define __NR_memfd_secret 447
|
||
#define __NR_migrate_pages 238
|
||
#define __NR_mincore 232
|
||
#define __NR_mkdirat 34
|
||
diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c
|
||
index 77a8130c18..3458b018bc 100644
|
||
--- a/sysdeps/unix/sysv/linux/semctl.c
|
||
+++ b/sysdeps/unix/sysv/linux/semctl.c
|
||
@@ -140,6 +140,13 @@ __semctl64 (int semid, int semnum, int cmd, ...)
|
||
union semun64 arg64 = { 0 };
|
||
va_list ap;
|
||
|
||
+ /* Some applications pass the __IPC_64 flag in cmd, to invoke
|
||
+ previously unsupported commands back when there was no EINVAL
|
||
+ error checking in glibc. Mask the flag for the switch statements
|
||
+ below. semctl_syscall adds back the __IPC_64 flag for the actual
|
||
+ system call. */
|
||
+ cmd &= ~__IPC_64;
|
||
+
|
||
/* Get the argument only if required. */
|
||
switch (cmd)
|
||
{
|
||
diff --git a/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h b/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h
|
||
new file mode 100644
|
||
index 0000000000..0f7c9cdc89
|
||
--- /dev/null
|
||
+++ b/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h
|
||
@@ -0,0 +1,139 @@
|
||
+/* Definition for struct stat. Linux/sh version.
|
||
+ Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library. If not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
|
||
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
|
||
+#endif
|
||
+
|
||
+#ifndef _BITS_STRUCT_STAT_H
|
||
+#define _BITS_STRUCT_STAT_H 1
|
||
+
|
||
+#include <bits/endian.h>
|
||
+#include <bits/wordsize.h>
|
||
+
|
||
+struct stat
|
||
+ {
|
||
+#ifdef __USE_TIME_BITS64
|
||
+# include <bits/struct_stat_time64_helper.h>
|
||
+#else
|
||
+ __dev_t st_dev; /* Device. */
|
||
+ unsigned short int __pad1;
|
||
+# ifndef __USE_FILE_OFFSET64
|
||
+ __ino_t st_ino; /* File serial number. */
|
||
+# else
|
||
+ __ino_t __st_ino; /* 32bit file serial number. */
|
||
+# endif
|
||
+ __mode_t st_mode; /* File mode. */
|
||
+ __nlink_t st_nlink; /* Link count. */
|
||
+ __uid_t st_uid; /* User ID of the file's owner. */
|
||
+ __gid_t st_gid; /* Group ID of the file's group.*/
|
||
+ __dev_t st_rdev; /* Device number, if device. */
|
||
+ unsigned short int __pad2;
|
||
+# ifndef __USE_FILE_OFFSET64
|
||
+ __off_t st_size; /* Size of file, in bytes. */
|
||
+# else
|
||
+ __off64_t st_size; /* Size of file, in bytes. */
|
||
+# endif
|
||
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
+
|
||
+# ifndef __USE_FILE_OFFSET64
|
||
+ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */
|
||
+# else
|
||
+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
|
||
+# endif
|
||
+# ifdef __USE_XOPEN2K8
|
||
+ /* Nanosecond resolution timestamps are stored in a format
|
||
+ equivalent to 'struct timespec'. This is the type used
|
||
+ whenever possible but the Unix namespace rules do not allow the
|
||
+ identifier 'timespec' to appear in the <sys/stat.h> header.
|
||
+ Therefore we have to handle the use of this header in strictly
|
||
+ standard-compliant sources special. */
|
||
+ struct timespec st_atim; /* Time of last access. */
|
||
+ struct timespec st_mtim; /* Time of last modification. */
|
||
+ struct timespec st_ctim; /* Time of last status change. */
|
||
+# define st_atime st_atim.tv_sec /* Backward compatibility. */
|
||
+# define st_mtime st_mtim.tv_sec
|
||
+# define st_ctime st_ctim.tv_sec
|
||
+# else
|
||
+ __time_t st_atime; /* Time of last access. */
|
||
+ unsigned long int st_atimensec; /* Nscecs of last access. */
|
||
+ __time_t st_mtime; /* Time of last modification. */
|
||
+ unsigned long int st_mtimensec; /* Nsecs of last modification. */
|
||
+ __time_t st_ctime; /* Time of last status change. */
|
||
+ unsigned long int st_ctimensec; /* Nsecs of last status change. */
|
||
+# endif
|
||
+# ifndef __USE_FILE_OFFSET64
|
||
+ unsigned long int __glibc_reserved4;
|
||
+ unsigned long int __glibc_reserved5;
|
||
+# else
|
||
+ __ino64_t st_ino; /* File serial number. */
|
||
+# endif
|
||
+#endif /* __USE_TIME_BITS64 */
|
||
+ };
|
||
+
|
||
+#ifdef __USE_LARGEFILE64
|
||
+struct stat64
|
||
+ {
|
||
+# ifdef __USE_TIME_BITS64
|
||
+# include <bits/struct_stat_time64_helper.h>
|
||
+# else
|
||
+ __dev_t st_dev; /* Device. */
|
||
+ unsigned int __pad1;
|
||
+
|
||
+ __ino_t __st_ino; /* 32bit file serial number. */
|
||
+ __mode_t st_mode; /* File mode. */
|
||
+ __nlink_t st_nlink; /* Link count. */
|
||
+ __uid_t st_uid; /* User ID of the file's owner. */
|
||
+ __gid_t st_gid; /* Group ID of the file's group.*/
|
||
+ __dev_t st_rdev; /* Device number, if device. */
|
||
+ unsigned int __pad2;
|
||
+ __off64_t st_size; /* Size of file, in bytes. */
|
||
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
|
||
+
|
||
+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
|
||
+# ifdef __USE_XOPEN2K8
|
||
+ /* Nanosecond resolution timestamps are stored in a format
|
||
+ equivalent to 'struct timespec'. This is the type used
|
||
+ whenever possible but the Unix namespace rules do not allow the
|
||
+ identifier 'timespec' to appear in the <sys/stat.h> header.
|
||
+ Therefore we have to handle the use of this header in strictly
|
||
+ standard-compliant sources special. */
|
||
+ struct timespec st_atim; /* Time of last access. */
|
||
+ struct timespec st_mtim; /* Time of last modification. */
|
||
+ struct timespec st_ctim; /* Time of last status change. */
|
||
+# else
|
||
+ __time_t st_atime; /* Time of last access. */
|
||
+ unsigned long int st_atimensec; /* Nscecs of last access. */
|
||
+ __time_t st_mtime; /* Time of last modification. */
|
||
+ unsigned long int st_mtimensec; /* Nsecs of last modification. */
|
||
+ __time_t st_ctime; /* Time of last status change. */
|
||
+ unsigned long int st_ctimensec; /* Nsecs of last status change. */
|
||
+# endif
|
||
+ __ino64_t st_ino; /* File serial number. */
|
||
+# endif /* __USE_TIME_BITS64 */
|
||
+ };
|
||
+#endif
|
||
+
|
||
+/* Tell code we have these members. */
|
||
+#define _STATBUF_ST_BLKSIZE
|
||
+#define _STATBUF_ST_RDEV
|
||
+/* Nanosecond resolution time values are supported. */
|
||
+#define _STATBUF_ST_NSEC
|
||
+
|
||
+
|
||
+#endif /* _BITS_STRUCT_STAT_H */
|
||
diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c
|
||
index ea38935497..f00817a6f6 100644
|
||
--- a/sysdeps/unix/sysv/linux/shmctl.c
|
||
+++ b/sysdeps/unix/sysv/linux/shmctl.c
|
||
@@ -85,11 +85,19 @@ shmctl_syscall (int shmid, int cmd, shmctl_arg_t *buf)
|
||
int
|
||
__shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
|
||
{
|
||
-#if __IPC_TIME64
|
||
+#if IPC_CTL_NEED_TRANSLATION
|
||
+# if __IPC_TIME64
|
||
struct kernel_shmid64_ds kshmid, *arg = NULL;
|
||
-#else
|
||
+# else
|
||
shmctl_arg_t *arg;
|
||
-#endif
|
||
+# endif
|
||
+
|
||
+ /* Some applications pass the __IPC_64 flag in cmd, to invoke
|
||
+ previously unsupported commands back when there was no EINVAL
|
||
+ error checking in glibc. Mask the flag for the switch statements
|
||
+ below. shmctl_syscall adds back the __IPC_64 flag for the actual
|
||
+ system call. */
|
||
+ cmd &= ~__IPC_64;
|
||
|
||
switch (cmd)
|
||
{
|
||
@@ -103,19 +111,19 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
|
||
case IPC_STAT:
|
||
case SHM_STAT:
|
||
case SHM_STAT_ANY:
|
||
-#if __IPC_TIME64
|
||
+# if __IPC_TIME64
|
||
if (buf != NULL)
|
||
{
|
||
shmid64_to_kshmid64 (buf, &kshmid);
|
||
arg = &kshmid;
|
||
}
|
||
-# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
|
||
+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
|
||
if (cmd == IPC_SET)
|
||
arg->shm_perm.mode *= 0x10000U;
|
||
-# endif
|
||
-#else
|
||
+# endif
|
||
+# else
|
||
arg = buf;
|
||
-#endif
|
||
+# endif
|
||
break;
|
||
|
||
case IPC_INFO:
|
||
@@ -140,21 +148,25 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
|
||
case IPC_STAT:
|
||
case SHM_STAT:
|
||
case SHM_STAT_ANY:
|
||
-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
|
||
+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
|
||
arg->shm_perm.mode >>= 16;
|
||
-#else
|
||
+# else
|
||
/* Old Linux kernel versions might not clear the mode padding. */
|
||
if (sizeof ((struct shmid_ds){0}.shm_perm.mode)
|
||
!= sizeof (__kernel_mode_t))
|
||
arg->shm_perm.mode &= 0xFFFF;
|
||
-#endif
|
||
+# endif
|
||
|
||
-#if __IPC_TIME64
|
||
+# if __IPC_TIME64
|
||
kshmid64_to_shmid64 (arg, buf);
|
||
-#endif
|
||
+# endif
|
||
}
|
||
|
||
return ret;
|
||
+
|
||
+#else /* !IPC_CTL_NEED_TRANSLATION */
|
||
+ return shmctl_syscall (shmid, cmd, buf);
|
||
+#endif
|
||
}
|
||
#if __TIMESIZE != 64
|
||
libc_hidden_def (__shmctl64)
|
||
diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h
|
||
index f965986ba8..19841d0738 100644
|
||
--- a/sysdeps/unix/sysv/linux/sys/mount.h
|
||
+++ b/sysdeps/unix/sysv/linux/sys/mount.h
|
||
@@ -27,77 +27,113 @@
|
||
#include <stddef.h>
|
||
#include <sys/ioctl.h>
|
||
|
||
-#define BLOCK_SIZE 1024
|
||
+#ifdef __has_include
|
||
+# if __has_include ("linux/mount.h")
|
||
+# include "linux/mount.h"
|
||
+# endif
|
||
+#endif
|
||
+
|
||
+
|
||
#define BLOCK_SIZE_BITS 10
|
||
+#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
|
||
|
||
|
||
/* These are the fs-independent mount-flags: up to 16 flags are
|
||
supported */
|
||
enum
|
||
{
|
||
+#undef MS_RDONLY
|
||
MS_RDONLY = 1, /* Mount read-only. */
|
||
#define MS_RDONLY MS_RDONLY
|
||
+#undef MS_NOSUID
|
||
MS_NOSUID = 2, /* Ignore suid and sgid bits. */
|
||
#define MS_NOSUID MS_NOSUID
|
||
+#undef MS_NODEV
|
||
MS_NODEV = 4, /* Disallow access to device special files. */
|
||
#define MS_NODEV MS_NODEV
|
||
+#undef MS_NOEXEC
|
||
MS_NOEXEC = 8, /* Disallow program execution. */
|
||
#define MS_NOEXEC MS_NOEXEC
|
||
+#undef MS_SYNCHRONOUS
|
||
MS_SYNCHRONOUS = 16, /* Writes are synced at once. */
|
||
#define MS_SYNCHRONOUS MS_SYNCHRONOUS
|
||
+#undef MS_REMOUNT
|
||
MS_REMOUNT = 32, /* Alter flags of a mounted FS. */
|
||
#define MS_REMOUNT MS_REMOUNT
|
||
+#undef MS_MANDLOCK
|
||
MS_MANDLOCK = 64, /* Allow mandatory locks on an FS. */
|
||
#define MS_MANDLOCK MS_MANDLOCK
|
||
+#undef MS_DIRSYNC
|
||
MS_DIRSYNC = 128, /* Directory modifications are synchronous. */
|
||
#define MS_DIRSYNC MS_DIRSYNC
|
||
+#undef MS_NOSYMFOLLOW
|
||
MS_NOSYMFOLLOW = 256, /* Do not follow symlinks. */
|
||
#define MS_NOSYMFOLLOW MS_NOSYMFOLLOW
|
||
+#undef MS_NOATIME
|
||
MS_NOATIME = 1024, /* Do not update access times. */
|
||
#define MS_NOATIME MS_NOATIME
|
||
+#undef MS_NODIRATIME
|
||
MS_NODIRATIME = 2048, /* Do not update directory access times. */
|
||
#define MS_NODIRATIME MS_NODIRATIME
|
||
+#undef MS_BIND
|
||
MS_BIND = 4096, /* Bind directory at different place. */
|
||
#define MS_BIND MS_BIND
|
||
+#undef MS_MOVE
|
||
MS_MOVE = 8192,
|
||
#define MS_MOVE MS_MOVE
|
||
+#undef MS_REC
|
||
MS_REC = 16384,
|
||
#define MS_REC MS_REC
|
||
+#undef MS_SILENT
|
||
MS_SILENT = 32768,
|
||
#define MS_SILENT MS_SILENT
|
||
+#undef MS_POSIXACL
|
||
MS_POSIXACL = 1 << 16, /* VFS does not apply the umask. */
|
||
#define MS_POSIXACL MS_POSIXACL
|
||
+#undef MS_UNBINDABLE
|
||
MS_UNBINDABLE = 1 << 17, /* Change to unbindable. */
|
||
#define MS_UNBINDABLE MS_UNBINDABLE
|
||
+#undef MS_PRIVATE
|
||
MS_PRIVATE = 1 << 18, /* Change to private. */
|
||
#define MS_PRIVATE MS_PRIVATE
|
||
+#undef MS_SLAVE
|
||
MS_SLAVE = 1 << 19, /* Change to slave. */
|
||
#define MS_SLAVE MS_SLAVE
|
||
+#undef MS_SHARED
|
||
MS_SHARED = 1 << 20, /* Change to shared. */
|
||
#define MS_SHARED MS_SHARED
|
||
+#undef MS_RELATIME
|
||
MS_RELATIME = 1 << 21, /* Update atime relative to mtime/ctime. */
|
||
#define MS_RELATIME MS_RELATIME
|
||
+#undef MS_KERNMOUNT
|
||
MS_KERNMOUNT = 1 << 22, /* This is a kern_mount call. */
|
||
#define MS_KERNMOUNT MS_KERNMOUNT
|
||
+#undef MS_I_VERSION
|
||
MS_I_VERSION = 1 << 23, /* Update inode I_version field. */
|
||
#define MS_I_VERSION MS_I_VERSION
|
||
+#undef MS_STRICTATIME
|
||
MS_STRICTATIME = 1 << 24, /* Always perform atime updates. */
|
||
#define MS_STRICTATIME MS_STRICTATIME
|
||
+#undef MS_LAZYTIME
|
||
MS_LAZYTIME = 1 << 25, /* Update the on-disk [acm]times lazily. */
|
||
#define MS_LAZYTIME MS_LAZYTIME
|
||
+#undef MS_ACTIVE
|
||
MS_ACTIVE = 1 << 30,
|
||
#define MS_ACTIVE MS_ACTIVE
|
||
+#undef MS_NOUSER
|
||
MS_NOUSER = 1 << 31
|
||
#define MS_NOUSER MS_NOUSER
|
||
};
|
||
|
||
/* Flags that can be altered by MS_REMOUNT */
|
||
+#undef MS_RMT_MASK
|
||
#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION \
|
||
|MS_LAZYTIME)
|
||
|
||
|
||
/* Magic mount flag number. Has to be or-ed to the flag values. */
|
||
|
||
+#undef MS_MGC_VAL
|
||
#define MS_MGC_VAL 0xc0ed0000 /* Magic flag number to indicate "new" flags */
|
||
#define MS_MGC_MSK 0xffff0000 /* Magic flag number mask */
|
||
|
||
@@ -106,20 +142,35 @@ enum
|
||
is probably as bad and I don't want to create yet another include
|
||
file. */
|
||
|
||
+#undef BLKROSET
|
||
#define BLKROSET _IO(0x12, 93) /* Set device read-only (0 = read-write). */
|
||
+#undef BLKROGET
|
||
#define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */
|
||
+#undef BLKRRPART
|
||
#define BLKRRPART _IO(0x12, 95) /* Re-read partition table. */
|
||
+#undef BLKGETSIZE
|
||
#define BLKGETSIZE _IO(0x12, 96) /* Return device size. */
|
||
+#undef BLKFLSBUF
|
||
#define BLKFLSBUF _IO(0x12, 97) /* Flush buffer cache. */
|
||
+#undef BLKRASET
|
||
#define BLKRASET _IO(0x12, 98) /* Set read ahead for block device. */
|
||
+#undef BLKRAGET
|
||
#define BLKRAGET _IO(0x12, 99) /* Get current read ahead setting. */
|
||
+#undef BLKFRASET
|
||
#define BLKFRASET _IO(0x12,100) /* Set filesystem read-ahead. */
|
||
+#undef BLKFRAGET
|
||
#define BLKFRAGET _IO(0x12,101) /* Get filesystem read-ahead. */
|
||
+#undef BLKSECTSET
|
||
#define BLKSECTSET _IO(0x12,102) /* Set max sectors per request. */
|
||
+#undef BLKSECTGET
|
||
#define BLKSECTGET _IO(0x12,103) /* Get max sectors per request. */
|
||
+#undef BLKSSZGET
|
||
#define BLKSSZGET _IO(0x12,104) /* Get block device sector size. */
|
||
+#undef BLKBSZGET
|
||
#define BLKBSZGET _IOR(0x12,112,size_t)
|
||
+#undef BLKBSZSET
|
||
#define BLKBSZSET _IOW(0x12,113,size_t)
|
||
+#undef BLKGETSIZE64
|
||
#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size. */
|
||
|
||
|
||
@@ -137,9 +188,6 @@ enum
|
||
};
|
||
|
||
|
||
-/* fsopen flags. */
|
||
-#define FSOPEN_CLOEXEC 0x00000001
|
||
-
|
||
/* fsmount flags. */
|
||
#define FSMOUNT_CLOEXEC 0x00000001
|
||
|
||
@@ -157,6 +205,7 @@ enum
|
||
#define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 /* Do not follow symlinks. */
|
||
|
||
|
||
+#ifndef MOUNT_ATTR_SIZE_VER0
|
||
/* For mount_setattr. */
|
||
struct mount_attr
|
||
{
|
||
@@ -165,6 +214,7 @@ struct mount_attr
|
||
uint64_t propagation;
|
||
uint64_t userns_fd;
|
||
};
|
||
+#endif
|
||
|
||
#define MOUNT_ATTR_SIZE_VER0 32 /* sizeof first published struct */
|
||
|
||
@@ -185,26 +235,31 @@ struct mount_attr
|
||
#define FSPICK_EMPTY_PATH 0x00000008
|
||
|
||
|
||
+#ifndef FSOPEN_CLOEXEC
|
||
/* The type of fsconfig call made. */
|
||
enum fsconfig_command
|
||
{
|
||
FSCONFIG_SET_FLAG = 0, /* Set parameter, supplying no value */
|
||
-#define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
|
||
+# define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
|
||
FSCONFIG_SET_STRING = 1, /* Set parameter, supplying a string value */
|
||
-#define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
|
||
+# define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
|
||
FSCONFIG_SET_BINARY = 2, /* Set parameter, supplying a binary blob value */
|
||
-#define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
|
||
+# define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
|
||
FSCONFIG_SET_PATH = 3, /* Set parameter, supplying an object by path */
|
||
-#define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
|
||
+# define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
|
||
FSCONFIG_SET_PATH_EMPTY = 4, /* Set parameter, supplying an object by (empty) path */
|
||
-#define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
|
||
+# define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
|
||
FSCONFIG_SET_FD = 5, /* Set parameter, supplying an object by fd */
|
||
-#define FSCONFIG_SET_FD FSCONFIG_SET_FD
|
||
+# define FSCONFIG_SET_FD FSCONFIG_SET_FD
|
||
FSCONFIG_CMD_CREATE = 6, /* Invoke superblock creation */
|
||
-#define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
|
||
+# define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
|
||
FSCONFIG_CMD_RECONFIGURE = 7, /* Invoke superblock reconfiguration */
|
||
-#define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
|
||
+# define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
|
||
};
|
||
+#endif
|
||
+
|
||
+/* fsopen flags. */
|
||
+#define FSOPEN_CLOEXEC 0x00000001
|
||
|
||
/* open_tree flags. */
|
||
#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
|
||
diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
|
||
index 6c7b2f7011..028ad3107a 100644
|
||
--- a/sysdeps/unix/sysv/linux/syscall-names.list
|
||
+++ b/sysdeps/unix/sysv/linux/syscall-names.list
|
||
@@ -21,8 +21,8 @@
|
||
# This file can list all potential system calls. The names are only
|
||
# used if the installed kernel headers also provide them.
|
||
|
||
-# The list of system calls is current as of Linux 5.18.
|
||
-kernel 5.18
|
||
+# The list of system calls is current as of Linux 5.19.
|
||
+kernel 5.19
|
||
|
||
FAST_atomic_update
|
||
FAST_cmpxchg
|
||
diff --git a/sysdeps/unix/sysv/linux/tst-mount-compile.py b/sysdeps/unix/sysv/linux/tst-mount-compile.py
|
||
new file mode 100755
|
||
index 0000000000..0ec74d4e0b
|
||
--- /dev/null
|
||
+++ b/sysdeps/unix/sysv/linux/tst-mount-compile.py
|
||
@@ -0,0 +1,66 @@
|
||
+#!/usr/bin/python3
|
||
+# Check if glibc provided sys/mount.h can be used along related kernel
|
||
+# headers.
|
||
+# Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+# This file is part of the GNU C Library.
|
||
+#
|
||
+# The GNU C Library is free software; you can redistribute it and/or
|
||
+# modify it under the terms of the GNU Lesser General Public
|
||
+# License as published by the Free Software Foundation; either
|
||
+# version 2.1 of the License, or (at your option) any later version.
|
||
+#
|
||
+# The GNU C Library is distributed in the hope that it will be useful,
|
||
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+# Lesser General Public License for more details.
|
||
+#
|
||
+# You should have received a copy of the GNU Lesser General Public
|
||
+# License along with the GNU C Library; if not, see
|
||
+# <https://www.gnu.org/licenses/>.
|
||
+
|
||
+import argparse
|
||
+import sys
|
||
+
|
||
+import glibcextract
|
||
+
|
||
+
|
||
+def main():
|
||
+ """The main entry point."""
|
||
+ parser = argparse.ArgumentParser(
|
||
+ description='Check if glibc provided sys/mount.h can be '
|
||
+ ' used along related kernel headers.')
|
||
+ parser.add_argument('--cc', metavar='CC',
|
||
+ help='C compiler (including options) to use')
|
||
+ args = parser.parse_args()
|
||
+
|
||
+ if glibcextract.compile_c_snippet(
|
||
+ '#include <linux/mount.h>',
|
||
+ args.cc).returncode != 0:
|
||
+ sys.exit (77)
|
||
+
|
||
+ def check(testname, snippet):
|
||
+ # Add -Werror to catch macro redefinitions and _ISOMAC to avoid
|
||
+ # internal glibc definitions.
|
||
+ r = glibcextract.compile_c_snippet(snippet, args.cc,
|
||
+ '-Werror -D_ISOMAC')
|
||
+ if r.returncode != 0:
|
||
+ print('error: test {}:\n{}'.format(testname, r.output.decode()))
|
||
+ return r.returncode
|
||
+
|
||
+ status = max(
|
||
+ check("sys/mount.h + linux/mount.h",
|
||
+ "#include <sys/mount.h>\n"
|
||
+ "#include <linux/mount.h>"),
|
||
+ check("sys/mount.h + linux/fs.h",
|
||
+ "#include <sys/mount.h>\n"
|
||
+ "#include <linux/fs.h>"),
|
||
+ check("linux/mount.h + sys/mount.h",
|
||
+ "#include <linux/mount.h>\n"
|
||
+ "#include <sys/mount.h>"),
|
||
+ check("linux/fs.h + sys/mount.h",
|
||
+ "#include <linux/fs.h>\n"
|
||
+ "#include <sys/mount.h>"))
|
||
+ sys.exit(status)
|
||
+
|
||
+if __name__ == '__main__':
|
||
+ main()
|
||
diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py
|
||
index a62f803123..be2ef2daf1 100755
|
||
--- a/sysdeps/unix/sysv/linux/tst-mount-consts.py
|
||
+++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py
|
||
@@ -33,6 +33,11 @@ def main():
|
||
help='C compiler (including options) to use')
|
||
args = parser.parse_args()
|
||
|
||
+ if glibcextract.compile_c_snippet(
|
||
+ '#include <linux/mount.h>',
|
||
+ args.cc).returncode != 0:
|
||
+ sys.exit (77)
|
||
+
|
||
linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
|
||
# Constants in glibc were updated to match Linux v5.16. When glibc
|
||
# constants are updated this value should be updated to match the
|
||
diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
|
||
index 90cbb9be64..d732173abd 100644
|
||
--- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
|
||
+++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
|
||
@@ -33,11 +33,13 @@ def main():
|
||
help='C compiler (including options) to use')
|
||
args = parser.parse_args()
|
||
|
||
- linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
|
||
- # Linux started to provide pidfd.h with 5.10.
|
||
- if linux_version_headers < (5, 10):
|
||
+ if glibcextract.compile_c_snippet(
|
||
+ '#include <linux/pidfd.h>',
|
||
+ args.cc).returncode != 0:
|
||
sys.exit (77)
|
||
- linux_version_glibc = (5, 18)
|
||
+
|
||
+ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
|
||
+ linux_version_glibc = (5, 19)
|
||
sys.exit(glibcextract.compare_macro_consts(
|
||
'#include <sys/pidfd.h>\n',
|
||
'#include <asm/fcntl.h>\n'
|
||
diff --git a/sysdeps/unix/sysv/linux/tst-pidfd.c b/sysdeps/unix/sysv/linux/tst-pidfd.c
|
||
index 037af22290..5711d1c312 100644
|
||
--- a/sysdeps/unix/sysv/linux/tst-pidfd.c
|
||
+++ b/sysdeps/unix/sysv/linux/tst-pidfd.c
|
||
@@ -147,8 +147,11 @@ do_test (void)
|
||
may be denied if the process doesn't have CAP_SYS_PTRACE or
|
||
if a LSM security_ptrace_access_check denies access. */
|
||
if (fd == -1 && errno == EPERM)
|
||
- FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, "
|
||
- "skipping test");
|
||
+ {
|
||
+ TEST_COMPARE (pidfd_send_signal (pidfd, SIGKILL, NULL, 0), 0);
|
||
+ FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, "
|
||
+ "skipping test");
|
||
+ }
|
||
TEST_VERIFY (fd > 0);
|
||
|
||
char *path = xasprintf ("/proc/%d/fd/%d", pid, remote_fd);
|
||
diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h
|
||
index e9f3382108..637b5a022d 100644
|
||
--- a/sysdeps/x86/dl-cacheinfo.h
|
||
+++ b/sysdeps/x86/dl-cacheinfo.h
|
||
@@ -861,6 +861,18 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
|
||
share of the cache, it has a substantial risk of negatively
|
||
impacting the performance of other threads running on the chip. */
|
||
unsigned long int non_temporal_threshold = shared * 3 / 4;
|
||
+ /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of
|
||
+ 'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best
|
||
+ if that operation cannot overflow. Minimum of 0x4040 (16448) because the
|
||
+ L(large_memset_4x) loops need 64-byte to cache align and enough space for
|
||
+ at least 1 iteration of 4x PAGE_SIZE unrolled loop. Both values are
|
||
+ reflected in the manual. */
|
||
+ unsigned long int maximum_non_temporal_threshold = SIZE_MAX >> 4;
|
||
+ unsigned long int minimum_non_temporal_threshold = 0x4040;
|
||
+ if (non_temporal_threshold < minimum_non_temporal_threshold)
|
||
+ non_temporal_threshold = minimum_non_temporal_threshold;
|
||
+ else if (non_temporal_threshold > maximum_non_temporal_threshold)
|
||
+ non_temporal_threshold = maximum_non_temporal_threshold;
|
||
|
||
#if HAVE_TUNABLES
|
||
/* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */
|
||
@@ -915,8 +927,8 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
|
||
shared = tunable_size;
|
||
|
||
tunable_size = TUNABLE_GET (x86_non_temporal_threshold, long int, NULL);
|
||
- /* NB: Ignore the default value 0. */
|
||
- if (tunable_size != 0)
|
||
+ if (tunable_size > minimum_non_temporal_threshold
|
||
+ && tunable_size <= maximum_non_temporal_threshold)
|
||
non_temporal_threshold = tunable_size;
|
||
|
||
tunable_size = TUNABLE_GET (x86_rep_movsb_threshold, long int, NULL);
|
||
@@ -931,14 +943,9 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
|
||
|
||
TUNABLE_SET_WITH_BOUNDS (x86_data_cache_size, data, 0, SIZE_MAX);
|
||
TUNABLE_SET_WITH_BOUNDS (x86_shared_cache_size, shared, 0, SIZE_MAX);
|
||
- /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of
|
||
- 'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best
|
||
- if that operation cannot overflow. Minimum of 0x4040 (16448) because the
|
||
- L(large_memset_4x) loops need 64-byte to cache align and enough space for
|
||
- at least 1 iteration of 4x PAGE_SIZE unrolled loop. Both values are
|
||
- reflected in the manual. */
|
||
TUNABLE_SET_WITH_BOUNDS (x86_non_temporal_threshold, non_temporal_threshold,
|
||
- 0x4040, SIZE_MAX >> 4);
|
||
+ minimum_non_temporal_threshold,
|
||
+ maximum_non_temporal_threshold);
|
||
TUNABLE_SET_WITH_BOUNDS (x86_rep_movsb_threshold, rep_movsb_threshold,
|
||
minimum_rep_movsb_threshold, SIZE_MAX);
|
||
TUNABLE_SET_WITH_BOUNDS (x86_rep_stosb_threshold, rep_stosb_threshold, 1,
|
||
diff --git a/sysdeps/x86/get-isa-level.h b/sysdeps/x86/get-isa-level.h
|
||
index 1ade78ab73..5b4dd5f062 100644
|
||
--- a/sysdeps/x86/get-isa-level.h
|
||
+++ b/sysdeps/x86/get-isa-level.h
|
||
@@ -47,6 +47,8 @@ get_isa_level (const struct cpu_features *cpu_features)
|
||
isa_level |= GNU_PROPERTY_X86_ISA_1_V2;
|
||
if (CPU_FEATURE_USABLE_P (cpu_features, AVX)
|
||
&& CPU_FEATURE_USABLE_P (cpu_features, AVX2)
|
||
+ && CPU_FEATURE_USABLE_P (cpu_features, BMI1)
|
||
+ && CPU_FEATURE_USABLE_P (cpu_features, BMI2)
|
||
&& CPU_FEATURE_USABLE_P (cpu_features, F16C)
|
||
&& CPU_FEATURE_USABLE_P (cpu_features, FMA)
|
||
&& CPU_FEATURE_USABLE_P (cpu_features, LZCNT)
|
||
diff --git a/sysdeps/x86/isa-level.h b/sysdeps/x86/isa-level.h
|
||
index 3c4480aba7..06f6c9663e 100644
|
||
--- a/sysdeps/x86/isa-level.h
|
||
+++ b/sysdeps/x86/isa-level.h
|
||
@@ -79,7 +79,9 @@
|
||
/* ISA level >= 3 guaranteed includes. */
|
||
#define AVX_X86_ISA_LEVEL 3
|
||
#define AVX2_X86_ISA_LEVEL 3
|
||
+#define BMI1_X86_ISA_LEVEL 3
|
||
#define BMI2_X86_ISA_LEVEL 3
|
||
+#define LZCNT_X86_ISA_LEVEL 3
|
||
#define MOVBE_X86_ISA_LEVEL 3
|
||
|
||
/* ISA level >= 2 guaranteed includes. */
|
||
diff --git a/sysdeps/x86_64/fpu/fraiseexcpt.c b/sysdeps/x86_64/fpu/fraiseexcpt.c
|
||
index 864f4777a2..23446ff4ac 100644
|
||
--- a/sysdeps/x86_64/fpu/fraiseexcpt.c
|
||
+++ b/sysdeps/x86_64/fpu/fraiseexcpt.c
|
||
@@ -33,7 +33,7 @@ __feraiseexcept (int excepts)
|
||
/* One example of an invalid operation is 0.0 / 0.0. */
|
||
float f = 0.0;
|
||
|
||
- __asm__ __volatile__ ("divss %0, %0 " : : "x" (f));
|
||
+ __asm__ __volatile__ ("divss %0, %0 " : "+x" (f));
|
||
(void) &f;
|
||
}
|
||
|
||
@@ -43,7 +43,7 @@ __feraiseexcept (int excepts)
|
||
float f = 1.0;
|
||
float g = 0.0;
|
||
|
||
- __asm__ __volatile__ ("divss %1, %0" : : "x" (f), "x" (g));
|
||
+ __asm__ __volatile__ ("divss %1, %0" : "+x" (f) : "x" (g));
|
||
(void) &f;
|
||
}
|
||
|
||
diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h
|
||
index a57a9952f3..f2f5e8a211 100644
|
||
--- a/sysdeps/x86_64/multiarch/ifunc-avx2.h
|
||
+++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h
|
||
@@ -36,7 +36,9 @@ IFUNC_SELECTOR (void)
|
||
const struct cpu_features *cpu_features = __get_cpu_features ();
|
||
|
||
if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2)
|
||
+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI1)
|
||
&& X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)
|
||
+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, LZCNT)
|
||
&& X86_ISA_CPU_FEATURES_ARCH_P (cpu_features,
|
||
AVX_Fast_Unaligned_Load, ))
|
||
{
|
||
diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c
|
||
index a71444eccb..00a91123d3 100644
|
||
--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c
|
||
+++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c
|
||
@@ -69,10 +69,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
&& CPU_FEATURE_USABLE (BMI2)),
|
||
__memchr_evex_rtm)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, memchr,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__memchr_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, memchr,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__memchr_avx2_rtm)
|
||
/* ISA V2 wrapper for SSE2 implementation because the SSE2
|
||
@@ -207,13 +209,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
IFUNC_IMPL (i, name, memrchr,
|
||
X86_IFUNC_IMPL_ADD_V4 (array, i, memrchr,
|
||
(CPU_FEATURE_USABLE (AVX512VL)
|
||
- && CPU_FEATURE_USABLE (AVX512BW)),
|
||
+ && CPU_FEATURE_USABLE (AVX512BW)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
+ && CPU_FEATURE_USABLE (LZCNT)),
|
||
__memrchr_evex)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, memrchr,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
+ && CPU_FEATURE_USABLE (LZCNT)),
|
||
__memrchr_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, memrchr,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
+ && CPU_FEATURE_USABLE (LZCNT)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__memrchr_avx2_rtm)
|
||
/* ISA V2 wrapper for SSE2 implementation because the SSE2
|
||
@@ -335,10 +343,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
&& CPU_FEATURE_USABLE (BMI2)),
|
||
__rawmemchr_evex_rtm)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, rawmemchr,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__rawmemchr_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, rawmemchr,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__rawmemchr_avx2_rtm)
|
||
/* ISA V2 wrapper for SSE2 implementation because the SSE2
|
||
@@ -448,13 +458,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
IFUNC_IMPL (i, name, strcasecmp,
|
||
X86_IFUNC_IMPL_ADD_V4 (array, i, strcasecmp,
|
||
(CPU_FEATURE_USABLE (AVX512VL)
|
||
- && CPU_FEATURE_USABLE (AVX512BW)),
|
||
+ && CPU_FEATURE_USABLE (AVX512BW)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__strcasecmp_evex)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__strcasecmp_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__strcasecmp_avx2_rtm)
|
||
X86_IFUNC_IMPL_ADD_V2 (array, i, strcasecmp,
|
||
@@ -470,13 +483,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
IFUNC_IMPL (i, name, strcasecmp_l,
|
||
X86_IFUNC_IMPL_ADD_V4 (array, i, strcasecmp,
|
||
(CPU_FEATURE_USABLE (AVX512VL)
|
||
- && CPU_FEATURE_USABLE (AVX512BW)),
|
||
+ && CPU_FEATURE_USABLE (AVX512BW)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__strcasecmp_l_evex)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__strcasecmp_l_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__strcasecmp_l_avx2_rtm)
|
||
X86_IFUNC_IMPL_ADD_V2 (array, i, strcasecmp_l,
|
||
@@ -562,13 +578,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
IFUNC_IMPL (i, name, strrchr,
|
||
X86_IFUNC_IMPL_ADD_V4 (array, i, strrchr,
|
||
(CPU_FEATURE_USABLE (AVX512VL)
|
||
- && CPU_FEATURE_USABLE (AVX512BW)),
|
||
+ && CPU_FEATURE_USABLE (AVX512BW)
|
||
+ && CPU_FEATURE_USABLE (BMI1)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__strrchr_evex)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strrchr,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI1)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__strrchr_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strrchr,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI1)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__strrchr_avx2_rtm)
|
||
/* ISA V2 wrapper for SSE2 implementation because the SSE2
|
||
@@ -585,10 +607,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
&& CPU_FEATURE_USABLE (BMI2)),
|
||
__strcmp_evex)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strcmp,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__strcmp_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strcmp,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__strcmp_avx2_rtm)
|
||
X86_IFUNC_IMPL_ADD_V2 (array, i, strcmp,
|
||
@@ -638,13 +662,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
IFUNC_IMPL (i, name, strncasecmp,
|
||
X86_IFUNC_IMPL_ADD_V4 (array, i, strncasecmp,
|
||
(CPU_FEATURE_USABLE (AVX512VL)
|
||
- && CPU_FEATURE_USABLE (AVX512BW)),
|
||
+ && CPU_FEATURE_USABLE (AVX512BW)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__strncasecmp_evex)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__strncasecmp_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__strncasecmp_avx2_rtm)
|
||
X86_IFUNC_IMPL_ADD_V2 (array, i, strncasecmp,
|
||
@@ -660,13 +687,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
IFUNC_IMPL (i, name, strncasecmp_l,
|
||
X86_IFUNC_IMPL_ADD_V4 (array, i, strncasecmp,
|
||
(CPU_FEATURE_USABLE (AVX512VL)
|
||
- && CPU_FEATURE_USABLE (AVX512BW)),
|
||
+ & CPU_FEATURE_USABLE (AVX512BW)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__strncasecmp_l_evex)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__strncasecmp_l_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__strncasecmp_l_avx2_rtm)
|
||
X86_IFUNC_IMPL_ADD_V2 (array, i, strncasecmp_l,
|
||
@@ -773,13 +803,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
X86_IFUNC_IMPL_ADD_V4 (array, i, wcsrchr,
|
||
(CPU_FEATURE_USABLE (AVX512VL)
|
||
&& CPU_FEATURE_USABLE (AVX512BW)
|
||
+ && CPU_FEATURE_USABLE (BMI1)
|
||
&& CPU_FEATURE_USABLE (BMI2)),
|
||
__wcsrchr_evex)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, wcsrchr,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI1)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__wcsrchr_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, wcsrchr,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI1)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__wcsrchr_avx2_rtm)
|
||
/* ISA V2 wrapper for SSE2 implementation because the SSE2
|
||
@@ -796,10 +831,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
&& CPU_FEATURE_USABLE (BMI2)),
|
||
__wcscmp_evex)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, wcscmp,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__wcscmp_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, wcscmp,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__wcscmp_avx2_rtm)
|
||
/* ISA V2 wrapper for SSE2 implementation because the SSE2
|
||
@@ -816,10 +853,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
&& CPU_FEATURE_USABLE (BMI2)),
|
||
__wcsncmp_evex)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, wcsncmp,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__wcsncmp_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, wcsncmp,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__wcsncmp_avx2_rtm)
|
||
/* ISA V2 wrapper for GENERIC implementation because the
|
||
@@ -909,10 +948,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
&& CPU_FEATURE_USABLE (BMI2)),
|
||
__wmemchr_evex_rtm)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, wmemchr,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__wmemchr_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, wmemchr,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__wmemchr_avx2_rtm)
|
||
/* ISA V2 wrapper for SSE2 implementation because the SSE2
|
||
@@ -1162,13 +1203,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
IFUNC_IMPL (i, name, strncmp,
|
||
X86_IFUNC_IMPL_ADD_V4 (array, i, strncmp,
|
||
(CPU_FEATURE_USABLE (AVX512VL)
|
||
- && CPU_FEATURE_USABLE (AVX512BW)),
|
||
+ && CPU_FEATURE_USABLE (AVX512BW)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__strncmp_evex)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strncmp,
|
||
- CPU_FEATURE_USABLE (AVX2),
|
||
+ (CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)),
|
||
__strncmp_avx2)
|
||
X86_IFUNC_IMPL_ADD_V3 (array, i, strncmp,
|
||
(CPU_FEATURE_USABLE (AVX2)
|
||
+ && CPU_FEATURE_USABLE (BMI2)
|
||
&& CPU_FEATURE_USABLE (RTM)),
|
||
__strncmp_avx2_rtm)
|
||
X86_IFUNC_IMPL_ADD_V2 (array, i, strncmp,
|
||
diff --git a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h
|
||
index 68646ef199..7622af259c 100644
|
||
--- a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h
|
||
+++ b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h
|
||
@@ -34,6 +34,7 @@ IFUNC_SELECTOR (void)
|
||
const struct cpu_features *cpu_features = __get_cpu_features ();
|
||
|
||
if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2)
|
||
+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)
|
||
&& X86_ISA_CPU_FEATURES_ARCH_P (cpu_features,
|
||
AVX_Fast_Unaligned_Load, ))
|
||
{
|
||
diff --git a/sysdeps/x86_64/multiarch/memcmp-sse2.S b/sysdeps/x86_64/multiarch/memcmp-sse2.S
|
||
index afd450d020..51bc9344f0 100644
|
||
--- a/sysdeps/x86_64/multiarch/memcmp-sse2.S
|
||
+++ b/sysdeps/x86_64/multiarch/memcmp-sse2.S
|
||
@@ -308,7 +308,17 @@ L(ret_nonzero_vec_end_0):
|
||
setg %dl
|
||
leal -1(%rdx, %rdx), %eax
|
||
# else
|
||
- addl %edx, %eax
|
||
+ /* Use `addq` instead of `addl` here so that even if `rax` + `rdx`
|
||
+ is negative value of the sum will be usable as a 64-bit offset
|
||
+ (negative 32-bit numbers zero-extend to a large and often
|
||
+ out-of-bounds 64-bit offsets). Note that `rax` + `rdx` >= 0 is
|
||
+ an invariant when `memcmp` is used correctly, but if the input
|
||
+ strings `rsi`/`rdi` are concurrently modified as the function
|
||
+ runs (there is a Data-Race) it is possible for `rax` + `rdx` to
|
||
+ be negative. Given that there is virtually no extra to cost
|
||
+ using `addq` instead of `addl` we may as well protect the
|
||
+ data-race case. */
|
||
+ addq %rdx, %rax
|
||
movzbl (VEC_SIZE * -1 + SIZE_OFFSET)(%rsi, %rax), %ecx
|
||
movzbl (VEC_SIZE * -1 + SIZE_OFFSET)(%rdi, %rax), %eax
|
||
subl %ecx, %eax
|
||
diff --git a/sysdeps/x86_64/multiarch/rtld-strcpy.S b/sysdeps/x86_64/multiarch/rtld-strcpy.S
|
||
new file mode 100644
|
||
index 0000000000..19439c553d
|
||
--- /dev/null
|
||
+++ b/sysdeps/x86_64/multiarch/rtld-strcpy.S
|
||
@@ -0,0 +1,18 @@
|
||
+/* Copyright (C) 2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include "../strcpy.S"
|
||
diff --git a/sysdeps/x86_64/multiarch/strcmp.c b/sysdeps/x86_64/multiarch/strcmp.c
|
||
index fdd5afe3af..9d6c9f66ba 100644
|
||
--- a/sysdeps/x86_64/multiarch/strcmp.c
|
||
+++ b/sysdeps/x86_64/multiarch/strcmp.c
|
||
@@ -45,12 +45,12 @@ IFUNC_SELECTOR (void)
|
||
const struct cpu_features *cpu_features = __get_cpu_features ();
|
||
|
||
if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2)
|
||
+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)
|
||
&& X86_ISA_CPU_FEATURES_ARCH_P (cpu_features,
|
||
AVX_Fast_Unaligned_Load, ))
|
||
{
|
||
if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)
|
||
- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)
|
||
- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2))
|
||
+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW))
|
||
return OPTIMIZE (evex);
|
||
|
||
if (CPU_FEATURE_USABLE_P (cpu_features, RTM))
|
||
diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S
|
||
index 0593fb303b..b9b58ef599 100644
|
||
--- a/sysdeps/x86_64/multiarch/strlen-avx2.S
|
||
+++ b/sysdeps/x86_64/multiarch/strlen-avx2.S
|
||
@@ -544,14 +544,11 @@ L(return_vzeroupper):
|
||
L(cross_page_less_vec):
|
||
tzcntl %eax, %eax
|
||
# ifdef USE_AS_WCSLEN
|
||
- /* NB: Multiply length by 4 to get byte count. */
|
||
- sall $2, %esi
|
||
+ /* NB: Divide by 4 to convert from byte-count to length. */
|
||
+ shrl $2, %eax
|
||
# endif
|
||
cmpq %rax, %rsi
|
||
cmovb %esi, %eax
|
||
-# ifdef USE_AS_WCSLEN
|
||
- shrl $2, %eax
|
||
-# endif
|
||
VZEROUPPER_RETURN
|
||
# endif
|
||
|
||
diff --git a/sysdeps/x86_64/multiarch/strncmp.c b/sysdeps/x86_64/multiarch/strncmp.c
|
||
index 4ebe4bde30..c4f8b6bbb5 100644
|
||
--- a/sysdeps/x86_64/multiarch/strncmp.c
|
||
+++ b/sysdeps/x86_64/multiarch/strncmp.c
|
||
@@ -41,12 +41,12 @@ IFUNC_SELECTOR (void)
|
||
const struct cpu_features *cpu_features = __get_cpu_features ();
|
||
|
||
if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2)
|
||
+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)
|
||
&& X86_ISA_CPU_FEATURES_ARCH_P (cpu_features,
|
||
AVX_Fast_Unaligned_Load, ))
|
||
{
|
||
if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)
|
||
- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)
|
||
- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2))
|
||
+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW))
|
||
return OPTIMIZE (evex);
|
||
|
||
if (CPU_FEATURE_USABLE_P (cpu_features, RTM))
|
||
diff --git a/time/Makefile b/time/Makefile
|
||
index 470275b90c..2f4aa2d528 100644
|
||
--- a/time/Makefile
|
||
+++ b/time/Makefile
|
||
@@ -50,7 +50,7 @@ tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
|
||
tst-clock tst-clock2 tst-clock_nanosleep tst-cpuclock1 \
|
||
tst-adjtime tst-ctime tst-difftime tst-mktime4 tst-clock_settime \
|
||
tst-settimeofday tst-itimer tst-gmtime tst-timegm \
|
||
- tst-timespec_get tst-timespec_getres
|
||
+ tst-timespec_get tst-timespec_getres tst-strftime4
|
||
|
||
tests-time64 := \
|
||
tst-adjtime-time64 \
|
||
@@ -65,6 +65,7 @@ tests-time64 := \
|
||
tst-itimer-time64 \
|
||
tst-mktime4-time64 \
|
||
tst-settimeofday-time64 \
|
||
+ tst-strftime4-time64 \
|
||
tst-timegm-time64 \
|
||
tst-timespec_get-time64 \
|
||
tst-timespec_getres-time64 \
|
||
diff --git a/time/mktime.c b/time/mktime.c
|
||
index 494c89bf54..e9a6006710 100644
|
||
--- a/time/mktime.c
|
||
+++ b/time/mktime.c
|
||
@@ -429,8 +429,13 @@ __mktime_internal (struct tm *tp,
|
||
time with the right value, and use its UTC offset.
|
||
|
||
Heuristic: probe the adjacent timestamps in both directions,
|
||
- looking for the desired isdst. This should work for all real
|
||
- time zone histories in the tz database. */
|
||
+ looking for the desired isdst. If none is found within a
|
||
+ reasonable duration bound, assume a one-hour DST difference.
|
||
+ This should work for all real time zone histories in the tz
|
||
+ database. */
|
||
+
|
||
+ /* +1 if we wanted standard time but got DST, -1 if the reverse. */
|
||
+ int dst_difference = (isdst == 0) - (tm.tm_isdst == 0);
|
||
|
||
/* Distance between probes when looking for a DST boundary. In
|
||
tzdata2003a, the shortest period of DST is 601200 seconds
|
||
@@ -441,12 +446,14 @@ __mktime_internal (struct tm *tp,
|
||
periods when probing. */
|
||
int stride = 601200;
|
||
|
||
- /* The longest period of DST in tzdata2003a is 536454000 seconds
|
||
- (e.g., America/Jujuy starting 1946-10-01 01:00). The longest
|
||
- period of non-DST is much longer, but it makes no real sense
|
||
- to search for more than a year of non-DST, so use the DST
|
||
- max. */
|
||
- int duration_max = 536454000;
|
||
+ /* In TZDB 2021e, the longest period of DST (or of non-DST), in
|
||
+ which the DST (or adjacent DST) difference is not one hour,
|
||
+ is 457243209 seconds: e.g., America/Cambridge_Bay with leap
|
||
+ seconds, starting 1965-10-31 00:00 in a switch from
|
||
+ double-daylight time (-05) to standard time (-07), and
|
||
+ continuing to 1980-04-27 02:00 in a switch from standard time
|
||
+ (-07) to daylight time (-06). */
|
||
+ int duration_max = 457243209;
|
||
|
||
/* Search in both directions, so the maximum distance is half
|
||
the duration; add the stride to avoid off-by-1 problems. */
|
||
@@ -483,6 +490,11 @@ __mktime_internal (struct tm *tp,
|
||
}
|
||
}
|
||
|
||
+ /* No unusual DST offset was found nearby. Assume one-hour DST. */
|
||
+ t += 60 * 60 * dst_difference;
|
||
+ if (mktime_min <= t && t <= mktime_max && convert_time (convert, t, &tm))
|
||
+ goto offset_found;
|
||
+
|
||
__set_errno (EOVERFLOW);
|
||
return -1;
|
||
}
|
||
diff --git a/time/strftime_l.c b/time/strftime_l.c
|
||
index 75554fee7c..4d7c4ea828 100644
|
||
--- a/time/strftime_l.c
|
||
+++ b/time/strftime_l.c
|
||
@@ -159,6 +159,10 @@ extern char *tzname[];
|
||
#ifdef _LIBC
|
||
# define tzname __tzname
|
||
# define tzset __tzset
|
||
+
|
||
+# define time_t __time64_t
|
||
+# define __gmtime_r(t, tp) __gmtime64_r (t, tp)
|
||
+# define mktime(tp) __mktime64 (tp)
|
||
#endif
|
||
|
||
#if !HAVE_TM_GMTOFF
|
||
diff --git a/time/strptime_l.c b/time/strptime_l.c
|
||
index a3c5681fc2..f927448204 100644
|
||
--- a/time/strptime_l.c
|
||
+++ b/time/strptime_l.c
|
||
@@ -30,8 +30,10 @@
|
||
#ifdef _LIBC
|
||
# define HAVE_LOCALTIME_R 0
|
||
# include "../locale/localeinfo.h"
|
||
-#endif
|
||
|
||
+# define time_t __time64_t
|
||
+# define __localtime_r(t, tp) __localtime64_r (t, tp)
|
||
+#endif
|
||
|
||
#if ! HAVE_LOCALTIME_R && ! defined localtime_r
|
||
# ifdef _LIBC
|
||
diff --git a/time/tst-strftime4-time64.c b/time/tst-strftime4-time64.c
|
||
new file mode 100644
|
||
index 0000000000..4d47ee7d79
|
||
--- /dev/null
|
||
+++ b/time/tst-strftime4-time64.c
|
||
@@ -0,0 +1 @@
|
||
+#include "tst-strftime4.c"
|
||
diff --git a/time/tst-strftime4.c b/time/tst-strftime4.c
|
||
new file mode 100644
|
||
index 0000000000..659716d0fa
|
||
--- /dev/null
|
||
+++ b/time/tst-strftime4.c
|
||
@@ -0,0 +1,52 @@
|
||
+/* Test strftime and strptime after 2038-01-19 03:14:07 UTC (bug 30053).
|
||
+ Copyright (C) 2023 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <time.h>
|
||
+#include <stdlib.h>
|
||
+#include <stdio.h>
|
||
+#include <string.h>
|
||
+#include <support/check.h>
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ TEST_VERIFY_EXIT (setenv ("TZ", "UTC0", 1) == 0);
|
||
+ tzset ();
|
||
+ if (sizeof (time_t) > 4)
|
||
+ {
|
||
+ time_t wrap = (time_t) 2147483648LL;
|
||
+ char buf[80];
|
||
+ struct tm *tm = gmtime (&wrap);
|
||
+ TEST_VERIFY_EXIT (tm != NULL);
|
||
+ TEST_VERIFY_EXIT (strftime (buf, sizeof buf, "%s", tm) > 0);
|
||
+ puts (buf);
|
||
+ TEST_VERIFY (strcmp (buf, "2147483648") == 0);
|
||
+
|
||
+ struct tm tm2;
|
||
+ char *p = strptime (buf, "%s", &tm2);
|
||
+ TEST_VERIFY_EXIT (p != NULL && *p == '\0');
|
||
+ time_t t = mktime (&tm2);
|
||
+ printf ("%lld\n", (long long) t);
|
||
+ TEST_VERIFY (t == wrap);
|
||
+ }
|
||
+ else
|
||
+ FAIL_UNSUPPORTED ("32-bit time_t");
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/time/tzfile.c b/time/tzfile.c
|
||
index dd75848ba9..8bba4e5b8d 100644
|
||
--- a/time/tzfile.c
|
||
+++ b/time/tzfile.c
|
||
@@ -32,7 +32,7 @@
|
||
int __use_tzfile;
|
||
static dev_t tzfile_dev;
|
||
static ino64_t tzfile_ino;
|
||
-static time_t tzfile_mtime;
|
||
+static __time64_t tzfile_mtime;
|
||
|
||
struct ttinfo
|
||
{
|
||
@@ -61,6 +61,10 @@ static size_t num_leaps;
|
||
static struct leap *leaps;
|
||
static char *tzspec;
|
||
|
||
+/* Used to restore the daylight variable during time conversion, as if
|
||
+ tzset had been called. */
|
||
+static int daylight_saved;
|
||
+
|
||
#include <endian.h>
|
||
#include <byteswap.h>
|
||
|
||
@@ -438,36 +442,35 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||
if (__tzname[1] == NULL)
|
||
__tzname[1] = __tzname[0];
|
||
|
||
+ daylight_saved = 0;
|
||
if (num_transitions == 0)
|
||
/* Use the first rule (which should also be the only one). */
|
||
rule_stdoff = rule_dstoff = types[0].offset;
|
||
else
|
||
{
|
||
- int stdoff_set = 0, dstoff_set = 0;
|
||
- rule_stdoff = rule_dstoff = 0;
|
||
+ rule_stdoff = 0;
|
||
+
|
||
+ /* Search for the last rule with a standard time offset. This
|
||
+ will be used for the global timezone variable. */
|
||
i = num_transitions - 1;
|
||
do
|
||
- {
|
||
- if (!stdoff_set && !types[type_idxs[i]].isdst)
|
||
- {
|
||
- stdoff_set = 1;
|
||
- rule_stdoff = types[type_idxs[i]].offset;
|
||
- }
|
||
- else if (!dstoff_set && types[type_idxs[i]].isdst)
|
||
- {
|
||
- dstoff_set = 1;
|
||
- rule_dstoff = types[type_idxs[i]].offset;
|
||
- }
|
||
- if (stdoff_set && dstoff_set)
|
||
+ if (!types[type_idxs[i]].isdst)
|
||
+ {
|
||
+ rule_stdoff = types[type_idxs[i]].offset;
|
||
break;
|
||
- }
|
||
+ }
|
||
+ else
|
||
+ daylight_saved = 1;
|
||
while (i-- > 0);
|
||
|
||
- if (!dstoff_set)
|
||
- rule_dstoff = rule_stdoff;
|
||
+ /* Keep searching to see if there is a DST rule. This
|
||
+ information will be used to set the global daylight
|
||
+ variable. */
|
||
+ while (i-- > 0 && !daylight_saved)
|
||
+ daylight_saved = types[type_idxs[i]].isdst;
|
||
}
|
||
|
||
- __daylight = rule_stdoff != rule_dstoff;
|
||
+ __daylight = daylight_saved;
|
||
__timezone = -rule_stdoff;
|
||
|
||
done:
|
||
@@ -731,7 +734,7 @@ __tzfile_compute (__time64_t timer, int use_localtime,
|
||
}
|
||
|
||
struct ttinfo *info = &types[i];
|
||
- __daylight = rule_stdoff != rule_dstoff;
|
||
+ __daylight = daylight_saved;
|
||
__timezone = -rule_stdoff;
|
||
|
||
if (__tzname[0] == NULL)
|
||
diff --git a/timezone/Makefile b/timezone/Makefile
|
||
index a789c22d26..5002de39ad 100644
|
||
--- a/timezone/Makefile
|
||
+++ b/timezone/Makefile
|
||
@@ -23,7 +23,7 @@ subdir := timezone
|
||
include ../Makeconfig
|
||
|
||
others := zdump zic
|
||
-tests := test-tz tst-timezone tst-tzset tst-bz28707
|
||
+tests := test-tz tst-timezone tst-tzset tst-bz28707 tst-bz29951
|
||
|
||
generated-dirs += testdata
|
||
|
||
@@ -86,11 +86,13 @@ $(objpfx)tst-timezone.out: $(addprefix $(testdata)/, \
|
||
Europe/London)
|
||
$(objpfx)tst-tzset.out: $(addprefix $(testdata)/XT, 1 2 3 4)
|
||
$(objpfx)tst-bz28707.out: $(testdata)/XT5
|
||
+$(objpfx)tst-bz29951.out: $(testdata)/XT6
|
||
|
||
test-tz-ENV = TZDIR=$(testdata)
|
||
tst-timezone-ENV = TZDIR=$(testdata)
|
||
tst-tzset-ENV = TZDIR=$(testdata)
|
||
tst-bz28707-ENV = TZDIR=$(testdata)
|
||
+tst-bz29951-ENV = TZDIR=$(testdata)
|
||
|
||
# Note this must come second in the deps list for $(built-program-cmd) to work.
|
||
zic-deps = $(objpfx)zic $(leapseconds) yearistype
|
||
diff --git a/timezone/testdata/XT6 b/timezone/testdata/XT6
|
||
new file mode 100644
|
||
index 0000000000..07b393bb7d
|
||
Binary files /dev/null and b/timezone/testdata/XT6 differ
|
||
diff --git a/timezone/tst-bz29951.c b/timezone/tst-bz29951.c
|
||
new file mode 100644
|
||
index 0000000000..abd334683b
|
||
--- /dev/null
|
||
+++ b/timezone/tst-bz29951.c
|
||
@@ -0,0 +1,68 @@
|
||
+/* Check that daylight is set if the last DST transition did not change offset.
|
||
+ Copyright (C) 2023 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <errno.h>
|
||
+#include <stdlib.h>
|
||
+#include <support/check.h>
|
||
+#include <time.h>
|
||
+
|
||
+/* Set the specified time zone with error checking. */
|
||
+static void
|
||
+set_timezone (const char *name)
|
||
+{
|
||
+ TEST_VERIFY (setenv ("TZ", name, 1) == 0);
|
||
+ errno = 0;
|
||
+ tzset ();
|
||
+ TEST_COMPARE (errno, 0);
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ /* Test zone based on tz-2022g version of Africa/Tripoli. The last
|
||
+ DST transition coincided with a change in the standard time
|
||
+ offset, effectively making it a no-op.
|
||
+
|
||
+ Africa/Tripoli Thu Oct 24 23:59:59 2013 UT
|
||
+ = Fri Oct 25 01:59:59 2013 CEST isdst=1 gmtoff=7200
|
||
+ Africa/Tripoli Fri Oct 25 00:00:00 2013 UT
|
||
+ = Fri Oct 25 02:00:00 2013 EET isdst=0 gmtoff=7200
|
||
+ */
|
||
+ set_timezone ("XT6");
|
||
+ TEST_VERIFY (daylight != 0);
|
||
+ TEST_COMPARE (timezone, -7200);
|
||
+
|
||
+ /* Check that localtime re-initializes the two variables. */
|
||
+ daylight = timezone = 17;
|
||
+ time_t t = 844034401;
|
||
+ struct tm *tm = localtime (&t);
|
||
+ TEST_VERIFY (daylight != 0);
|
||
+ TEST_COMPARE (timezone, -7200);
|
||
+ TEST_COMPARE (tm->tm_year, 96);
|
||
+ TEST_COMPARE (tm->tm_mon, 8);
|
||
+ TEST_COMPARE (tm->tm_mday, 29);
|
||
+ TEST_COMPARE (tm->tm_hour, 23);
|
||
+ TEST_COMPARE (tm->tm_min, 0);
|
||
+ TEST_COMPARE (tm->tm_sec, 1);
|
||
+ TEST_COMPARE (tm->tm_gmtoff, 3600);
|
||
+ TEST_COMPARE (tm->tm_isdst, 0);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
|
||
index e6b9e8743a..4af102a3f6 100644
|
||
--- a/wcsmbs/Makefile
|
||
+++ b/wcsmbs/Makefile
|
||
@@ -22,8 +22,9 @@ subdir := wcsmbs
|
||
|
||
include ../Makeconfig
|
||
|
||
-headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar-ldbl.h uchar.h \
|
||
- bits/types/__mbstate_t.h bits/types/mbstate_t.h bits/types/wint_t.h
|
||
+headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar2-decl.h \
|
||
+ bits/wchar-ldbl.h uchar.h bits/types/__mbstate_t.h \
|
||
+ bits/types/mbstate_t.h bits/types/wint_t.h
|
||
|
||
routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
|
||
wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \
|
||
@@ -73,6 +74,8 @@ $(objpfx)tst-wcstol-locale.out: $(gen-locales)
|
||
$(objpfx)tst-wcstod-nan-locale.out: $(gen-locales)
|
||
$(objpfx)tst-c16-surrogate.out: $(gen-locales)
|
||
$(objpfx)tst-c32-state.out: $(gen-locales)
|
||
+$(objpfx)test-c8rtomb.out: $(gen-locales)
|
||
+$(objpfx)test-mbrtoc8.out: $(gen-locales)
|
||
endif
|
||
|
||
$(objpfx)tst-wcstod-round: $(libm)
|
||
diff --git a/wcsmbs/bits/wchar2-decl.h b/wcsmbs/bits/wchar2-decl.h
|
||
new file mode 100644
|
||
index 0000000000..8e1735c33b
|
||
--- /dev/null
|
||
+++ b/wcsmbs/bits/wchar2-decl.h
|
||
@@ -0,0 +1,124 @@
|
||
+/* Checking macros for wchar functions. Declarations only.
|
||
+ Copyright (C) 2004-2022 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <https://www.gnu.org/licenses/>. */
|
||
+
|
||
+#ifndef _BITS_WCHAR2_DECL_H
|
||
+#define _BITS_WCHAR2_DECL_H 1
|
||
+
|
||
+#ifndef _WCHAR_H
|
||
+# error "Never include <bits/wchar2-decl.h> directly; use <wchar.h> instead."
|
||
+#endif
|
||
+
|
||
+
|
||
+extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1,
|
||
+ const wchar_t *__restrict __s2, size_t __n,
|
||
+ size_t __ns1) __THROW;
|
||
+extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2,
|
||
+ size_t __n, size_t __ns1) __THROW;
|
||
+
|
||
+
|
||
+#ifdef __USE_GNU
|
||
+
|
||
+extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1,
|
||
+ const wchar_t *__restrict __s2, size_t __n,
|
||
+ size_t __ns1) __THROW;
|
||
+
|
||
+#endif
|
||
+
|
||
+
|
||
+extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n,
|
||
+ size_t __ns) __THROW;
|
||
+extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest,
|
||
+ const wchar_t *__restrict __src,
|
||
+ size_t __n) __THROW;
|
||
+extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest,
|
||
+ const wchar_t *__restrict __src,
|
||
+ size_t __destlen) __THROW;
|
||
+extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest,
|
||
+ const wchar_t *__restrict __src, size_t __n,
|
||
+ size_t __destlen) __THROW;
|
||
+extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest,
|
||
+ const wchar_t *__restrict __src, size_t __n,
|
||
+ size_t __destlen) __THROW;
|
||
+extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest,
|
||
+ const wchar_t *__restrict __src,
|
||
+ size_t __destlen) __THROW;
|
||
+extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest,
|
||
+ const wchar_t *__restrict __src,
|
||
+ size_t __n, size_t __destlen) __THROW;
|
||
+extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n,
|
||
+ int __flag, size_t __s_len,
|
||
+ const wchar_t *__restrict __format, ...)
|
||
+ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */;
|
||
+extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
|
||
+ int __flag, size_t __s_len,
|
||
+ const wchar_t *__restrict __format,
|
||
+ __gnuc_va_list __arg)
|
||
+ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
|
||
+
|
||
+#if __USE_FORTIFY_LEVEL > 1
|
||
+
|
||
+extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag,
|
||
+ const wchar_t *__restrict __format, ...);
|
||
+extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format,
|
||
+ ...);
|
||
+extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag,
|
||
+ const wchar_t *__restrict __format,
|
||
+ __gnuc_va_list __ap);
|
||
+extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format,
|
||
+ __gnuc_va_list __ap);
|
||
+
|
||
+#endif
|
||
+
|
||
+extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n,
|
||
+ __FILE *__restrict __stream) __wur;
|
||
+
|
||
+#ifdef __USE_GNU
|
||
+
|
||
+extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size,
|
||
+ int __n, __FILE *__restrict __stream)
|
||
+ __wur;
|
||
+
|
||
+#endif
|
||
+
|
||
+extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar,
|
||
+ mbstate_t *__restrict __p,
|
||
+ size_t __buflen) __THROW __wur;
|
||
+extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst,
|
||
+ const char **__restrict __src,
|
||
+ size_t __len, mbstate_t *__restrict __ps,
|
||
+ size_t __dstlen) __THROW;
|
||
+extern size_t __wcsrtombs_chk (char *__restrict __dst,
|
||
+ const wchar_t **__restrict __src,
|
||
+ size_t __len, mbstate_t *__restrict __ps,
|
||
+ size_t __dstlen) __THROW;
|
||
+
|
||
+#ifdef __USE_XOPEN2K8
|
||
+
|
||
+extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst,
|
||
+ const char **__restrict __src, size_t __nmc,
|
||
+ size_t __len, mbstate_t *__restrict __ps,
|
||
+ size_t __dstlen) __THROW;
|
||
+extern size_t __wcsnrtombs_chk (char *__restrict __dst,
|
||
+ const wchar_t **__restrict __src,
|
||
+ size_t __nwc, size_t __len,
|
||
+ mbstate_t *__restrict __ps, size_t __dstlen)
|
||
+ __THROW;
|
||
+
|
||
+#endif
|
||
+
|
||
+#endif /* bits/wchar2-decl.h. */
|
||
diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
|
||
index 0e017f458b..3f110efe57 100644
|
||
--- a/wcsmbs/bits/wchar2.h
|
||
+++ b/wcsmbs/bits/wchar2.h
|
||
@@ -21,9 +21,6 @@
|
||
#endif
|
||
|
||
|
||
-extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1,
|
||
- const wchar_t *__restrict __s2, size_t __n,
|
||
- size_t __ns1) __THROW;
|
||
extern wchar_t *__REDIRECT_NTH (__wmemcpy_alias,
|
||
(wchar_t *__restrict __s1,
|
||
const wchar_t *__restrict __s2, size_t __n),
|
||
@@ -45,8 +42,6 @@ __NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
|
||
}
|
||
|
||
|
||
-extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2,
|
||
- size_t __n, size_t __ns1) __THROW;
|
||
extern wchar_t *__REDIRECT_NTH (__wmemmove_alias, (wchar_t *__s1,
|
||
const wchar_t *__s2,
|
||
size_t __n), wmemmove);
|
||
@@ -66,9 +61,6 @@ __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n))
|
||
|
||
|
||
#ifdef __USE_GNU
|
||
-extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1,
|
||
- const wchar_t *__restrict __s2, size_t __n,
|
||
- size_t __ns1) __THROW;
|
||
extern wchar_t *__REDIRECT_NTH (__wmempcpy_alias,
|
||
(wchar_t *__restrict __s1,
|
||
const wchar_t *__restrict __s2,
|
||
@@ -91,8 +83,6 @@ __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
|
||
#endif
|
||
|
||
|
||
-extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n,
|
||
- size_t __ns) __THROW;
|
||
extern wchar_t *__REDIRECT_NTH (__wmemset_alias, (wchar_t *__s, wchar_t __c,
|
||
size_t __n), wmemset);
|
||
extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn,
|
||
@@ -110,9 +100,6 @@ __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n))
|
||
}
|
||
|
||
|
||
-extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest,
|
||
- const wchar_t *__restrict __src,
|
||
- size_t __n) __THROW;
|
||
extern wchar_t *__REDIRECT_NTH (__wcscpy_alias,
|
||
(wchar_t *__restrict __dest,
|
||
const wchar_t *__restrict __src), wcscpy);
|
||
@@ -127,9 +114,6 @@ __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
|
||
}
|
||
|
||
|
||
-extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest,
|
||
- const wchar_t *__restrict __src,
|
||
- size_t __destlen) __THROW;
|
||
extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias,
|
||
(wchar_t *__restrict __dest,
|
||
const wchar_t *__restrict __src), wcpcpy);
|
||
@@ -144,9 +128,6 @@ __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
|
||
}
|
||
|
||
|
||
-extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest,
|
||
- const wchar_t *__restrict __src, size_t __n,
|
||
- size_t __destlen) __THROW;
|
||
extern wchar_t *__REDIRECT_NTH (__wcsncpy_alias,
|
||
(wchar_t *__restrict __dest,
|
||
const wchar_t *__restrict __src,
|
||
@@ -168,9 +149,6 @@ __NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
|
||
}
|
||
|
||
|
||
-extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest,
|
||
- const wchar_t *__restrict __src, size_t __n,
|
||
- size_t __destlen) __THROW;
|
||
extern wchar_t *__REDIRECT_NTH (__wcpncpy_alias,
|
||
(wchar_t *__restrict __dest,
|
||
const wchar_t *__restrict __src,
|
||
@@ -192,9 +170,6 @@ __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
|
||
}
|
||
|
||
|
||
-extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest,
|
||
- const wchar_t *__restrict __src,
|
||
- size_t __destlen) __THROW;
|
||
extern wchar_t *__REDIRECT_NTH (__wcscat_alias,
|
||
(wchar_t *__restrict __dest,
|
||
const wchar_t *__restrict __src), wcscat);
|
||
@@ -209,9 +184,6 @@ __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
|
||
}
|
||
|
||
|
||
-extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest,
|
||
- const wchar_t *__restrict __src,
|
||
- size_t __n, size_t __destlen) __THROW;
|
||
extern wchar_t *__REDIRECT_NTH (__wcsncat_alias,
|
||
(wchar_t *__restrict __dest,
|
||
const wchar_t *__restrict __src,
|
||
@@ -228,10 +200,6 @@ __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
|
||
}
|
||
|
||
|
||
-extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n,
|
||
- int __flag, size_t __s_len,
|
||
- const wchar_t *__restrict __format, ...)
|
||
- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */;
|
||
|
||
extern int __REDIRECT_NTH_LDBL (__swprintf_alias,
|
||
(wchar_t *__restrict __s, size_t __n,
|
||
@@ -258,11 +226,6 @@ __NTH (swprintf (wchar_t *__restrict __s, size_t __n,
|
||
: swprintf (s, n, __VA_ARGS__))
|
||
#endif
|
||
|
||
-extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
|
||
- int __flag, size_t __s_len,
|
||
- const wchar_t *__restrict __format,
|
||
- __gnuc_va_list __arg)
|
||
- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
|
||
|
||
extern int __REDIRECT_NTH_LDBL (__vswprintf_alias,
|
||
(wchar_t *__restrict __s, size_t __n,
|
||
@@ -283,16 +246,6 @@ __NTH (vswprintf (wchar_t *__restrict __s, size_t __n,
|
||
|
||
#if __USE_FORTIFY_LEVEL > 1
|
||
|
||
-extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag,
|
||
- const wchar_t *__restrict __format, ...);
|
||
-extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format,
|
||
- ...);
|
||
-extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag,
|
||
- const wchar_t *__restrict __format,
|
||
- __gnuc_va_list __ap);
|
||
-extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format,
|
||
- __gnuc_va_list __ap);
|
||
-
|
||
# ifdef __va_arg_pack
|
||
__fortify_function int
|
||
wprintf (const wchar_t *__restrict __fmt, ...)
|
||
@@ -328,8 +281,6 @@ vfwprintf (__FILE *__restrict __stream,
|
||
|
||
#endif
|
||
|
||
-extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n,
|
||
- __FILE *__restrict __stream) __wur;
|
||
extern wchar_t *__REDIRECT (__fgetws_alias,
|
||
(wchar_t *__restrict __s, int __n,
|
||
__FILE *__restrict __stream), fgetws) __wur;
|
||
@@ -351,9 +302,6 @@ fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
|
||
}
|
||
|
||
#ifdef __USE_GNU
|
||
-extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size,
|
||
- int __n, __FILE *__restrict __stream)
|
||
- __wur;
|
||
extern wchar_t *__REDIRECT (__fgetws_unlocked_alias,
|
||
(wchar_t *__restrict __s, int __n,
|
||
__FILE *__restrict __stream), fgetws_unlocked)
|
||
@@ -379,9 +327,6 @@ fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
|
||
#endif
|
||
|
||
|
||
-extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar,
|
||
- mbstate_t *__restrict __p,
|
||
- size_t __buflen) __THROW __wur;
|
||
extern size_t __REDIRECT_NTH (__wcrtomb_alias,
|
||
(char *__restrict __s, wchar_t __wchar,
|
||
mbstate_t *__restrict __ps), wcrtomb) __wur;
|
||
@@ -404,10 +349,6 @@ __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar,
|
||
}
|
||
|
||
|
||
-extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst,
|
||
- const char **__restrict __src,
|
||
- size_t __len, mbstate_t *__restrict __ps,
|
||
- size_t __dstlen) __THROW;
|
||
extern size_t __REDIRECT_NTH (__mbsrtowcs_alias,
|
||
(wchar_t *__restrict __dst,
|
||
const char **__restrict __src,
|
||
@@ -431,10 +372,6 @@ __NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
|
||
}
|
||
|
||
|
||
-extern size_t __wcsrtombs_chk (char *__restrict __dst,
|
||
- const wchar_t **__restrict __src,
|
||
- size_t __len, mbstate_t *__restrict __ps,
|
||
- size_t __dstlen) __THROW;
|
||
extern size_t __REDIRECT_NTH (__wcsrtombs_alias,
|
||
(char *__restrict __dst,
|
||
const wchar_t **__restrict __src,
|
||
@@ -458,10 +395,6 @@ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
|
||
|
||
|
||
#ifdef __USE_XOPEN2K8
|
||
-extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst,
|
||
- const char **__restrict __src, size_t __nmc,
|
||
- size_t __len, mbstate_t *__restrict __ps,
|
||
- size_t __dstlen) __THROW;
|
||
extern size_t __REDIRECT_NTH (__mbsnrtowcs_alias,
|
||
(wchar_t *__restrict __dst,
|
||
const char **__restrict __src, size_t __nmc,
|
||
@@ -485,11 +418,6 @@ __NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
|
||
}
|
||
|
||
|
||
-extern size_t __wcsnrtombs_chk (char *__restrict __dst,
|
||
- const wchar_t **__restrict __src,
|
||
- size_t __nwc, size_t __len,
|
||
- mbstate_t *__restrict __ps, size_t __dstlen)
|
||
- __THROW;
|
||
extern size_t __REDIRECT_NTH (__wcsnrtombs_alias,
|
||
(char *__restrict __dst,
|
||
const wchar_t **__restrict __src,
|
||
diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h
|
||
index c37e8619a0..5f7139f279 100644
|
||
--- a/wcsmbs/uchar.h
|
||
+++ b/wcsmbs/uchar.h
|
||
@@ -34,8 +34,16 @@
|
||
/* Declare the C2x char8_t typedef in C2x modes, but only if the C++
|
||
__cpp_char8_t feature test macro is not defined. */
|
||
#if __GLIBC_USE (ISOC2X) && !defined __cpp_char8_t
|
||
+#if __GNUC_PREREQ (10, 0) && defined __cplusplus
|
||
+/* Suppress the diagnostic regarding char8_t being a keyword in C++20. */
|
||
+# pragma GCC diagnostic push
|
||
+# pragma GCC diagnostic ignored "-Wc++20-compat"
|
||
+#endif
|
||
/* Define the 8-bit character type. */
|
||
typedef unsigned char char8_t;
|
||
+#if __GNUC_PREREQ (10, 0) && defined __cplusplus
|
||
+# pragma GCC diagnostic pop
|
||
+#endif
|
||
#endif
|
||
|
||
#ifndef __USE_ISOCXX11
|
||
diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h
|
||
index 5d6a40853d..c1321c7518 100644
|
||
--- a/wcsmbs/wchar.h
|
||
+++ b/wcsmbs/wchar.h
|
||
@@ -864,14 +864,21 @@ extern size_t wcsftime_l (wchar_t *__restrict __s, size_t __maxsize,
|
||
|
||
/* Define some macros helping to catch buffer overflows. */
|
||
#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
|
||
-# include <bits/wchar2.h>
|
||
+/* Declare all functions from bits/wchar2-decl.h first. */
|
||
+# include <bits/wchar2-decl.h>
|
||
#endif
|
||
|
||
-#include <bits/floatn.h>
|
||
+/* The following headers provide asm redirections. These redirections must
|
||
+ appear before the first usage of these functions, e.g. in bits/wchar.h. */
|
||
#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
|
||
# include <bits/wchar-ldbl.h>
|
||
#endif
|
||
|
||
+#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
|
||
+/* Now include the function definitions and redirects too. */
|
||
+# include <bits/wchar2.h>
|
||
+#endif
|
||
+
|
||
__END_DECLS
|
||
|
||
#endif /* wchar.h */
|