git-updates
authorGNU Libc Maintainers <debian-glibc@lists.debian.org>
Sun, 25 Dec 2022 18:42:32 +0000 (18:42 +0000)
committerAurelien Jarno <aurel32@debian.org>
Sun, 25 Dec 2022 18:42:32 +0000 (18:42 +0000)
GIT update of https://sourceware.org/git/glibc.git/release/2.36/master from glibc-2.36

GIT update of https://sourceware.org/git/glibc.git/release/2.36/master from glibc-2.36

Gbp-Pq: Name git-updates.diff

106 files changed:
Makeconfig
Makerules
NEWS
bits/socket.h
dlfcn/dlopen.c
elf/Makefile
elf/dl-cache.c
elf/dl-hwcaps.c
elf/dl-lookup.c
elf/dl-open.c
elf/dl-sort-maps.c
elf/dso-sort-tests-1.def
elf/elf.h
elf/rtld-Rules
elf/rtld.c
elf/tst-dlmopen-twice-mod1.c [new file with mode: 0644]
elf/tst-dlmopen-twice-mod2.c [new file with mode: 0644]
elf/tst-dlmopen-twice.c [new file with mode: 0644]
iconv/gconv_parseconfdir.h
include/arpa/nameser.h
include/bits/wchar2-decl.h [new file with mode: 0644]
include/resolv.h
misc/syslog.c
misc/tst-syslog.c
nscd/aicache.c
nscd/connections.c
nss/getent.c
nss/tst-nss-files-hosts-long.c
nss/tst-reload1.c
resolv/Makefile
resolv/README
resolv/mapv4v6addr.h [deleted file]
resolv/mapv4v6hostent.h [deleted file]
resolv/ns_name_length_uncompressed.c [new file with mode: 0644]
resolv/ns_rr_cursor_init.c [new file with mode: 0644]
resolv/ns_rr_cursor_next.c [new file with mode: 0644]
resolv/ns_samebinaryname.c [new file with mode: 0644]
resolv/nss_dns/dns-host.c
resolv/res-name-checking.c
resolv/tst-ns_name_length_uncompressed.c [new file with mode: 0644]
resolv/tst-ns_rr_cursor.c [new file with mode: 0644]
resolv/tst-ns_samebinaryname.c [new file with mode: 0644]
resolv/tst-resolv-aliases.c [new file with mode: 0644]
resolv/tst-resolv-byaddr.c [new file with mode: 0644]
resolv/tst-resolv-invalid-cname.c [new file with mode: 0644]
resolv/tst-resolv-maybe_insert_sig.h [new file with mode: 0644]
scripts/dso-ordering-test.py
scripts/glibcextract.py
socket/Makefile
socket/tst-cmsghdr-skeleton.c [new file with mode: 0644]
socket/tst-cmsghdr.c [new file with mode: 0644]
stdlib/arc4random.c
stdlib/longlong.h
string/test-strnlen.c
sysdeps/aarch64/dl-trampoline.S
sysdeps/generic/ldsodefs.h
sysdeps/generic/libc-lock-arch.h [new file with mode: 0644]
sysdeps/hppa/dl-machine.h
sysdeps/ieee754/ldbl-128/e_j1l.c
sysdeps/ieee754/ldbl-128ibm/e_j1l.c
sysdeps/ieee754/ldbl-128ibm/s_llroundl.c
sysdeps/mach/hurd/bits/socket.h
sysdeps/nptl/libc-lock.h
sysdeps/nptl/libc-lockP.h
sysdeps/posix/getaddrinfo.c
sysdeps/unix/sysv/linux/Makefile
sysdeps/unix/sysv/linux/alpha/brk_call.h
sysdeps/unix/sysv/linux/arm/bits/struct_stat.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/bits/socket.h
sysdeps/unix/sysv/linux/bits/struct_stat.h
sysdeps/unix/sysv/linux/cmsg_nxthdr.c
sysdeps/unix/sysv/linux/csky/bits/struct_stat.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/generic/bits/struct_stat.h [deleted file]
sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/hppa/kernel-features.h
sysdeps/unix/sysv/linux/ipc_priv.h
sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/msgctl.c
sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/not-cancel.h
sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
sysdeps/unix/sysv/linux/semctl.c
sysdeps/unix/sysv/linux/sh/bits/struct_stat.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/shmctl.c
sysdeps/unix/sysv/linux/sys/mount.h
sysdeps/unix/sysv/linux/syscall-names.list
sysdeps/unix/sysv/linux/tst-mount-compile.py [new file with mode: 0755]
sysdeps/unix/sysv/linux/tst-mount-consts.py
sysdeps/unix/sysv/linux/tst-pidfd-consts.py
sysdeps/unix/sysv/linux/tst-pidfd.c
sysdeps/x86/get-isa-level.h
sysdeps/x86/isa-level.h
sysdeps/x86_64/multiarch/ifunc-avx2.h
sysdeps/x86_64/multiarch/ifunc-impl-list.c
sysdeps/x86_64/multiarch/ifunc-strcasecmp.h
sysdeps/x86_64/multiarch/strcmp.c
sysdeps/x86_64/multiarch/strlen-avx2.S
sysdeps/x86_64/multiarch/strncmp.c
time/mktime.c
wcsmbs/Makefile
wcsmbs/bits/wchar2-decl.h [new file with mode: 0644]
wcsmbs/bits/wchar2.h
wcsmbs/uchar.h
wcsmbs/wchar.h

