diff options
-rw-r--r-- | .SRCINFO | 28 | ||||
-rw-r--r-- | 0001-Revert-elf-Correct-absolute-SHN_ABS-symbol-run-time-.patch | 194 | ||||
-rw-r--r-- | PKGBUILD | 28 | ||||
-rw-r--r-- | bz20338.patch | 114 | ||||
-rw-r--r-- | file-truncated-while-reading-soname-after-patchelf.patch | 85 | ||||
-rw-r--r-- | glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch | 4059 | ||||
-rw-r--r-- | glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch | 1798 |
7 files changed, 4489 insertions, 1817 deletions
@@ -1,17 +1,15 @@ -# Generated by mksrcinfo v8 -# Sun Feb 3 02:32:08 UTC 2019 pkgbase = arm-linux-gnueabihf-glibc pkgdesc = GNU C Library (arm-linux-gnueabihf) - pkgver = 2.28 - pkgrel = 5 - url = http://www.gnu.org/software/libc/ + pkgver = 2.29 + pkgrel = 3 + url = https://www.gnu.org/software/libc/ arch = any license = GPL license = LGPL makedepends = arm-linux-gnueabihf-gcc-stage2>=8.2.1+20181127 makedepends = gperf depends = arm-linux-gnueabihf-linux-api-headers>=4.17.11-1 - provides = arm-linux-gnueabihf-glibc-headers=2.28 + provides = arm-linux-gnueabihf-glibc-headers=2.29 provides = arm-linux-gnueabihf-eglibc conflicts = arm-linux-gnueabihf-glibc-headers conflicts = arm-linux-gnueabihf-eglibc @@ -19,12 +17,20 @@ pkgbase = arm-linux-gnueabihf-glibc options = !buildflags options = !strip options = staticlibs - source = https://ftp.gnu.org/gnu/glibc/glibc-2.28.tar.xz - source = https://ftp.gnu.org/gnu/glibc/glibc-2.28.tar.xz.sig - source = glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch - md5sums = c81d2388896379997bc359d4f2084239 + source = https://ftp.gnu.org/gnu/glibc/glibc-2.29.tar.xz + source = https://ftp.gnu.org/gnu/glibc/glibc-2.29.tar.xz.sig + source = glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch + source = bz20338.patch + source = 0001-Revert-elf-Correct-absolute-SHN_ABS-symbol-run-time-.patch + source = file-truncated-while-reading-soname-after-patchelf.patch + validpgpkeys = 7273542B39962DF7B299931416792B4EA25340F8 + validpgpkeys = BC7C7372637EC10C57D7AA6579C43DFBF1CF2187 + md5sums = e6c279d5b2f0736f740216f152acf974 md5sums = SKIP - md5sums = b64d9921601d1e25cca2c802f15d6dcf + md5sums = 35a4ca5cdf86d706e054e02bb31d1616 + md5sums = dc0d3ad59aeaaf591b085a77de6e03e9 + md5sums = af5d3c5227ac639effe39667a43879a1 + md5sums = 0820504d2e83ee15f74a656771361872 pkgname = arm-linux-gnueabihf-glibc diff --git a/0001-Revert-elf-Correct-absolute-SHN_ABS-symbol-run-time-.patch b/0001-Revert-elf-Correct-absolute-SHN_ABS-symbol-run-time-.patch new file mode 100644 index 000000000000..ba9b874f3617 --- /dev/null +++ b/0001-Revert-elf-Correct-absolute-SHN_ABS-symbol-run-time-.patch @@ -0,0 +1,194 @@ +From 2cbf10ae2ea9e378ff91b8f5c4d8cb77ed05378e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bart=C5=82omiej=20Piotrowski?= <bpiotrowski@archlinux.org> +Date: Fri, 10 Aug 2018-2019 14:12:40 +0000 +Subject: [PATCH] Revert "elf: Correct absolute (SHN_ABS) symbol run-time + calculation [BZ #19818]" + +This reverts commit e7feec374c635b6a29d65c39ae5e1855528fed39. +--- + elf/Makefile | 14 ++----------- + elf/dl-addr.c | 2 -- + elf/tst-absolute-sym-lib.c | 25 ------------------------ + elf/tst-absolute-sym-lib.lds | 19 ------------------ + elf/tst-absolute-sym.c | 38 ------------------------------------ + sysdeps/generic/ldsodefs.h | 3 +-- + 6 files changed, 3 insertions(+), 98 deletions(-) + delete mode 100644 elf/tst-absolute-sym-lib.c + delete mode 100644 elf/tst-absolute-sym-lib.lds + delete mode 100644 elf/tst-absolute-sym.c + +diff --git a/elf/Makefile b/elf/Makefile +index cd0771307f..5084ba4f6f 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -186,7 +186,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \ + tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \ + tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ +- tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \ ++ tst-debug1 tst-main1 \ + tst-unwind-ctor tst-unwind-main + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ +@@ -272,8 +272,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \ + tst-latepthreadmod $(tst-tls-many-dynamic-modules) \ + tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \ +- tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \ +- tst-absolute-zero-lib tst-big-note-lib tst-unwind-ctor-lib ++ tst-main1mod tst-libc_dlvsym-dso tst-unwind-ctor-lib + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. + modules-names-tests = $(filter-out ifuncmod% tst-libc_dlvsym-dso tst-tlsmod%,\ +@@ -1465,14 +1463,6 @@ tst-main1-no-pie = yes + LDLIBS-tst-main1 = $(libsupport) + tst-main1mod.so-no-z-defs = yes + +-LDLIBS-tst-absolute-sym-lib.so = tst-absolute-sym-lib.lds +-$(objpfx)tst-absolute-sym-lib.so: $(LDLIBS-tst-absolute-sym-lib.so) +-$(objpfx)tst-absolute-sym: $(objpfx)tst-absolute-sym-lib.so +- +-LDLIBS-tst-absolute-zero-lib.so = tst-absolute-zero-lib.lds +-$(objpfx)tst-absolute-zero-lib.so: $(LDLIBS-tst-absolute-zero-lib.so) +-$(objpfx)tst-absolute-zero: $(objpfx)tst-absolute-zero-lib.so +- + # Both the main program and the DSO for tst-libc_dlvsym need to link + # against libdl. + $(objpfx)tst-libc_dlvsym: $(libdl) +diff --git a/elf/dl-addr.c b/elf/dl-addr.c +index e6c7d02094..2250617a73 100644 +--- a/elf/dl-addr.c ++++ b/elf/dl-addr.c +@@ -59,7 +59,6 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info, + we can omit that test here. */ + if ((symtab[symndx].st_shndx != SHN_UNDEF + || symtab[symndx].st_value != 0) +- && symtab[symndx].st_shndx != SHN_ABS + && ELFW(ST_TYPE) (symtab[symndx].st_info) != STT_TLS + && DL_ADDR_SYM_MATCH (match, &symtab[symndx], + matchsym, addr) +@@ -92,7 +91,6 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info, + && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS + && (symtab->st_shndx != SHN_UNDEF + || symtab->st_value != 0) +- && symtab->st_shndx != SHN_ABS + && DL_ADDR_SYM_MATCH (match, symtab, matchsym, addr) + && symtab->st_name < strtabsize) + matchsym = (ElfW(Sym) *) symtab; +diff --git a/elf/tst-absolute-sym-lib.c b/elf/tst-absolute-sym-lib.c +deleted file mode 100644 +index 912cb0048a..0000000000 +--- a/elf/tst-absolute-sym-lib.c ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* BZ #19818 absolute symbol calculation shared module. +- Copyright (C) 2018-2019 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 +- <http://www.gnu.org/licenses/>. */ +- +-extern char absolute; +- +-void * +-get_absolute (void) +-{ +- return &absolute; +-} +diff --git a/elf/tst-absolute-sym-lib.lds b/elf/tst-absolute-sym-lib.lds +deleted file mode 100644 +index d4a4128514..0000000000 +--- a/elf/tst-absolute-sym-lib.lds ++++ /dev/null +@@ -1,19 +0,0 @@ +-/* BZ #19818 absolute symbol calculation linker script. +- Copyright (C) 2018-2019 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 +- <http://www.gnu.org/licenses/>. */ +- +-"absolute" = 0x55aa; +diff --git a/elf/tst-absolute-sym.c b/elf/tst-absolute-sym.c +deleted file mode 100644 +index 111491d159..0000000000 +--- a/elf/tst-absolute-sym.c ++++ /dev/null +@@ -1,38 +0,0 @@ +-/* BZ #19818 absolute symbol calculation main executable. +- Copyright (C) 2018-2019 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 +- <http://www.gnu.org/licenses/>. */ +- +-#include <support/check.h> +-#include <support/support.h> +-#include <support/test-driver.h> +- +-void *get_absolute (void); +- +-static int +-do_test (void) +-{ +- void *ref = (void *) 0x55aa; +- void *ptr; +- +- ptr = get_absolute (); +- if (ptr != ref) +- FAIL_EXIT1 ("Got %p, expected %p\n", ptr, ref); +- +- return 0; +-} +- +-#include <support/test-driver.c> +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 95dc87519b..3cac4fa362 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -72,8 +72,7 @@ typedef struct link_map *lookup_t; + if non-NULL. Don't check for NULL map if MAP_SET is TRUE. */ + #define SYMBOL_ADDRESS(map, ref, map_set) \ + ((ref) == NULL ? 0 \ +- : (__glibc_unlikely ((ref)->st_shndx == SHN_ABS) ? 0 \ +- : LOOKUP_VALUE_ADDRESS (map, map_set)) + (ref)->st_value) ++ : LOOKUP_VALUE_ADDRESS (map, map_set) + (ref)->st_value) + + /* On some architectures a pointer to a function is not just a pointer + to the actual code of the function but rather an architecture +-- +2.18.0 + @@ -7,11 +7,11 @@ _target="arm-linux-gnueabihf" pkgname=${_target}-glibc -pkgver=2.28 -pkgrel=5 +pkgver=2.29 +pkgrel=3 pkgdesc="GNU C Library (${_target})" arch=('any') -url="http://www.gnu.org/software/libc/" +url="https://www.gnu.org/software/libc/" license=(GPL LGPL) depends=("${_target}-linux-api-headers>=4.17.11-1") makedepends=("${_target}-gcc-stage2>=8.2.1+20181127" gperf) @@ -19,14 +19,21 @@ provides=("${_target}-glibc-headers=${pkgver}" "${_target}-eglibc") conflicts=("${_target}-glibc-headers" "${_target}-eglibc") replaces=("${_target}-glibc-headers") options=(!buildflags !strip staticlibs) -_commit=5a74abda201907cafbdabd1debf98890313ff71e +_commit=34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4 #source=(git+https://sourceware.org/git/glibc.git#commit=$_commit source=(https://ftp.gnu.org/gnu/glibc/glibc-$pkgver.tar.xz{,.sig} - glibc-${_commit}.patch) -validpgpkeys=(7273542B39962DF7B299931416792B4EA25340F8) # Carlos O'Donell -md5sums=('c81d2388896379997bc359d4f2084239' + glibc-${_commit}.patch + bz20338.patch + 0001-Revert-elf-Correct-absolute-SHN_ABS-symbol-run-time-.patch + file-truncated-while-reading-soname-after-patchelf.patch) +validpgpkeys=(7273542B39962DF7B299931416792B4EA25340F8 # Carlos O'Donell + BC7C7372637EC10C57D7AA6579C43DFBF1CF2187) # Siddhesh Poyarekar +md5sums=('e6c279d5b2f0736f740216f152acf974' 'SKIP' - 'b64d9921601d1e25cca2c802f15d6dcf') + '35a4ca5cdf86d706e054e02bb31d1616' + 'dc0d3ad59aeaaf591b085a77de6e03e9' + 'af5d3c5227ac639effe39667a43879a1' + '0820504d2e83ee15f74a656771361872') prepare() { mkdir -p glibc-build @@ -68,6 +75,11 @@ build() { # remove fortify for building libraries CPPFLAGS=${CPPFLAGS/-D_FORTIFY_SOURCE=2/} + # + CFLAGS=${CFLAGS/-fno-plt/} + CXXFLAGS=${CXXFLAGS/-fno-plt/} + LDFLAGS=${LDFLAGS/,-z,now/} + export BUILD_CC=gcc export CC=${_target}-gcc export CXX=${_target}-g++ diff --git a/bz20338.patch b/bz20338.patch new file mode 100644 index 000000000000..d223e9f08882 --- /dev/null +++ b/bz20338.patch @@ -0,0 +1,114 @@ +From 74250a7cdf106d4ca7d9506e6d5dc7c448dc3434 Mon Sep 17 00:00:00 2001 +From: David Michael <david.michael@coreos.com> +Date: Thu, 15 Dec 2016 15:22:57 -0800 +Subject: [PATCH] gshadow: Sync fgetsgent_r.c with grp/fgetgrent_r.c + + [BZ #20338] + * gshadow/fgetsgent_r.c: Include <libio/iolibio.h>. + (flockfile): New macro. + (funlockfile): Likewise. + (__fgetsgent_r): Sync with __fgetgrent_r. + * nss/nss_files/files-sgrp.c: Fix "fgetsgent_r.c" typo. +--- + gshadow/fgetsgent_r.c | 35 ++++++++++++++++++++++++----------- + nss/nss_files/files-sgrp.c | 2 +- + 2 files changed, 25 insertions(+), 12 deletions(-) + +diff --git a/gshadow/fgetsgent_r.c b/gshadow/fgetsgent_r.c +index b70f6fa..02cd33a 100644 +--- a/gshadow/fgetsgent_r.c ++++ b/gshadow/fgetsgent_r.c +@@ -20,39 +20,44 @@ + #include <gshadow.h> + #include <stdio.h> + ++#include <libio/iolibio.h> ++#define flockfile(s) _IO_flockfile (s) ++#define funlockfile(s) _IO_funlockfile (s) ++ + /* Define a line parsing function using the common code + used in the nss_files module. */ + + #define STRUCTURE sgrp + #define ENTNAME sgent +-#define EXTERN_PARSER 1 ++#define EXTERN_PARSER 1 + struct sgent_data {}; + + #include <nss/nss_files/files-parse.c> + + +-/* Read one shadow entry from the given stream. */ ++/* Read one entry from the given stream. */ + int + __fgetsgent_r (FILE *stream, struct sgrp *resbuf, char *buffer, size_t buflen, + struct sgrp **result) + { + char *p; ++ int parse_result; + +- _IO_flockfile (stream); ++ flockfile (stream); + do + { + buffer[buflen - 1] = '\xff'; + p = fgets_unlocked (buffer, buflen, stream); +- if (p == NULL && feof_unlocked (stream)) ++ if (__builtin_expect (p == NULL, 0) && feof_unlocked (stream)) + { +- _IO_funlockfile (stream); ++ funlockfile (stream); + *result = NULL; + __set_errno (ENOENT); + return errno; + } +- if (p == NULL || buffer[buflen - 1] != '\xff') ++ if (__builtin_expect (p == NULL, 0) || buffer[buflen - 1] != '\xff') + { +- _IO_funlockfile (stream); ++ funlockfile (stream); + *result = NULL; + __set_errno (ERANGE); + return errno; +@@ -61,13 +66,21 @@ __fgetsgent_r (FILE *stream, struct sgrp *resbuf, char *buffer, size_t buflen, + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; +- } while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ ++ } while (*p == '\0' || *p == '#' /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ +- ! parse_line (buffer, (void *) resbuf, (void *) buffer, buflen, +- &errno)); ++ || ! (parse_result = parse_line (p, resbuf, ++ (void *) buffer, buflen, ++ &errno))); ++ ++ funlockfile (stream); + +- _IO_funlockfile (stream); ++ if (__builtin_expect (parse_result, 0) == -1) ++ { ++ /* The parser ran out of space. */ ++ *result = NULL; ++ return errno; ++ } + + *result = resbuf; + return 0; +diff --git a/nss/nss_files/files-sgrp.c b/nss/nss_files/files-sgrp.c +index 15dc659..05c3805 100644 +--- a/nss/nss_files/files-sgrp.c ++++ b/nss/nss_files/files-sgrp.c +@@ -23,7 +23,7 @@ + #define DATABASE "gshadow" + struct sgent_data {}; + +-/* Our parser function is already defined in sgetspent_r.c, so use that ++/* Our parser function is already defined in sgetsgent_r.c, so use that + to parse lines from the database file. */ + #define EXTERN_PARSER + #include "files-parse.c" +-- +2.7.4 + diff --git a/file-truncated-while-reading-soname-after-patchelf.patch b/file-truncated-while-reading-soname-after-patchelf.patch new file mode 100644 index 000000000000..4c21284bf0b0 --- /dev/null +++ b/file-truncated-while-reading-soname-after-patchelf.patch @@ -0,0 +1,85 @@ +[PATCH] ldconfig: file truncated while reading soname after patchelf [BZ #23964] + +The way loadaddr is computed from the first LOAD segment in process_elf_file +assumes .dynstr is also contained in that segment. That is not necessarily +true, especially for libraries that have been touched by patchelf. + +With this patch, the address read from the dynamic segment is checked against +all applicable segments instead of only the first one. + + [BZ #23964] + * elf/readelflib.c: Fix resolving of loadaddr for .dynstr vaddr. +--- + elf/readelflib.c | 33 ++++++++++++++++----------------- + 1 file changed, 16 insertions(+), 17 deletions(-) + +diff --git a/elf/readelflib.c b/elf/readelflib.c +index 5a1e2dc2df..bc1195c175 100644 +--- a/elf/readelflib.c ++++ b/elf/readelflib.c +@@ -98,11 +98,6 @@ process_elf_file (const char *file_name, const char *lib, int *flag, + + switch (segment->p_type) + { +- case PT_LOAD: +- if (loadaddr == (ElfW(Addr)) -1) +- loadaddr = segment->p_vaddr - segment->p_offset; +- break; +- + case PT_DYNAMIC: + if (dynamic_addr) + error (0, 0, _("more than one dynamic segment\n")); +@@ -176,11 +171,6 @@ process_elf_file (const char *file_name, const char *lib, int *flag, + } + + } +- if (loadaddr == (ElfW(Addr)) -1) +- { +- /* Very strange. */ +- loadaddr = 0; +- } + + /* Now we can read the dynamic sections. */ + if (dynamic_size == 0) +@@ -190,22 +180,31 @@ process_elf_file (const char *file_name, const char *lib, int *flag, + check_ptr (dynamic_segment); + + /* Find the string table. */ +- dynamic_strings = NULL; + for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL; + ++dyn_entry) + { + check_ptr (dyn_entry); + if (dyn_entry->d_tag == DT_STRTAB) +- { +- dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr); +- check_ptr (dynamic_strings); +- break; +- } ++ break; + } + +- if (dynamic_strings == NULL) ++ for (i = 0, segment = elf_pheader;i < elf_header->e_phnum; i++, segment++) ++ { ++ ElfW(Addr) vaddr = dyn_entry->d_un.d_ptr; ++ if (segment->p_type == PT_LOAD && ++ vaddr >= segment->p_vaddr && ++ vaddr < segment->p_vaddr + segment->p_filesz) ++ { ++ loadaddr = segment->p_vaddr - segment->p_offset; ++ break; ++ } ++ } ++ if (loadaddr == (ElfW(Addr)) -1) + return 1; + ++ dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr); ++ check_ptr (dynamic_strings); ++ + /* Now read the DT_NEEDED and DT_SONAME entries. */ + for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL; + ++dyn_entry) +-- +2.19.2 + diff --git a/glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch b/glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch new file mode 100644 index 000000000000..fa7f94c4a793 --- /dev/null +++ b/glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch @@ -0,0 +1,4059 @@ +diff --git a/ChangeLog b/ChangeLog +index 59dab18463..20b650e026 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,219 @@ ++2019-06-20 Dmitry V. Levin <ldv@altlinux.org> ++ Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #24228] ++ * libio/genops.c (_IO_unbuffer_all) ++ [SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)]: Do not attempt to free wide ++ buffers and access _IO_FILE_complete members of legacy libio streams. ++ * libio/tst-bz24228.c: New file. ++ * libio/tst-bz24228.map: Likewise. ++ * libio/Makefile [build-shared] (tests): Add tst-bz24228. ++ [build-shared] (generated): Add tst-bz24228.mtrace and ++ tst-bz24228.check. ++ [run-built-tests && build-shared] (tests-special): Add ++ $(objpfx)tst-bz24228-mem.out. ++ (LDFLAGS-tst-bz24228, tst-bz24228-ENV): New variables. ++ ($(objpfx)tst-bz24228-mem.out): New rule. ++ ++2019-03-13 Zack Weinberg <zackw@panix.com> ++ ++ * scripts/check-obsolete-constructs.py: New test script. ++ * scripts/check-installed-headers.sh: Remove tests for ++ obsolete typedefs, superseded by check-obsolete-constructs.py. ++ * Rules: Run scripts/check-obsolete-constructs.py over $(headers) ++ as a special test. Update commentary. ++ * posix/bits/types.h (__SQUAD_TYPE, __S64_TYPE): Define as __int64_t. ++ (__UQUAD_TYPE, __U64_TYPE): Define as __uint64_t. ++ Update commentary. ++ * posix/sys/types.h (__u_intN_t): Remove. ++ (u_int8_t): Typedef using __uint8_t. ++ (u_int16_t): Typedef using __uint16_t. ++ (u_int32_t): Typedef using __uint32_t. ++ (u_int64_t): Typedef using __uint64_t. ++ ++2019-04-18 Adhemerval Zanella <adhemerval.zanella@linaro.org> ++ ++ * malloc/tst-memalign.c (do_test): Disable ++ -Walloc-size-larger-than= around tests of malloc with negative ++ sizes. ++ * malloc/tst-malloc-too-large.c (do_test): Likewise. ++ ++2019-05-22 Wilco Dijkstra <wdijkstr@arm.com> ++ ++ [BZ #24531] ++ * malloc/malloc.c (MAX_TCACHE_COUNT): New define. ++ (do_set_tcache_count): Only update if count is small enough. ++ * manual/tunables.texi (glibc.malloc.tcache_count): Document max value. ++ ++2019-05-15 Mark Wielaard <mark@klomp.org> ++ ++ [BZ#24476] ++ * dlfcn/dlerror.c (__dlerror_main_freeres): Guard using ++ __libc_once_get (once) and static_buf == NULL. ++ (__dlerror): Check we have a valid key, set result to static_buf ++ otherwise. ++ ++2019-05-15 Andreas Schwab <schwab@suse.de> ++ ++ [BZ #20568] ++ * libio/wfileops.c (_IO_wfile_sync): Correct last argument to ++ __codecvt_do_length. ++ * libio/Makefile (tests): Add tst-wfile-sync. ++ ($(objpfx)tst-wfile-sync.out): Depend on $(gen-locales). ++ * libio/tst-wfile-sync.c: New file. ++ * libio/tst-wfile-sync.input: New file. ++ ++2019-04-23 Adhemerval Zanella <adhemerval.zanella@linaro.org> ++ ++ [BZ #18035] ++ * elf/Makefile (tests-container): Add tst-pldd. ++ * elf/pldd-xx.c: Use _Static_assert in of pldd_assert. ++ (E(find_maps)): Avoid use alloca, use default read file operations ++ instead of explicit LFS names, and fix infinite loop. ++ * elf/pldd.c: Explicit set _FILE_OFFSET_BITS, cleanup headers. ++ (get_process_info): Use _Static_assert instead of assert, use default ++ directory operations instead of explicit LFS names, and free some ++ leadek pointers. ++ * elf/tst-pldd.c: New file. ++ ++2019-04-17 Adhemerval Zanella <adhemerval.zanella@linaro.org> ++ ++ * support/Makefile (libsupport-routines): Add support_subprocess, ++ xposix_spawn, xposix_spawn_file_actions_addclose, and ++ xposix_spawn_file_actions_adddup2. ++ (tst-support_capture_subprocess-ARGS): New rule. ++ * support/capture_subprocess.h (support_capture_subprogram): New ++ prototype. ++ * support/support_capture_subprocess.c (support_capture_subprocess): ++ Refactor to use support_subprocess and support_capture_poll. ++ (support_capture_subprogram): New function. ++ * support/tst-support_capture_subprocess.c (write_mode_to_str, ++ str_to_write_mode, test_common, parse_int, handle_restart, ++ do_subprocess, do_subprogram, do_multiple_tests): New functions. ++ (do_test): Add support_capture_subprogram tests. ++ * support/subprocess.h: New file. ++ * support/support_subprocess.c: Likewise. ++ * support/xposix_spawn.c: Likewise. ++ * support/xposix_spawn_file_actions_addclose.c: Likewise. ++ * support/xposix_spawn_file_actions_adddup2.c: Likewise. ++ * support/xspawn.h: Likewise. ++ ++2019-04-09 Carlos O'Donell <carlos@redhat.com> ++ Kwok Cheung Yeung <kcy@codesourcery.com> ++ ++ [BZ #16573] ++ * malloc/mtrace.c: Define prototypes for all hooks. ++ (set_default_hooks): New function. ++ (set_trace_hooks): Likewise. ++ (save_default_hooks): Likewise. ++ (tr_freehook): Use new s*_hooks functions. ++ (tr_mallochook): Likewise. ++ (tr_reallochook): Likewise. ++ (tr_memalignhook): Likewise. ++ (mtrace): Likewise. ++ (muntrace): Likewise. ++ ++2019-04-02 TAMUKI Shoichi <tamuki@linet.gr.jp> ++ ++ [BZ #22964] ++ * localedata/locales/ja_JP (LC_TIME): Add entry for the new Japanese ++ era. ++ ++2019-03-02 TAMUKI Shoichi <tamuki@linet.gr.jp> ++ ++ [BZ #24162] ++ * localedata/locales/ja_JP (LC_TIME): Change the offset for Taisho ++ gan-nen from 2 to 1. Problem reported by Morimitsu, Junji. ++ ++2019-03-21 Stefan Liebler <stli@linux.ibm.com> ++ ++ * sysdeps/s390/dl-procinfo.h (HWCAP_IMPORTANT): ++ Add HWCAP_S390_VX and HWCAP_S390_VXE. ++ ++2019-01-31 Paul Eggert <eggert@cs.ucla.edu> ++ ++ CVE-2019-9169 ++ regex: fix read overrun [BZ #24114] ++ Problem found by AddressSanitizer, reported by Hongxu Chen in: ++ https://debbugs.gnu.org/34140 ++ * posix/regexec.c (proceed_next_node): ++ Do not read past end of input buffer. ++ ++2019-03-13 Stefan Liebler <stli@linux.ibm.com> ++ ++ * elf/dl-sysdep.c (_dl_show_auxv): Remove condition and always ++ call _dl_procinfo. ++ * sysdeps/unix/sysv/linux/s390/dl-procinfo.h (_dl_procinfo): ++ Ignore types other than AT_HWCAP. ++ * sysdeps/sparc/dl-procinfo.h (_dl_procinfo): Likewise. ++ * sysdeps/unix/sysv/linux/i386/dl-procinfo.h (_dl_procinfo): ++ Likewise. ++ * sysdeps/powerpc/dl-procinfo.h (_dl_procinfo): Adjust comment ++ in the case of falling back to generic output mechanism. ++ * sysdeps/unix/sysv/linux/arm/dl-procinfo.h (_dl_procinfo): ++ Likewise. ++ ++2019-02-15 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #24211] ++ * nptl/pthread_join_common.c (__pthread_timedjoin_ex): Do not read ++ pd->result after the thread descriptor has been freed. ++ ++2019-02-08 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #24161] ++ * sysdeps/nptl/fork.h (__run_fork_handlers): Add multiple_threads ++ argument. ++ * nptl/register-atfork.c (__run_fork_handlers): Only perform ++ locking if the new do_locking argument is true. ++ * sysdeps/nptl/fork.c (__libc_fork): Pass multiple_threads to ++ __run_fork_handlers. ++ ++2019-02-07 Stefan Liebler <stli@linux.ibm.com> ++ ++ [BZ #24180] ++ * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock): ++ Add compiler barriers and comments. ++ ++2019-02-05 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #24164] ++ arm: Use "nr" constraint for Systemtap probes, to avoid the ++ compiler using memory operands for constants, due to the "o" ++ alternative in the default "nor" constraint. ++ * include/stap-probe.h [USE_STAP_PROBE]: Include ++ <stap-probe-machine.h> ++ * sysdeps/generic/stap-probe-machine.h: New file. ++ * sysdeps/arm/stap-probe-machine.h: Likewise. ++ ++2019-02-04 H.J. Lu <hongjiu.lu@intel.com> ++ ++ [BZ #24155] ++ CVE-2019-7309 ++ * NEWS: Updated for CVE-2019-7309. ++ * sysdeps/x86_64/memcmp.S: Use RDX_LP for size. Clear the ++ upper 32 bits of RDX register for x32. Use unsigned Jcc ++ instructions, instead of signed. ++ * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp-2. ++ * sysdeps/x86_64/x32/tst-size_t-memcmp-2.c: New test. ++ ++2019-01-31 Carlos O'Donell <carlos@redhat.com> ++ Torvald Riegel <triegel@redhat.com> ++ Rik Prohaska <prohaska7@gmail.com> ++ ++ [BZ# 23844] ++ * nptl/Makefile (tests): Add tst-rwlock-tryrdlock-stall, and ++ tst-rwlock-trywrlock-stall. ++ * nptl/pthread_rwlock_tryrdlock.c (__pthread_rwlock_tryrdlock): ++ Wake waiters if PTHREAD_RWLOCK_FUTEX_USED is set. ++ * nptl/pthread_rwlock_trywrlock.c (__pthread_rwlock_trywrlock): ++ Set __wrphase_fute to 1 only if we started the write phase. ++ * nptl/tst-rwlock-tryrdlock-stall.c: New file. ++ * nptl/tst-rwlock-trywrlock-stall.c: New file. ++ * support/Makefile (libsupport-routines): Add xpthread_rwlock_destroy. ++ * support/xpthread_rwlock_destroy.c: New file. ++ * support/xthread.h: Declare xpthread_rwlock_destroy. ++ + 2019-01-31 Siddhesh Poyarekar <siddhesh@sourceware.org> + + * version.h (RELEASE): Set to "stable". +diff --git a/NEWS b/NEWS +index 912a9bdc0f..68d88b1036 100644 +--- a/NEWS ++++ b/NEWS +@@ -4,6 +4,39 @@ See the end for copying conditions. + + Please send GNU C library bug reports via <https://sourceware.org/bugzilla/> + using `glibc' in the "product" field. ++ ++Version 2.29.1 ++ ++Major new features: ++ ++* The entry for the new Japanese era has been added for ja_JP locale. ++ ++The following bugs are resolved with this release: ++ ++ [16573] malloc: Set and reset all hooks for tracing ++ [18035] Fix pldd hang ++ [20568] Fix crash in _IO_wfile_sync ++ [24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309) ++ [24164] Systemtap probes need to use "nr" constraint on 32-bit Arm ++ [24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2 ++ [24211] Use-after-free in Systemtap probe in pthread_join ++ [24228] old x86 applications that use legacy libio crash on exit ++ [24476] dlfcn: Guard __dlerror_main_freeres with __libc_once_get (once) ++ ++Security related changes: ++ ++ CVE-2019-7309: x86-64 memcmp used signed Jcc instructions to check ++ size. For x86-64, memcmp on an object size larger than SSIZE_MAX ++ has undefined behavior. On x32, the size_t argument may be passed ++ in the lower 32 bits of the 64-bit RDX register with non-zero upper ++ 32 bits. When it happened with the sign bit of RDX register set, ++ memcmp gave the wrong result since it treated the size argument as ++ zero. Reported by H.J. Lu. ++ ++ CVE-2019-9169: Attempted case-insensitive regular-expression match ++ via proceed_next_node in posix/regexec.c leads to heap-based buffer ++ over-read. Reported by Hongxu Chen. ++ + + Version 2.29 + +diff --git a/Rules b/Rules +index 1562f2ce6d..16afa6acaa 100644 +--- a/Rules ++++ b/Rules +@@ -82,7 +82,8 @@ $(common-objpfx)dummy.c: + common-generated += dummy.o dummy.c + + ifneq "$(headers)" "" +-# Special test of all the installed headers in this directory. ++# Test that all of the headers installed by this directory can be compiled ++# in isolation. + tests-special += $(objpfx)check-installed-headers-c.out + libof-check-installed-headers-c := testsuite + $(objpfx)check-installed-headers-c.out: \ +@@ -93,6 +94,8 @@ $(objpfx)check-installed-headers-c.out: \ + $(evaluate-test) + + ifneq "$(CXX)" "" ++# If a C++ compiler is available, also test that they can be compiled ++# in isolation as C++. + tests-special += $(objpfx)check-installed-headers-cxx.out + libof-check-installed-headers-cxx := testsuite + $(objpfx)check-installed-headers-cxx.out: \ +diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c +index 27376582d0..ca42c126c1 100644 +--- a/dlfcn/dlerror.c ++++ b/dlfcn/dlerror.c +@@ -72,9 +72,16 @@ __dlerror (void) + __libc_once (once, init); + + /* Get error string. */ +- result = (struct dl_action_result *) __libc_getspecific (key); +- if (result == NULL) +- result = &last_result; ++ if (static_buf != NULL) ++ result = static_buf; ++ else ++ { ++ /* init () has been run and we don't use the static buffer. ++ So we have a valid key. */ ++ result = (struct dl_action_result *) __libc_getspecific (key); ++ if (result == NULL) ++ result = &last_result; ++ } + + /* Test whether we already returned the string. */ + if (result->returned != 0) +@@ -230,13 +237,19 @@ free_key_mem (void *mem) + void + __dlerror_main_freeres (void) + { +- void *mem; + /* Free the global memory if used. */ + check_free (&last_result); +- /* Free the TSD memory if used. */ +- mem = __libc_getspecific (key); +- if (mem != NULL) +- free_key_mem (mem); ++ ++ if (__libc_once_get (once) && static_buf == NULL) ++ { ++ /* init () has been run and we don't use the static buffer. ++ So we have a valid key. */ ++ void *mem; ++ /* Free the TSD memory if used. */ ++ mem = __libc_getspecific (key); ++ if (mem != NULL) ++ free_key_mem (mem); ++ } + } + + struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon)); +diff --git a/elf/Makefile b/elf/Makefile +index 9cf5cd8dfd..e7457e809f 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -194,6 +194,7 @@ tests-internal += loadtest unload unload2 circleload1 \ + tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \ + tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \ + tst-create_format1 ++tests-container += tst-pldd + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout + tst-dlopen-aout-no-pie = yes +diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c +index 5f6c679a3f..5d19b100b2 100644 +--- a/elf/dl-sysdep.c ++++ b/elf/dl-sysdep.c +@@ -328,14 +328,9 @@ _dl_show_auxv (void) + assert (AT_NULL == 0); + assert (AT_IGNORE == 1); + +- if (av->a_type == AT_HWCAP || av->a_type == AT_HWCAP2 +- || AT_L1I_CACHEGEOMETRY || AT_L1D_CACHEGEOMETRY +- || AT_L2_CACHEGEOMETRY || AT_L3_CACHEGEOMETRY) +- { +- /* These are handled in a special way per platform. */ +- if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0) +- continue; +- } ++ /* Some entries are handled in a special way per platform. */ ++ if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0) ++ continue; + + if (idx < sizeof (auxvars) / sizeof (auxvars[0]) + && auxvars[idx].form != unknown) +diff --git a/elf/pldd-xx.c b/elf/pldd-xx.c +index 547f840ee1..756f6d7a1c 100644 +--- a/elf/pldd-xx.c ++++ b/elf/pldd-xx.c +@@ -23,10 +23,6 @@ + #define EW_(e, w, t) EW__(e, w, _##t) + #define EW__(e, w, t) e##w##t + +-#define pldd_assert(name, exp) \ +- typedef int __assert_##name[((exp) != 0) - 1] +- +- + struct E(link_map) + { + EW(Addr) l_addr; +@@ -39,12 +35,12 @@ struct E(link_map) + EW(Addr) l_libname; + }; + #if CLASS == __ELF_NATIVE_CLASS +-pldd_assert (l_addr, (offsetof (struct link_map, l_addr) +- == offsetof (struct E(link_map), l_addr))); +-pldd_assert (l_name, (offsetof (struct link_map, l_name) +- == offsetof (struct E(link_map), l_name))); +-pldd_assert (l_next, (offsetof (struct link_map, l_next) +- == offsetof (struct E(link_map), l_next))); ++_Static_assert (offsetof (struct link_map, l_addr) ++ == offsetof (struct E(link_map), l_addr), "l_addr"); ++_Static_assert (offsetof (struct link_map, l_name) ++ == offsetof (struct E(link_map), l_name), "l_name"); ++_Static_assert (offsetof (struct link_map, l_next) ++ == offsetof (struct E(link_map), l_next), "l_next"); + #endif + + +@@ -54,10 +50,10 @@ struct E(libname_list) + EW(Addr) next; + }; + #if CLASS == __ELF_NATIVE_CLASS +-pldd_assert (name, (offsetof (struct libname_list, name) +- == offsetof (struct E(libname_list), name))); +-pldd_assert (next, (offsetof (struct libname_list, next) +- == offsetof (struct E(libname_list), next))); ++_Static_assert (offsetof (struct libname_list, name) ++ == offsetof (struct E(libname_list), name), "name"); ++_Static_assert (offsetof (struct libname_list, next) ++ == offsetof (struct E(libname_list), next), "next"); + #endif + + struct E(r_debug) +@@ -69,16 +65,17 @@ struct E(r_debug) + EW(Addr) r_map; + }; + #if CLASS == __ELF_NATIVE_CLASS +-pldd_assert (r_version, (offsetof (struct r_debug, r_version) +- == offsetof (struct E(r_debug), r_version))); +-pldd_assert (r_map, (offsetof (struct r_debug, r_map) +- == offsetof (struct E(r_debug), r_map))); ++_Static_assert (offsetof (struct r_debug, r_version) ++ == offsetof (struct E(r_debug), r_version), "r_version"); ++_Static_assert (offsetof (struct r_debug, r_map) ++ == offsetof (struct E(r_debug), r_map), "r_map"); + #endif + + + static int + +-E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) ++E(find_maps) (const char *exe, int memfd, pid_t pid, void *auxv, ++ size_t auxv_size) + { + EW(Addr) phdr = 0; + unsigned int phnum = 0; +@@ -104,12 +101,9 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) + if (phdr == 0 || phnum == 0 || phent == 0) + error (EXIT_FAILURE, 0, gettext ("cannot find program header of process")); + +- EW(Phdr) *p = alloca (phnum * phent); +- if (pread64 (memfd, p, phnum * phent, phdr) != phnum * phent) +- { +- error (0, 0, gettext ("cannot read program header")); +- return EXIT_FAILURE; +- } ++ EW(Phdr) *p = xmalloc (phnum * phent); ++ if (pread (memfd, p, phnum * phent, phdr) != phnum * phent) ++ error (EXIT_FAILURE, 0, gettext ("cannot read program header")); + + /* Determine the load offset. We need this for interpreting the + other program header entries so we do this in a separate loop. +@@ -129,24 +123,18 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) + if (p[i].p_type == PT_DYNAMIC) + { + EW(Dyn) *dyn = xmalloc (p[i].p_filesz); +- if (pread64 (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr) ++ if (pread (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr) + != p[i].p_filesz) +- { +- error (0, 0, gettext ("cannot read dynamic section")); +- return EXIT_FAILURE; +- } ++ error (EXIT_FAILURE, 0, gettext ("cannot read dynamic section")); + + /* Search for the DT_DEBUG entry. */ + for (unsigned int j = 0; j < p[i].p_filesz / sizeof (EW(Dyn)); ++j) + if (dyn[j].d_tag == DT_DEBUG && dyn[j].d_un.d_ptr != 0) + { + struct E(r_debug) r; +- if (pread64 (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr) ++ if (pread (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr) + != sizeof (r)) +- { +- error (0, 0, gettext ("cannot read r_debug")); +- return EXIT_FAILURE; +- } ++ error (EXIT_FAILURE, 0, gettext ("cannot read r_debug")); + + if (r.r_map != 0) + { +@@ -160,13 +148,10 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) + } + else if (p[i].p_type == PT_INTERP) + { +- interp = alloca (p[i].p_filesz); +- if (pread64 (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr) ++ interp = xmalloc (p[i].p_filesz); ++ if (pread (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr) + != p[i].p_filesz) +- { +- error (0, 0, gettext ("cannot read program interpreter")); +- return EXIT_FAILURE; +- } ++ error (EXIT_FAILURE, 0, gettext ("cannot read program interpreter")); + } + + if (list == 0) +@@ -174,14 +159,16 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) + if (interp == NULL) + { + // XXX check whether the executable itself is the loader +- return EXIT_FAILURE; ++ exit (EXIT_FAILURE); + } + + // XXX perhaps try finding ld.so and _r_debug in it +- +- return EXIT_FAILURE; ++ exit (EXIT_FAILURE); + } + ++ free (p); ++ free (interp); ++ + /* Print the PID and program name first. */ + printf ("%lu:\t%s\n", (unsigned long int) pid, exe); + +@@ -192,47 +179,27 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) + do + { + struct E(link_map) m; +- if (pread64 (memfd, &m, sizeof (m), list) != sizeof (m)) +- { +- error (0, 0, gettext ("cannot read link map")); +- status = EXIT_FAILURE; +- goto out; +- } ++ if (pread (memfd, &m, sizeof (m), list) != sizeof (m)) ++ error (EXIT_FAILURE, 0, gettext ("cannot read link map")); + + EW(Addr) name_offset = m.l_name; +- again: + while (1) + { +- ssize_t n = pread64 (memfd, tmpbuf.data, tmpbuf.length, name_offset); ++ ssize_t n = pread (memfd, tmpbuf.data, tmpbuf.length, name_offset); + if (n == -1) +- { +- error (0, 0, gettext ("cannot read object name")); +- status = EXIT_FAILURE; +- goto out; +- } ++ error (EXIT_FAILURE, 0, gettext ("cannot read object name")); + + if (memchr (tmpbuf.data, '\0', n) != NULL) + break; + + if (!scratch_buffer_grow (&tmpbuf)) +- { +- error (0, 0, gettext ("cannot allocate buffer for object name")); +- status = EXIT_FAILURE; +- goto out; +- } ++ error (EXIT_FAILURE, 0, ++ gettext ("cannot allocate buffer for object name")); + } + +- if (((char *)tmpbuf.data)[0] == '\0' && name_offset == m.l_name +- && m.l_libname != 0) +- { +- /* Try the l_libname element. */ +- struct E(libname_list) ln; +- if (pread64 (memfd, &ln, sizeof (ln), m.l_libname) == sizeof (ln)) +- { +- name_offset = ln.name; +- goto again; +- } +- } ++ /* The m.l_name and m.l_libname.name for loader linkmap points to same ++ values (since BZ#387 fix). Trying to use l_libname name as the ++ shared object name might lead to an infinite loop (BZ#18035). */ + + /* Skip over the executable. */ + if (((char *)tmpbuf.data)[0] != '\0') +@@ -242,7 +209,6 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) + } + while (list != 0); + +- out: + scratch_buffer_free (&tmpbuf); + return status; + } +diff --git a/elf/pldd.c b/elf/pldd.c +index f3fac4e487..69629bd5d2 100644 +--- a/elf/pldd.c ++++ b/elf/pldd.c +@@ -17,23 +17,17 @@ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +-#include <alloca.h> ++#define _FILE_OFFSET_BITS 64 ++ + #include <argp.h> +-#include <assert.h> + #include <dirent.h> +-#include <elf.h> +-#include <errno.h> + #include <error.h> + #include <fcntl.h> + #include <libintl.h> +-#include <link.h> +-#include <stddef.h> + #include <stdio.h> + #include <stdlib.h> +-#include <string.h> + #include <unistd.h> + #include <sys/ptrace.h> +-#include <sys/stat.h> + #include <sys/wait.h> + #include <scratch_buffer.h> + +@@ -76,14 +70,9 @@ static struct argp argp = + options, parse_opt, args_doc, doc, NULL, more_help, NULL + }; + +-// File descriptor of /proc/*/mem file. +-static int memfd; +- +-/* Name of the executable */ +-static char *exe; + + /* Local functions. */ +-static int get_process_info (int dfd, long int pid); ++static int get_process_info (const char *exe, int dfd, long int pid); + static void wait_for_ptrace_stop (long int pid); + + +@@ -102,8 +91,10 @@ main (int argc, char *argv[]) + return 1; + } + +- assert (sizeof (pid_t) == sizeof (int) +- || sizeof (pid_t) == sizeof (long int)); ++ _Static_assert (sizeof (pid_t) == sizeof (int) ++ || sizeof (pid_t) == sizeof (long int), ++ "sizeof (pid_t) != sizeof (int) or sizeof (long int)"); ++ + char *endp; + errno = 0; + long int pid = strtol (argv[remaining], &endp, 10); +@@ -119,25 +110,24 @@ main (int argc, char *argv[]) + if (dfd == -1) + error (EXIT_FAILURE, errno, gettext ("cannot open %s"), buf); + +- struct scratch_buffer exebuf; +- scratch_buffer_init (&exebuf); ++ /* Name of the executable */ ++ struct scratch_buffer exe; ++ scratch_buffer_init (&exe); + ssize_t nexe; + while ((nexe = readlinkat (dfd, "exe", +- exebuf.data, exebuf.length)) == exebuf.length) ++ exe.data, exe.length)) == exe.length) + { +- if (!scratch_buffer_grow (&exebuf)) ++ if (!scratch_buffer_grow (&exe)) + { + nexe = -1; + break; + } + } + if (nexe == -1) +- exe = (char *) "<program name undetermined>"; ++ /* Default stack allocation is at least 1024. */ ++ snprintf (exe.data, exe.length, "<program name undetermined>"); + else +- { +- exe = exebuf.data; +- exe[nexe] = '\0'; +- } ++ ((char*)exe.data)[nexe] = '\0'; + + /* Stop all threads since otherwise the list of loaded modules might + change while we are reading it. */ +@@ -155,8 +145,8 @@ main (int argc, char *argv[]) + error (EXIT_FAILURE, errno, gettext ("cannot prepare reading %s/task"), + buf); + +- struct dirent64 *d; +- while ((d = readdir64 (dir)) != NULL) ++ struct dirent *d; ++ while ((d = readdir (dir)) != NULL) + { + if (! isdigit (d->d_name[0])) + continue; +@@ -182,7 +172,7 @@ main (int argc, char *argv[]) + + wait_for_ptrace_stop (tid); + +- struct thread_list *newp = alloca (sizeof (*newp)); ++ struct thread_list *newp = xmalloc (sizeof (*newp)); + newp->tid = tid; + newp->next = thread_list; + thread_list = newp; +@@ -190,17 +180,22 @@ main (int argc, char *argv[]) + + closedir (dir); + +- int status = get_process_info (dfd, pid); ++ if (thread_list == NULL) ++ error (EXIT_FAILURE, 0, gettext ("no valid %s/task entries"), buf); ++ ++ int status = get_process_info (exe.data, dfd, pid); + +- assert (thread_list != NULL); + do + { + ptrace (PTRACE_DETACH, thread_list->tid, NULL, NULL); ++ struct thread_list *prev = thread_list; + thread_list = thread_list->next; ++ free (prev); + } + while (thread_list != NULL); + + close (dfd); ++ scratch_buffer_free (&exe); + + return status; + } +@@ -281,9 +276,10 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ + + + static int +-get_process_info (int dfd, long int pid) ++get_process_info (const char *exe, int dfd, long int pid) + { +- memfd = openat (dfd, "mem", O_RDONLY); ++ /* File descriptor of /proc/<pid>/mem file. */ ++ int memfd = openat (dfd, "mem", O_RDONLY); + if (memfd == -1) + goto no_info; + +@@ -333,9 +329,9 @@ get_process_info (int dfd, long int pid) + + int retval; + if (e_ident[EI_CLASS] == ELFCLASS32) +- retval = find_maps32 (pid, auxv, auxv_size); ++ retval = find_maps32 (exe, memfd, pid, auxv, auxv_size); + else +- retval = find_maps64 (pid, auxv, auxv_size); ++ retval = find_maps64 (exe, memfd, pid, auxv, auxv_size); + + free (auxv); + close (memfd); +diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c +new file mode 100644 +index 0000000000..ed19cedd05 +--- /dev/null ++++ b/elf/tst-pldd.c +@@ -0,0 +1,118 @@ ++/* Basic tests for pldd program. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <stdio.h> ++#include <string.h> ++#include <unistd.h> ++#include <stdint.h> ++#include <libgen.h> ++#include <stdbool.h> ++ ++#include <array_length.h> ++#include <gnu/lib-names.h> ++ ++#include <support/subprocess.h> ++#include <support/capture_subprocess.h> ++#include <support/check.h> ++ ++static void ++target_process (void *arg) ++{ ++ pause (); ++} ++ ++/* The test runs in a container because pldd does not support tracing ++ a binary started by the loader iself (as with testrun.sh). */ ++ ++static int ++do_test (void) ++{ ++ /* Create a copy of current test to check with pldd. */ ++ struct support_subprocess target = support_subprocess (target_process, NULL); ++ ++ /* Run 'pldd' on test subprocess. */ ++ struct support_capture_subprocess pldd; ++ { ++ /* Three digits per byte plus null terminator. */ ++ char pid[3 * sizeof (uint32_t) + 1]; ++ snprintf (pid, array_length (pid), "%d", target.pid); ++ ++ const char prog[] = "/usr/bin/pldd"; ++ ++ pldd = support_capture_subprogram (prog, ++ (char *const []) { (char *) prog, pid, NULL }); ++ ++ support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout); ++ } ++ ++ /* Check 'pldd' output. The test is expected to be linked against only ++ loader and libc. */ ++ { ++ pid_t pid; ++ char buffer[512]; ++#define STRINPUT(size) "%" # size "s" ++ ++ FILE *out = fmemopen (pldd.out.buffer, pldd.out.length, "r"); ++ TEST_VERIFY (out != NULL); ++ ++ /* First line is in the form of <pid>: <full path of executable> */ ++ TEST_COMPARE (fscanf (out, "%u: " STRINPUT (512), &pid, buffer), 2); ++ ++ TEST_COMPARE (pid, target.pid); ++ TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0); ++ ++ /* It expects only one loader and libc loaded by the program. */ ++ bool interpreter_found = false, libc_found = false; ++ while (fgets (buffer, array_length (buffer), out) != NULL) ++ { ++ /* Ignore vDSO. */ ++ if (buffer[0] != '/') ++ continue; ++ ++ /* Remove newline so baseline (buffer) can compare against the ++ LD_SO and LIBC_SO macros unmodified. */ ++ if (buffer[strlen(buffer)-1] == '\n') ++ buffer[strlen(buffer)-1] = '\0'; ++ ++ if (strcmp (basename (buffer), LD_SO) == 0) ++ { ++ TEST_COMPARE (interpreter_found, false); ++ interpreter_found = true; ++ continue; ++ } ++ ++ if (strcmp (basename (buffer), LIBC_SO) == 0) ++ { ++ TEST_COMPARE (libc_found, false); ++ libc_found = true; ++ continue; ++ } ++ } ++ TEST_COMPARE (interpreter_found, true); ++ TEST_COMPARE (libc_found, true); ++ ++ fclose (out); ++ } ++ ++ support_capture_subprocess_free (&pldd); ++ support_process_terminate (&target); ++ ++ return 0; ++} ++ ++#include <support/test-driver.c> +diff --git a/include/stap-probe.h b/include/stap-probe.h +index c53dd86592..8c26292edd 100644 +--- a/include/stap-probe.h ++++ b/include/stap-probe.h +@@ -21,6 +21,7 @@ + + #ifdef USE_STAP_PROBE + ++# include <stap-probe-machine.h> + # include <sys/sdt.h> + + /* Our code uses one macro LIBC_PROBE (name, n, arg1, ..., argn). +diff --git a/libio/Makefile b/libio/Makefile +index 5bee83e55c..9626a16b01 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -65,7 +65,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ + tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \ + tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \ + tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \ +- tst-sprintf-ub tst-sprintf-chk-ub ++ tst-sprintf-ub tst-sprintf-chk-ub tst-wfile-sync + + tests-internal = tst-vtables tst-vtables-interposed tst-readline + +@@ -73,6 +73,9 @@ ifeq (yes,$(build-shared)) + # Add test-fopenloc only if shared library is enabled since it depends on + # shared localedata objects. + tests += tst-fopenloc ++# Add tst-bz24228 only if shared library is enabled since it can never meet its ++# objective with static linking because the relevant code just is not there. ++tests += tst-bz24228 + endif + test-srcs = test-freopen + +@@ -157,11 +160,14 @@ CFLAGS-tst_putwc.c += -DOBJPFX=\"$(objpfx)\" + CFLAGS-tst-sprintf-ub.c += -Wno-restrict + CFLAGS-tst-sprintf-chk-ub.c += -Wno-restrict + ++LDFLAGS-tst-bz24228 = -Wl,--version-script=tst-bz24228.map ++ + tst_wprintf2-ARGS = "Some Text" + + test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace + tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace + tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace ++tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace + + generated += test-fmemopen.mtrace test-fmemopen.check + generated += tst-fopenloc.mtrace tst-fopenloc.check +@@ -170,6 +176,7 @@ generated += tst-bz22415.mtrace tst-bz22415.check + aux := fileops genops stdfiles stdio strops + + ifeq ($(build-shared),yes) ++generated += tst-bz24228.mtrace tst-bz24228.check + aux += oldfileops oldstdfiles + endif + +@@ -184,7 +191,8 @@ tests-special += $(objpfx)test-freopen.out $(objpfx)test-fmemopen-mem.out \ + ifeq (yes,$(build-shared)) + # Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared + # library is enabled since they depend on tst-fopenloc.out. +-tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out ++tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \ ++ $(objpfx)tst-bz24228-mem.out + endif + endif + +@@ -212,6 +220,7 @@ $(objpfx)tst-ungetwc1.out: $(gen-locales) + $(objpfx)tst-ungetwc2.out: $(gen-locales) + $(objpfx)tst-widetext.out: $(gen-locales) + $(objpfx)tst_wprintf2.out: $(gen-locales) ++$(objpfx)tst-wfile-sync.out: $(gen-locales) + endif + + $(objpfx)test-freopen.out: test-freopen.sh $(objpfx)test-freopen +@@ -235,3 +244,7 @@ $(objpfx)tst-fopenloc-mem.out: $(objpfx)tst-fopenloc.out + $(objpfx)tst-bz22415-mem.out: $(objpfx)tst-bz22415.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-bz22415.mtrace > $@; \ + $(evaluate-test) ++ ++$(objpfx)tst-bz24228-mem.out: $(objpfx)tst-bz24228.out ++ $(common-objpfx)malloc/mtrace $(objpfx)tst-bz24228.mtrace > $@; \ ++ $(evaluate-test) +diff --git a/libio/genops.c b/libio/genops.c +index 2a0d9b81df..11a15549e8 100644 +--- a/libio/genops.c ++++ b/libio/genops.c +@@ -789,9 +789,16 @@ _IO_unbuffer_all (void) + + for (fp = (FILE *) _IO_list_all; fp; fp = fp->_chain) + { ++ int legacy = 0; ++ ++#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1) ++ if (__glibc_unlikely (_IO_vtable_offset (fp) != 0)) ++ legacy = 1; ++#endif ++ + if (! (fp->_flags & _IO_UNBUFFERED) + /* Iff stream is un-orientated, it wasn't used. */ +- && fp->_mode != 0) ++ && (legacy || fp->_mode != 0)) + { + #ifdef _IO_MTSAFE_IO + int cnt; +@@ -805,7 +812,7 @@ _IO_unbuffer_all (void) + __sched_yield (); + #endif + +- if (! dealloc_buffers && !(fp->_flags & _IO_USER_BUF)) ++ if (! legacy && ! dealloc_buffers && !(fp->_flags & _IO_USER_BUF)) + { + fp->_flags |= _IO_USER_BUF; + +@@ -816,7 +823,7 @@ _IO_unbuffer_all (void) + + _IO_SETBUF (fp, NULL, 0); + +- if (fp->_mode > 0) ++ if (! legacy && fp->_mode > 0) + _IO_wsetb (fp, NULL, NULL, 0); + + #ifdef _IO_MTSAFE_IO +@@ -827,7 +834,8 @@ _IO_unbuffer_all (void) + + /* Make sure that never again the wide char functions can be + used. */ +- fp->_mode = -1; ++ if (! legacy) ++ fp->_mode = -1; + } + + #ifdef _IO_MTSAFE_IO +diff --git a/libio/tst-bz24228.c b/libio/tst-bz24228.c +new file mode 100644 +index 0000000000..6a74500d47 +--- /dev/null ++++ b/libio/tst-bz24228.c +@@ -0,0 +1,29 @@ ++/* BZ #24228 check for memory corruption in legacy libio ++ Copyright (C) 2019 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 <mcheck.h> ++#include <support/test-driver.h> ++ ++static int ++do_test (void) ++{ ++ mtrace (); ++ return 0; ++} ++ ++#include <support/test-driver.c> +diff --git a/libio/tst-bz24228.map b/libio/tst-bz24228.map +new file mode 100644 +index 0000000000..4383e0817d +--- /dev/null ++++ b/libio/tst-bz24228.map +@@ -0,0 +1,5 @@ ++# Hide the symbol from libc.so.6 to switch to the libio/oldfileops.c ++# implementation when it is available for the architecture. ++{ ++ local: _IO_stdin_used; ++}; +diff --git a/libio/tst-wfile-sync.c b/libio/tst-wfile-sync.c +new file mode 100644 +index 0000000000..618682064d +--- /dev/null ++++ b/libio/tst-wfile-sync.c +@@ -0,0 +1,39 @@ ++/* Test that _IO_wfile_sync does not crash (bug 20568). ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <locale.h> ++#include <stdio.h> ++#include <wchar.h> ++#include <support/check.h> ++#include <support/xunistd.h> ++ ++static int ++do_test (void) ++{ ++ TEST_VERIFY_EXIT (setlocale (LC_ALL, "de_DE.UTF-8") != NULL); ++ /* Fill the stdio buffer and advance the read pointer. */ ++ TEST_VERIFY_EXIT (fgetwc (stdin) != WEOF); ++ /* This calls _IO_wfile_sync, it should not crash. */ ++ TEST_VERIFY_EXIT (setvbuf (stdin, NULL, _IONBF, 0) == 0); ++ /* Verify that the external file offset has been synchronized. */ ++ TEST_COMPARE (xlseek (0, 0, SEEK_CUR), 1); ++ ++ return 0; ++} ++ ++#include <support/test-driver.c> +diff --git a/libio/tst-wfile-sync.input b/libio/tst-wfile-sync.input +new file mode 100644 +index 0000000000..12d0958f7a +--- /dev/null ++++ b/libio/tst-wfile-sync.input +@@ -0,0 +1 @@ ++This is a test of _IO_wfile_sync. +diff --git a/libio/wfileops.c b/libio/wfileops.c +index 78f20486e5..bab2ba4892 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -508,11 +508,12 @@ _IO_wfile_sync (FILE *fp) + generate the wide characters up to the current reading + position. */ + int nread; +- ++ size_t wnread = (fp->_wide_data->_IO_read_ptr ++ - fp->_wide_data->_IO_read_base); + fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; + nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state, + fp->_IO_read_base, +- fp->_IO_read_end, delta); ++ fp->_IO_read_end, wnread); + fp->_IO_read_ptr = fp->_IO_read_base + nread; + delta = -(fp->_IO_read_end - fp->_IO_read_base - nread); + } +diff --git a/localedata/locales/ja_JP b/localedata/locales/ja_JP +index 1fd2fee44b..c64aaaff55 100644 +--- a/localedata/locales/ja_JP ++++ b/localedata/locales/ja_JP +@@ -14946,12 +14946,14 @@ am_pm "<U5348><U524D>";"<U5348><U5F8C>" + + t_fmt_ampm "%p%I<U6642>%M<U5206>%S<U79D2>" + +-era "+:2:1990//01//01:+*:<U5E73><U6210>:%EC%Ey<U5E74>";/ ++era "+:2:2020//01//01:+*:<U4EE4><U548C>:%EC%Ey<U5E74>";/ ++ "+:1:2019//05//01:2019//12//31:<U4EE4><U548C>:%EC<U5143><U5E74>";/ ++ "+:2:1990//01//01:2019//04//30:<U5E73><U6210>:%EC%Ey<U5E74>";/ + "+:1:1989//01//08:1989//12//31:<U5E73><U6210>:%EC<U5143><U5E74>";/ + "+:2:1927//01//01:1989//01//07:<U662D><U548C>:%EC%Ey<U5E74>";/ + "+:1:1926//12//25:1926//12//31:<U662D><U548C>:%EC<U5143><U5E74>";/ + "+:2:1913//01//01:1926//12//24:<U5927><U6B63>:%EC%Ey<U5E74>";/ +- "+:2:1912//07//30:1912//12//31:<U5927><U6B63>:%EC<U5143><U5E74>";/ ++ "+:1:1912//07//30:1912//12//31:<U5927><U6B63>:%EC<U5143><U5E74>";/ + "+:6:1873//01//01:1912//07//29:<U660E><U6CBB>:%EC%Ey<U5E74>";/ + "+:1:0001//01//01:1872//12//31:<U897F><U66A6>:%EC%Ey<U5E74>";/ + "+:1:-0001//12//31:-*:<U7D00><U5143><U524D>:%EC%Ey<U5E74>" +diff --git a/malloc/malloc.c b/malloc/malloc.c +index feaf7ee0bf..0abd653be2 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2919,6 +2919,8 @@ typedef struct tcache_perthread_struct + tcache_entry *entries[TCACHE_MAX_BINS]; + } tcache_perthread_struct; + ++#define MAX_TCACHE_COUNT 127 /* Maximum value of counts[] entries. */ ++ + static __thread bool tcache_shutting_down = false; + static __thread tcache_perthread_struct *tcache = NULL; + +@@ -3876,10 +3878,14 @@ _int_malloc (mstate av, size_t bytes) + { + victim->fd_nextsize = fwd; + victim->bk_nextsize = fwd->bk_nextsize; ++ if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd)) ++ malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)"); + fwd->bk_nextsize = victim; + victim->bk_nextsize->fd_nextsize = victim; + } + bck = fwd->bk; ++ if (bck->fd != fwd) ++ malloc_printerr ("malloc(): largebin double linked list corrupted (bk)"); + } + } + else +@@ -5120,8 +5126,11 @@ static inline int + __always_inline + do_set_tcache_count (size_t value) + { +- LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count); +- mp_.tcache_count = value; ++ if (value <= MAX_TCACHE_COUNT) ++ { ++ LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count); ++ mp_.tcache_count = value; ++ } + return 1; + } + +diff --git a/malloc/mtrace.c b/malloc/mtrace.c +index a2facf65ea..2fda262508 100644 +--- a/malloc/mtrace.c ++++ b/malloc/mtrace.c +@@ -121,6 +121,41 @@ lock_and_info (const void *caller, Dl_info *mem) + return res; + } + ++static void tr_freehook (void *, const void *); ++static void * tr_mallochook (size_t, const void *); ++static void * tr_reallochook (void *, size_t, const void *); ++static void * tr_memalignhook (size_t, size_t, const void *); ++ ++/* Set all the default non-trace hooks. */ ++static __always_inline void ++set_default_hooks (void) ++{ ++ __free_hook = tr_old_free_hook; ++ __malloc_hook = tr_old_malloc_hook; ++ __realloc_hook = tr_old_realloc_hook; ++ __memalign_hook = tr_old_memalign_hook; ++} ++ ++/* Set all of the tracing hooks used for mtrace. */ ++static __always_inline void ++set_trace_hooks (void) ++{ ++ __free_hook = tr_freehook; ++ __malloc_hook = tr_mallochook; ++ __realloc_hook = tr_reallochook; ++ __memalign_hook = tr_memalignhook; ++} ++ ++/* Save the current set of hooks as the default hooks. */ ++static __always_inline void ++save_default_hooks (void) ++{ ++ tr_old_free_hook = __free_hook; ++ tr_old_malloc_hook = __malloc_hook; ++ tr_old_realloc_hook = __realloc_hook; ++ tr_old_memalign_hook = __memalign_hook; ++} ++ + static void + tr_freehook (void *ptr, const void *caller) + { +@@ -138,12 +173,12 @@ tr_freehook (void *ptr, const void *caller) + tr_break (); + __libc_lock_lock (lock); + } +- __free_hook = tr_old_free_hook; ++ set_default_hooks (); + if (tr_old_free_hook != NULL) + (*tr_old_free_hook)(ptr, caller); + else + free (ptr); +- __free_hook = tr_freehook; ++ set_trace_hooks (); + __libc_lock_unlock (lock); + } + +@@ -155,12 +190,12 @@ tr_mallochook (size_t size, const void *caller) + Dl_info mem; + Dl_info *info = lock_and_info (caller, &mem); + +- __malloc_hook = tr_old_malloc_hook; ++ set_default_hooks (); + if (tr_old_malloc_hook != NULL) + hdr = (void *) (*tr_old_malloc_hook)(size, caller); + else + hdr = (void *) malloc (size); +- __malloc_hook = tr_mallochook; ++ set_trace_hooks (); + + tr_where (caller, info); + /* We could be printing a NULL here; that's OK. */ +@@ -185,16 +220,12 @@ tr_reallochook (void *ptr, size_t size, const void *caller) + Dl_info mem; + Dl_info *info = lock_and_info (caller, &mem); + +- __free_hook = tr_old_free_hook; +- __malloc_hook = tr_old_malloc_hook; +- __realloc_hook = tr_old_realloc_hook; ++ set_default_hooks (); + if (tr_old_realloc_hook != NULL) + hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller); + else + hdr = (void *) realloc (ptr, size); +- __free_hook = tr_freehook; +- __malloc_hook = tr_mallochook; +- __realloc_hook = tr_reallochook; ++ set_trace_hooks (); + + tr_where (caller, info); + if (hdr == NULL) +@@ -230,14 +261,12 @@ tr_memalignhook (size_t alignment, size_t size, const void *caller) + Dl_info mem; + Dl_info *info = lock_and_info (caller, &mem); + +- __memalign_hook = tr_old_memalign_hook; +- __malloc_hook = tr_old_malloc_hook; ++ set_default_hooks (); + if (tr_old_memalign_hook != NULL) + hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller); + else + hdr = (void *) memalign (alignment, size); +- __memalign_hook = tr_memalignhook; +- __malloc_hook = tr_mallochook; ++ set_trace_hooks (); + + tr_where (caller, info); + /* We could be printing a NULL here; that's OK. */ +@@ -305,14 +334,8 @@ mtrace (void) + malloc_trace_buffer = mtb; + setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE); + fprintf (mallstream, "= Start\n"); +- tr_old_free_hook = __free_hook; +- __free_hook = tr_freehook; +- tr_old_malloc_hook = __malloc_hook; +- __malloc_hook = tr_mallochook; +- tr_old_realloc_hook = __realloc_hook; +- __realloc_hook = tr_reallochook; +- tr_old_memalign_hook = __memalign_hook; +- __memalign_hook = tr_memalignhook; ++ save_default_hooks (); ++ set_trace_hooks (); + #ifdef _LIBC + if (!added_atexit_handler) + { +@@ -338,10 +361,7 @@ muntrace (void) + file. */ + FILE *f = mallstream; + mallstream = NULL; +- __free_hook = tr_old_free_hook; +- __malloc_hook = tr_old_malloc_hook; +- __realloc_hook = tr_old_realloc_hook; +- __memalign_hook = tr_old_memalign_hook; ++ set_default_hooks (); + + fprintf (f, "= End\n"); + fclose (f); +diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c +index 15e25f558e..51d42cee81 100644 +--- a/malloc/tst-malloc-too-large.c ++++ b/malloc/tst-malloc-too-large.c +@@ -72,13 +72,28 @@ test_large_allocations (size_t size) + void * ptr_to_realloc; + + test_setup (); ++ DIAG_PUSH_NEEDS_COMMENT; ++#if __GNUC_PREREQ (7, 0) ++ /* GCC 7 warns about too-large allocations; here we want to test ++ that they fail. */ ++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); ++#endif + TEST_VERIFY (malloc (size) == NULL); ++#if __GNUC_PREREQ (7, 0) ++ DIAG_POP_NEEDS_COMMENT; ++#endif + TEST_VERIFY (errno == ENOMEM); + + ptr_to_realloc = malloc (16); + TEST_VERIFY_EXIT (ptr_to_realloc != NULL); + test_setup (); ++#if __GNUC_PREREQ (7, 0) ++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); ++#endif + TEST_VERIFY (realloc (ptr_to_realloc, size) == NULL); ++#if __GNUC_PREREQ (7, 0) ++ DIAG_POP_NEEDS_COMMENT; ++#endif + TEST_VERIFY (errno == ENOMEM); + free (ptr_to_realloc); + +@@ -135,7 +150,13 @@ test_large_aligned_allocations (size_t size) + for (align = 1; align <= pagesize; align *= 2) + { + test_setup (); ++#if __GNUC_PREREQ (7, 0) ++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); ++#endif + TEST_VERIFY (memalign (align, size) == NULL); ++#if __GNUC_PREREQ (7, 0) ++ DIAG_POP_NEEDS_COMMENT; ++#endif + TEST_VERIFY (errno == ENOMEM); + + /* posix_memalign expects an alignment that is a power of 2 *and* a +@@ -151,7 +172,13 @@ test_large_aligned_allocations (size_t size) + if ((size % align) == 0) + { + test_setup (); ++#if __GNUC_PREREQ (7, 0) ++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); ++#endif + TEST_VERIFY (aligned_alloc (align, size) == NULL); ++#if __GNUC_PREREQ (7, 0) ++ DIAG_POP_NEEDS_COMMENT; ++#endif + TEST_VERIFY (errno == ENOMEM); + } + } +@@ -159,11 +186,23 @@ test_large_aligned_allocations (size_t size) + /* Both valloc and pvalloc return page-aligned memory. */ + + test_setup (); ++#if __GNUC_PREREQ (7, 0) ++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); ++#endif + TEST_VERIFY (valloc (size) == NULL); ++#if __GNUC_PREREQ (7, 0) ++ DIAG_POP_NEEDS_COMMENT; ++#endif + TEST_VERIFY (errno == ENOMEM); + + test_setup (); ++#if __GNUC_PREREQ (7, 0) ++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); ++#endif + TEST_VERIFY (pvalloc (size) == NULL); ++#if __GNUC_PREREQ (7, 0) ++ DIAG_POP_NEEDS_COMMENT; ++#endif + TEST_VERIFY (errno == ENOMEM); + } + +diff --git a/malloc/tst-memalign.c b/malloc/tst-memalign.c +index a6a9140a3d..e7997518cb 100644 +--- a/malloc/tst-memalign.c ++++ b/malloc/tst-memalign.c +@@ -21,6 +21,7 @@ + #include <stdio.h> + #include <string.h> + #include <unistd.h> ++#include <libc-diag.h> + + static int errors = 0; + +@@ -41,9 +42,18 @@ do_test (void) + + errno = 0; + ++ DIAG_PUSH_NEEDS_COMMENT; ++#if __GNUC_PREREQ (7, 0) ++ /* GCC 7 warns about too-large allocations; here we want to test ++ that they fail. */ ++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); ++#endif + /* An attempt to allocate a huge value should return NULL and set + errno to ENOMEM. */ + p = memalign (sizeof (void *), -1); ++#if __GNUC_PREREQ (7, 0) ++ DIAG_POP_NEEDS_COMMENT; ++#endif + + save = errno; + +diff --git a/manual/tunables.texi b/manual/tunables.texi +index af820820e0..8edfea4edd 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -189,8 +189,8 @@ per-thread cache. The default (and maximum) value is 1032 bytes on + + @deftp Tunable glibc.malloc.tcache_count + The maximum number of chunks of each size to cache. The default is 7. +-There is no upper limit, other than available system memory. If set +-to zero, the per-thread cache is effectively disabled. ++The upper limit is 127. If set to zero, the per-thread cache is effectively ++disabled. + + The approximate maximum overhead of the per-thread cache is thus equal + to the number of bins times the chunk count in each bin times the size +diff --git a/nptl/Makefile b/nptl/Makefile +index 340282c6cb..0e316edfac 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -319,7 +319,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ + tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-cnd-timedwait tst-thrd-detach tst-mtx-basic tst-thrd-sleep \ + tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \ +- tst-rwlock-pwn ++ tst-rwlock-pwn \ ++ tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall + + tests-internal := tst-rwlock19 tst-rwlock20 \ + tst-sem11 tst-sem12 tst-sem13 \ +diff --git a/nptl/pthread_join_common.c b/nptl/pthread_join_common.c +index ecb78ffba5..366feb376b 100644 +--- a/nptl/pthread_join_common.c ++++ b/nptl/pthread_join_common.c +@@ -86,6 +86,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return, + pthread_cleanup_pop (0); + } + ++ void *pd_result = pd->result; + if (__glibc_likely (result == 0)) + { + /* We mark the thread as terminated and as joined. */ +@@ -93,7 +94,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return, + + /* Store the return value if the caller is interested. */ + if (thread_return != NULL) +- *thread_return = pd->result; ++ *thread_return = pd_result; + + /* Free the TCB. */ + __free_tcb (pd); +@@ -101,7 +102,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return, + else + pd->joinid = NULL; + +- LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd->result); ++ LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd_result); + + return result; + } +diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c +index 8fe43b8f0f..bf2869eca2 100644 +--- a/nptl/pthread_mutex_trylock.c ++++ b/nptl/pthread_mutex_trylock.c +@@ -94,6 +94,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP: + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + &mutex->__data.__list.__next); ++ /* We need to set op_pending before starting the operation. Also ++ see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + + oldval = mutex->__data.__lock; + do +@@ -119,7 +122,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + /* But it is inconsistent unless marked otherwise. */ + mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; + ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + ENQUEUE_MUTEX (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Note that we deliberately exist here. If we fall +@@ -135,6 +143,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + int kind = PTHREAD_MUTEX_TYPE (mutex); + if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP) + { ++ /* We do not need to ensure ordering wrt another memory ++ access. Also see comments at ENQUEUE_MUTEX. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + NULL); + return EDEADLK; +@@ -142,6 +152,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + + if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP) + { ++ /* We do not need to ensure ordering wrt another memory ++ access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + NULL); + +@@ -160,6 +172,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + id, 0); + if (oldval != 0 && (oldval & FUTEX_OWNER_DIED) == 0) + { ++ /* We haven't acquired the lock as it is already acquired by ++ another owner. We do not need to ensure ordering wrt another ++ memory access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + return EBUSY; +@@ -173,13 +188,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + if (oldval == id) + lll_unlock (mutex->__data.__lock, + PTHREAD_ROBUST_MUTEX_PSHARED (mutex)); ++ /* FIXME This violates the mutex destruction requirements. See ++ __pthread_mutex_unlock_full. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return ENOTRECOVERABLE; + } + } + while ((oldval & FUTEX_OWNER_DIED) != 0); + ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + ENQUEUE_MUTEX (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + mutex->__data.__owner = id; +@@ -211,10 +233,15 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + } + + if (robust) +- /* Note: robust PI futexes are signaled by setting bit 0. */ +- THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, +- (void *) (((uintptr_t) &mutex->__data.__list.__next) +- | 1)); ++ { ++ /* Note: robust PI futexes are signaled by setting bit 0. */ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, ++ (void *) (((uintptr_t) &mutex->__data.__list.__next) ++ | 1)); ++ /* We need to set op_pending before starting the operation. Also ++ see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); ++ } + + oldval = mutex->__data.__lock; + +@@ -223,12 +250,16 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + { + if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) + { ++ /* We do not need to ensure ordering wrt another memory ++ access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return EDEADLK; + } + + if (kind == PTHREAD_MUTEX_RECURSIVE_NP) + { ++ /* We do not need to ensure ordering wrt another memory ++ access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Just bump the counter. */ +@@ -250,6 +281,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + { + if ((oldval & FUTEX_OWNER_DIED) == 0) + { ++ /* We haven't acquired the lock as it is already acquired by ++ another owner. We do not need to ensure ordering wrt another ++ memory access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + return EBUSY; +@@ -270,6 +304,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + if (INTERNAL_SYSCALL_ERROR_P (e, __err) + && INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK) + { ++ /* The kernel has not yet finished the mutex owner death. ++ We do not need to ensure ordering wrt another memory ++ access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + return EBUSY; +@@ -287,7 +324,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + /* But it is inconsistent unless marked otherwise. */ + mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; + ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + ENQUEUE_MUTEX (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Note that we deliberately exit here. If we fall +@@ -310,13 +352,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + PTHREAD_ROBUST_MUTEX_PSHARED (mutex)), + 0, 0); + ++ /* To the kernel, this will be visible after the kernel has ++ acquired the mutex in the syscall. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return ENOTRECOVERABLE; + } + + if (robust) + { ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + ENQUEUE_MUTEX_PI (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + } + +diff --git a/nptl/pthread_rwlock_tryrdlock.c b/nptl/pthread_rwlock_tryrdlock.c +index 368862ff07..2f94f17f36 100644 +--- a/nptl/pthread_rwlock_tryrdlock.c ++++ b/nptl/pthread_rwlock_tryrdlock.c +@@ -94,15 +94,22 @@ __pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) + /* Same as in __pthread_rwlock_rdlock_full: + We started the read phase, so we are also responsible for + updating the write-phase futex. Relaxed MO is sufficient. +- Note that there can be no other reader that we have to wake +- because all other readers will see the read phase started by us +- (or they will try to start it themselves); if a writer started +- the read phase, we cannot have started it. Furthermore, we +- cannot discard a PTHREAD_RWLOCK_FUTEX_USED flag because we will +- overwrite the value set by the most recent writer (or the readers +- before it in case of explicit hand-over) and we know that there +- are no waiting readers. */ +- atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0); ++ We have to do the same steps as a writer would when handing over the ++ read phase to use because other readers cannot distinguish between ++ us and the writer. ++ Note that __pthread_rwlock_tryrdlock callers will not have to be ++ woken up because they will either see the read phase started by us ++ or they will try to start it themselves; however, callers of ++ __pthread_rwlock_rdlock_full just increase the reader count and then ++ check what state the lock is in, so they cannot distinguish between ++ us and a writer that acquired and released the lock in the ++ meantime. */ ++ if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0) ++ & PTHREAD_RWLOCK_FUTEX_USED) != 0) ++ { ++ int private = __pthread_rwlock_get_private (rwlock); ++ futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private); ++ } + } + + return 0; +diff --git a/nptl/pthread_rwlock_trywrlock.c b/nptl/pthread_rwlock_trywrlock.c +index fd37a71ce4..fae475cc70 100644 +--- a/nptl/pthread_rwlock_trywrlock.c ++++ b/nptl/pthread_rwlock_trywrlock.c +@@ -46,8 +46,15 @@ __pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) + &rwlock->__data.__readers, &r, + r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED)) + { ++ /* We have become the primary writer and we cannot have shared ++ the PTHREAD_RWLOCK_FUTEX_USED flag with someone else, so we ++ can simply enable blocking (see full wrlock code). */ + atomic_store_relaxed (&rwlock->__data.__writers_futex, 1); +- atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); ++ /* If we started a write phase, we need to enable readers to ++ wait. If we did not, we must not change it because other threads ++ may have set the PTHREAD_RWLOCK_FUTEX_USED in the meantime. */ ++ if ((r & PTHREAD_RWLOCK_WRPHASE) == 0) ++ atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); + atomic_store_relaxed (&rwlock->__data.__cur_writer, + THREAD_GETMEM (THREAD_SELF, tid)); + return 0; +diff --git a/nptl/register-atfork.c b/nptl/register-atfork.c +index bc797b761a..80a1becb5f 100644 +--- a/nptl/register-atfork.c ++++ b/nptl/register-atfork.c +@@ -107,13 +107,14 @@ __unregister_atfork (void *dso_handle) + } + + void +-__run_fork_handlers (enum __run_fork_handler_type who) ++__run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking) + { + struct fork_handler *runp; + + if (who == atfork_run_prepare) + { +- lll_lock (atfork_lock, LLL_PRIVATE); ++ if (do_locking) ++ lll_lock (atfork_lock, LLL_PRIVATE); + size_t sl = fork_handler_list_size (&fork_handlers); + for (size_t i = sl; i > 0; i--) + { +@@ -133,7 +134,8 @@ __run_fork_handlers (enum __run_fork_handler_type who) + else if (who == atfork_run_parent && runp->parent_handler) + runp->parent_handler (); + } +- lll_unlock (atfork_lock, LLL_PRIVATE); ++ if (do_locking) ++ lll_unlock (atfork_lock, LLL_PRIVATE); + } + } + +diff --git a/nptl/tst-rwlock-tryrdlock-stall.c b/nptl/tst-rwlock-tryrdlock-stall.c +new file mode 100644 +index 0000000000..5e476da2b8 +--- /dev/null ++++ b/nptl/tst-rwlock-tryrdlock-stall.c +@@ -0,0 +1,355 @@ ++/* Bug 23844: Test for pthread_rwlock_tryrdlock stalls. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++/* For a full analysis see comment: ++ https://sourceware.org/bugzilla/show_bug.cgi?id=23844#c14 ++ ++ Provided here for reference: ++ ++ --- Analysis of pthread_rwlock_tryrdlock() stall --- ++ A read lock begins to execute. ++ ++ In __pthread_rwlock_rdlock_full: ++ ++ We can attempt a read lock, but find that the lock is ++ in a write phase (PTHREAD_RWLOCK_WRPHASE, or WP-bit ++ is set), and the lock is held by a primary writer ++ (PTHREAD_RWLOCK_WRLOCKED is set). In this case we must ++ wait for explicit hand over from the writer to us or ++ one of the other waiters. The read lock threads are ++ about to execute: ++ ++ 341 r = (atomic_fetch_add_acquire (&rwlock->__data.__readers, ++ 342 (1 << PTHREAD_RWLOCK_READER_SHIFT)) ++ 343 + (1 << PTHREAD_RWLOCK_READER_SHIFT)); ++ ++ An unlock beings to execute. ++ ++ Then in __pthread_rwlock_wrunlock: ++ ++ 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers); ++ ... ++ 549 while (!atomic_compare_exchange_weak_release ++ 550 (&rwlock->__data.__readers, &r, ++ 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED) ++ 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0 ++ 553 : PTHREAD_RWLOCK_WRPHASE)))) ++ 554 { ++ ... ++ 556 } ++ ++ We clear PTHREAD_RWLOCK_WRLOCKED, and if there are ++ no readers so we leave the lock in PTHRAD_RWLOCK_WRPHASE. ++ ++ Back in the read lock. ++ ++ The read lock adjusts __readres as above. ++ ++ 383 while ((r & PTHREAD_RWLOCK_WRPHASE) != 0 ++ 384 && (r & PTHREAD_RWLOCK_WRLOCKED) == 0) ++ 385 { ++ ... ++ 390 if (atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, &r, ++ 391 r ^ PTHREAD_RWLOCK_WRPHASE)) ++ 392 { ++ ++ And then attemps to start the read phase. ++ ++ Assume there happens to be a tryrdlock at this point, noting ++ that PTHREAD_RWLOCK_WRLOCKED is clear, and PTHREAD_RWLOCK_WRPHASE ++ is 1. So the try lock attemps to start the read phase. ++ ++ In __pthread_rwlock_tryrdlock: ++ ++ 44 if ((r & PTHREAD_RWLOCK_WRPHASE) == 0) ++ 45 { ++ ... ++ 49 if (((r & PTHREAD_RWLOCK_WRLOCKED) != 0) ++ 50 && (rwlock->__data.__flags ++ 51 == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)) ++ 52 return EBUSY; ++ 53 rnew = r + (1 << PTHREAD_RWLOCK_READER_SHIFT); ++ 54 } ++ ... ++ 89 while (!atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, ++ 90 &r, rnew)); ++ ++ And succeeds. ++ ++ Back in the write unlock: ++ ++ 557 if ((r >> PTHREAD_RWLOCK_READER_SHIFT) != 0) ++ 558 { ++ ... ++ 563 if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0) ++ 564 & PTHREAD_RWLOCK_FUTEX_USED) != 0) ++ 565 futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private); ++ 566 } ++ ++ We note that PTHREAD_RWLOCK_FUTEX_USED is non-zero ++ and don't wake anyone. This is OK because we handed ++ over to the trylock. It will be the trylock's responsibility ++ to wake any waiters. ++ ++ Back in the read lock: ++ ++ The read lock fails to install PTHRAD_REWLOCK_WRPHASE as 0 because ++ the __readers value was adjusted by the trylock, and so it falls through ++ to waiting on the lock for explicit handover from either a new writer ++ or a new reader. ++ ++ 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, ++ 449 1 | PTHREAD_RWLOCK_FUTEX_USED, ++ 450 abstime, private); ++ ++ We use PTHREAD_RWLOCK_FUTEX_USED to indicate the futex ++ is in use. ++ ++ At this point we have readers waiting on the read lock ++ to unlock. The wrlock is done. The trylock is finishing ++ the installation of the read phase. ++ ++ 92 if ((r & PTHREAD_RWLOCK_WRPHASE) != 0) ++ 93 { ++ ... ++ 105 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0); ++ 106 } ++ ++ The trylock does note that we were the one that ++ installed the read phase, but the comments are not ++ correct, the execution ordering above shows that ++ readers might indeed be waiting, and they are. ++ ++ The atomic_store_relaxed throws away PTHREAD_RWLOCK_FUTEX_USED, ++ and the waiting reader is never worken becuase as noted ++ above it is conditional on the futex being used. ++ ++ The solution is for the trylock thread to inspect ++ PTHREAD_RWLOCK_FUTEX_USED and wake the waiting readers. ++ ++ --- Analysis of pthread_rwlock_trywrlock() stall --- ++ ++ A write lock begins to execute, takes the write lock, ++ and then releases the lock... ++ ++ In pthread_rwlock_wrunlock(): ++ ++ 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers); ++ ... ++ 549 while (!atomic_compare_exchange_weak_release ++ 550 (&rwlock->__data.__readers, &r, ++ 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED) ++ 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0 ++ 553 : PTHREAD_RWLOCK_WRPHASE)))) ++ 554 { ++ ... ++ 556 } ++ ++ ... leaving it in the write phase with zero readers ++ (the case where we leave the write phase in place ++ during a write unlock). ++ ++ A write trylock begins to execute. ++ ++ In __pthread_rwlock_trywrlock: ++ ++ 40 while (((r & PTHREAD_RWLOCK_WRLOCKED) == 0) ++ 41 && (((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0) ++ 42 || (prefer_writer && ((r & PTHREAD_RWLOCK_WRPHASE) != 0)))) ++ 43 { ++ ++ The lock is not locked. ++ ++ There are no readers. ++ ++ 45 if (atomic_compare_exchange_weak_acquire ( ++ 46 &rwlock->__data.__readers, &r, ++ 47 r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED)) ++ ++ We atomically install the write phase and we take the ++ exclusive write lock. ++ ++ 48 { ++ 49 atomic_store_relaxed (&rwlock->__data.__writers_futex, 1); ++ ++ We get this far. ++ ++ A reader lock begins to execute. ++ ++ In pthread_rwlock_rdlock: ++ ++ 437 for (;;) ++ 438 { ++ 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) ++ 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) ++ 441 { ++ 442 int private = __pthread_rwlock_get_private (rwlock); ++ 443 if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) ++ 444 && (!atomic_compare_exchange_weak_relaxed ++ 445 (&rwlock->__data.__wrphase_futex, ++ 446 &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED))) ++ 447 continue; ++ 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, ++ 449 1 | PTHREAD_RWLOCK_FUTEX_USED, ++ 450 abstime, private); ++ ++ We are in a write phase, so the while() on line 439 is true. ++ ++ The value of wpf does not have PTHREAD_RWLOCK_FUTEX_USED set ++ since this is the first reader to lock. ++ ++ The atomic operation sets wpf with PTHREAD_RELOCK_FUTEX_USED ++ on the expectation that this reader will be woken during ++ the handoff. ++ ++ Back in pthread_rwlock_trywrlock: ++ ++ 50 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); ++ 51 atomic_store_relaxed (&rwlock->__data.__cur_writer, ++ 52 THREAD_GETMEM (THREAD_SELF, tid)); ++ 53 return 0; ++ 54 } ++ ... ++ 57 } ++ ++ We write 1 to __wrphase_futex discarding PTHREAD_RWLOCK_FUTEX_USED, ++ and so in the unlock we will not awaken the waiting reader. ++ ++ The solution to this is to realize that if we did not start the write ++ phase we need not write 1 or any other value to __wrphase_futex. ++ This ensures that any readers (which saw __wrphase_futex != 0) can ++ set PTHREAD_RWLOCK_FUTEX_USED and this can be used at unlock to ++ wake them. ++ ++ If we installed the write phase then all other readers are looping ++ here: ++ ++ In __pthread_rwlock_rdlock_full: ++ ++ 437 for (;;) ++ 438 { ++ 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) ++ 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) ++ 441 { ++ ... ++ 508 } ++ ++ waiting for the write phase to be installed or removed before they ++ can begin waiting on __wrphase_futex (part of the algorithm), or ++ taking a concurrent read lock, and thus we can safely write 1 to ++ __wrphase_futex. ++ ++ If we did not install the write phase then the readers may already ++ be waiting on the futex, the original writer wrote 1 to __wrphase_futex ++ as part of starting the write phase, and we cannot also write 1 ++ without loosing the PTHREAD_RWLOCK_FUTEX_USED bit. ++ ++ --- ++ ++ Summary for the pthread_rwlock_tryrdlock() stall: ++ ++ The stall is caused by pthread_rwlock_tryrdlock failing to check ++ that PTHREAD_RWLOCK_FUTEX_USED is set in the __wrphase_futex futex ++ and then waking the futex. ++ ++ The fix for bug 23844 ensures that waiters on __wrphase_futex are ++ correctly woken. Before the fix the test stalls as readers can ++ wait forever on __wrphase_futex. */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <pthread.h> ++#include <support/xthread.h> ++#include <errno.h> ++ ++/* We need only one lock to reproduce the issue. We will need multiple ++ threads to get the exact case where we have a read, try, and unlock ++ all interleaving to produce the case where the readers are waiting ++ and the try fails to wake them. */ ++pthread_rwlock_t onelock; ++ ++/* The number of threads is arbitrary but empirically chosen to have ++ enough threads that we see the condition where waiting readers are ++ not woken by a successful tryrdlock. */ ++#define NTHREADS 32 ++ ++_Atomic int do_exit; ++ ++void * ++run_loop (void *arg) ++{ ++ int i = 0, ret; ++ while (!do_exit) ++ { ++ /* Arbitrarily choose if we are the writer or reader. Choose a ++ high enough ratio of readers to writers to make it likely ++ that readers block (and eventually are susceptable to ++ stalling). ++ ++ If we are a writer, take the write lock, and then unlock. ++ If we are a reader, try the lock, then lock, then unlock. */ ++ if ((i % 8) != 0) ++ xpthread_rwlock_wrlock (&onelock); ++ else ++ { ++ if ((ret = pthread_rwlock_tryrdlock (&onelock)) != 0) ++ { ++ if (ret == EBUSY) ++ xpthread_rwlock_rdlock (&onelock); ++ else ++ exit (EXIT_FAILURE); ++ } ++ } ++ /* Thread does some work and then unlocks. */ ++ xpthread_rwlock_unlock (&onelock); ++ i++; ++ } ++ return NULL; ++} ++ ++int ++do_test (void) ++{ ++ int i; ++ pthread_t tids[NTHREADS]; ++ xpthread_rwlock_init (&onelock, NULL); ++ for (i = 0; i < NTHREADS; i++) ++ tids[i] = xpthread_create (NULL, run_loop, NULL); ++ /* Run for some amount of time. Empirically speaking exercising ++ the stall via pthread_rwlock_tryrdlock is much harder, and on ++ a 3.5GHz 4 core x86_64 VM system it takes somewhere around ++ 20-200s to stall, approaching 100% stall past 200s. We can't ++ wait that long for a regression test so we just test for 20s, ++ and expect the stall to happen with a 5-10% chance (enough for ++ developers to see). */ ++ sleep (20); ++ /* Then exit. */ ++ printf ("INFO: Exiting...\n"); ++ do_exit = 1; ++ /* If any readers stalled then we will timeout waiting for them. */ ++ for (i = 0; i < NTHREADS; i++) ++ xpthread_join (tids[i]); ++ printf ("INFO: Done.\n"); ++ xpthread_rwlock_destroy (&onelock); ++ printf ("PASS: No pthread_rwlock_tryrdlock stalls detected.\n"); ++ return 0; ++} ++ ++#define TIMEOUT 30 ++#include <support/test-driver.c> +diff --git a/nptl/tst-rwlock-trywrlock-stall.c b/nptl/tst-rwlock-trywrlock-stall.c +new file mode 100644 +index 0000000000..14d27cbcbc +--- /dev/null ++++ b/nptl/tst-rwlock-trywrlock-stall.c +@@ -0,0 +1,108 @@ ++/* Bug 23844: Test for pthread_rwlock_trywrlock stalls. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++/* For a full analysis see comments in tst-rwlock-tryrdlock-stall.c. ++ ++ Summary for the pthread_rwlock_trywrlock() stall: ++ ++ The stall is caused by pthread_rwlock_trywrlock setting ++ __wrphase_futex futex to 1 and loosing the ++ PTHREAD_RWLOCK_FUTEX_USED bit. ++ ++ The fix for bug 23844 ensures that waiters on __wrphase_futex are ++ correctly woken. Before the fix the test stalls as readers can ++ wait forever on __wrphase_futex. */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <pthread.h> ++#include <support/xthread.h> ++#include <errno.h> ++ ++/* We need only one lock to reproduce the issue. We will need multiple ++ threads to get the exact case where we have a read, try, and unlock ++ all interleaving to produce the case where the readers are waiting ++ and the try clears the PTHREAD_RWLOCK_FUTEX_USED bit and a ++ subsequent unlock fails to wake them. */ ++pthread_rwlock_t onelock; ++ ++/* The number of threads is arbitrary but empirically chosen to have ++ enough threads that we see the condition where waiting readers are ++ not woken by a successful unlock. */ ++#define NTHREADS 32 ++ ++_Atomic int do_exit; ++ ++void * ++run_loop (void *arg) ++{ ++ int i = 0, ret; ++ while (!do_exit) ++ { ++ /* Arbitrarily choose if we are the writer or reader. Choose a ++ high enough ratio of readers to writers to make it likely ++ that readers block (and eventually are susceptable to ++ stalling). ++ ++ If we are a writer, take the write lock, and then unlock. ++ If we are a reader, try the lock, then lock, then unlock. */ ++ if ((i % 8) != 0) ++ { ++ if ((ret = pthread_rwlock_trywrlock (&onelock)) != 0) ++ { ++ if (ret == EBUSY) ++ xpthread_rwlock_wrlock (&onelock); ++ else ++ exit (EXIT_FAILURE); ++ } ++ } ++ else ++ xpthread_rwlock_rdlock (&onelock); ++ /* Thread does some work and then unlocks. */ ++ xpthread_rwlock_unlock (&onelock); ++ i++; ++ } ++ return NULL; ++} ++ ++int ++do_test (void) ++{ ++ int i; ++ pthread_t tids[NTHREADS]; ++ xpthread_rwlock_init (&onelock, NULL); ++ for (i = 0; i < NTHREADS; i++) ++ tids[i] = xpthread_create (NULL, run_loop, NULL); ++ /* Run for some amount of time. The pthread_rwlock_tryrwlock stall ++ is very easy to trigger and happens in seconds under the test ++ conditions. */ ++ sleep (10); ++ /* Then exit. */ ++ printf ("INFO: Exiting...\n"); ++ do_exit = 1; ++ /* If any readers stalled then we will timeout waiting for them. */ ++ for (i = 0; i < NTHREADS; i++) ++ xpthread_join (tids[i]); ++ printf ("INFO: Done.\n"); ++ xpthread_rwlock_destroy (&onelock); ++ printf ("PASS: No pthread_rwlock_tryrwlock stalls detected.\n"); ++ return 0; ++} ++ ++#include <support/test-driver.c> +diff --git a/posix/bits/types.h b/posix/bits/types.h +index 27e065c3be..0de6c59bb4 100644 +--- a/posix/bits/types.h ++++ b/posix/bits/types.h +@@ -87,7 +87,7 @@ __extension__ typedef unsigned long long int __uintmax_t; + 32 -- "natural" 32-bit type (always int) + 64 -- "natural" 64-bit type (long or long long) + LONG32 -- 32-bit type, traditionally long +- QUAD -- 64-bit type, always long long ++ QUAD -- 64-bit type, traditionally long long + WORD -- natural type of __WORDSIZE bits (int or long) + LONGWORD -- type of __WORDSIZE bits, traditionally long + +@@ -113,14 +113,14 @@ __extension__ typedef unsigned long long int __uintmax_t; + #define __SLONGWORD_TYPE long int + #define __ULONGWORD_TYPE unsigned long int + #if __WORDSIZE == 32 +-# define __SQUAD_TYPE __quad_t +-# define __UQUAD_TYPE __u_quad_t ++# define __SQUAD_TYPE __int64_t ++# define __UQUAD_TYPE __uint64_t + # define __SWORD_TYPE int + # define __UWORD_TYPE unsigned int + # define __SLONG32_TYPE long int + # define __ULONG32_TYPE unsigned long int +-# define __S64_TYPE __quad_t +-# define __U64_TYPE __u_quad_t ++# define __S64_TYPE __int64_t ++# define __U64_TYPE __uint64_t + /* We want __extension__ before typedef's that use nonstandard base types + such as `long long' in C89 mode. */ + # define __STD_TYPE __extension__ typedef +diff --git a/posix/regexec.c b/posix/regexec.c +index 91d5a797b8..084b1222d9 100644 +--- a/posix/regexec.c ++++ b/posix/regexec.c +@@ -1293,8 +1293,10 @@ proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs, + else if (naccepted) + { + char *buf = (char *) re_string_get_buffer (&mctx->input); +- if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, +- naccepted) != 0) ++ if (mctx->input.valid_len - *pidx < naccepted ++ || (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, ++ naccepted) ++ != 0)) + return -1; + } + } +diff --git a/posix/sys/types.h b/posix/sys/types.h +index 27129c5c23..0e37b1ce6a 100644 +--- a/posix/sys/types.h ++++ b/posix/sys/types.h +@@ -154,37 +154,20 @@ typedef unsigned int uint; + + #include <bits/stdint-intn.h> + +-#if !__GNUC_PREREQ (2, 7) +- + /* These were defined by ISO C without the first `_'. */ +-typedef unsigned char u_int8_t; +-typedef unsigned short int u_int16_t; +-typedef unsigned int u_int32_t; +-# if __WORDSIZE == 64 +-typedef unsigned long int u_int64_t; +-# else +-__extension__ typedef unsigned long long int u_int64_t; +-# endif +- +-typedef int register_t; +- +-#else +- +-/* For GCC 2.7 and later, we can use specific type-size attributes. */ +-# define __u_intN_t(N, MODE) \ +- typedef unsigned int u_int##N##_t __attribute__ ((__mode__ (MODE))) +- +-__u_intN_t (8, __QI__); +-__u_intN_t (16, __HI__); +-__u_intN_t (32, __SI__); +-__u_intN_t (64, __DI__); ++typedef __uint8_t u_int8_t; ++typedef __uint16_t u_int16_t; ++typedef __uint32_t u_int32_t; ++typedef __uint64_t u_int64_t; + ++#if __GNUC_PREREQ (2, 7) + typedef int register_t __attribute__ ((__mode__ (__word__))); +- ++#else ++typedef int register_t; ++#endif + + /* Some code from BIND tests this macro to see if the types above are + defined. */ +-#endif + #define __BIT_TYPES_DEFINED__ 1 + + +diff --git a/scripts/check-installed-headers.sh b/scripts/check-installed-headers.sh +index 8e7beffd82..63bc8d4fa6 100644 +--- a/scripts/check-installed-headers.sh ++++ b/scripts/check-installed-headers.sh +@@ -16,11 +16,9 @@ + # License along with the GNU C Library; if not, see + # <http://www.gnu.org/licenses/>. + +-# Check installed headers for cleanliness. For each header, confirm +-# that it's possible to compile a file that includes that header and +-# does nothing else, in several different compilation modes. Also, +-# scan the header for a set of obsolete typedefs that should no longer +-# appear. ++# For each installed header, confirm that it's possible to compile a ++# file that includes that header and does nothing else, in several ++# different compilation modes. + + # These compilation switches assume GCC or compatible, which is probably + # fine since we also assume that when _building_ glibc. +@@ -31,13 +29,6 @@ cxx_modes="-std=c++98 -std=gnu++98 -std=c++11 -std=gnu++11" + # These are probably the most commonly used three. + lib_modes="-D_DEFAULT_SOURCE=1 -D_GNU_SOURCE=1 -D_XOPEN_SOURCE=700" + +-# sys/types.h+bits/types.h have to define the obsolete types. +-# rpc(svc)/* have the obsolete types too deeply embedded in their API +-# to remove. +-skip_obsolete_type_check='*/sys/types.h|*/bits/types.h|*/rpc/*|*/rpcsvc/*' +-obsolete_type_re=\ +-'\<((__)?(quad_t|u(short|int|long|_(char|short|int([0-9]+_t)?|long|quad_t))))\>' +- + if [ $# -lt 3 ]; then + echo "usage: $0 c|c++ \"compile command\" header header header..." >&2 + exit 2 +@@ -46,14 +37,10 @@ case "$1" in + (c) + lang_modes="$c_modes" + cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.c) +- already="$skip_obsolete_type_check" + ;; + (c++) + lang_modes="$cxx_modes" + cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.cc) +- # The obsolete-type check can be skipped for C++; it is +- # sufficient to do it for C. +- already="*" + ;; + (*) + echo "usage: $0 c|c++ \"compile command\" header header header..." >&2 +@@ -151,22 +138,8 @@ $expanded_lib_mode + int avoid_empty_translation_unit; + EOF + if $cc_cmd -fsyntax-only $lang_mode "$cih_test_c" 2>&1 +- then +- includes=$($cc_cmd -fsyntax-only -H $lang_mode \ +- "$cih_test_c" 2>&1 | sed -ne 's/^[.][.]* //p') +- for h in $includes; do +- # Don't repeat work. +- eval 'case "$h" in ('"$already"') continue;; esac' +- +- if grep -qE "$obsolete_type_re" "$h"; then +- echo "*** Obsolete types detected:" +- grep -HE "$obsolete_type_re" "$h" +- failed=1 +- fi +- already="$already|$h" +- done +- else +- failed=1 ++ then : ++ else failed=1 + fi + done + done +diff --git a/scripts/check-obsolete-constructs.py b/scripts/check-obsolete-constructs.py +new file mode 100755 +index 0000000000..ce5c72251f +--- /dev/null ++++ b/scripts/check-obsolete-constructs.py +@@ -0,0 +1,466 @@ ++#! /usr/bin/python3 ++# Copyright (C) 2019 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 ++# <http://www.gnu.org/licenses/>. ++ ++"""Verifies that installed headers do not use any obsolete constructs: ++ * legacy BSD typedefs superseded by <stdint.h>: ++ ushort uint ulong u_char u_short u_int u_long u_intNN_t quad_t u_quad_t ++ (sys/types.h is allowed to _define_ these types, but not to use them ++ to define anything else). ++""" ++ ++import argparse ++import collections ++import re ++import sys ++ ++# Simplified lexical analyzer for C preprocessing tokens. ++# Does not implement trigraphs. ++# Does not implement backslash-newline in the middle of any lexical ++# item other than a string literal. ++# Does not implement universal-character-names in identifiers. ++# Treats prefixed strings (e.g. L"...") as two tokens (L and "...") ++# Accepts non-ASCII characters only within comments and strings. ++ ++# Caution: The order of the outermost alternation matters. ++# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST, ++# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must ++# be last. ++# Caution: There should be no capturing groups other than the named ++# captures in the outermost alternation. ++ ++# For reference, these are all of the C punctuators as of C11: ++# [ ] ( ) { } , ; ? ~ ++# ! != * *= / /= ^ ^= = == ++# # ## ++# % %= %> %: %:%: ++# & &= && ++# | |= || ++# + += ++ ++# - -= -- -> ++# . ... ++# : :> ++# < <% <: << <<= <= ++# > >= >> >>= ++ ++# The BAD_* tokens are not part of the official definition of pp-tokens; ++# they match unclosed strings, character constants, and block comments, ++# so that the regex engine doesn't have to backtrack all the way to the ++# beginning of a broken construct and then emit dozens of junk tokens. ++ ++PP_TOKEN_RE_ = re.compile(r""" ++ (?P<STRING> \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\") ++ |(?P<BAD_STRING> \"(?:[^\"\\\r\n]|\\[ -~])*) ++ |(?P<CHARCONST> \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\') ++ |(?P<BAD_CHARCONST> \'(?:[^\'\\\r\n]|\\[ -~])*) ++ |(?P<BLOCK_COMMENT> /\*(?:\*(?!/)|[^*])*\*/) ++ |(?P<BAD_BLOCK_COM> /\*(?:\*(?!/)|[^*])*\*?) ++ |(?P<LINE_COMMENT> //[^\r\n]*) ++ |(?P<IDENT> [_a-zA-Z][_a-zA-Z0-9]*) ++ |(?P<PP_NUMBER> \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*) ++ |(?P<PUNCTUATOR> ++ [,;?~(){}\[\]] ++ | [!*/^=]=? ++ | \#\#? ++ | %(?:[=>]|:(?:%:)?)? ++ | &[=&]? ++ |\|[=|]? ++ |\+[=+]? ++ | -[=->]? ++ |\.(?:\.\.)? ++ | :>? ++ | <(?:[%:]|<(?:=|<=?)?)? ++ | >(?:=|>=?)?) ++ |(?P<ESCNL> \\(?:\r|\n|\r\n)) ++ |(?P<WHITESPACE> [ \t\n\r\v\f]+) ++ |(?P<OTHER> .) ++""", re.DOTALL | re.VERBOSE) ++ ++HEADER_NAME_RE_ = re.compile(r""" ++ < [^>\r\n]+ > ++ | " [^"\r\n]+ " ++""", re.DOTALL | re.VERBOSE) ++ ++ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""") ++ ++# based on the sample code in the Python re documentation ++Token_ = collections.namedtuple("Token", ( ++ "kind", "text", "line", "column", "context")) ++Token_.__doc__ = """ ++ One C preprocessing token, comment, or chunk of whitespace. ++ 'kind' identifies the token type, which will be one of: ++ STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT, ++ PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME, ++ or OTHER. The BAD_* alternatives in PP_TOKEN_RE_ are ++ handled within tokenize_c, below. ++ ++ 'text' is the sequence of source characters making up the token; ++ no decoding whatsoever is performed. ++ ++ 'line' and 'column' give the position of the first character of the ++ token within the source file. They are both 1-based. ++ ++ 'context' indicates whether or not this token occurred within a ++ preprocessing directive; it will be None for running text, ++ '<null>' for the leading '#' of a directive line (because '#' ++ all by itself on a line is a "null directive"), or the name of ++ the directive for tokens within a directive line, starting with ++ the IDENT for the name itself. ++""" ++ ++def tokenize_c(file_contents, reporter): ++ """Yield a series of Token objects, one for each preprocessing ++ token, comment, or chunk of whitespace within FILE_CONTENTS. ++ The REPORTER object is expected to have one method, ++ reporter.error(token, message), which will be called to ++ indicate a lexical error at the position of TOKEN. ++ If MESSAGE contains the four-character sequence '{!r}', that ++ is expected to be replaced by repr(token.text). ++ """ ++ ++ Token = Token_ ++ PP_TOKEN_RE = PP_TOKEN_RE_ ++ ENDLINE_RE = ENDLINE_RE_ ++ HEADER_NAME_RE = HEADER_NAME_RE_ ++ ++ line_num = 1 ++ line_start = 0 ++ pos = 0 ++ limit = len(file_contents) ++ directive = None ++ at_bol = True ++ while pos < limit: ++ if directive == "include": ++ mo = HEADER_NAME_RE.match(file_contents, pos) ++ if mo: ++ kind = "HEADER_NAME" ++ directive = "after_include" ++ else: ++ mo = PP_TOKEN_RE.match(file_contents, pos) ++ kind = mo.lastgroup ++ if kind != "WHITESPACE": ++ directive = "after_include" ++ else: ++ mo = PP_TOKEN_RE.match(file_contents, pos) ++ kind = mo.lastgroup ++ ++ text = mo.group() ++ line = line_num ++ column = mo.start() - line_start ++ adj_line_start = 0 ++ # only these kinds can contain a newline ++ if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT", ++ "STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"): ++ for tmo in ENDLINE_RE.finditer(text): ++ line_num += 1 ++ adj_line_start = tmo.end() ++ if adj_line_start: ++ line_start = mo.start() + adj_line_start ++ ++ # Track whether or not we are scanning a preprocessing directive. ++ if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start): ++ at_bol = True ++ directive = None ++ else: ++ if kind == "PUNCTUATOR" and text == "#" and at_bol: ++ directive = "<null>" ++ elif kind == "IDENT" and directive == "<null>": ++ directive = text ++ at_bol = False ++ ++ # Report ill-formed tokens and rewrite them as their well-formed ++ # equivalents, so downstream processing doesn't have to know about them. ++ # (Rewriting instead of discarding provides better error recovery.) ++ if kind == "BAD_BLOCK_COM": ++ reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""), ++ "unclosed block comment") ++ text += "*/" ++ kind = "BLOCK_COMMENT" ++ elif kind == "BAD_STRING": ++ reporter.error(Token("BAD_STRING", "", line, column+1, ""), ++ "unclosed string") ++ text += "\"" ++ kind = "STRING" ++ elif kind == "BAD_CHARCONST": ++ reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""), ++ "unclosed char constant") ++ text += "'" ++ kind = "CHARCONST" ++ ++ tok = Token(kind, text, line, column+1, ++ "include" if directive == "after_include" else directive) ++ # Do not complain about OTHER tokens inside macro definitions. ++ # $ and @ appear in macros defined by headers intended to be ++ # included from assembly language, e.g. sysdeps/mips/sys/asm.h. ++ if kind == "OTHER" and directive != "define": ++ self.error(tok, "stray {!r} in program") ++ ++ yield tok ++ pos = mo.end() ++ ++# ++# Base and generic classes for individual checks. ++# ++ ++class ConstructChecker: ++ """Scan a stream of C preprocessing tokens and possibly report ++ problems with them. The REPORTER object passed to __init__ has ++ one method, reporter.error(token, message), which should be ++ called to indicate a problem detected at the position of TOKEN. ++ If MESSAGE contains the four-character sequence '{!r}' then that ++ will be replaced with a textual representation of TOKEN. ++ """ ++ def __init__(self, reporter): ++ self.reporter = reporter ++ ++ def examine(self, tok): ++ """Called once for each token in a header file. ++ Call self.reporter.error if a problem is detected. ++ """ ++ raise NotImplementedError ++ ++ def eof(self): ++ """Called once at the end of the stream. Subclasses need only ++ override this if it might have something to do.""" ++ pass ++ ++class NoCheck(ConstructChecker): ++ """Generic checker class which doesn't do anything. Substitute this ++ class for a real checker when a particular check should be skipped ++ for some file.""" ++ ++ def examine(self, tok): ++ pass ++ ++# ++# Check for obsolete type names. ++# ++ ++# The obsolete type names we're looking for: ++OBSOLETE_TYPE_RE_ = re.compile(r"""\A ++ (__)? ++ ( quad_t ++ | u(?: short | int | long ++ | _(?: char | short | int(?:[0-9]+_t)? | long | quad_t ))) ++\Z""", re.VERBOSE) ++ ++class ObsoleteNotAllowed(ConstructChecker): ++ """Don't allow any use of the obsolete typedefs.""" ++ def examine(self, tok): ++ if OBSOLETE_TYPE_RE_.match(tok.text): ++ self.reporter.error(tok, "use of {!r}") ++ ++class ObsoletePrivateDefinitionsAllowed(ConstructChecker): ++ """Allow definitions of the private versions of the ++ obsolete typedefs; that is, 'typedef [anything] __obsolete;' ++ """ ++ def __init__(self, reporter): ++ super().__init__(reporter) ++ self.in_typedef = False ++ self.prev_token = None ++ ++ def examine(self, tok): ++ # bits/types.h hides 'typedef' in a macro sometimes. ++ if (tok.kind == "IDENT" ++ and tok.text in ("typedef", "__STD_TYPE") ++ and tok.context is None): ++ self.in_typedef = True ++ elif tok.kind == "PUNCTUATOR" and tok.text == ";" and self.in_typedef: ++ self.in_typedef = False ++ if self.prev_token.kind == "IDENT": ++ m = OBSOLETE_TYPE_RE_.match(self.prev_token.text) ++ if m and m.group(1) != "__": ++ self.reporter.error(self.prev_token, "use of {!r}") ++ self.prev_token = None ++ else: ++ self._check_prev() ++ ++ self.prev_token = tok ++ ++ def eof(self): ++ self._check_prev() ++ ++ def _check_prev(self): ++ if (self.prev_token is not None ++ and self.prev_token.kind == "IDENT" ++ and OBSOLETE_TYPE_RE_.match(self.prev_token.text)): ++ self.reporter.error(self.prev_token, "use of {!r}") ++ ++class ObsoletePublicDefinitionsAllowed(ConstructChecker): ++ """Allow definitions of the public versions of the obsolete ++ typedefs. Only specific forms of definition are allowed: ++ ++ typedef __obsolete obsolete; // identifiers must agree ++ typedef __uintN_t u_intN_t; // N must agree ++ typedef unsigned long int ulong; ++ typedef unsigned short int ushort; ++ typedef unsigned int uint; ++ """ ++ def __init__(self, reporter): ++ super().__init__(reporter) ++ self.typedef_tokens = [] ++ ++ def examine(self, tok): ++ if tok.kind in ("WHITESPACE", "BLOCK_COMMENT", ++ "LINE_COMMENT", "NL", "ESCNL"): ++ pass ++ ++ elif (tok.kind == "IDENT" and tok.text == "typedef" ++ and tok.context is None): ++ if self.typedef_tokens: ++ self.reporter.error(tok, "typedef inside typedef") ++ self._reset() ++ self.typedef_tokens.append(tok) ++ ++ elif tok.kind == "PUNCTUATOR" and tok.text == ";": ++ self._finish() ++ ++ elif self.typedef_tokens: ++ self.typedef_tokens.append(tok) ++ ++ def eof(self): ++ self._reset() ++ ++ def _reset(self): ++ while self.typedef_tokens: ++ tok = self.typedef_tokens.pop(0) ++ if tok.kind == "IDENT" and OBSOLETE_TYPE_RE_.match(tok.text): ++ self.reporter.error(tok, "use of {!r}") ++ ++ def _finish(self): ++ if not self.typedef_tokens: return ++ if self.typedef_tokens[-1].kind == "IDENT": ++ m = OBSOLETE_TYPE_RE_.match(self.typedef_tokens[-1].text) ++ if m: ++ if self._permissible_public_definition(m): ++ self.typedef_tokens.clear() ++ self._reset() ++ ++ def _permissible_public_definition(self, m): ++ if m.group(1) == "__": return False ++ name = m.group(2) ++ toks = self.typedef_tokens ++ ntok = len(toks) ++ if ntok == 3 and toks[1].kind == "IDENT": ++ defn = toks[1].text ++ n = OBSOLETE_TYPE_RE_.match(defn) ++ if n and n.group(1) == "__" and n.group(2) == name: ++ return True ++ ++ if (name[:5] == "u_int" and name[-2:] == "_t" ++ and defn[:6] == "__uint" and defn[-2:] == "_t" ++ and name[5:-2] == defn[6:-2]): ++ return True ++ ++ return False ++ ++ if (name == "ulong" and ntok == 5 ++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned" ++ and toks[2].kind == "IDENT" and toks[2].text == "long" ++ and toks[3].kind == "IDENT" and toks[3].text == "int"): ++ return True ++ ++ if (name == "ushort" and ntok == 5 ++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned" ++ and toks[2].kind == "IDENT" and toks[2].text == "short" ++ and toks[3].kind == "IDENT" and toks[3].text == "int"): ++ return True ++ ++ if (name == "uint" and ntok == 4 ++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned" ++ and toks[2].kind == "IDENT" and toks[2].text == "int"): ++ return True ++ ++ return False ++ ++def ObsoleteTypedefChecker(reporter, fname): ++ """Factory: produce an instance of the appropriate ++ obsolete-typedef checker for FNAME.""" ++ ++ # The obsolete rpc/ and rpcsvc/ headers are allowed to use the ++ # obsolete types, because it would be more trouble than it's ++ # worth to remove them from headers that we intend to stop ++ # installing eventually anyway. ++ if (fname.startswith("rpc/") ++ or fname.startswith("rpcsvc/") ++ or "/rpc/" in fname ++ or "/rpcsvc/" in fname): ++ return NoCheck(reporter) ++ ++ # bits/types.h is allowed to define the __-versions of the ++ # obsolete types. ++ if (fname == "bits/types.h" ++ or fname.endswith("/bits/types.h")): ++ return ObsoletePrivateDefinitionsAllowed(reporter) ++ ++ # sys/types.h is allowed to use the __-versions of the ++ # obsolete types, but only to define the unprefixed versions. ++ if (fname == "sys/types.h" ++ or fname.endswith("/sys/types.h")): ++ return ObsoletePublicDefinitionsAllowed(reporter) ++ ++ return ObsoleteNotAllowed(reporter) ++ ++# ++# Master control ++# ++ ++class HeaderChecker: ++ """Perform all of the checks on each header. This is also the ++ "reporter" object expected by tokenize_c and ConstructChecker. ++ """ ++ def __init__(self): ++ self.fname = None ++ self.status = 0 ++ ++ def error(self, tok, message): ++ self.status = 1 ++ if '{!r}' in message: ++ message = message.format(tok.text) ++ sys.stderr.write("{}:{}:{}: error: {}\n".format( ++ self.fname, tok.line, tok.column, message)) ++ ++ def check(self, fname): ++ self.fname = fname ++ try: ++ with open(fname, "rt") as fp: ++ contents = fp.read() ++ except OSError as e: ++ sys.stderr.write("{}: {}\n".format(fname, e.strerror)) ++ self.status = 1 ++ return ++ ++ typedef_checker = ObsoleteTypedefChecker(self, self.fname) ++ ++ for tok in tokenize_c(contents, self): ++ typedef_checker.examine(tok) ++ ++def main(): ++ ap = argparse.ArgumentParser(description=__doc__) ++ ap.add_argument("headers", metavar="header", nargs="+", ++ help="one or more headers to scan for obsolete constructs") ++ args = ap.parse_args() ++ ++ checker = HeaderChecker() ++ for fname in args.headers: ++ # Headers whose installed name begins with "finclude/" contain ++ # Fortran, not C, and this program should completely ignore them. ++ if not (fname.startswith("finclude/") or "/finclude/" in fname): ++ checker.check(fname) ++ sys.exit(checker.status) ++ ++main() +diff --git a/support/Makefile b/support/Makefile +index 432cf2fe6c..8d61de6c57 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -63,6 +63,7 @@ libsupport-routines = \ + support_record_failure \ + support_run_diff \ + support_shared_allocate \ ++ support_subprocess \ + support_test_compare_blob \ + support_test_compare_failure \ + support_test_compare_string \ +@@ -129,6 +130,7 @@ libsupport-routines = \ + xpthread_mutexattr_settype \ + xpthread_once \ + xpthread_rwlock_init \ ++ xpthread_rwlock_destroy \ + xpthread_rwlock_rdlock \ + xpthread_rwlock_unlock \ + xpthread_rwlock_wrlock \ +@@ -147,6 +149,9 @@ libsupport-routines = \ + xsignal \ + xsigstack \ + xsocket \ ++ xposix_spawn \ ++ xposix_spawn_file_actions_addclose \ ++ xposix_spawn_file_actions_adddup2 \ + xstrdup \ + xstrndup \ + xsymlink \ +@@ -222,4 +227,6 @@ endif + + $(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so + ++tst-support_capture_subprocess-ARGS = -- $(host-test-program-cmd) ++ + include ../Rules +diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h +index 2dce42e3a3..2832cfc635 100644 +--- a/support/capture_subprocess.h ++++ b/support/capture_subprocess.h +@@ -35,6 +35,12 @@ struct support_capture_subprocess + struct support_capture_subprocess support_capture_subprocess + (void (*callback) (void *), void *closure); + ++/* Issue FILE with ARGV arguments by using posix_spawn and capture standard ++ output, standard error, and the exit status. The out.buffer and err.buffer ++ are handle as support_capture_subprocess. */ ++struct support_capture_subprocess support_capture_subprogram ++ (const char *file, char *const argv[]); ++ + /* Deallocate the subprocess data captured by + support_capture_subprocess. */ + void support_capture_subprocess_free (struct support_capture_subprocess *); +diff --git a/support/subprocess.h b/support/subprocess.h +new file mode 100644 +index 0000000000..c031878d94 +--- /dev/null ++++ b/support/subprocess.h +@@ -0,0 +1,49 @@ ++/* Create a subprocess. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_SUBPROCESS_H ++#define SUPPORT_SUBPROCESS_H ++ ++#include <sys/types.h> ++ ++struct support_subprocess ++{ ++ int stdout_pipe[2]; ++ int stderr_pipe[2]; ++ pid_t pid; ++}; ++ ++/* Invoke CALLBACK (CLOSURE) in a subprocess created with fork and return ++ its PID, a pipe redirected to STDOUT, and a pipe redirected to STDERR. */ ++struct support_subprocess support_subprocess ++ (void (*callback) (void *), void *closure); ++ ++/* Issue FILE with ARGV arguments by using posix_spawn and return is PID, a ++ pipe redirected to STDOUT, and a pipe redirected to STDERR. */ ++struct support_subprocess support_subprogram ++ (const char *file, char *const argv[]); ++ ++/* Wait for the subprocess indicated by PROC::PID. Return the status ++ indicate by waitpid call. */ ++int support_process_wait (struct support_subprocess *proc); ++ ++/* Terminate the subprocess indicated by PROC::PID, first with a SIGTERM and ++ then with a SIGKILL. Return the status as for waitpid call. */ ++int support_process_terminate (struct support_subprocess *proc); ++ ++#endif +diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c +index 167514faf1..948ce5a0c6 100644 +--- a/support/support_capture_subprocess.c ++++ b/support/support_capture_subprocess.c +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + ++#include <support/subprocess.h> + #include <support/capture_subprocess.h> + + #include <errno.h> +@@ -23,6 +24,7 @@ + #include <support/check.h> + #include <support/xunistd.h> + #include <support/xsocket.h> ++#include <support/xspawn.h> + + static void + transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) +@@ -50,59 +52,53 @@ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) + } + } + +-struct support_capture_subprocess +-support_capture_subprocess (void (*callback) (void *), void *closure) ++static void ++support_capture_poll (struct support_capture_subprocess *result, ++ struct support_subprocess *proc) + { +- struct support_capture_subprocess result; +- xopen_memstream (&result.out); +- xopen_memstream (&result.err); +- +- int stdout_pipe[2]; +- xpipe (stdout_pipe); +- TEST_VERIFY (stdout_pipe[0] > STDERR_FILENO); +- TEST_VERIFY (stdout_pipe[1] > STDERR_FILENO); +- int stderr_pipe[2]; +- xpipe (stderr_pipe); +- TEST_VERIFY (stderr_pipe[0] > STDERR_FILENO); +- TEST_VERIFY (stderr_pipe[1] > STDERR_FILENO); +- +- TEST_VERIFY (fflush (stdout) == 0); +- TEST_VERIFY (fflush (stderr) == 0); +- +- pid_t pid = xfork (); +- if (pid == 0) +- { +- xclose (stdout_pipe[0]); +- xclose (stderr_pipe[0]); +- xdup2 (stdout_pipe[1], STDOUT_FILENO); +- xdup2 (stderr_pipe[1], STDERR_FILENO); +- xclose (stdout_pipe[1]); +- xclose (stderr_pipe[1]); +- callback (closure); +- _exit (0); +- } +- xclose (stdout_pipe[1]); +- xclose (stderr_pipe[1]); +- + struct pollfd fds[2] = + { +- { .fd = stdout_pipe[0], .events = POLLIN }, +- { .fd = stderr_pipe[0], .events = POLLIN }, ++ { .fd = proc->stdout_pipe[0], .events = POLLIN }, ++ { .fd = proc->stderr_pipe[0], .events = POLLIN }, + }; + + do + { + xpoll (fds, 2, -1); +- transfer ("stdout", &fds[0], &result.out); +- transfer ("stderr", &fds[1], &result.err); ++ transfer ("stdout", &fds[0], &result->out); ++ transfer ("stderr", &fds[1], &result->err); + } + while (fds[0].events != 0 || fds[1].events != 0); +- xclose (stdout_pipe[0]); +- xclose (stderr_pipe[0]); + +- xfclose_memstream (&result.out); +- xfclose_memstream (&result.err); +- xwaitpid (pid, &result.status, 0); ++ xfclose_memstream (&result->out); ++ xfclose_memstream (&result->err); ++ ++ result->status = support_process_wait (proc); ++} ++ ++struct support_capture_subprocess ++support_capture_subprocess (void (*callback) (void *), void *closure) ++{ ++ struct support_capture_subprocess result; ++ xopen_memstream (&result.out); ++ xopen_memstream (&result.err); ++ ++ struct support_subprocess proc = support_subprocess (callback, closure); ++ ++ support_capture_poll (&result, &proc); ++ return result; ++} ++ ++struct support_capture_subprocess ++support_capture_subprogram (const char *file, char *const argv[]) ++{ ++ struct support_capture_subprocess result; ++ xopen_memstream (&result.out); ++ xopen_memstream (&result.err); ++ ++ struct support_subprocess proc = support_subprogram (file, argv); ++ ++ support_capture_poll (&result, &proc); + return result; + } + +diff --git a/support/support_subprocess.c b/support/support_subprocess.c +new file mode 100644 +index 0000000000..0c8cc6af30 +--- /dev/null ++++ b/support/support_subprocess.c +@@ -0,0 +1,152 @@ ++/* Create subprocess. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <stdio.h> ++#include <signal.h> ++#include <time.h> ++#include <sys/wait.h> ++#include <stdbool.h> ++#include <support/xspawn.h> ++#include <support/check.h> ++#include <support/xunistd.h> ++#include <support/subprocess.h> ++ ++static struct support_subprocess ++support_suprocess_init (void) ++{ ++ struct support_subprocess result; ++ ++ xpipe (result.stdout_pipe); ++ TEST_VERIFY (result.stdout_pipe[0] > STDERR_FILENO); ++ TEST_VERIFY (result.stdout_pipe[1] > STDERR_FILENO); ++ ++ xpipe (result.stderr_pipe); ++ TEST_VERIFY (result.stderr_pipe[0] > STDERR_FILENO); ++ TEST_VERIFY (result.stderr_pipe[1] > STDERR_FILENO); ++ ++ TEST_VERIFY (fflush (stdout) == 0); ++ TEST_VERIFY (fflush (stderr) == 0); ++ ++ return result; ++} ++ ++struct support_subprocess ++support_subprocess (void (*callback) (void *), void *closure) ++{ ++ struct support_subprocess result = support_suprocess_init (); ++ ++ result.pid = xfork (); ++ if (result.pid == 0) ++ { ++ xclose (result.stdout_pipe[0]); ++ xclose (result.stderr_pipe[0]); ++ xdup2 (result.stdout_pipe[1], STDOUT_FILENO); ++ xdup2 (result.stderr_pipe[1], STDERR_FILENO); ++ xclose (result.stdout_pipe[1]); ++ xclose (result.stderr_pipe[1]); ++ callback (closure); ++ _exit (0); ++ } ++ xclose (result.stdout_pipe[1]); ++ xclose (result.stderr_pipe[1]); ++ ++ return result; ++} ++ ++struct support_subprocess ++support_subprogram (const char *file, char *const argv[]) ++{ ++ struct support_subprocess result = support_suprocess_init (); ++ ++ posix_spawn_file_actions_t fa; ++ /* posix_spawn_file_actions_init does not fail. */ ++ posix_spawn_file_actions_init (&fa); ++ ++ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[0]); ++ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[0]); ++ xposix_spawn_file_actions_adddup2 (&fa, result.stdout_pipe[1], STDOUT_FILENO); ++ xposix_spawn_file_actions_adddup2 (&fa, result.stderr_pipe[1], STDERR_FILENO); ++ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]); ++ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]); ++ ++ result.pid = xposix_spawn (file, &fa, NULL, argv, NULL); ++ ++ xclose (result.stdout_pipe[1]); ++ xclose (result.stderr_pipe[1]); ++ ++ return result; ++} ++ ++int ++support_process_wait (struct support_subprocess *proc) ++{ ++ xclose (proc->stdout_pipe[0]); ++ xclose (proc->stderr_pipe[0]); ++ ++ int status; ++ xwaitpid (proc->pid, &status, 0); ++ return status; ++} ++ ++ ++static bool ++support_process_kill (int pid, int signo, int *status) ++{ ++ /* Kill the whole process group. */ ++ kill (-pid, signo); ++ /* In case setpgid failed in the child, kill it individually too. */ ++ kill (pid, signo); ++ ++ /* Wait for it to terminate. */ ++ pid_t killed; ++ for (int i = 0; i < 5; ++i) ++ { ++ int status; ++ killed = xwaitpid (pid, &status, WNOHANG|WUNTRACED); ++ if (killed != 0) ++ break; ++ ++ /* Delay, give the system time to process the kill. If the ++ nanosleep() call return prematurely, all the better. We ++ won't restart it since this probably means the child process ++ finally died. */ ++ nanosleep (&((struct timespec) { 0, 100000000 }), NULL); ++ } ++ if (killed != 0 && killed != pid) ++ return false; ++ ++ return true; ++} ++ ++int ++support_process_terminate (struct support_subprocess *proc) ++{ ++ xclose (proc->stdout_pipe[0]); ++ xclose (proc->stderr_pipe[0]); ++ ++ int status; ++ pid_t killed = xwaitpid (proc->pid, &status, WNOHANG|WUNTRACED); ++ if (killed != 0 && killed == proc->pid) ++ return status; ++ ++ /* Subprocess is still running, terminate it. */ ++ if (!support_process_kill (proc->pid, SIGTERM, &status) ) ++ support_process_kill (proc->pid, SIGKILL, &status); ++ ++ return status; ++} +diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c +index d8ba42ea8b..ab363e41ac 100644 +--- a/support/tst-support_capture_subprocess.c ++++ b/support/tst-support_capture_subprocess.c +@@ -23,8 +23,20 @@ + #include <support/capture_subprocess.h> + #include <support/check.h> + #include <support/support.h> ++#include <support/temp_file.h> + #include <sys/wait.h> + #include <unistd.h> ++#include <paths.h> ++#include <getopt.h> ++#include <limits.h> ++#include <errno.h> ++#include <array_length.h> ++ ++/* Nonzero if the program gets called via 'exec'. */ ++static int restart; ++ ++/* Hold the four initial argument used to respawn the process. */ ++static char *initial_argv[5]; + + /* Write one byte at *P to FD and advance *P. Do nothing if *P is + '\0'. */ +@@ -42,6 +54,30 @@ transfer (const unsigned char **p, int fd) + enum write_mode { out_first, err_first, interleave, + write_mode_last = interleave }; + ++static const char * ++write_mode_to_str (enum write_mode mode) ++{ ++ switch (mode) ++ { ++ case out_first: return "out_first"; ++ case err_first: return "err_first"; ++ case interleave: return "interleave"; ++ default: return "write_mode_last"; ++ } ++} ++ ++static enum write_mode ++str_to_write_mode (const char *mode) ++{ ++ if (strcmp (mode, "out_first") == 0) ++ return out_first; ++ else if (strcmp (mode, "err_first") == 0) ++ return err_first; ++ else if (strcmp (mode, "interleave") == 0) ++ return interleave; ++ return write_mode_last; ++} ++ + /* Describe what to write in the subprocess. */ + struct test + { +@@ -52,11 +88,9 @@ struct test + int status; + }; + +-/* For use with support_capture_subprocess. */ +-static void +-callback (void *closure) ++_Noreturn static void ++test_common (const struct test *test) + { +- const struct test *test = closure; + bool mode_ok = false; + switch (test->write_mode) + { +@@ -95,6 +129,40 @@ callback (void *closure) + exit (test->status); + } + ++static int ++parse_int (const char *str) ++{ ++ char *endptr; ++ long int ret = strtol (str, &endptr, 10); ++ TEST_COMPARE (errno, 0); ++ TEST_VERIFY (ret >= 0 && ret <= INT_MAX); ++ return ret; ++} ++ ++/* For use with support_capture_subprogram. */ ++_Noreturn static void ++handle_restart (char *out, char *err, const char *write_mode, ++ const char *signal, const char *status) ++{ ++ struct test test = ++ { ++ out, ++ err, ++ str_to_write_mode (write_mode), ++ parse_int (signal), ++ parse_int (status) ++ }; ++ test_common (&test); ++} ++ ++/* For use with support_capture_subprocess. */ ++_Noreturn static void ++callback (void *closure) ++{ ++ const struct test *test = closure; ++ test_common (test); ++} ++ + /* Create a heap-allocated random string of letters. */ + static char * + random_string (size_t length) +@@ -130,12 +198,59 @@ check_stream (const char *what, const struct xmemstream *stream, + } + } + ++static struct support_capture_subprocess ++do_subprocess (struct test *test) ++{ ++ return support_capture_subprocess (callback, test); ++} ++ ++static struct support_capture_subprocess ++do_subprogram (const struct test *test) ++{ ++ /* Three digits per byte plus null terminator. */ ++ char signalstr[3 * sizeof(int) + 1]; ++ snprintf (signalstr, sizeof (signalstr), "%d", test->signal); ++ char statusstr[3 * sizeof(int) + 1]; ++ snprintf (statusstr, sizeof (statusstr), "%d", test->status); ++ ++ int argc = 0; ++ enum { ++ /* 4 elements from initial_argv (path to ld.so, '--library-path', the ++ path', and application name'), 2 for restart argument ('--direct', ++ '--restart'), 5 arguments plus NULL. */ ++ argv_size = 12 ++ }; ++ char *args[argv_size]; ++ ++ for (char **arg = initial_argv; *arg != NULL; arg++) ++ args[argc++] = *arg; ++ ++ args[argc++] = (char*) "--direct"; ++ args[argc++] = (char*) "--restart"; ++ ++ args[argc++] = test->out; ++ args[argc++] = test->err; ++ args[argc++] = (char*) write_mode_to_str (test->write_mode); ++ args[argc++] = signalstr; ++ args[argc++] = statusstr; ++ args[argc] = NULL; ++ TEST_VERIFY (argc < argv_size); ++ ++ return support_capture_subprogram (args[0], args); ++} ++ ++enum test_type ++{ ++ subprocess, ++ subprogram, ++}; ++ + static int +-do_test (void) ++do_multiple_tests (enum test_type type) + { + const int lengths[] = {0, 1, 17, 512, 20000, -1}; + +- /* Test multiple combinations of support_capture_subprocess. ++ /* Test multiple combinations of support_capture_sub{process,program}. + + length_idx_stdout: Index into the lengths array above, + controls how many bytes are written by the subprocess to +@@ -164,8 +279,10 @@ do_test (void) + TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]); + TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]); + +- struct support_capture_subprocess result +- = support_capture_subprocess (callback, &test); ++ struct support_capture_subprocess result ++ = type == subprocess ? do_subprocess (&test) ++ : do_subprogram (&test); ++ + check_stream ("stdout", &result.out, test.out); + check_stream ("stderr", &result.err, test.err); + +@@ -199,4 +316,54 @@ do_test (void) + return 0; + } + ++static int ++do_test (int argc, char *argv[]) ++{ ++ /* We must have either: ++ ++ - one or four parameters if called initially: ++ + argv[1]: path for ld.so optional ++ + argv[2]: "--library-path" optional ++ + argv[3]: the library path optional ++ + argv[4]: the application name ++ ++ - six parameters left if called through re-execution: ++ + argv[1]: the application name ++ + argv[2]: the stdout to print ++ + argv[3]: the stderr to print ++ + argv[4]: the write mode to use ++ + argv[5]: the signal to issue ++ + argv[6]: the exit status code to use ++ ++ * When built with --enable-hardcoded-path-in-tests or issued without ++ using the loader directly. ++ */ ++ ++ if (argc != (restart ? 6 : 5) && argc != (restart ? 6 : 2)) ++ FAIL_EXIT1 ("wrong number of arguments (%d)", argc); ++ ++ if (restart) ++ { ++ handle_restart (argv[1], /* stdout */ ++ argv[2], /* stderr */ ++ argv[3], /* write_mode */ ++ argv[4], /* signal */ ++ argv[5]); /* status */ ++ } ++ ++ initial_argv[0] = argv[1]; /* path for ld.so */ ++ initial_argv[1] = argv[2]; /* "--library-path" */ ++ initial_argv[2] = argv[3]; /* the library path */ ++ initial_argv[3] = argv[4]; /* the application name */ ++ initial_argv[4] = NULL; ++ ++ do_multiple_tests (subprocess); ++ do_multiple_tests (subprogram); ++ ++ return 0; ++} ++ ++#define CMDLINE_OPTIONS \ ++ { "restart", no_argument, &restart, 1 }, ++#define TEST_FUNCTION_ARGV do_test + #include <support/test-driver.c> +diff --git a/support/xposix_spawn.c b/support/xposix_spawn.c +new file mode 100644 +index 0000000000..e846017632 +--- /dev/null ++++ b/support/xposix_spawn.c +@@ -0,0 +1,32 @@ ++/* xposix_spawn implementation. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xspawn.h> ++#include <support/check.h> ++ ++pid_t ++xposix_spawn (const char *file, const posix_spawn_file_actions_t *fa, ++ const posix_spawnattr_t *attr, char *const args[], ++ char *const envp[]) ++{ ++ pid_t pid; ++ int status = posix_spawn (&pid, file, fa, attr, args, envp); ++ if (status != 0) ++ FAIL_EXIT1 ("posix_spawn to %s file failed: %m", file); ++ return pid; ++} +diff --git a/support/xposix_spawn_file_actions_addclose.c b/support/xposix_spawn_file_actions_addclose.c +new file mode 100644 +index 0000000000..eed54a6514 +--- /dev/null ++++ b/support/xposix_spawn_file_actions_addclose.c +@@ -0,0 +1,29 @@ ++/* xposix_spawn_file_actions_addclose implementation. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xspawn.h> ++#include <support/check.h> ++ ++int ++xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *fa, int fd) ++{ ++ int status = posix_spawn_file_actions_addclose (fa, fd); ++ if (status == -1) ++ FAIL_EXIT1 ("posix_spawn_file_actions_addclose failed: %m\n"); ++ return status; ++} +diff --git a/support/xposix_spawn_file_actions_adddup2.c b/support/xposix_spawn_file_actions_adddup2.c +new file mode 100644 +index 0000000000..a43b6490be +--- /dev/null ++++ b/support/xposix_spawn_file_actions_adddup2.c +@@ -0,0 +1,30 @@ ++/* xposix_spawn_file_actions_adddup2 implementation. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xspawn.h> ++#include <support/check.h> ++ ++int ++xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *fa, int fd, ++ int newfd) ++{ ++ int status = posix_spawn_file_actions_adddup2 (fa, fd, newfd); ++ if (status == -1) ++ FAIL_EXIT1 ("posix_spawn_file_actions_adddup2 failed: %m\n"); ++ return status; ++} +diff --git a/support/xpthread_rwlock_destroy.c b/support/xpthread_rwlock_destroy.c +new file mode 100644 +index 0000000000..6d6e953569 +--- /dev/null ++++ b/support/xpthread_rwlock_destroy.c +@@ -0,0 +1,26 @@ ++/* pthread_rwlock_destroy with error checking. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_rwlock_destroy (pthread_rwlock_t *rwlock) ++{ ++ xpthread_check_return ("pthread_rwlock_destroy", ++ pthread_rwlock_destroy (rwlock)); ++} +diff --git a/support/xspawn.h b/support/xspawn.h +new file mode 100644 +index 0000000000..bbf89132e4 +--- /dev/null ++++ b/support/xspawn.h +@@ -0,0 +1,34 @@ ++/* posix_spawn with support checks. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_XSPAWN_H ++#define SUPPORT_XSPAWN_H ++ ++#include <spawn.h> ++ ++__BEGIN_DECLS ++ ++int xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *, int); ++int xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *, int, int); ++ ++pid_t xposix_spawn (const char *, const posix_spawn_file_actions_t *, ++ const posix_spawnattr_t *, char *const [], char *const []); ++ ++__END_DECLS ++ ++#endif +diff --git a/support/xthread.h b/support/xthread.h +index 47c23235f3..9fe1f68b3b 100644 +--- a/support/xthread.h ++++ b/support/xthread.h +@@ -84,6 +84,7 @@ void xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref); + void xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock); + void xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock); + void xpthread_rwlock_unlock (pthread_rwlock_t *rwlock); ++void xpthread_rwlock_destroy (pthread_rwlock_t *rwlock); + + __END_DECLS + +diff --git a/sysdeps/arm/stap-probe-machine.h b/sysdeps/arm/stap-probe-machine.h +new file mode 100644 +index 0000000000..d27ca22040 +--- /dev/null ++++ b/sysdeps/arm/stap-probe-machine.h +@@ -0,0 +1,22 @@ ++/* Macros for customizing Systemtap <sys/sdt.h>. Arm version. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++/* The default "nor" constraint produces unparseable memory references ++ for constants. Omit the problematic "o" constraint. See bug 24164 ++ and GCC PR 89146. */ ++#define STAP_SDT_ARG_CONSTRAINT nr +diff --git a/sysdeps/generic/stap-probe-machine.h b/sysdeps/generic/stap-probe-machine.h +new file mode 100644 +index 0000000000..2e5790c3b2 +--- /dev/null ++++ b/sysdeps/generic/stap-probe-machine.h +@@ -0,0 +1,19 @@ ++/* Macros for customizing Systemtap <sys/sdt.h>. Generic version. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++/* By default, there are no customizations. */ +diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c +index bd68f18b45..14b69a6f89 100644 +--- a/sysdeps/nptl/fork.c ++++ b/sysdeps/nptl/fork.c +@@ -55,7 +55,7 @@ __libc_fork (void) + but our current fork implementation is not. */ + bool multiple_threads = THREAD_GETMEM (THREAD_SELF, header.multiple_threads); + +- __run_fork_handlers (atfork_run_prepare); ++ __run_fork_handlers (atfork_run_prepare, multiple_threads); + + /* If we are not running multiple threads, we do not have to + preserve lock state. If fork runs from a signal handler, only +@@ -134,7 +134,7 @@ __libc_fork (void) + __rtld_lock_initialize (GL(dl_load_lock)); + + /* Run the handlers registered for the child. */ +- __run_fork_handlers (atfork_run_child); ++ __run_fork_handlers (atfork_run_child, multiple_threads); + } + else + { +@@ -149,7 +149,7 @@ __libc_fork (void) + } + + /* Run the handlers registered for the parent. */ +- __run_fork_handlers (atfork_run_parent); ++ __run_fork_handlers (atfork_run_parent, multiple_threads); + } + + return pid; +diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h +index a1c3b26b68..99ed76034b 100644 +--- a/sysdeps/nptl/fork.h ++++ b/sysdeps/nptl/fork.h +@@ -52,9 +52,11 @@ enum __run_fork_handler_type + - atfork_run_child: run all the CHILD_HANDLER and unlocks the internal + lock. + - atfork_run_parent: run all the PARENT_HANDLER and unlocks the internal +- lock. */ +-extern void __run_fork_handlers (enum __run_fork_handler_type who) +- attribute_hidden; ++ lock. ++ ++ Perform locking only if DO_LOCKING. */ ++extern void __run_fork_handlers (enum __run_fork_handler_type who, ++ _Bool do_locking) attribute_hidden; + + /* C library side function to register new fork handlers. */ + extern int __register_atfork (void (*__prepare) (void), +diff --git a/sysdeps/powerpc/dl-procinfo.h b/sysdeps/powerpc/dl-procinfo.h +index f542f7318f..dfc3b33a72 100644 +--- a/sysdeps/powerpc/dl-procinfo.h ++++ b/sysdeps/powerpc/dl-procinfo.h +@@ -225,7 +225,7 @@ _dl_procinfo (unsigned int type, unsigned long int word) + break; + } + default: +- /* This should not happen. */ ++ /* Fallback to generic output mechanism. */ + return -1; + } + _dl_printf ("\n"); +diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +index b4b81fc70a..99697ae649 100644 +--- a/sysdeps/s390/dl-procinfo.h ++++ b/sysdeps/s390/dl-procinfo.h +@@ -57,7 +57,8 @@ enum + }; + + #define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \ +- | HWCAP_S390_EIMM | HWCAP_S390_DFP) ++ | HWCAP_S390_EIMM | HWCAP_S390_DFP \ ++ | HWCAP_S390_VX | HWCAP_S390_VXE) + + /* We cannot provide a general printing function. */ + #define _dl_procinfo(type, word) -1 +diff --git a/sysdeps/sparc/dl-procinfo.h b/sysdeps/sparc/dl-procinfo.h +index 282b8c5117..64ee267fc7 100644 +--- a/sysdeps/sparc/dl-procinfo.h ++++ b/sysdeps/sparc/dl-procinfo.h +@@ -31,8 +31,8 @@ _dl_procinfo (unsigned int type, unsigned long int word) + { + int i; + +- /* Fallback to unknown output mechanism. */ +- if (type == AT_HWCAP2) ++ /* Fallback to generic output mechanism. */ ++ if (type != AT_HWCAP) + return -1; + + _dl_printf ("AT_HWCAP: "); +diff --git a/sysdeps/unix/sysv/linux/arm/dl-procinfo.h b/sysdeps/unix/sysv/linux/arm/dl-procinfo.h +index 66c00297b7..05c62c8687 100644 +--- a/sysdeps/unix/sysv/linux/arm/dl-procinfo.h ++++ b/sysdeps/unix/sysv/linux/arm/dl-procinfo.h +@@ -67,7 +67,7 @@ _dl_procinfo (unsigned int type, unsigned long int word) + break; + } + default: +- /* This should not happen. */ ++ /* Fallback to generic output mechanism. */ + return -1; + } + _dl_printf ("\n"); +diff --git a/sysdeps/unix/sysv/linux/i386/dl-procinfo.h b/sysdeps/unix/sysv/linux/i386/dl-procinfo.h +index 22b43431bc..0585cdaa9c 100644 +--- a/sysdeps/unix/sysv/linux/i386/dl-procinfo.h ++++ b/sysdeps/unix/sysv/linux/i386/dl-procinfo.h +@@ -30,8 +30,8 @@ _dl_procinfo (unsigned int type, unsigned long int word) + in the kernel sources. */ + int i; + +- /* Fallback to unknown output mechanism. */ +- if (type == AT_HWCAP2) ++ /* Fallback to generic output mechanism. */ ++ if (type != AT_HWCAP) + return -1; + + _dl_printf ("AT_HWCAP: "); +diff --git a/sysdeps/unix/sysv/linux/s390/dl-procinfo.h b/sysdeps/unix/sysv/linux/s390/dl-procinfo.h +index 19329a335b..d67fde368f 100644 +--- a/sysdeps/unix/sysv/linux/s390/dl-procinfo.h ++++ b/sysdeps/unix/sysv/linux/s390/dl-procinfo.h +@@ -32,8 +32,8 @@ _dl_procinfo (unsigned int type, unsigned long int word) + in the kernel sources. */ + int i; + +- /* Fallback to unknown output mechanism. */ +- if (type == AT_HWCAP2) ++ /* Fallback to generic output mechanism. */ ++ if (type != AT_HWCAP) + return -1; + + _dl_printf ("AT_HWCAP: "); +diff --git a/sysdeps/x86_64/memcmp.S b/sysdeps/x86_64/memcmp.S +index 1fc487caa5..1322bb3b92 100644 +--- a/sysdeps/x86_64/memcmp.S ++++ b/sysdeps/x86_64/memcmp.S +@@ -21,14 +21,18 @@ + + .text + ENTRY (memcmp) +- test %rdx, %rdx ++#ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++#endif ++ test %RDX_LP, %RDX_LP + jz L(finz) + cmpq $1, %rdx +- jle L(finr1b) ++ jbe L(finr1b) + subq %rdi, %rsi + movq %rdx, %r10 + cmpq $32, %r10 +- jge L(gt32) ++ jae L(gt32) + /* Handle small chunks and last block of less than 32 bytes. */ + L(small): + testq $1, %r10 +@@ -156,7 +160,7 @@ L(A32): + movq %r11, %r10 + andq $-32, %r10 + cmpq %r10, %rdi +- jge L(mt16) ++ jae L(mt16) + /* Pre-unroll to be ready for unrolled 64B loop. */ + testq $32, %rdi + jz L(A64) +@@ -178,7 +182,7 @@ L(A64): + movq %r11, %r10 + andq $-64, %r10 + cmpq %r10, %rdi +- jge L(mt32) ++ jae L(mt32) + + L(A64main): + movdqu (%rdi,%rsi), %xmm0 +@@ -216,7 +220,7 @@ L(mt32): + movq %r11, %r10 + andq $-32, %r10 + cmpq %r10, %rdi +- jge L(mt16) ++ jae L(mt16) + + L(A32main): + movdqu (%rdi,%rsi), %xmm0 +@@ -254,7 +258,7 @@ L(ATR): + movq %r11, %r10 + andq $-32, %r10 + cmpq %r10, %rdi +- jge L(mt16) ++ jae L(mt16) + testq $16, %rdi + jz L(ATR32) + +@@ -325,7 +329,7 @@ L(ATR64main): + movq %r11, %r10 + andq $-32, %r10 + cmpq %r10, %rdi +- jge L(mt16) ++ jae L(mt16) + + L(ATR32res): + movdqa (%rdi,%rsi), %xmm0 +diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile +index 1557724b0c..8748956563 100644 +--- a/sysdeps/x86_64/x32/Makefile ++++ b/sysdeps/x86_64/x32/Makefile +@@ -8,7 +8,8 @@ endif + ifeq ($(subdir),string) + tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy \ + tst-size_t-memrchr tst-size_t-memset tst-size_t-strncasecmp \ +- tst-size_t-strncmp tst-size_t-strncpy tst-size_t-strnlen ++ tst-size_t-strncmp tst-size_t-strncpy tst-size_t-strnlen \ ++ tst-size_t-memcmp-2 + endif + + ifeq ($(subdir),wcsmbs) +diff --git a/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c b/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c +new file mode 100644 +index 0000000000..d8ae1a0813 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c +@@ -0,0 +1,79 @@ ++/* Test memcmp with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#define TEST_MAIN ++#ifdef WIDE ++# define TEST_NAME "wmemcmp" ++#else ++# define TEST_NAME "memcmp" ++#endif ++ ++#include "test-size_t.h" ++ ++#ifdef WIDE ++# include <inttypes.h> ++# include <wchar.h> ++ ++# define MEMCMP wmemcmp ++# define CHAR wchar_t ++#else ++# define MEMCMP memcmp ++# define CHAR char ++#endif ++ ++IMPL (MEMCMP, 1) ++ ++typedef int (*proto_t) (const CHAR *, const CHAR *, size_t); ++ ++static int ++__attribute__ ((noinline, noclone)) ++do_memcmp (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t dest = { { page_size / sizeof (CHAR) }, buf1 }; ++ parameter_t src = { { 0 }, buf2 }; ++ ++ memcpy (buf1, buf2, page_size); ++ ++ CHAR *p = (CHAR *) buf1; ++ p[page_size / sizeof (CHAR) - 1] = (CHAR) 1; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ int res = do_memcmp (dest, src); ++ if (res >= 0) ++ { ++ error (0, 0, "Wrong result in function %s: %i >= 0", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include <support/test-driver.c> diff --git a/glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch b/glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch deleted file mode 100644 index a80eacfd2c78..000000000000 --- a/glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch +++ /dev/null @@ -1,1798 +0,0 @@ -diff --git a/ChangeLog b/ChangeLog -index 08b42bd2f5..7f4c6a48bc 100644 ---- a/ChangeLog -+++ b/ChangeLog -@@ -1,3 +1,159 @@ -+2018-10-09 H.J. Lu <hongjiu.lu@intel.com> -+ -+ [BZ #23716] -+ * sysdeps/i386/dl-cet.c: Removed. -+ * sysdeps/i386/dl-machine.h (_dl_runtime_resolve_shstk): New -+ prototype. -+ (_dl_runtime_profile_shstk): Likewise. -+ (elf_machine_runtime_setup): Use _dl_runtime_profile_shstk or -+ _dl_runtime_resolve_shstk if SHSTK is enabled by kernel. -+ -+2018-10-09 Rafal Luzynski <digitalfreak@lingonborough.com> -+ -+ [BZ #20209] -+ * localedata/locales/kl_GL: (abday): Fix spelling of Sun (Sunday), -+ should be "sap" rather than "sab". -+ (day): Fix spelling of Sunday, should be "sapaat" rather than -+ "sabaat". -+ -+2018-09-28 Adhemerval Zanella <adhemerval.zanella@linaro.org> -+ -+ [BZ #23579] -+ * misc/tst-preadvwritev2-common.c (do_test_with_invalid_fd, -+ do_test_with_invalid_iov): New tests. -+ * misc/tst-preadvwritev2.c, misc/tst-preadvwritev64v2.c (do_test): -+ Call do_test_with_invalid_fd and do_test_with_invalid_iov. -+ * sysdeps/unix/sysv/linux/preadv2.c (preadv2): Use fallback code iff -+ errno is ENOSYS. -+ * sysdeps/unix/sysv/linux/preadv64v2.c (preadv64v2): Likewise. -+ * sysdeps/unix/sysv/linux/pwritev2.c (pwritev2): Likewise. -+ * sysdeps/unix/sysv/linux/pwritev64v2.c (pwritev64v2): Likewise. -+ * NEWS: Add bug fixed. -+ -+2018-09-27 Andreas Schwab <schwab@suse.de> -+ -+ [BZ #23717] -+ * stdlib/tst-setcontext9.c (f1a): Make st2 static. -+ (do_test): Make st1 static. -+ -+2018-09-21 H.J. Lu <hongjiu.lu@intel.com> -+ Xuepeng Guo <xuepeng.guo@intel.com> -+ -+ [BZ #23606] -+ * sysdeps/i386/start.S: Include <sysdep.h> -+ (_start): Use ENTRY/END to insert ENDBR32 at entry when CET is -+ enabled. Add cfi_undefined (eip). -+ -+2018-09-19 Wilco Dijkstra <wdijkstr@arm.com> -+ -+ [BZ #23637] -+ * string/test-strstr.c (pr23637): New function. -+ (test_main): Add tests with longer needles. -+ * string/strcasestr.c (AVAILABLE): Fix readahead distance. -+ * string/strstr.c (AVAILABLE): Likewise. -+ -+2018-09-19 Carlos O'Donell <carlos@redhat.com> -+ -+ * stdlib/tst-setcontext9.c (f1): Rename to... -+ (f1a): ... this. -+ (f1b): New function implementing lower half of f1 in alternate stack. -+ -+2018-09-20 Florian Weimer <fweimer@redhat.com> -+ -+ * misc/tst-gethostid.c: New file. -+ * misc/Makefile [$(build-shared)] (tests): Add tst-gethostid. -+ (tst-gethostid): Link with -ldl. -+ -+2018-09-20 Mingli Yu <Mingli.Yu@windriver.com> -+ -+ * sysdeps/unix/sysv/linux/gethostid.c (gethostid): Check for NULL -+ value from gethostbyname_r. -+ -+2018-09-06 Stefan Liebler <stli@linux.ibm.com> -+ -+ * sysdeps/unix/sysv/linux/spawni.c (maybe_script_execute): -+ Increment size of new_argv by one. -+ -+2018-08-28 Florian Weimer <fweimer@redhat.com> -+ -+ [BZ #23578] -+ * posix/tst-regcomp-truncated.c: New file. -+ * posix/Makefile (tests): Add it. -+ (tst-regcomp-truncated.out): Depend on generated locales. -+ -+2018-08-25 Paul Eggert <eggert@cs.ucla.edu> -+ -+ [BZ #23578] -+ regex: fix uninitialized memory access -+ I introduced this bug into gnulib in commit -+ 8335a4d6c7b4448cd0bcb6d0bebf1d456bcfdb17 dated 2006-04-10; -+ eventually it was merged into glibc. The bug was found by -+ project-repo <bugs@feusi.co> and reported here: -+ https://lists.gnu.org/r/sed-devel/2018-08/msg00017.html -+ Diagnosis and draft fix reported by Assaf Gordon here: -+ https://lists.gnu.org/r/bug-gnulib/2018-08/msg00071.html -+ https://lists.gnu.org/r/bug-gnulib/2018-08/msg00142.html -+ * posix/regex_internal.c (build_wcs_upper_buffer): -+ Fix bug when mbrtowc returns 0. -+ -+2018-08-27 Martin Kuchta <martin.kuchta@netapp.com> -+ Torvald Riegel <triegel@redhat.com> -+ -+ [BZ #23538] -+ * nptl/pthread_cond_common.c (__condvar_quiesce_and_switch_g1): -+ Update r to include the set wake-request flag if waiters are -+ remaining after spinning. -+ -+2018-08-03 DJ Delorie <dj@redhat.com> -+ -+ * sysdeps/riscv/rvf/math_private.h (libc_feholdexcept_setround_riscv): -+ Move libc_fesetround_riscv after libc_feholdexcept_riscv. -+ -+ * sysdeps/riscv/rv64/rvd/libm-test-ulps: Update. -+ -+2018-08-14 Florian Weimer <fweimer@redhat.com> -+ -+ [BZ #23521] -+ [BZ #23522] -+ * nss/nss_files/files-alias.c (get_next_alias): During :include: -+ processing, bail out if no room, and close the stream before -+ returning ERANGE. -+ * nss/Makefile (tests): Add tst-nss-files-alias-leak. -+ (tst-nss-files-alias-leak): Link with libdl. -+ (tst-nss-files-alias-leak.out): Depend on nss_files. -+ -+ * nss/tst-nss-files-alias-leak.c: New file. -+ -+2018-08-14 Florian Weimer <fweimer@redhat.com> -+ -+ * nscd/nscd_conf.c (nscd_parse_file): Deallocate old storage for -+ server_user, stat_user. -+ -+2018-08-13 Florian Weimer <fweimer@redhat.com> -+ -+ * misc/error.c (error): Add missing va_end call. -+ (error_at_line): Likewise. -+ -+2018-08-10 Florian Weimer <fweimer@redhat.com> -+ -+ [BZ #23497] -+ * sysdeps/unix/sysv/linux/getdents64.c (handle_overflow): New -+ function. -+ (__old_getdents64): Use getdents64. Convert entries without -+ moving them. -+ * sysdeps/unix/sysv/linux/tst-readdir64-compat.c: New file. -+ * sysdeps/unix/sysv/linux/Makefile (tests-internal): Add -+ tst-readdir64-compat. -+ -+2018-08-08 Samuel Thibault <samuel.thibault@ens-lyon.org> -+ -+ * htl/Versions (__pthread_getspecific, __pthread_setspecific): Add -+ symbols. -+ * sysdeps/htl/pthreadP.h [IS_IN (libpthread)] (__pthread_getspecific, -+ __pthread_setspecific): Add hidden proto. -+ * sysdeps/htl/pt-getspecific.c (__pthread_getspecific): Add hidden def. -+ * sysdeps/htl/pt-setspecific.c (__pthread_setspecific): Add hidden def. -+ - 2018-08-01 Carlos O'Donel <carlos@redhat.com> - - * version.h (RELEASE): Set to "stable". -diff --git a/NEWS b/NEWS -index 154ab22d7c..594cecfc75 100644 ---- a/NEWS -+++ b/NEWS -@@ -5,6 +5,21 @@ See the end for copying conditions. - Please send GNU C library bug reports via <https://sourceware.org/bugzilla/> - using `glibc' in the "product" field. - -+Version 2.28.1 -+ -+The following bugs are resolved with this release: -+ -+ [20209] localedata: Spelling mistake for Sunday in Greenlandic kl_GL -+ [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream -+ [23521] nss_files aliases database file stream leak -+ [23538] pthread_cond_broadcast: Fix waiters-after-spinning case -+ [23578] regex: Fix memory overread in re_compile_pattern -+ [23579] libc: Errors misreported in preadv2 -+ [23606] Missing ENDBR32 in sysdeps/i386/start.S -+ [23679] gethostid: Missing NULL check for gethostbyname_r result -+ [23717] Fix stack overflow in stdlib/tst-setcontext9 -+ -+ - Version 2.28 - - Major new features: -diff --git a/htl/Versions b/htl/Versions -index 6a63a1b8a1..c5a616da10 100644 ---- a/htl/Versions -+++ b/htl/Versions -@@ -150,6 +150,8 @@ libpthread { - __cthread_keycreate; - __cthread_getspecific; - __cthread_setspecific; -+ __pthread_getspecific; -+ __pthread_setspecific; - __pthread_getattr_np; - __pthread_attr_getstack; - } -diff --git a/localedata/locales/kl_GL b/localedata/locales/kl_GL -index 5ab14a31aa..5723ce7dcf 100644 ---- a/localedata/locales/kl_GL -+++ b/localedata/locales/kl_GL -@@ -70,11 +70,11 @@ copy "da_DK" - END LC_NUMERIC - - LC_TIME --abday "sab";"ata";/ -+abday "sap";"ata";/ - "mar";"pin";/ - "sis";"tal";/ - "arf" --day "sabaat";/ -+day "sapaat";/ - "ataasinngorneq";/ - "marlunngorneq";/ - "pingasunngorneq";/ -diff --git a/misc/Makefile b/misc/Makefile -index b7be2bc19a..c9f81515ac 100644 ---- a/misc/Makefile -+++ b/misc/Makefile -@@ -86,6 +86,11 @@ tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \ - tst-preadvwritev tst-preadvwritev64 tst-makedev tst-empty \ - tst-preadvwritev2 tst-preadvwritev64v2 - -+# Tests which need libdl. -+ifeq (yes,$(build-shared)) -+tests += tst-gethostid -+endif -+ - tests-internal := tst-atomic tst-atomic-long tst-allocate_once - tests-static := tst-empty - -@@ -145,3 +150,5 @@ tst-allocate_once-ENV = MALLOC_TRACE=$(objpfx)tst-allocate_once.mtrace - $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out - $(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \ - $(evaluate-test) -+ -+$(objpfx)tst-gethostid: $(libdl) -diff --git a/misc/error.c b/misc/error.c -index b4e8b6c938..03378e2f2a 100644 ---- a/misc/error.c -+++ b/misc/error.c -@@ -319,6 +319,7 @@ error (int status, int errnum, const char *message, ...) - - va_start (args, message); - error_tail (status, errnum, message, args); -+ va_end (args); - - #ifdef _LIBC - _IO_funlockfile (stderr); -@@ -390,6 +391,7 @@ error_at_line (int status, int errnum, const char *file_name, - - va_start (args, message); - error_tail (status, errnum, message, args); -+ va_end (args); - - #ifdef _LIBC - _IO_funlockfile (stderr); -diff --git a/misc/tst-gethostid.c b/misc/tst-gethostid.c -new file mode 100644 -index 0000000000..1490aaf3f5 ---- /dev/null -+++ b/misc/tst-gethostid.c -@@ -0,0 +1,108 @@ -+/* Basic test for gethostid. -+ Copyright (C) 2018 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 -+ <http://www.gnu.org/licenses/>. */ -+ -+#include <gnu/lib-names.h> -+#include <nss.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+#include <support/namespace.h> -+#include <support/support.h> -+#include <support/temp_file.h> -+#include <support/xdlfcn.h> -+#include <support/xstdio.h> -+#include <support/xunistd.h> -+#include <unistd.h> -+ -+/* Initial test is run outside a chroot, to increase the likelihood of -+ success. */ -+static void -+outside_chroot (void *closure) -+{ -+ long id = gethostid (); -+ printf ("info: host ID outside chroot: 0x%lx\n", id); -+} -+ -+/* The same, but this time perform a chroot operation. */ -+static void -+in_chroot (void *closure) -+{ -+ const char *chroot_path = closure; -+ xchroot (chroot_path); -+ long id = gethostid (); -+ printf ("info: host ID in chroot: 0x%lx\n", id); -+} -+ -+static int -+do_test (void) -+{ -+ support_isolate_in_subprocess (outside_chroot, NULL); -+ -+ /* Now run the test inside a chroot. */ -+ support_become_root (); -+ if (!support_can_chroot ()) -+ /* Cannot perform further tests. */ -+ return 0; -+ -+ /* Only use nss_files. */ -+ __nss_configure_lookup ("hosts", "files"); -+ -+ /* Load the DSO outside of the chroot. */ -+ xdlopen (LIBNSS_FILES_SO, RTLD_LAZY); -+ -+ char *chroot_dir = support_create_temp_directory ("tst-gethostid-"); -+ support_isolate_in_subprocess (in_chroot, chroot_dir); -+ -+ /* Tests with /etc/hosts in the chroot. */ -+ { -+ char *path = xasprintf ("%s/etc", chroot_dir); -+ add_temp_file (path); -+ xmkdir (path, 0777); -+ free (path); -+ path = xasprintf ("%s/etc/hosts", chroot_dir); -+ add_temp_file (path); -+ -+ FILE *fp = xfopen (path, "w"); -+ xfclose (fp); -+ printf ("info: chroot test with an empty /etc/hosts file\n"); -+ support_isolate_in_subprocess (in_chroot, chroot_dir); -+ -+ char hostname[1024]; -+ int ret = gethostname (hostname, sizeof (hostname)); -+ if (ret < 0) -+ printf ("warning: invalid result from gethostname: %d\n", ret); -+ else if (strlen (hostname) == 0) -+ puts ("warning: gethostname returned empty string"); -+ else -+ { -+ printf ("info: chroot test with IPv6 address in /etc/hosts for: %s\n", -+ hostname); -+ fp = xfopen (path, "w"); -+ /* Use an IPv6 address to induce another lookup failure. */ -+ fprintf (fp, "2001:db8::1 %s\n", hostname); -+ xfclose (fp); -+ support_isolate_in_subprocess (in_chroot, chroot_dir); -+ } -+ free (path); -+ } -+ free (chroot_dir); -+ -+ return 0; -+} -+ -+#include <support/test-driver.c> -diff --git a/misc/tst-preadvwritev2-common.c b/misc/tst-preadvwritev2-common.c -index f889a21544..50b9da3fea 100644 ---- a/misc/tst-preadvwritev2-common.c -+++ b/misc/tst-preadvwritev2-common.c -@@ -19,9 +19,6 @@ - #include <limits.h> - #include <support/check.h> - --static void --do_test_with_invalid_flags (void) --{ - #ifndef RWF_HIPRI - # define RWF_HIPRI 0 - #endif -@@ -39,6 +36,68 @@ do_test_with_invalid_flags (void) - #endif - #define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT \ - | RWF_APPEND) -+ -+static void -+do_test_with_invalid_fd (void) -+{ -+ char buf[256]; -+ struct iovec iov = { buf, sizeof buf }; -+ -+ /* Check with flag being 0 to use the fallback code which calls pwritev -+ or writev. */ -+ TEST_VERIFY (preadv2 (-1, &iov, 1, -1, 0) == -1); -+ TEST_COMPARE (errno, EBADF); -+ TEST_VERIFY (pwritev2 (-1, &iov, 1, -1, 0) == -1); -+ TEST_COMPARE (errno, EBADF); -+ -+ /* Same tests as before but with flags being different than 0. Since -+ there is no emulation for any flag value, fallback code returns -+ ENOTSUP. This is different running on a kernel with preadv2/pwritev2 -+ support, where EBADF is returned). */ -+ TEST_VERIFY (preadv2 (-1, &iov, 1, 0, RWF_HIPRI) == -1); -+ TEST_VERIFY (errno == EBADF || errno == ENOTSUP); -+ TEST_VERIFY (pwritev2 (-1, &iov, 1, 0, RWF_HIPRI) == -1); -+ TEST_VERIFY (errno == EBADF || errno == ENOTSUP); -+} -+ -+static void -+do_test_with_invalid_iov (void) -+{ -+ { -+ char buf[256]; -+ struct iovec iov; -+ -+ iov.iov_base = buf; -+ iov.iov_len = (size_t)SSIZE_MAX + 1; -+ -+ TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, 0) == -1); -+ TEST_COMPARE (errno, EINVAL); -+ TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, 0) == -1); -+ TEST_COMPARE (errno, EINVAL); -+ -+ /* Same as for invalid file descriptor tests, emulation fallback -+ first checks for flag value and return ENOTSUP. */ -+ TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1); -+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); -+ TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1); -+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); -+ } -+ -+ { -+ /* An invalid iovec buffer should trigger an invalid memory access -+ or an error (Linux for instance returns EFAULT). */ -+ struct iovec iov[IOV_MAX+1] = { 0 }; -+ -+ TEST_VERIFY (preadv2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1); -+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); -+ TEST_VERIFY (pwritev2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1); -+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); -+ } -+} -+ -+static void -+do_test_with_invalid_flags (void) -+{ - /* Set the next bit from the mask of all supported flags. */ - int invalid_flag = RWF_SUPPORTED != 0 ? __builtin_clz (RWF_SUPPORTED) : 2; - invalid_flag = 0x1 << ((sizeof (int) * CHAR_BIT) - invalid_flag); -diff --git a/misc/tst-preadvwritev2.c b/misc/tst-preadvwritev2.c -index be22802dbe..cb58cbe41e 100644 ---- a/misc/tst-preadvwritev2.c -+++ b/misc/tst-preadvwritev2.c -@@ -30,6 +30,8 @@ do_test (void) - { - do_test_with_invalid_flags (); - do_test_without_offset (); -+ do_test_with_invalid_fd (); -+ do_test_with_invalid_iov (); - - return do_test_with_offset (0); - } -diff --git a/misc/tst-preadvwritev64v2.c b/misc/tst-preadvwritev64v2.c -index 8d3cc32b28..6a9de54c78 100644 ---- a/misc/tst-preadvwritev64v2.c -+++ b/misc/tst-preadvwritev64v2.c -@@ -32,6 +32,8 @@ do_test (void) - { - do_test_with_invalid_flags (); - do_test_without_offset (); -+ do_test_with_invalid_fd (); -+ do_test_with_invalid_iov (); - - return do_test_with_offset (0); - } -diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c -index 8e425eb01e..479e54febb 100644 ---- a/nptl/pthread_cond_common.c -+++ b/nptl/pthread_cond_common.c -@@ -405,8 +405,12 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, - { - /* There is still a waiter after spinning. Set the wake-request - flag and block. Relaxed MO is fine because this is just about -- this futex word. */ -- r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1); -+ this futex word. -+ -+ Update r to include the set wake-request flag so that the upcoming -+ futex_wait only blocks if the flag is still set (otherwise, we'd -+ violate the basic client-side futex protocol). */ -+ r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1) | 1; - - if ((r >> 1) > 0) - futex_wait_simple (cond->__data.__g_refs + g1, r, private); -diff --git a/nscd/nscd_conf.c b/nscd/nscd_conf.c -index 265a02434d..7293b795b6 100644 ---- a/nscd/nscd_conf.c -+++ b/nscd/nscd_conf.c -@@ -190,7 +190,10 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb]) - if (!arg1) - error (0, 0, _("Must specify user name for server-user option")); - else -- server_user = xstrdup (arg1); -+ { -+ free ((char *) server_user); -+ server_user = xstrdup (arg1); -+ } - } - else if (strcmp (entry, "stat-user") == 0) - { -@@ -198,6 +201,7 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb]) - error (0, 0, _("Must specify user name for stat-user option")); - else - { -+ free ((char *) stat_user); - stat_user = xstrdup (arg1); - - struct passwd *pw = getpwnam (stat_user); -diff --git a/nss/Makefile b/nss/Makefile -index 66fac7f5b8..5209fc0456 100644 ---- a/nss/Makefile -+++ b/nss/Makefile -@@ -65,6 +65,7 @@ ifeq (yes,$(build-shared)) - tests += tst-nss-files-hosts-erange - tests += tst-nss-files-hosts-multi - tests += tst-nss-files-hosts-getent -+tests += tst-nss-files-alias-leak - endif - - # If we have a thread library then we can test cancellation against -@@ -171,3 +172,5 @@ endif - $(objpfx)tst-nss-files-hosts-erange: $(libdl) - $(objpfx)tst-nss-files-hosts-multi: $(libdl) - $(objpfx)tst-nss-files-hosts-getent: $(libdl) -+$(objpfx)tst-nss-files-alias-leak: $(libdl) -+$(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so -diff --git a/nss/nss_files/files-alias.c b/nss/nss_files/files-alias.c -index cfd34b66b9..35b0bfc5d2 100644 ---- a/nss/nss_files/files-alias.c -+++ b/nss/nss_files/files-alias.c -@@ -221,6 +221,13 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, - { - while (! feof_unlocked (listfile)) - { -+ if (room_left < 2) -+ { -+ free (old_line); -+ fclose (listfile); -+ goto no_more_room; -+ } -+ - first_unused[room_left - 1] = '\xff'; - line = fgets_unlocked (first_unused, room_left, - listfile); -@@ -229,6 +236,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, - if (first_unused[room_left - 1] != '\xff') - { - free (old_line); -+ fclose (listfile); - goto no_more_room; - } - -@@ -256,6 +264,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, - + __alignof__ (char *))) - { - free (old_line); -+ fclose (listfile); - goto no_more_room; - } - room_left -= ((first_unused - cp) -diff --git a/nss/tst-nss-files-alias-leak.c b/nss/tst-nss-files-alias-leak.c -new file mode 100644 -index 0000000000..26d38e2dba ---- /dev/null -+++ b/nss/tst-nss-files-alias-leak.c -@@ -0,0 +1,237 @@ -+/* Check for file descriptor leak in alias :include: processing (bug 23521). -+ Copyright (C) 2018 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 -+ <http://www.gnu.org/licenses/>. */ -+ -+#include <aliases.h> -+#include <array_length.h> -+#include <dlfcn.h> -+#include <errno.h> -+#include <gnu/lib-names.h> -+#include <nss.h> -+#include <stdlib.h> -+#include <string.h> -+#include <support/check.h> -+#include <support/namespace.h> -+#include <support/support.h> -+#include <support/temp_file.h> -+#include <support/test-driver.h> -+#include <support/xstdio.h> -+#include <support/xunistd.h> -+ -+static struct support_chroot *chroot_env; -+ -+/* Number of the aliases for the "many" user. This must be large -+ enough to trigger reallocation for the pointer array, but result in -+ answers below the maximum size tried in do_test. */ -+enum { many_aliases = 30 }; -+ -+static void -+prepare (int argc, char **argv) -+{ -+ chroot_env = support_chroot_create -+ ((struct support_chroot_configuration) { } ); -+ -+ char *path = xasprintf ("%s/etc/aliases", chroot_env->path_chroot); -+ add_temp_file (path); -+ support_write_file_string -+ (path, -+ "user1: :include:/etc/aliases.user1\n" -+ "user2: :include:/etc/aliases.user2\n" -+ "comment: comment1, :include:/etc/aliases.comment\n" -+ "many: :include:/etc/aliases.many\n"); -+ free (path); -+ -+ path = xasprintf ("%s/etc/aliases.user1", chroot_env->path_chroot); -+ add_temp_file (path); -+ support_write_file_string (path, "alias1\n"); -+ free (path); -+ -+ path = xasprintf ("%s/etc/aliases.user2", chroot_env->path_chroot); -+ add_temp_file (path); -+ support_write_file_string (path, "alias1a, alias2\n"); -+ free (path); -+ -+ path = xasprintf ("%s/etc/aliases.comment", chroot_env->path_chroot); -+ add_temp_file (path); -+ support_write_file_string -+ (path, -+ /* The line must be longer than the line with the :include: -+ directive in /etc/aliases. */ -+ "# Long line. ##############################################\n" -+ "comment2\n"); -+ free (path); -+ -+ path = xasprintf ("%s/etc/aliases.many", chroot_env->path_chroot); -+ add_temp_file (path); -+ FILE *fp = xfopen (path, "w"); -+ for (int i = 0; i < many_aliases; ++i) -+ fprintf (fp, "a%d\n", i); -+ TEST_VERIFY_EXIT (! ferror (fp)); -+ xfclose (fp); -+ free (path); -+} -+ -+/* The names of the users to test. */ -+static const char *users[] = { "user1", "user2", "comment", "many" }; -+ -+static void -+check_aliases (int id, const struct aliasent *e) -+{ -+ TEST_VERIFY_EXIT (id >= 0 || id < array_length (users)); -+ const char *name = users[id]; -+ TEST_COMPARE_BLOB (e->alias_name, strlen (e->alias_name), -+ name, strlen (name)); -+ -+ switch (id) -+ { -+ case 0: -+ TEST_COMPARE (e->alias_members_len, 1); -+ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]), -+ "alias1", strlen ("alias1")); -+ break; -+ -+ case 1: -+ TEST_COMPARE (e->alias_members_len, 2); -+ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]), -+ "alias1a", strlen ("alias1a")); -+ TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]), -+ "alias2", strlen ("alias2")); -+ break; -+ -+ case 2: -+ TEST_COMPARE (e->alias_members_len, 2); -+ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]), -+ "comment1", strlen ("comment1")); -+ TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]), -+ "comment2", strlen ("comment2")); -+ break; -+ -+ case 3: -+ TEST_COMPARE (e->alias_members_len, many_aliases); -+ for (int i = 0; i < e->alias_members_len; ++i) -+ { -+ char alias[30]; -+ int len = snprintf (alias, sizeof (alias), "a%d", i); -+ TEST_VERIFY_EXIT (len > 0); -+ TEST_COMPARE_BLOB (e->alias_members[i], strlen (e->alias_members[i]), -+ alias, len); -+ } -+ break; -+ } -+} -+ -+static int -+do_test (void) -+{ -+ /* Make sure we don't try to load the module in the chroot. */ -+ if (dlopen (LIBNSS_FILES_SO, RTLD_NOW) == NULL) -+ FAIL_EXIT1 ("could not load " LIBNSS_FILES_SO ": %s", dlerror ()); -+ -+ /* Some of these descriptors will become unavailable if there is a -+ file descriptor leak. 10 is chosen somewhat arbitrarily. The -+ array must be longer than the number of files opened by nss_files -+ at the same time (currently that number is 2). */ -+ int next_descriptors[10]; -+ for (size_t i = 0; i < array_length (next_descriptors); ++i) -+ { -+ next_descriptors[i] = dup (0); -+ TEST_VERIFY_EXIT (next_descriptors[i] > 0); -+ } -+ for (size_t i = 0; i < array_length (next_descriptors); ++i) -+ xclose (next_descriptors[i]); -+ -+ support_become_root (); -+ if (!support_can_chroot ()) -+ return EXIT_UNSUPPORTED; -+ -+ __nss_configure_lookup ("aliases", "files"); -+ -+ xchroot (chroot_env->path_chroot); -+ -+ /* Attempt various buffer sizes. If the operation succeeds, we -+ expect correct data. */ -+ for (int id = 0; id < array_length (users); ++id) -+ { -+ bool found = false; -+ for (size_t size = 1; size <= 1000; ++size) -+ { -+ void *buffer = malloc (size); -+ struct aliasent result; -+ struct aliasent *res; -+ errno = EINVAL; -+ int ret = getaliasbyname_r (users[id], &result, buffer, size, &res); -+ if (ret == 0) -+ { -+ if (res != NULL) -+ { -+ found = true; -+ check_aliases (id, res); -+ } -+ else -+ { -+ support_record_failure (); -+ printf ("error: failed lookup for user \"%s\", size %zu\n", -+ users[id], size); -+ } -+ } -+ else if (ret != ERANGE) -+ { -+ support_record_failure (); -+ printf ("error: invalid return code %d (user \%s\", size %zu)\n", -+ ret, users[id], size); -+ } -+ free (buffer); -+ -+ /* Make sure that we did not have a file descriptor leak. */ -+ for (size_t i = 0; i < array_length (next_descriptors); ++i) -+ { -+ int new_fd = dup (0); -+ if (new_fd != next_descriptors[i]) -+ { -+ support_record_failure (); -+ printf ("error: descriptor %d at index %zu leaked" -+ " (user \"%s\", size %zu)\n", -+ next_descriptors[i], i, users[id], size); -+ -+ /* Close unexpected descriptor, the leak probing -+ descriptors, and the leaked descriptor -+ next_descriptors[i]. */ -+ xclose (new_fd); -+ for (size_t j = 0; j <= i; ++j) -+ xclose (next_descriptors[j]); -+ goto next_size; -+ } -+ } -+ for (size_t i = 0; i < array_length (next_descriptors); ++i) -+ xclose (next_descriptors[i]); -+ -+ next_size: -+ ; -+ } -+ if (!found) -+ { -+ support_record_failure (); -+ printf ("error: user %s not found\n", users[id]); -+ } -+ } -+ -+ support_chroot_free (chroot_env); -+ return 0; -+} -+ -+#define PREPARE prepare -+#include <support/test-driver.c> -diff --git a/posix/Makefile b/posix/Makefile -index 00c62841a2..83162123f9 100644 ---- a/posix/Makefile -+++ b/posix/Makefile -@@ -96,7 +96,7 @@ tests := test-errno tstgetopt testfnm runtests runptests \ - tst-posix_fadvise tst-posix_fadvise64 \ - tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \ - tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \ -- bug-regex38 -+ bug-regex38 tst-regcomp-truncated - tests-internal := bug-regex5 bug-regex20 bug-regex33 \ - tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \ - tst-glob_lstat_compat tst-spawn4-compat -@@ -194,6 +194,7 @@ $(objpfx)tst-regex2.out: $(gen-locales) - $(objpfx)tst-regexloc.out: $(gen-locales) - $(objpfx)tst-rxspencer.out: $(gen-locales) - $(objpfx)tst-rxspencer-no-utf8.out: $(gen-locales) -+$(objpfx)tst-regcomp-truncated.out: $(gen-locales) - endif - - # If we will use the generic uname implementation, we must figure out what -diff --git a/posix/regex_internal.c b/posix/regex_internal.c -index 7f0083b918..b10588f1cc 100644 ---- a/posix/regex_internal.c -+++ b/posix/regex_internal.c -@@ -317,7 +317,7 @@ build_wcs_upper_buffer (re_string_t *pstr) - mbclen = __mbrtowc (&wc, - ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx - + byte_idx), remain_len, &pstr->cur_state); -- if (BE (mbclen < (size_t) -2, 1)) -+ if (BE (0 < mbclen && mbclen < (size_t) -2, 1)) - { - wchar_t wcu = __towupper (wc); - if (wcu != wc) -@@ -386,7 +386,7 @@ build_wcs_upper_buffer (re_string_t *pstr) - else - p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx; - mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state); -- if (BE (mbclen < (size_t) -2, 1)) -+ if (BE (0 < mbclen && mbclen < (size_t) -2, 1)) - { - wchar_t wcu = __towupper (wc); - if (wcu != wc) -diff --git a/posix/tst-regcomp-truncated.c b/posix/tst-regcomp-truncated.c -new file mode 100644 -index 0000000000..a4a1581bbc ---- /dev/null -+++ b/posix/tst-regcomp-truncated.c -@@ -0,0 +1,191 @@ -+/* Test compilation of truncated regular expressions. -+ Copyright (C) 2018 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 -+ <http://www.gnu.org/licenses/>. */ -+ -+/* This test constructs various patterns in an attempt to trigger -+ over-reading the regular expression compiler, such as bug -+ 23578. */ -+ -+#include <array_length.h> -+#include <errno.h> -+#include <locale.h> -+#include <regex.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+#include <support/check.h> -+#include <support/next_to_fault.h> -+#include <support/support.h> -+#include <support/test-driver.h> -+#include <wchar.h> -+ -+/* Locales to test. */ -+static const char locales[][17] = -+ { -+ "C", -+ "en_US.UTF-8", -+ "de_DE.ISO-8859-1", -+ }; -+ -+/* Syntax options. Will be combined with other flags. */ -+static const reg_syntax_t syntaxes[] = -+ { -+ RE_SYNTAX_EMACS, -+ RE_SYNTAX_AWK, -+ RE_SYNTAX_GNU_AWK, -+ RE_SYNTAX_POSIX_AWK, -+ RE_SYNTAX_GREP, -+ RE_SYNTAX_EGREP, -+ RE_SYNTAX_POSIX_EGREP, -+ RE_SYNTAX_POSIX_BASIC, -+ RE_SYNTAX_POSIX_EXTENDED, -+ RE_SYNTAX_POSIX_MINIMAL_EXTENDED, -+ }; -+ -+/* Trailing characters placed after the initial character. */ -+static const char trailing_strings[][4] = -+ { -+ "", -+ "[", -+ "\\", -+ "[\\", -+ "(", -+ "(\\", -+ "\\(", -+ }; -+ -+static int -+do_test (void) -+{ -+ /* Staging buffer for the constructed regular expression. */ -+ char buffer[16]; -+ -+ /* Allocation used to detect over-reading by the regular expression -+ compiler. */ -+ struct support_next_to_fault ntf -+ = support_next_to_fault_allocate (sizeof (buffer)); -+ -+ /* Arbitrary Unicode codepoint at which we stop generating -+ characters. We do not probe the whole range because that would -+ take too long due to combinatorical exploision as the result of -+ combination with other flags. */ -+ static const wchar_t last_character = 0xfff; -+ -+ for (size_t locale_idx = 0; locale_idx < array_length (locales); -+ ++ locale_idx) -+ { -+ if (setlocale (LC_ALL, locales[locale_idx]) == NULL) -+ { -+ support_record_failure (); -+ printf ("error: setlocale (\"%s\"): %m", locales[locale_idx]); -+ continue; -+ } -+ if (test_verbose > 0) -+ printf ("info: testing locale \"%s\"\n", locales[locale_idx]); -+ -+ for (wchar_t wc = 0; wc <= last_character; ++wc) -+ { -+ char *after_wc; -+ if (wc == 0) -+ { -+ /* wcrtomb treats L'\0' in a special way. */ -+ *buffer = '\0'; -+ after_wc = &buffer[1]; -+ } -+ else -+ { -+ mbstate_t ps = { }; -+ size_t ret = wcrtomb (buffer, wc, &ps); -+ if (ret == (size_t) -1) -+ { -+ /* EILSEQ means that the target character set -+ cannot encode the character. */ -+ if (errno != EILSEQ) -+ { -+ support_record_failure (); -+ printf ("error: wcrtomb (0x%x) failed: %m\n", -+ (unsigned) wc); -+ } -+ continue; -+ } -+ TEST_VERIFY_EXIT (ret != 0); -+ after_wc = &buffer[ret]; -+ } -+ -+ for (size_t trailing_idx = 0; -+ trailing_idx < array_length (trailing_strings); -+ ++trailing_idx) -+ { -+ char *after_trailing -+ = stpcpy (after_wc, trailing_strings[trailing_idx]); -+ -+ for (int do_nul = 0; do_nul < 2; ++do_nul) -+ { -+ char *after_nul; -+ if (do_nul) -+ { -+ *after_trailing = '\0'; -+ after_nul = &after_trailing[1]; -+ } -+ else -+ after_nul = after_trailing; -+ -+ size_t length = after_nul - buffer; -+ -+ /* Make sure that the faulting region starts -+ after the used portion of the buffer. */ -+ char *ntf_start = ntf.buffer + sizeof (buffer) - length; -+ memcpy (ntf_start, buffer, length); -+ -+ for (const reg_syntax_t *psyntax = syntaxes; -+ psyntax < array_end (syntaxes); ++psyntax) -+ for (int do_icase = 0; do_icase < 2; ++do_icase) -+ { -+ re_syntax_options = *psyntax; -+ if (do_icase) -+ re_syntax_options |= RE_ICASE; -+ -+ regex_t reg; -+ memset (®, 0, sizeof (reg)); -+ const char *msg = re_compile_pattern -+ (ntf_start, length, ®); -+ if (msg != NULL) -+ { -+ if (test_verbose > 0) -+ { -+ char *quoted = support_quote_blob -+ (buffer, length); -+ printf ("info: compilation failed for pattern" -+ " \"%s\", syntax 0x%lx: %s\n", -+ quoted, re_syntax_options, msg); -+ free (quoted); -+ } -+ } -+ else -+ regfree (®); -+ } -+ } -+ } -+ } -+ } -+ -+ support_next_to_fault_free (&ntf); -+ -+ return 0; -+} -+ -+#include <support/test-driver.c> -diff --git a/stdlib/tst-setcontext9.c b/stdlib/tst-setcontext9.c -index 4636ce9030..009928235d 100644 ---- a/stdlib/tst-setcontext9.c -+++ b/stdlib/tst-setcontext9.c -@@ -41,30 +41,59 @@ f2 (void) - } - - static void --f1 (void) -+f1b (void) - { -- puts ("start f1"); -- if (getcontext (&ctx[2]) != 0) -- { -- printf ("%s: getcontext: %m\n", __FUNCTION__); -- exit (EXIT_FAILURE); -- } - if (done) - { -- puts ("set context in f1"); -+ puts ("set context in f1b"); - if (setcontext (&ctx[3]) != 0) - { - printf ("%s: setcontext: %m\n", __FUNCTION__); - exit (EXIT_FAILURE); - } - } -+ exit (EXIT_FAILURE); -+} -+ -+static void -+f1a (void) -+{ -+ static char st2[32768]; -+ puts ("start f1a"); -+ if (getcontext (&ctx[2]) != 0) -+ { -+ printf ("%s: getcontext: %m\n", __FUNCTION__); -+ exit (EXIT_FAILURE); -+ } -+ ctx[2].uc_stack.ss_sp = st2; -+ ctx[2].uc_stack.ss_size = sizeof st2; -+ ctx[2].uc_link = &ctx[0]; -+ makecontext (&ctx[2], (void (*) (void)) f1b, 0); - f2 (); - } - -+/* The execution path through the test looks like this: -+ do_test (call) -+ -> "making contexts" -+ -> "swap contexts" -+ f1a (via swapcontext to ctx[1], with alternate stack) -+ -> "start f1a" -+ f2 (call) -+ -> "swap contexts in f2" -+ f1b (via swapcontext to ctx[2], with alternate stack) -+ -> "set context in f1b" -+ do_test (via setcontext to ctx[3], main stack) -+ -> "setcontext" -+ f2 (via setcontext to ctx[4], with alternate stack) -+ -> "end f2" -+ -+ We must use an alternate stack for f1b, because if we don't then the -+ result of executing an earlier caller may overwrite registers -+ spilled to the stack in f2. */ - static int - do_test (void) - { -- char st1[32768]; -+ static char st1[32768]; - puts ("making contexts"); - if (getcontext (&ctx[0]) != 0) - { -@@ -79,7 +108,7 @@ do_test (void) - ctx[1].uc_stack.ss_sp = st1; - ctx[1].uc_stack.ss_size = sizeof st1; - ctx[1].uc_link = &ctx[0]; -- makecontext (&ctx[1], (void (*) (void)) f1, 0); -+ makecontext (&ctx[1], (void (*) (void)) f1a, 0); - puts ("swap contexts"); - if (swapcontext (&ctx[3], &ctx[1]) != 0) - { -diff --git a/string/strcasestr.c b/string/strcasestr.c -index 5909fe3cdb..421764bd1b 100644 ---- a/string/strcasestr.c -+++ b/string/strcasestr.c -@@ -37,8 +37,9 @@ - /* Two-Way algorithm. */ - #define RETURN_TYPE char * - #define AVAILABLE(h, h_l, j, n_l) \ -- (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \ -- (j) + (n_l) <= (h_l))) -+ (((j) + (n_l) <= (h_l)) \ -+ || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \ -+ (j) + (n_l) <= (h_l))) - #define CHECK_EOL (1) - #define RET0_IF_0(a) if (!a) goto ret0 - #define CANON_ELEMENT(c) TOLOWER (c) -diff --git a/string/strstr.c b/string/strstr.c -index 265e9f310c..79ebcc7532 100644 ---- a/string/strstr.c -+++ b/string/strstr.c -@@ -33,8 +33,9 @@ - - #define RETURN_TYPE char * - #define AVAILABLE(h, h_l, j, n_l) \ -- (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \ -- (j) + (n_l) <= (h_l))) -+ (((j) + (n_l) <= (h_l)) \ -+ || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \ -+ (j) + (n_l) <= (h_l))) - #define CHECK_EOL (1) - #define RET0_IF_0(a) if (!a) goto ret0 - #define FASTSEARCH(S,C,N) (void*) strchr ((void*)(S), (C)) -diff --git a/string/test-strstr.c b/string/test-strstr.c -index 8d99716ff3..5861b01b73 100644 ---- a/string/test-strstr.c -+++ b/string/test-strstr.c -@@ -151,6 +151,32 @@ check2 (void) - } - } - -+#define N 1024 -+ -+static void -+pr23637 (void) -+{ -+ char *h = (char*) buf1; -+ char *n = (char*) buf2; -+ -+ for (int i = 0; i < N; i++) -+ { -+ n[i] = 'x'; -+ h[i] = ' '; -+ h[i + N] = 'x'; -+ } -+ -+ n[N] = '\0'; -+ h[N * 2] = '\0'; -+ -+ /* Ensure we don't match at the first 'x'. */ -+ h[0] = 'x'; -+ -+ char *exp_result = stupid_strstr (h, n); -+ FOR_EACH_IMPL (impl, 0) -+ check_result (impl, h, n, exp_result); -+} -+ - static int - test_main (void) - { -@@ -158,6 +184,7 @@ test_main (void) - - check1 (); - check2 (); -+ pr23637 (); - - printf ("%23s", ""); - FOR_EACH_IMPL (impl, 0) -@@ -202,6 +229,9 @@ test_main (void) - do_test (15, 9, hlen, klen, 1); - do_test (15, 15, hlen, klen, 0); - do_test (15, 15, hlen, klen, 1); -+ -+ do_test (15, 15, hlen + klen * 4, klen * 4, 0); -+ do_test (15, 15, hlen + klen * 4, klen * 4, 1); - } - - do_test (0, 0, page_size - 1, 16, 0); -diff --git a/sysdeps/htl/pt-getspecific.c b/sysdeps/htl/pt-getspecific.c -index a0227a67f6..64ddf9551a 100644 ---- a/sysdeps/htl/pt-getspecific.c -+++ b/sysdeps/htl/pt-getspecific.c -@@ -36,3 +36,4 @@ __pthread_getspecific (pthread_key_t key) - return self->thread_specifics[key]; - } - strong_alias (__pthread_getspecific, pthread_getspecific); -+hidden_def (__pthread_getspecific) -diff --git a/sysdeps/htl/pt-setspecific.c b/sysdeps/htl/pt-setspecific.c -index a46a12f157..02aff417ef 100644 ---- a/sysdeps/htl/pt-setspecific.c -+++ b/sysdeps/htl/pt-setspecific.c -@@ -48,3 +48,4 @@ __pthread_setspecific (pthread_key_t key, const void *value) - return 0; - } - strong_alias (__pthread_setspecific, pthread_setspecific); -+hidden_def (__pthread_setspecific) -diff --git a/sysdeps/htl/pthreadP.h b/sysdeps/htl/pthreadP.h -index 132ac1718e..71c2fcd9c6 100644 ---- a/sysdeps/htl/pthreadP.h -+++ b/sysdeps/htl/pthreadP.h -@@ -68,6 +68,8 @@ struct __pthread_cancelation_handler **___pthread_get_cleanup_stack (void) attri - - #if IS_IN (libpthread) - hidden_proto (__pthread_key_create) -+hidden_proto (__pthread_getspecific) -+hidden_proto (__pthread_setspecific) - hidden_proto (_pthread_mutex_init) - #endif - -diff --git a/sysdeps/i386/dl-cet.c b/sysdeps/i386/dl-cet.c -deleted file mode 100644 -index 5d9a4e8d51..0000000000 ---- a/sysdeps/i386/dl-cet.c -+++ /dev/null -@@ -1,67 +0,0 @@ --/* Linux/i386 CET initializers function. -- Copyright (C) 2018 Free Software Foundation, Inc. -- -- 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 -- <http://www.gnu.org/licenses/>. */ -- -- --#define LINKAGE static inline --#define _dl_cet_check cet_check --#include <sysdeps/x86/dl-cet.c> --#undef _dl_cet_check -- --#ifdef SHARED --void --_dl_cet_check (struct link_map *main_map, const char *program) --{ -- cet_check (main_map, program); -- -- if ((GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) -- { -- /* Replace _dl_runtime_resolve and _dl_runtime_profile with -- _dl_runtime_resolve_shstk and _dl_runtime_profile_shstk, -- respectively if SHSTK is enabled. */ -- extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden; -- extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden; -- extern void _dl_runtime_profile (Elf32_Word) attribute_hidden; -- extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden; -- unsigned int i; -- struct link_map *l; -- Elf32_Addr *got; -- -- if (main_map->l_info[DT_JMPREL]) -- { -- got = (Elf32_Addr *) D_PTR (main_map, l_info[DT_PLTGOT]); -- if (got[2] == (Elf32_Addr) &_dl_runtime_resolve) -- got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk; -- else if (got[2] == (Elf32_Addr) &_dl_runtime_profile) -- got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk; -- } -- -- i = main_map->l_searchlist.r_nlist; -- while (i-- > 0) -- { -- l = main_map->l_initfini[i]; -- if (l->l_info[DT_JMPREL]) -- { -- got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]); -- if (got[2] == (Elf32_Addr) &_dl_runtime_resolve) -- got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk; -- else if (got[2] == (Elf32_Addr) &_dl_runtime_profile) -- got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk; -- } -- } -- } --} --#endif -diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h -index 1afdcbd9ea..f6cfb90e21 100644 ---- a/sysdeps/i386/dl-machine.h -+++ b/sysdeps/i386/dl-machine.h -@@ -67,6 +67,11 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) - Elf32_Addr *got; - extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden; - extern void _dl_runtime_profile (Elf32_Word) attribute_hidden; -+ extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden; -+ extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden; -+ /* Check if SHSTK is enabled by kernel. */ -+ bool shstk_enabled -+ = (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0; - - if (l->l_info[DT_JMPREL] && lazy) - { -@@ -93,7 +98,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) - end in this function. */ - if (__glibc_unlikely (profile)) - { -- got[2] = (Elf32_Addr) &_dl_runtime_profile; -+ got[2] = (shstk_enabled -+ ? (Elf32_Addr) &_dl_runtime_profile_shstk -+ : (Elf32_Addr) &_dl_runtime_profile); - - if (GLRO(dl_profile) != NULL - && _dl_name_match_p (GLRO(dl_profile), l)) -@@ -104,7 +111,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) - else - /* This function will get called to fix up the GOT entry indicated by - the offset on the stack, and then jump to the resolved address. */ -- got[2] = (Elf32_Addr) &_dl_runtime_resolve; -+ got[2] = (shstk_enabled -+ ? (Elf32_Addr) &_dl_runtime_resolve_shstk -+ : (Elf32_Addr) &_dl_runtime_resolve); - } - - return lazy; -diff --git a/sysdeps/i386/start.S b/sysdeps/i386/start.S -index 91035fa83f..e35e9bd31b 100644 ---- a/sysdeps/i386/start.S -+++ b/sysdeps/i386/start.S -@@ -52,10 +52,11 @@ - NULL - */ - -- .text -- .globl _start -- .type _start,@function --_start: -+#include <sysdep.h> -+ -+ENTRY (_start) -+ /* Clearing frame pointer is insufficient, use CFI. */ -+ cfi_undefined (eip) - /* Clear the frame pointer. The ABI suggests this be done, to mark - the outermost frame obviously. */ - xorl %ebp, %ebp -@@ -131,6 +132,7 @@ _start: - 1: movl (%esp), %ebx - ret - #endif -+END (_start) - - /* To fulfill the System V/i386 ABI we need this symbol. Yuck, it's so - meaningless since we don't support machines < 80386. */ -diff --git a/sysdeps/riscv/rv64/rvd/libm-test-ulps b/sysdeps/riscv/rv64/rvd/libm-test-ulps -index f8feadcd0d..61be2df60d 100644 ---- a/sysdeps/riscv/rv64/rvd/libm-test-ulps -+++ b/sysdeps/riscv/rv64/rvd/libm-test-ulps -@@ -1006,6 +1006,8 @@ ildouble: 2 - ldouble: 2 - - Function: "cos": -+double: 1 -+idouble: 1 - ildouble: 1 - ldouble: 1 - -@@ -1348,9 +1350,9 @@ ildouble: 4 - ldouble: 4 - - Function: Imaginary part of "ctan_towardzero": --double: 1 -+double: 2 - float: 2 --idouble: 1 -+idouble: 2 - ifloat: 2 - ildouble: 5 - ldouble: 5 -@@ -1898,10 +1900,12 @@ ldouble: 2 - Function: "log_upward": - double: 1 - idouble: 1 --ildouble: 1 --ldouble: 1 -+ildouble: 2 -+ldouble: 2 - - Function: "pow": -+double: 1 -+idouble: 1 - ildouble: 2 - ldouble: 2 - -@@ -1930,6 +1934,8 @@ ildouble: 2 - ldouble: 2 - - Function: "sin": -+double: 1 -+idouble: 1 - ildouble: 1 - ldouble: 1 - -@@ -1952,6 +1958,8 @@ ildouble: 3 - ldouble: 3 - - Function: "sincos": -+double: 1 -+idouble: 1 - ildouble: 1 - ldouble: 1 - -diff --git a/sysdeps/riscv/rvf/math_private.h b/sysdeps/riscv/rvf/math_private.h -index cdb7858fc8..ca587620cb 100644 ---- a/sysdeps/riscv/rvf/math_private.h -+++ b/sysdeps/riscv/rvf/math_private.h -@@ -72,8 +72,8 @@ libc_fesetround_riscv (int round) - static __always_inline void - libc_feholdexcept_setround_riscv (fenv_t *envp, int round) - { -- libc_fesetround_riscv (round); - libc_feholdexcept_riscv (envp); -+ libc_fesetround_riscv (round); - } - - #define libc_feholdexcept_setround libc_feholdexcept_setround_riscv -diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile -index f71cc39c7e..773aaea0e9 100644 ---- a/sysdeps/unix/sysv/linux/Makefile -+++ b/sysdeps/unix/sysv/linux/Makefile -@@ -161,6 +161,7 @@ inhibit-glue = yes - - ifeq ($(subdir),dirent) - sysdep_routines += getdirentries getdirentries64 -+tests-internal += tst-readdir64-compat - endif - - ifeq ($(subdir),nis) -diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c -index 3bde0cf4f0..bc140b5a7f 100644 ---- a/sysdeps/unix/sysv/linux/getdents64.c -+++ b/sysdeps/unix/sysv/linux/getdents64.c -@@ -33,41 +33,80 @@ strong_alias (__getdents64, __getdents) - # include <shlib-compat.h> - - # if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) --# include <olddirent.h> -+# include <olddirent.h> -+# include <unistd.h> - --/* kernel definition of as of 3.2. */ --struct compat_linux_dirent -+static ssize_t -+handle_overflow (int fd, __off64_t offset, ssize_t count) - { -- /* Both d_ino and d_off are compat_ulong_t which are defined in all -- architectures as 'u32'. */ -- uint32_t d_ino; -- uint32_t d_off; -- unsigned short d_reclen; -- char d_name[1]; --}; -+ /* If this is the first entry in the buffer, we can report the -+ error. */ -+ if (count == 0) -+ { -+ __set_errno (EOVERFLOW); -+ return -1; -+ } -+ -+ /* Otherwise, seek to the overflowing entry, so that the next call -+ will report the error, and return the data read so far.. */ -+ if (__lseek64 (fd, offset, SEEK_SET) != 0) -+ return -1; -+ return count; -+} - - ssize_t - __old_getdents64 (int fd, char *buf, size_t nbytes) - { -- ssize_t retval = INLINE_SYSCALL_CALL (getdents, fd, buf, nbytes); -+ /* We do not move the individual directory entries. This is only -+ possible if the target type (struct __old_dirent64) is smaller -+ than the source type. */ -+ _Static_assert (offsetof (struct __old_dirent64, d_name) -+ <= offsetof (struct dirent64, d_name), -+ "__old_dirent64 is larger than dirent64"); -+ _Static_assert (__alignof__ (struct __old_dirent64) -+ <= __alignof__ (struct dirent64), -+ "alignment of __old_dirent64 is larger than dirent64"); - -- /* The kernel added the d_type value after the name. Change this now. */ -- if (retval != -1) -+ ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes); -+ if (retval > 0) - { -- union -- { -- struct compat_linux_dirent k; -- struct dirent u; -- } *kbuf = (void *) buf; -- -- while ((char *) kbuf < buf + retval) -+ char *p = buf; -+ char *end = buf + retval; -+ while (p < end) - { -- char d_type = *((char *) kbuf + kbuf->k.d_reclen - 1); -- memmove (kbuf->u.d_name, kbuf->k.d_name, -- strlen (kbuf->k.d_name) + 1); -- kbuf->u.d_type = d_type; -+ struct dirent64 *source = (struct dirent64 *) p; -+ -+ /* Copy out the fixed-size data. */ -+ __ino_t ino = source->d_ino; -+ __off64_t offset = source->d_off; -+ unsigned int reclen = source->d_reclen; -+ unsigned char type = source->d_type; -+ -+ /* Check for ino_t overflow. */ -+ if (__glibc_unlikely (ino != source->d_ino)) -+ return handle_overflow (fd, offset, p - buf); -+ -+ /* Convert to the target layout. Use a separate struct and -+ memcpy to side-step aliasing issues. */ -+ struct __old_dirent64 result; -+ result.d_ino = ino; -+ result.d_off = offset; -+ result.d_reclen = reclen; -+ result.d_type = type; -+ -+ /* Write the fixed-sized part of the result to the -+ buffer. */ -+ size_t result_name_offset = offsetof (struct __old_dirent64, d_name); -+ memcpy (p, &result, result_name_offset); -+ -+ /* Adjust the position of the name if necessary. Copy -+ everything until the end of the record, including the -+ terminating NUL byte. */ -+ if (result_name_offset != offsetof (struct dirent64, d_name)) -+ memmove (p + result_name_offset, source->d_name, -+ reclen - offsetof (struct dirent64, d_name)); - -- kbuf = (void *) ((char *) kbuf + kbuf->k.d_reclen); -+ p += reclen; - } - } - return retval; -diff --git a/sysdeps/unix/sysv/linux/gethostid.c b/sysdeps/unix/sysv/linux/gethostid.c -index 2e20f034dc..ee0190e7f9 100644 ---- a/sysdeps/unix/sysv/linux/gethostid.c -+++ b/sysdeps/unix/sysv/linux/gethostid.c -@@ -102,12 +102,12 @@ gethostid (void) - { - int ret = __gethostbyname_r (hostname, &hostbuf, - tmpbuf.data, tmpbuf.length, &hp, &herr); -- if (ret == 0) -+ if (ret == 0 && hp != NULL) - break; - else - { - /* Enlarge the buffer on ERANGE. */ -- if (herr == NETDB_INTERNAL && errno == ERANGE) -+ if (ret != 0 && herr == NETDB_INTERNAL && errno == ERANGE) - { - if (!scratch_buffer_grow (&tmpbuf)) - return 0; -diff --git a/sysdeps/unix/sysv/linux/preadv2.c b/sysdeps/unix/sysv/linux/preadv2.c -index c8bf0764ef..bb08cbc5fd 100644 ---- a/sysdeps/unix/sysv/linux/preadv2.c -+++ b/sysdeps/unix/sysv/linux/preadv2.c -@@ -32,7 +32,7 @@ preadv2 (int fd, const struct iovec *vector, int count, off_t offset, - # ifdef __NR_preadv2 - ssize_t result = SYSCALL_CANCEL (preadv2, fd, vector, count, - LO_HI_LONG (offset), flags); -- if (result >= 0) -+ if (result >= 0 || errno != ENOSYS) - return result; - # endif - /* Trying to emulate the preadv2 syscall flags is troublesome: -diff --git a/sysdeps/unix/sysv/linux/preadv64v2.c b/sysdeps/unix/sysv/linux/preadv64v2.c -index d7400a0252..b72a047347 100644 ---- a/sysdeps/unix/sysv/linux/preadv64v2.c -+++ b/sysdeps/unix/sysv/linux/preadv64v2.c -@@ -30,7 +30,7 @@ preadv64v2 (int fd, const struct iovec *vector, int count, off64_t offset, - #ifdef __NR_preadv64v2 - ssize_t result = SYSCALL_CANCEL (preadv64v2, fd, vector, count, - LO_HI_LONG (offset), flags); -- if (result >= 0) -+ if (result >= 0 || errno != ENOSYS) - return result; - #endif - /* Trying to emulate the preadv2 syscall flags is troublesome: -diff --git a/sysdeps/unix/sysv/linux/pwritev2.c b/sysdeps/unix/sysv/linux/pwritev2.c -index 29c2264c8f..26333ebd43 100644 ---- a/sysdeps/unix/sysv/linux/pwritev2.c -+++ b/sysdeps/unix/sysv/linux/pwritev2.c -@@ -28,7 +28,7 @@ pwritev2 (int fd, const struct iovec *vector, int count, off_t offset, - # ifdef __NR_pwritev2 - ssize_t result = SYSCALL_CANCEL (pwritev2, fd, vector, count, - LO_HI_LONG (offset), flags); -- if (result >= 0) -+ if (result >= 0 || errno != ENOSYS) - return result; - # endif - /* Trying to emulate the pwritev2 syscall flags is troublesome: -diff --git a/sysdeps/unix/sysv/linux/pwritev64v2.c b/sysdeps/unix/sysv/linux/pwritev64v2.c -index 42da321149..17ea905aa6 100644 ---- a/sysdeps/unix/sysv/linux/pwritev64v2.c -+++ b/sysdeps/unix/sysv/linux/pwritev64v2.c -@@ -30,7 +30,7 @@ pwritev64v2 (int fd, const struct iovec *vector, int count, off64_t offset, - #ifdef __NR_pwritev64v2 - ssize_t result = SYSCALL_CANCEL (pwritev64v2, fd, vector, count, - LO_HI_LONG (offset), flags); -- if (result >= 0) -+ if (result >= 0 || errno != ENOSYS) - return result; - #endif - /* Trying to emulate the pwritev2 syscall flags is troublesome: -diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c -index cf0213ece5..85239cedbf 100644 ---- a/sysdeps/unix/sysv/linux/spawni.c -+++ b/sysdeps/unix/sysv/linux/spawni.c -@@ -101,7 +101,7 @@ maybe_script_execute (struct posix_spawn_args *args) - ptrdiff_t argc = args->argc; - - /* Construct an argument list for the shell. */ -- char *new_argv[argc + 1]; -+ char *new_argv[argc + 2]; - new_argv[0] = (char *) _PATH_BSHELL; - new_argv[1] = (char *) args->file; - if (argc > 1) -diff --git a/sysdeps/unix/sysv/linux/tst-readdir64-compat.c b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c -new file mode 100644 -index 0000000000..43c4a8477c ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c -@@ -0,0 +1,111 @@ -+/* Test readdir64 compatibility symbol. -+ Copyright (C) 2018 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 -+ <http://www.gnu.org/licenses/>. */ -+ -+#include <dirent.h> -+#include <dlfcn.h> -+#include <errno.h> -+#include <shlib-compat.h> -+#include <stdbool.h> -+#include <stdio.h> -+#include <string.h> -+#include <support/check.h> -+ -+/* Copied from <olddirent.h>. */ -+struct __old_dirent64 -+ { -+ __ino_t d_ino; -+ __off64_t d_off; -+ unsigned short int d_reclen; -+ unsigned char d_type; -+ char d_name[256]; -+ }; -+ -+typedef struct __old_dirent64 *(*compat_readdir64_type) (DIR *); -+ -+#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2) -+struct __old_dirent64 *compat_readdir64 (DIR *); -+compat_symbol_reference (libc, compat_readdir64, readdir64, GLIBC_2_1); -+#endif -+ -+static int -+do_test (void) -+{ -+#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2) -+ -+ /* Directory stream using the non-compat readdir64 symbol. The test -+ checks against this. */ -+ DIR *dir_reference = opendir ("."); -+ TEST_VERIFY_EXIT (dir_reference != NULL); -+ DIR *dir_test = opendir ("."); -+ TEST_VERIFY_EXIT (dir_test != NULL); -+ -+ /* This loop assumes that the enumeration order is consistent for -+ two different handles. Nothing should write to the current -+ directory (in the source tree) while this test runs, so there -+ should not be any difference due to races. */ -+ size_t count = 0; -+ while (true) -+ { -+ errno = 0; -+ struct dirent64 *entry_reference = readdir64 (dir_reference); -+ if (entry_reference == NULL && errno != 0) -+ FAIL_EXIT1 ("readdir64 entry %zu: %m\n", count); -+ struct __old_dirent64 *entry_test = compat_readdir64 (dir_test); -+ if (entry_reference == NULL) -+ { -+ if (errno == EOVERFLOW) -+ { -+ TEST_VERIFY (entry_reference->d_ino -+ != (__ino_t) entry_reference->d_ino); -+ printf ("info: inode number overflow at entry %zu\n", count); -+ break; -+ } -+ if (errno != 0) -+ FAIL_EXIT1 ("compat readdir64 entry %zu: %m\n", count); -+ } -+ -+ /* Check that both streams end at the same time. */ -+ if (entry_reference == NULL) -+ { -+ TEST_VERIFY (entry_test == NULL); -+ break; -+ } -+ else -+ TEST_VERIFY_EXIT (entry_test != NULL); -+ -+ /* Check that the entries are the same. */ -+ TEST_COMPARE_BLOB (entry_reference->d_name, -+ strlen (entry_reference->d_name), -+ entry_test->d_name, strlen (entry_test->d_name)); -+ TEST_COMPARE (entry_reference->d_ino, entry_test->d_ino); -+ TEST_COMPARE (entry_reference->d_off, entry_test->d_off); -+ TEST_COMPARE (entry_reference->d_type, entry_test->d_type); -+ TEST_COMPARE (entry_reference->d_reclen, entry_test->d_reclen); -+ -+ ++count; -+ } -+ printf ("info: %zu directory entries found\n", count); -+ TEST_VERIFY (count >= 3); /* ".", "..", and some source files. */ -+ -+ TEST_COMPARE (closedir (dir_test), 0); -+ TEST_COMPARE (closedir (dir_reference), 0); -+#endif -+ return 0; -+} -+ -+#include <support/test-driver.c> |