index ba70321af1d239edb7088ca12bc2ab28cb9684ad..2bbcabd8f9218d5caba616412c03ea2720222d26 100644 (file)
@@ -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)
@@ -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
index d1e139d03c1c448e14aee35af3e54ee7abe2180c..09c0cf8357310896c050234902025fa7da2566e1 100644 (file)
--- 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))
 \f
 # 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 f61e521fc88316f739f844ac18cfc580e6154feb..9f8edea5db9a302c60683336645e9cbe7ed57d2d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,49 @@ See the end for copying conditions.
 Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
 using `glibc' in the "product" field.
 \f
+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
+  [24816] Fix tst-nss-files-hosts-long on single-stack hosts
+  [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning
+  [29305] Conserve NSS buffer space during DNS packet parsing
+  [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
+  [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
+\f
 Version 2.36
 
 Major new features:
index 2b99dea33bfe0c2fa2d43fa6f08d578b2e07c89e..aac8c49b008f1b606fa1596222d6d1ac211a07f4 100644 (file)
@@ -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'.  */
index 2696dde4b1cdf510b78f173e8b69155890ddae66..9b07b4e132f2e73d00339d8702ff34c1d455ac23 100644 (file)
@@ -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 *
index fd77d0c7c8799c336c65278f6f8e939ed8707633..72178d33ffd6ed6b9cfea423595b86316ab5efef 100644 (file)
@@ -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 \
@@ -765,6 +768,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 +803,7 @@ modules-names += \
   tst-auditmanymod7 \
   tst-auditmanymod8 \
   tst-auditmanymod9 \
+  tst-auditmod-tlsdesc  \
   tst-auditmod1 \
   tst-auditmod9a \
   tst-auditmod9b \
@@ -834,6 +840,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 +998,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
@@ -2967,3 +2960,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
index 8bbf110d02c832df53924faf6b86a09df656c308..b97c17b3a9c5e750a673f6d1e3ed39022304652d 100644 (file)
@@ -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);
 }
 
index 6f161f6ad528661f6b577d7d5d8a1f6ec6825363..92eb53790ef8d32005c0da5e28804bc5843a94d3 100644 (file)
@@ -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)
index 4c86dc694e0eebb23421e08103ee7f3c0adaadf9..67fb2e31e2612a0ec8b1002efa7a3eb6ad3b84a7 100644 (file)
@@ -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);
 }
index a23e65926bcfe797f06f8b4175f65040f4547a05..e7db5e9642fd2b532f61f8a4f362521f519a6cf4 100644 (file)
@@ -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
index 96638d7ed1a2df2faf62caf035b636ed870514b5..3e2a6a584ec46f802a775ff088fdedb009014f0d 100644 (file)
    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.  */
index 5f7f18ef270bc12d8ef848f62c35b84bb1ddb41c..4bf9052db16fb3522375afad055f1ca0ba9f32f6 100644 (file)
@@ -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
index 02a1b3f52fdfa3d8d92fd4e3008316ab0a23f26d..014393f3ccc7a628d34c63a192ed31147ae92805 100644 (file)
--- 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
index ca00dd1fe23eda1196b9ae602b67eb1a3a7d9660..3c5e273f2b8faf3e38c987c61ab6637ce295e4fb 100644 (file)
@@ -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        :=
index cbbaf4a33196512c92ad4b2f7657a850b411d8b4..3e771a93d83457665d0e143cf6c22ace592ec6ac 100644 (file)
@@ -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-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c
new file mode 100644 (file)
index 0000000..0eaf049
--- /dev/null
@@ -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 (file)
index 0000000..40c6c01
--- /dev/null
@@ -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 (file)
index 0000000..70c71fe
--- /dev/null
@@ -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>
index debb96b322b0ceee27b203871a0e4a7b25c79993..b72933b526d0363ef829e1571c7ad49d0ea62b83 100644 (file)
 # 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);
index 53f1dbc7c3f659e930fee72f5fd36595f7104e84..c27e7886b7891997cbd4f8797595917a0e13de30 100644 (file)
@@ -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 (file)
index 0000000..00b1b93
--- /dev/null
@@ -0,0 +1 @@
+#include <wcsmbs/bits/wchar2-decl.h>
index 3590b6f496d47710d08e0a8e37bb597853097f6f..4dbbac3800b7ef302c8c93eb1cb3855c5a1c3d83 100644 (file)
@@ -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
index 554089bfc45244e87c08eb0482e61c35dd0fa3ca..f67d4b58a448cabdf63f629f72a9df6e009286cf 100644 (file)
@@ -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
         {
index e550d157967d2c57dfa57cd555582c81286996dc..3560b518a25d1ee1bb96f19db32a7d9ecb6ba091 100644 (file)
@@ -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;
 }
index 51e793199fff83137548501949b553bc2cad2f37..e0baed170b36d6d1ca2ca6c3f758e50c131d5e97 100644 (file)
@@ -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;
index 61d1674eb49a2eb48e3534662e675ff5b1936f6a..531d2e83df4fa417ff26a3cf14144f30895927f2 100644 (file)
@@ -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
index 8178b4b470063f27dc1975c7f186c3fbdb8b9c10..d2d2524b0cbef18b912f4de412e6bb37daa789eb 100644 (file)
@@ -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;
     }
index 3942cf5fca5d4961e26657df3e9e2305e43f11df..a7697e31431fc77cb41e8b1e92a73c5d6117b229 100644 (file)
@@ -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");
 
index fdc5bdd65b24bc3c7e485eee20f8855837236e7e..bc32bb132aa0a8da9d850ac8e10259c3038ef85f 100644 (file)
@@ -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[] = {
index 5b15321f9b4a093846da0b49cd94dba8d5ef7acb..f8a92c6cff9776dc1c69be6f8f054c9e5959d29d 100644 (file)
@@ -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)
index 514e9bb617e710f16126c1474561965a2b35653d..2146bc3b27a6dc5688958ac31d561bb4202098c0 100644 (file)
@@ -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 (file)
index 7f85f7d..0000000
+++ /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 (file)
index c11038a..0000000
+++ /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 (file)
index 0000000..51296b4
--- /dev/null
@@ -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 (file)
index 0000000..6ee80b3
--- /dev/null
@@ -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 (file)
index 0000000..33652fc
--- /dev/null
@@ -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 (file)
index 0000000..9a47d8e
--- /dev/null
@@ -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;
+}
index 544cffbecd1a1e9949d7cb7805fc0a1e14fad4f3..9fa81f23c853ba9e839e82e3db7c09cde54d6321 100644 (file)
@@ -69,6 +69,7 @@
  * --Copyright--
  */
 
+#include <alloc_buffer.h>
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #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
 #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;
 }
index 07a412d8ff4da7423393325cc4627a9b2398d8bc..213edceaf3dc677bcfe56dd33d95fe8aa72a7152 100644 (file)
@@ -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 (file)
index 0000000..c4a2904
--- /dev/null
@@ -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 (file)
index 0000000..c3c0908
--- /dev/null
@@ -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 (file)
index 0000000..b06ac61
--- /dev/null
@@ -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 (file)
index 0000000..b212823
--- /dev/null
@@ -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 (file)
index 0000000..6299e89
--- /dev/null
@@ -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 (file)
index 0000000..63dac90
--- /dev/null
@@ -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 (file)
index 0000000..0572522
--- /dev/null
@@ -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);
+}
index 2dd6bfda183257a8a4c7bad4862f6d3171c1eaca..b87cf2f80996de25ea4686704ec7b28cb5eaa8ba 100644 (file)
@@ -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))
index 43ab58ffe2a32c657b1f532ef552f515c673779e..36d204c9b0c9313c0335a32f00efb895de859aaf 100644 (file)
@@ -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)
index 156eec6c85b5c62267b84ee59cc744766eb89933..2bde78387f2befe6af62b8f5d0f6ce0bee16b60e 100644 (file)
@@ -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 (file)
index 0000000..4c68985
--- /dev/null
@@ -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 (file)
index 0000000..68c96d3
--- /dev/null
@@ -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>
index e417ef624d72952ed1bf68fa9006773a6c8fdb3c..960a38f2954d84e0011793ff893deefd87443496 100644 (file)
@@ -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)
index 9b89469ac21ed70562d99a8d1436dfecaeebd577..d8f76a43b50ffd45b5e7489eaf637bafe93843b3 100644 (file)
@@ -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.  */ \
index 4a9375112add204fa6466176ee18395ba42794ac..5cbaf4b73489f60b48150cb1a96c4c8fe62a93c2 100644 (file)
@@ -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);
+               }
+           }
+       }
     }
 }
 
index 909b208578225b22dd62a6d184809a9032e17ca9..d66f0b9c4579ef2fc95f9cb083ef3b87b8c56300 100644 (file)
@@ -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]
index 050a3032de8b0ed2879474dba3536fc9ea3be90f..6b256b83880cea967ea010d804d7288dd8d0cbad 100644 (file)
@@ -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 (file)
index 0000000..4713b30
--- /dev/null
@@ -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
index c865713be1e3f8e0430bbb35c8db7ebe3e7a6abf..1d5194856601e025cb4355c94c2b49358fc81076 100644 (file)
@@ -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 */                        \
                                                                        \
index 54c457681aecef079cb64d406ca89e05d2ce4fc5..9a9c5c6f00d7ca189d3068755c6be80dd80ff327 100644 (file)
@@ -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;
     }
 
index f85ba9446663d39d5fc6eaaea5a4a1f9a213c234..0a5fe68342fc974eec7ab3f528c7611d583cb391 100644 (file)
@@ -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;
     }
 
index d85154e73ac062e6c9ed403fe3cfc3889726ff72..d8c0de1faf29fd03180d6839e44818a8959cb045 100644 (file)
@@ -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
index 5b35ea81ecd72696f53d25be5412b445d0f21545..70fce4fb276588a7f900b58483f3334052c7c7bf 100644 (file)
@@ -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'.  */
index 5af476c48b7f64fedd4cd9c29c45abe907b00f90..63b3f3d75ca16c890bc6bd29002ca562b07839ba 100644 (file)
@@ -22,6 +22,7 @@
 #include <pthread.h>
 #define __need_NULL
 #include <stddef.h>
+#include <libc-lock-arch.h>
 
 
 /* Mutex type.  */
 # 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;
index d3a6837fd212f3f5dfd80f46d0e9ce365042ae0c..425f514c5c47409c004a7044e28e27f2b235bf55 100644 (file)
    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;
 
index bcff909b2f3939d04b6ad33a78ae4f510504f96c..5cda9bb072434d078a7114a26c3967195b6815e4 100644 (file)
@@ -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;
index a139a1653207df96bb22a471031ed885a7dd633d..3ceda9fdbfeec8c09cc2abe94108a8d67953044c 100644 (file)
@@ -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
index b8088cf13f938c88b263f83efa1941e3c59a1a8a..0b851b6c8664e8d5dfcde26de9b8ef3b72bcfd1a 100644 (file)
@@ -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 (file)
index 0000000..30ee627
--- /dev/null
@@ -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  */
index 4f1f810ea1d9bf00ff428e4e7c49a52c71620775..539b8d771618b6219b36f8113ff36c3fbeb94ec7 100644 (file)
@@ -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'.  */
index 25bd6cb6386b578949c7fc9e529cdc81cbb0ef67..fb11a3fba45fa4dc4f2ea30282ed2371e1e18c80 100644 (file)
 #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  */
index 15b7a3a9258083979ac46656f0267a8668b5075a..24f72b797a44b32dc8e18a1bb0371fc6a3846ce5 100644 (file)
 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/csky/bits/struct_stat.h b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h
new file mode 100644 (file)
index 0000000..f0ee455
--- /dev/null
@@ -0,0 +1,135 @@
+/* Definition for struct stat.  Linux/csky 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/generic/bits/struct_stat.h b/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h
deleted file mode 100644 (file)
index fb11a3f..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* Definition for struct stat.
-   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
-  {
-    __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];
-  };
-
-#undef __field64
-
-#ifdef __USE_LARGEFILE64
-struct stat64
-  {
-    __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
-
-/* 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/bits/struct_stat.h b/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h
new file mode 100644 (file)
index 0000000..38b6e13
--- /dev/null
@@ -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  */
index 0cd21ef0fa8b4e140c45c7af48aca6424932521a..079612e4aad88002b14d59356a7bf1c9f059a80a 100644 (file)
@@ -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
index 87893a675749579b9886ada759ec1d5dcde99f28..2f50c31a8e92162563d67e6fa7723a47adc7c42e 100644 (file)
@@ -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 (file)
index 0000000..1844bba
--- /dev/null
@@ -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 (file)
index 0000000..fe6c3a0
--- /dev/null
@@ -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)
index e824ebb09584f7d613471a07f838093d35424560..2072205252def23d310c0ecd73364641f35dc5a2 100644 (file)
@@ -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 (file)
index 0000000..e00e711
--- /dev/null
@@ -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  */
index a263d294b1bbfd00726667ae872ed829133a78a6..cf35c8bfc9043ec99b368fa9362d585c16f59c9c 100644 (file)
@@ -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);
index bf4be80f8d380963384dd022eea710f8c86bdfdb..202520ee254ec02f47b34413d825ce189fbdafd6 100644 (file)
 #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
index d656aedcc2be60098dafe60a663e6d0879ca8962..4e65f337d486de1f50019bf6fce2003c7792d8ae 100644 (file)
 #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
index 77a8130c18b2cf76e8457791ce232db489f2ea9f..3458b018bc5b58f207df4b797e1130759745e62b 100644 (file)
@@ -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 (file)
index 0000000..0f7c9cd
--- /dev/null
@@ -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  */
index ea389354973edbe13533370eb7b766e9029fc965..f00817a6f62de8402a1c14320e326bd0dbd94b90 100644 (file)
@@ -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)
index f965986ba8771af5441ee83b618831873f504340..19841d07385244813e3773d872348d37dcc8c97d 100644 (file)
 #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 */
index 6c7b2f70117757275e947855b310c313b38b0eb6..028ad3107a5116659ec00846310322c956f6bbe6 100644 (file)
@@ -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 (executable)
index 0000000..0ec74d4
--- /dev/null
@@ -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()
index a62f803123706c9e2cd71cafcd62a5131f87b7bf..be2ef2daf10e8f07468f79ebd7febef47c1fb74b 100755 (executable)
@@ -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
index 90cbb9be642f11d028fcef38c9673a3a57a8167e..d732173abda91332f6d586280cb776c3d047ba0d 100644 (file)
@@ -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'
index 037af22290a76ac6eb75cc87d2aba5d7e214cb38..5711d1c312948ca0f1436bfb08bcc5e40cdcec09 100644 (file)
@@ -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);
index 1ade78ab73ed261fcaef776abe632c3bf755614e..5b4dd5f062283b12eab59ab173488170f9330291 100644 (file)
@@ -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)
index 3c4480aba70193a22cc07703a421a81dde82fd3c..06f6c9663e76d4a48efb8fbfdb707cc5045f47dc 100644 (file)
@@ -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.  */
index a57a9952f31ff97cd64464565e11f284dfe9956b..f2f5e8a2119e8f060da125589daa90dd2dd008b3 100644 (file)
@@ -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, ))
     {
index a71444eccb3cb7cf59775408b3b2524397aaa2ec..00a91123d36743838728fed4599466ad27e23417 100644 (file)
@@ -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,
index 68646ef199ecb71ce93af9cdc98460c2c771437a..7622af259ca5c08fb0d7c0943d67c2cd5dc85cac 100644 (file)
@@ -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, ))
     {
index fdd5afe3af16eb473e3cfb7a39eb59836af3883a..9d6c9f66ba9254d8ab8c1062698bb611bc889055 100644 (file)
@@ -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))
index 0593fb303b3068115b3fba15b1c15b01d44a3a0e..b9b58ef599c19d2b13f9ff27c8af4bfbffecb735 100644 (file)
@@ -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
 
index 4ebe4bde30994e824b2a843033a7cc03d533537b..c4f8b6bbb5ee0f6a0ed70f070efb0690a000d8e6 100644 (file)
@@ -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))
index 494c89bf546e01072d6b939649d88c58174e2648..e9a60067107f0f78eabfb27a8ef932216475f001 100644 (file)
@@ -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;
     }
index e6b9e8743a5c4475e955bcca3cee8b730e7b4883..4af102a3f6c4fb479b87894e60f7bb943bd8d9c4 100644 (file)
@@ -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 (file)
index 0000000..8e1735c
--- /dev/null
@@ -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.  */
index 0e017f458be8c3f203bb8af96de29fa519d8c8b7..3f110efe57bc295b149100090e95942b5aa009c8 100644 (file)
@@ -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,
index c37e8619a004fa04bfeb9b83b6f0f5aff09bc1fc..5f7139f2790ae878e7909aa708f0ffbd7dff9544 100644 (file)
 /* 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
index 5d6a40853d5eb176140324d3faab8f9244aa8da5..c1321c75186ad1ed8f4d148cfff27be2354310ea 100644 (file)
@@ -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  */