From 2ab608c566ff056546bf9b0b792e36aed3e9e562 Mon Sep 17 00:00:00 2001 From: James Antill Date: Tue, 31 May 2022 14:30:09 -0400 Subject: [PATCH] Auto sync2gitlab import of glibc-2.28-203.el8.src.rpm --- glibc-rh1961109.patch | 165 +++ glibc-rh1982608.patch | 2216 ++++++++++++++++++++++++++++++++++++++ glibc-rh2065588-1.patch | 253 +++++ glibc-rh2065588-10.patch | 21 + glibc-rh2065588-11.patch | 39 + glibc-rh2065588-12.patch | 60 ++ glibc-rh2065588-13.patch | 66 ++ glibc-rh2065588-2.patch | 231 ++++ glibc-rh2065588-3.patch | 527 +++++++++ glibc-rh2065588-4.patch | 194 ++++ glibc-rh2065588-5.patch | 64 ++ glibc-rh2065588-6.patch | 56 + glibc-rh2065588-7.patch | 73 ++ glibc-rh2065588-8.patch | 74 ++ glibc-rh2065588-9.patch | 21 + glibc-rh2072329.patch | 86 ++ glibc-rh2077835.patch | 211 ++++ glibc-rh2086853.patch | 30 + glibc.spec | 38 +- 19 files changed, 4424 insertions(+), 1 deletion(-) create mode 100644 glibc-rh1961109.patch create mode 100644 glibc-rh1982608.patch create mode 100644 glibc-rh2065588-1.patch create mode 100644 glibc-rh2065588-10.patch create mode 100644 glibc-rh2065588-11.patch create mode 100644 glibc-rh2065588-12.patch create mode 100644 glibc-rh2065588-13.patch create mode 100644 glibc-rh2065588-2.patch create mode 100644 glibc-rh2065588-3.patch create mode 100644 glibc-rh2065588-4.patch create mode 100644 glibc-rh2065588-5.patch create mode 100644 glibc-rh2065588-6.patch create mode 100644 glibc-rh2065588-7.patch create mode 100644 glibc-rh2065588-8.patch create mode 100644 glibc-rh2065588-9.patch create mode 100644 glibc-rh2072329.patch create mode 100644 glibc-rh2077835.patch create mode 100644 glibc-rh2086853.patch diff --git a/glibc-rh1961109.patch b/glibc-rh1961109.patch new file mode 100644 index 0000000..e47c4d7 --- /dev/null +++ b/glibc-rh1961109.patch @@ -0,0 +1,165 @@ +commit f17164bd51db31f47fbbdae826c63b6d78184c45 +Author: Florian Weimer +Date: Tue May 18 07:21:33 2021 +0200 + + localedata: Use U+00AF MACRON in more EBCDIC charsets [BZ #27882] + + This updates IBM256, IBM277, IBM278, IBM280, IBM284, IBM297, IBM424 + in the same way that IBM273 was updated for bug 23290. + + IBM256 and IBM424 still have holes after this change, so HAS_HOLES + is not updated. + + Reviewed-by: Siddhesh Poyarekar + +diff --git a/iconvdata/ibm277.c b/iconvdata/ibm277.c +index f93ca2acb8718dd5..0e337dbbdc06a02f 100644 +--- a/iconvdata/ibm277.c ++++ b/iconvdata/ibm277.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM277//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/iconvdata/ibm278.c b/iconvdata/ibm278.c +index 4263000760472913..7450fb8e5b846101 100644 +--- a/iconvdata/ibm278.c ++++ b/iconvdata/ibm278.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM278//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/iconvdata/ibm280.c b/iconvdata/ibm280.c +index 3efddd7dec2728d9..2ea5478e4e0d7007 100644 +--- a/iconvdata/ibm280.c ++++ b/iconvdata/ibm280.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM280//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/iconvdata/ibm284.c b/iconvdata/ibm284.c +index 57dab27d0cec4a33..8dbbc6344d18528f 100644 +--- a/iconvdata/ibm284.c ++++ b/iconvdata/ibm284.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM284//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/iconvdata/ibm297.c b/iconvdata/ibm297.c +index f355659afd4b4502..81e63ba1f28f1548 100644 +--- a/iconvdata/ibm297.c ++++ b/iconvdata/ibm297.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM297//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/localedata/charmaps/IBM256 b/localedata/charmaps/IBM256 +index 5cfd2db5f436cd07..bdc1abf0ade3bfc4 100644 +--- a/localedata/charmaps/IBM256 ++++ b/localedata/charmaps/IBM256 +@@ -194,7 +194,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf DOUBLE LOW LINE +diff --git a/localedata/charmaps/IBM277 b/localedata/charmaps/IBM277 +index 1c0b5cb9fb659364..2f6e3992109a2b33 100644 +--- a/localedata/charmaps/IBM277 ++++ b/localedata/charmaps/IBM277 +@@ -195,7 +195,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM278 b/localedata/charmaps/IBM278 +index 646961501c74c4df..bdfae7621028f003 100644 +--- a/localedata/charmaps/IBM278 ++++ b/localedata/charmaps/IBM278 +@@ -196,7 +196,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM280 b/localedata/charmaps/IBM280 +index 5de3b3e7b96796c0..4c31242806b0ac19 100644 +--- a/localedata/charmaps/IBM280 ++++ b/localedata/charmaps/IBM280 +@@ -195,7 +195,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM284 b/localedata/charmaps/IBM284 +index c64b2a65ab748540..46a8737a715e4e56 100644 +--- a/localedata/charmaps/IBM284 ++++ b/localedata/charmaps/IBM284 +@@ -195,7 +195,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba CIRCUMFLEX ACCENT + /xbb EXCLAMATION MARK +- /xbc OVERLINE ++ /xbc MACRON + /xbd TILDE + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM297 b/localedata/charmaps/IBM297 +index 33b74eee437241aa..14361ad418cf1bc7 100644 +--- a/localedata/charmaps/IBM297 ++++ b/localedata/charmaps/IBM297 +@@ -195,7 +195,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd TILDE + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM424 b/localedata/charmaps/IBM424 +index 883e43b8ae04ee4c..deca11e1b18ec0a6 100644 +--- a/localedata/charmaps/IBM424 ++++ b/localedata/charmaps/IBM424 +@@ -175,7 +175,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba LEFT SQUARE BRACKET + /xbb RIGHT SQUARE BRACKET +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN diff --git a/glibc-rh1982608.patch b/glibc-rh1982608.patch new file mode 100644 index 0000000..6f67ed6 --- /dev/null +++ b/glibc-rh1982608.patch @@ -0,0 +1,2216 @@ +This is a rebase of posix/glob.c from upstream (gnulib->glibc->rhel). + +Relevent upstream commits: + +7c477b57a31487eda516db02b9e04f22d1a6e6af posix/glob.c: update from gnulib + (This is the master commit to which we're syncing) + +gnulib commit 98f034a0c2ba8917c96f363de1a8d66244e411da + (This is the gnulib commit to which glibc upstream sync'd) + +Additional glibc upstream commits of note: +84f7ce84474c1648ce96884f1c91ca7b97ca3fc2 posix: Add glob64 with 64-bit time_t support + (just posix/glob.c and sysdeps/gnu/glob64-lstat-compat.c) +9a7ab0769b295cbf5232140401742a8f34bda3de hurd: Fix glob lstat compatibility +4883360415f1ed772ba44decc501d59deb17bdf0 posix: Sync glob code with gnulib +04986243d1af37ac0177ed2f9db0a066ebd2b212 Remove internal usage of extensible stat functions +ddc650e9b3dc916eab417ce9f79e67337b05035c Fix use-after-free in glob when expanding ~user (bug 25414) + + +diff -rup a/posix/glob-lstat-compat.c b/posix/glob-lstat-compat.c +--- a/posix/glob-lstat-compat.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/posix/glob-lstat-compat.c 2022-05-02 22:49:06.504676711 -0400 +@@ -28,7 +28,8 @@ + # define GLOB_ATTRIBUTE attribute_compat_text_section + + /* Avoid calling gl_lstat with GLOB_ALTDIRFUNC. */ +-# define GLOB_NO_LSTAT ++# define GLOB_LSTAT gl_stat ++# define GLOB_LSTAT64 __stat64 + + # include + +diff -rup a/posix/glob.c b/posix/glob.c +--- a/posix/glob.c 2022-05-03 14:37:52.959042051 -0400 ++++ b/posix/glob.c 2022-05-02 22:49:18.655134696 -0400 +@@ -1,4 +1,4 @@ +-/* Copyright (C) 1991-2018 Free Software Foundation, Inc. ++/* Copyright (C) 1991-2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or +@@ -13,11 +13,22 @@ + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see +- . */ ++ . */ ++ ++#ifndef _LIBC ++ ++/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc ++ optimizes away the pattern == NULL test below. */ ++# define _GL_ARG_NONNULL(params) ++ ++# include ++ ++#endif + + #include + + #include ++#include + #include + #include + #include +@@ -26,7 +37,7 @@ + #include + #include + +-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ ++#if defined _WIN32 && ! defined __CYGWIN__ + # define WINDOWS32 + #endif + +@@ -46,30 +57,38 @@ + # define sysconf(id) __sysconf (id) + # define closedir(dir) __closedir (dir) + # define opendir(name) __opendir (name) ++# undef dirfd ++# define dirfd(str) __dirfd (str) + # define readdir(str) __readdir64 (str) + # define getpwnam_r(name, bufp, buf, len, res) \ + __getpwnam_r (name, bufp, buf, len, res) +-# ifndef __lstat64 +-# define __lstat64(fname, buf) __lxstat64 (_STAT_VER, fname, buf) ++# define FLEXIBLE_ARRAY_MEMBER ++# ifndef struct_stat ++# define struct_stat struct stat + # endif +-# ifndef __stat64 +-# define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf) ++# ifndef struct_stat64 ++# define struct_stat64 struct stat64 ++# endif ++# ifndef GLOB_LSTAT ++# define GLOB_LSTAT gl_lstat ++# endif ++# ifndef GLOB_FSTATAT64 ++# define GLOB_FSTATAT64 __fstatat64 + # endif +-# define struct_stat64 struct stat64 +-# define FLEXIBLE_ARRAY_MEMBER + # include + #else /* !_LIBC */ + # define __glob glob + # define __getlogin_r(buf, len) getlogin_r (buf, len) +-# define __lstat64(fname, buf) lstat (fname, buf) +-# define __stat64(fname, buf) stat (fname, buf) + # define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag) +-# define struct_stat64 struct stat + # ifndef __MVS__ + # define __alloca alloca + # endif + # define __readdir readdir + # define COMPILE_GLOB64 ++# define struct_stat struct stat ++# define struct_stat64 struct stat ++# define GLOB_LSTAT gl_lstat ++# define GLOB_FSTATAT64 fstatat + #endif /* _LIBC */ + + #include +@@ -80,7 +99,9 @@ + + static const char *next_brace_sub (const char *begin, int flags) __THROWNL; + +-typedef uint_fast8_t dirent_type; ++/* The type of ((struct dirent *) 0)->d_type is 'unsigned char' on most ++ platforms, but 'unsigned int' in the mingw from mingw.org. */ ++typedef uint_fast32_t dirent_type; + + #if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE + /* Any distinct values will do here. +@@ -119,9 +140,9 @@ readdir_result_type (struct readdir_resu + /* Construct an initializer for a struct readdir_result object from a + struct dirent *. No copy of the name is made. */ + #define READDIR_RESULT_INITIALIZER(source) \ +- { \ +- source->d_name, \ +- D_TYPE_TO_RESULT (source) \ ++ { \ ++ source->d_name, \ ++ D_TYPE_TO_RESULT (source) \ + } + + /* Call gl_readdir on STREAM. This macro can be overridden to reduce +@@ -186,22 +207,15 @@ glob_lstat (glob_t *pglob, int flags, co + { + /* Use on glob-lstat-compat.c to provide a compat symbol which does not + use lstat / gl_lstat. */ +-#ifdef GLOB_NO_LSTAT +-# define GL_LSTAT gl_stat +-# define LSTAT64 __stat64 +-#else +-# define GL_LSTAT gl_lstat +-# define LSTAT64 __lstat64 +-#endif +- + union + { +- struct stat st; ++ struct_stat st; + struct_stat64 st64; + } ust; + return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC) +- ? pglob->GL_LSTAT (fullname, &ust.st) +- : LSTAT64 (fullname, &ust.st64)); ++ ? pglob->GLOB_LSTAT (fullname, &ust.st) ++ : GLOB_FSTATAT64 (AT_FDCWD, fullname, &ust.st64, ++ AT_SYMLINK_NOFOLLOW)); + } + + /* Set *R = A + B. Return true if the answer is mathematically +@@ -211,7 +225,7 @@ glob_lstat (glob_t *pglob, int flags, co + static bool + size_add_wrapv (size_t a, size_t b, size_t *r) + { +-#if 5 <= __GNUC__ && !defined __ICC ++#if 7 <= __GNUC__ && !defined __ICC + return __builtin_add_overflow (a, b, r); + #else + *r = a + b; +@@ -228,8 +242,8 @@ glob_use_alloca (size_t alloca_used, siz + } + + static int glob_in_dir (const char *pattern, const char *directory, +- int flags, int (*errfunc) (const char *, int), +- glob_t *pglob, size_t alloca_used); ++ int flags, int (*errfunc) (const char *, int), ++ glob_t *pglob, size_t alloca_used); + static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL; + static int collated_compare (const void *, const void *) __THROWNL; + +@@ -239,11 +253,12 @@ static int collated_compare (const void + static bool + is_dir (char const *filename, int flags, glob_t const *pglob) + { +- struct stat st; ++ struct_stat st; + struct_stat64 st64; + return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC) + ? pglob->gl_stat (filename, &st) == 0 && S_ISDIR (st.st_mode) +- : __stat64 (filename, &st64) == 0 && S_ISDIR (st64.st_mode)); ++ : (GLOB_FSTATAT64 (AT_FDCWD, filename, &st64, 0) == 0 ++ && S_ISDIR (st64.st_mode))); + } + + /* Find the end of the sub-pattern in a brace expression. */ +@@ -254,17 +269,17 @@ next_brace_sub (const char *cp, int flag + while (*cp != '\0') + if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\') + { +- if (*++cp == '\0') +- break; +- ++cp; ++ if (*++cp == '\0') ++ break; ++ ++cp; + } + else + { +- if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0)) +- break; ++ if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0)) ++ break; + +- if (*cp++ == '{') +- depth++; ++ if (*cp++ == '{') ++ depth++; + } + + return *cp != '\0' ? cp : NULL; +@@ -285,7 +300,7 @@ next_brace_sub (const char *cp, int flag + int + GLOB_ATTRIBUTE + __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), +- glob_t *pglob) ++ glob_t *pglob) + { + const char *filename; + char *dirname = NULL; +@@ -319,22 +334,22 @@ __glob (const char *pattern, int flags, + { + pglob->gl_pathc = 0; + if (!(flags & GLOB_DOOFFS)) +- pglob->gl_pathv = NULL; ++ pglob->gl_pathv = NULL; + else +- { +- size_t i; ++ { ++ size_t i; + +- if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *)) +- return GLOB_NOSPACE; ++ if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *)) ++ return GLOB_NOSPACE; + +- pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1) +- * sizeof (char *)); +- if (pglob->gl_pathv == NULL) +- return GLOB_NOSPACE; +- +- for (i = 0; i <= pglob->gl_offs; ++i) +- pglob->gl_pathv[i] = NULL; +- } ++ pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1) ++ * sizeof (char *)); ++ if (pglob->gl_pathv == NULL) ++ return GLOB_NOSPACE; ++ ++ for (i = 0; i <= pglob->gl_offs; ++i) ++ pglob->gl_pathv[i] = NULL; ++ } + } + + if (flags & GLOB_BRACE) +@@ -342,129 +357,129 @@ __glob (const char *pattern, int flags, + const char *begin; + + if (flags & GLOB_NOESCAPE) +- begin = strchr (pattern, '{'); ++ begin = strchr (pattern, '{'); + else +- { +- begin = pattern; +- while (1) +- { +- if (*begin == '\0') +- { +- begin = NULL; +- break; +- } +- +- if (*begin == '\\' && begin[1] != '\0') +- ++begin; +- else if (*begin == '{') +- break; +- +- ++begin; +- } +- } ++ { ++ begin = pattern; ++ while (1) ++ { ++ if (*begin == '\0') ++ { ++ begin = NULL; ++ break; ++ } ++ ++ if (*begin == '\\' && begin[1] != '\0') ++ ++begin; ++ else if (*begin == '{') ++ break; ++ ++ ++begin; ++ } ++ } + + if (begin != NULL) +- { +- /* Allocate working buffer large enough for our work. Note that +- we have at least an opening and closing brace. */ +- size_t firstc; +- char *alt_start; +- const char *p; +- const char *next; +- const char *rest; +- size_t rest_len; +- char *onealt; +- size_t pattern_len = strlen (pattern) - 1; +- int alloca_onealt = glob_use_alloca (alloca_used, pattern_len); +- if (alloca_onealt) +- onealt = alloca_account (pattern_len, alloca_used); +- else +- { +- onealt = malloc (pattern_len); +- if (onealt == NULL) +- return GLOB_NOSPACE; +- } +- +- /* We know the prefix for all sub-patterns. */ +- alt_start = mempcpy (onealt, pattern, begin - pattern); +- +- /* Find the first sub-pattern and at the same time find the +- rest after the closing brace. */ +- next = next_brace_sub (begin + 1, flags); +- if (next == NULL) +- { +- /* It is an invalid expression. */ +- illegal_brace: +- if (__glibc_unlikely (!alloca_onealt)) +- free (onealt); +- flags &= ~GLOB_BRACE; +- goto no_brace; +- } +- +- /* Now find the end of the whole brace expression. */ +- rest = next; +- while (*rest != '}') +- { +- rest = next_brace_sub (rest + 1, flags); +- if (rest == NULL) +- /* It is an illegal expression. */ +- goto illegal_brace; +- } +- /* Please note that we now can be sure the brace expression +- is well-formed. */ +- rest_len = strlen (++rest) + 1; +- +- /* We have a brace expression. BEGIN points to the opening {, +- NEXT points past the terminator of the first element, and END +- points past the final }. We will accumulate result names from +- recursive runs for each brace alternative in the buffer using +- GLOB_APPEND. */ +- firstc = pglob->gl_pathc; +- +- p = begin + 1; +- while (1) +- { +- int result; +- +- /* Construct the new glob expression. */ +- mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len); +- +- result = __glob (onealt, +- ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC)) +- | GLOB_APPEND), +- errfunc, pglob); +- +- /* If we got an error, return it. */ +- if (result && result != GLOB_NOMATCH) +- { +- if (__glibc_unlikely (!alloca_onealt)) +- free (onealt); +- if (!(flags & GLOB_APPEND)) +- { +- globfree (pglob); +- pglob->gl_pathc = 0; +- } +- return result; +- } +- +- if (*next == '}') +- /* We saw the last entry. */ +- break; +- +- p = next + 1; +- next = next_brace_sub (p, flags); +- assert (next != NULL); +- } +- +- if (__glibc_unlikely (!alloca_onealt)) +- free (onealt); +- +- if (pglob->gl_pathc != firstc) +- /* We found some entries. */ +- return 0; +- else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) +- return GLOB_NOMATCH; +- } ++ { ++ /* Allocate working buffer large enough for our work. Note that ++ we have at least an opening and closing brace. */ ++ size_t firstc; ++ char *alt_start; ++ const char *p; ++ const char *next; ++ const char *rest; ++ size_t rest_len; ++ char *onealt; ++ size_t pattern_len = strlen (pattern) - 1; ++ int alloca_onealt = glob_use_alloca (alloca_used, pattern_len); ++ if (alloca_onealt) ++ onealt = alloca_account (pattern_len, alloca_used); ++ else ++ { ++ onealt = malloc (pattern_len); ++ if (onealt == NULL) ++ return GLOB_NOSPACE; ++ } ++ ++ /* We know the prefix for all sub-patterns. */ ++ alt_start = mempcpy (onealt, pattern, begin - pattern); ++ ++ /* Find the first sub-pattern and at the same time find the ++ rest after the closing brace. */ ++ next = next_brace_sub (begin + 1, flags); ++ if (next == NULL) ++ { ++ /* It is an invalid expression. */ ++ illegal_brace: ++ if (__glibc_unlikely (!alloca_onealt)) ++ free (onealt); ++ flags &= ~GLOB_BRACE; ++ goto no_brace; ++ } ++ ++ /* Now find the end of the whole brace expression. */ ++ rest = next; ++ while (*rest != '}') ++ { ++ rest = next_brace_sub (rest + 1, flags); ++ if (rest == NULL) ++ /* It is an illegal expression. */ ++ goto illegal_brace; ++ } ++ /* Please note that we now can be sure the brace expression ++ is well-formed. */ ++ rest_len = strlen (++rest) + 1; ++ ++ /* We have a brace expression. BEGIN points to the opening {, ++ NEXT points past the terminator of the first element, and END ++ points past the final }. We will accumulate result names from ++ recursive runs for each brace alternative in the buffer using ++ GLOB_APPEND. */ ++ firstc = pglob->gl_pathc; ++ ++ p = begin + 1; ++ while (1) ++ { ++ int result; ++ ++ /* Construct the new glob expression. */ ++ mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len); ++ ++ result = __glob (onealt, ++ ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC)) ++ | GLOB_APPEND), ++ errfunc, pglob); ++ ++ /* If we got an error, return it. */ ++ if (result && result != GLOB_NOMATCH) ++ { ++ if (__glibc_unlikely (!alloca_onealt)) ++ free (onealt); ++ if (!(flags & GLOB_APPEND)) ++ { ++ globfree (pglob); ++ pglob->gl_pathc = 0; ++ } ++ return result; ++ } ++ ++ if (*next == '}') ++ /* We saw the last entry. */ ++ break; ++ ++ p = next + 1; ++ next = next_brace_sub (p, flags); ++ assert (next != NULL); ++ } ++ ++ if (__glibc_unlikely (!alloca_onealt)) ++ free (onealt); ++ ++ if (pglob->gl_pathc != firstc) ++ /* We found some entries. */ ++ return 0; ++ else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) ++ return GLOB_NOMATCH; ++ } + } + + no_brace: +@@ -486,33 +501,33 @@ __glob (const char *pattern, int flags, + if (filename == NULL) + { + /* This can mean two things: a simple name or "~name". The latter +- case is nothing but a notation for a directory. */ ++ case is nothing but a notation for a directory. */ + if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~') +- { +- dirname = (char *) pattern; +- dirlen = strlen (pattern); +- +- /* Set FILENAME to NULL as a special flag. This is ugly but +- other solutions would require much more code. We test for +- this special case below. */ +- filename = NULL; +- } ++ { ++ dirname = (char *) pattern; ++ dirlen = strlen (pattern); ++ ++ /* Set FILENAME to NULL as a special flag. This is ugly but ++ other solutions would require much more code. We test for ++ this special case below. */ ++ filename = NULL; ++ } + else +- { +- if (__glibc_unlikely (pattern[0] == '\0')) +- { +- dirs.gl_pathv = NULL; +- goto no_matches; +- } +- +- filename = pattern; +- dirname = (char *) "."; +- dirlen = 0; +- } ++ { ++ if (__glibc_unlikely (pattern[0] == '\0')) ++ { ++ dirs.gl_pathv = NULL; ++ goto no_matches; ++ } ++ ++ filename = pattern; ++ dirname = (char *) "."; ++ dirlen = 0; ++ } + } + else if (filename == pattern +- || (filename == pattern + 1 && pattern[0] == '\\' +- && (flags & GLOB_NOESCAPE) == 0)) ++ || (filename == pattern + 1 && pattern[0] == '\\' ++ && (flags & GLOB_NOESCAPE) == 0)) + { + /* "/pattern" or "\\/pattern". */ + dirname = (char *) "/"; +@@ -525,32 +540,32 @@ __glob (const char *pattern, int flags, + dirlen = filename - pattern; + #if defined __MSDOS__ || defined WINDOWS32 + if (*filename == ':' +- || (filename > pattern + 1 && filename[-1] == ':')) +- { +- char *drive_spec; +- +- ++dirlen; +- drive_spec = __alloca (dirlen + 1); +- *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; +- /* For now, disallow wildcards in the drive spec, to +- prevent infinite recursion in glob. */ +- if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) +- return GLOB_NOMATCH; +- /* If this is "d:pattern", we need to copy ':' to DIRNAME +- as well. If it's "d:/pattern", don't remove the slash +- from "d:/", since "d:" and "d:/" are not the same.*/ +- } ++ || (filename > pattern + 1 && filename[-1] == ':')) ++ { ++ char *drive_spec; ++ ++ ++dirlen; ++ drive_spec = __alloca (dirlen + 1); ++ *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; ++ /* For now, disallow wildcards in the drive spec, to ++ prevent infinite recursion in glob. */ ++ if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) ++ return GLOB_NOMATCH; ++ /* If this is "d:pattern", we need to copy ':' to DIRNAME ++ as well. If it's "d:/pattern", don't remove the slash ++ from "d:/", since "d:" and "d:/" are not the same.*/ ++ } + #endif + + if (glob_use_alloca (alloca_used, dirlen + 1)) +- newp = alloca_account (dirlen + 1, alloca_used); ++ newp = alloca_account (dirlen + 1, alloca_used); + else +- { +- newp = malloc (dirlen + 1); +- if (newp == NULL) +- return GLOB_NOSPACE; +- malloc_dirname = 1; +- } ++ { ++ newp = malloc (dirlen + 1); ++ if (newp == NULL) ++ return GLOB_NOSPACE; ++ malloc_dirname = 1; ++ } + *((char *) mempcpy (newp, pattern, dirlen)) = '\0'; + dirname = newp; + ++filename; +@@ -566,363 +581,383 @@ __glob (const char *pattern, int flags, + + if (filename[0] == '\0' && dirlen > 1 && !drive_root) + /* "pattern/". Expand "pattern", appending slashes. */ +- { +- int orig_flags = flags; +- if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\') +- { +- /* "pattern\\/". Remove the final backslash if it hasn't +- been quoted. */ +- char *p = (char *) &dirname[dirlen - 1]; +- +- while (p > dirname && p[-1] == '\\') --p; +- if ((&dirname[dirlen] - p) & 1) +- { +- *(char *) &dirname[--dirlen] = '\0'; +- flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); +- } +- } +- int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob); +- if (val == 0) +- pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) +- | (flags & GLOB_MARK)); +- else if (val == GLOB_NOMATCH && flags != orig_flags) +- { +- /* Make sure globfree (&dirs); is a nop. */ +- dirs.gl_pathv = NULL; +- flags = orig_flags; +- oldcount = pglob->gl_pathc + pglob->gl_offs; +- goto no_matches; +- } +- retval = val; +- goto out; +- } ++ { ++ int orig_flags = flags; ++ if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\') ++ { ++ /* "pattern\\/". Remove the final backslash if it hasn't ++ been quoted. */ ++ char *p = (char *) &dirname[dirlen - 1]; ++ ++ while (p > dirname && p[-1] == '\\') --p; ++ if ((&dirname[dirlen] - p) & 1) ++ { ++ *(char *) &dirname[--dirlen] = '\0'; ++ flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); ++ } ++ } ++ int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob); ++ if (val == 0) ++ pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) ++ | (flags & GLOB_MARK)); ++ else if (val == GLOB_NOMATCH && flags != orig_flags) ++ { ++ /* Make sure globfree (&dirs); is a nop. */ ++ dirs.gl_pathv = NULL; ++ flags = orig_flags; ++ oldcount = pglob->gl_pathc + pglob->gl_offs; ++ goto no_matches; ++ } ++ retval = val; ++ goto out; ++ } + } + + if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~') + { + if (dirname[1] == '\0' || dirname[1] == '/' +- || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\' +- && (dirname[2] == '\0' || dirname[2] == '/'))) +- { +- /* Look up home directory. */ +- char *home_dir = getenv ("HOME"); +- int malloc_home_dir = 0; +- if (home_dir == NULL || home_dir[0] == '\0') +- { ++ || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\' ++ && (dirname[2] == '\0' || dirname[2] == '/'))) ++ { ++ /* Look up home directory. */ ++ char *home_dir = getenv ("HOME"); ++ int malloc_home_dir = 0; ++ if (home_dir == NULL || home_dir[0] == '\0') ++ { + #ifdef WINDOWS32 +- /* Windows NT defines HOMEDRIVE and HOMEPATH. But give +- preference to HOME, because the user can change HOME. */ +- const char *home_drive = getenv ("HOMEDRIVE"); +- const char *home_path = getenv ("HOMEPATH"); +- +- if (home_drive != NULL && home_path != NULL) +- { +- size_t home_drive_len = strlen (home_drive); +- size_t home_path_len = strlen (home_path); +- char *mem = alloca (home_drive_len + home_path_len + 1); +- +- memcpy (mem, home_drive, home_drive_len); +- memcpy (mem + home_drive_len, home_path, home_path_len + 1); +- home_dir = mem; +- } +- else +- home_dir = "c:/users/default"; /* poor default */ ++ /* Windows NT defines HOMEDRIVE and HOMEPATH. But give ++ preference to HOME, because the user can change HOME. */ ++ const char *home_drive = getenv ("HOMEDRIVE"); ++ const char *home_path = getenv ("HOMEPATH"); ++ ++ if (home_drive != NULL && home_path != NULL) ++ { ++ size_t home_drive_len = strlen (home_drive); ++ size_t home_path_len = strlen (home_path); ++ char *mem = alloca (home_drive_len + home_path_len + 1); ++ ++ memcpy (mem, home_drive, home_drive_len); ++ memcpy (mem + home_drive_len, home_path, home_path_len + 1); ++ home_dir = mem; ++ } ++ else ++ home_dir = "c:/users/default"; /* poor default */ + #else +- int err; +- struct passwd *p; +- struct passwd pwbuf; +- struct scratch_buffer s; +- scratch_buffer_init (&s); +- while (true) +- { +- p = NULL; +- err = __getlogin_r (s.data, s.length); +- if (err == 0) +- { ++ int err; ++ struct passwd *p; ++ struct passwd pwbuf; ++ struct scratch_buffer s; ++ scratch_buffer_init (&s); ++ while (true) ++ { ++ p = NULL; ++ err = __getlogin_r (s.data, s.length); ++ if (err == 0) ++ { + # if defined HAVE_GETPWNAM_R || defined _LIBC +- size_t ssize = strlen (s.data) + 1; +- char *sdata = s.data; +- err = getpwnam_r (sdata, &pwbuf, sdata + ssize, +- s.length - ssize, &p); ++ size_t ssize = strlen (s.data) + 1; ++ char *sdata = s.data; ++ err = getpwnam_r (sdata, &pwbuf, sdata + ssize, ++ s.length - ssize, &p); + # else +- p = getpwnam (s.data); +- if (p == NULL) +- err = errno; ++ p = getpwnam (s.data); ++ if (p == NULL) ++ err = errno; + # endif +- } +- if (err != ERANGE) +- break; +- if (!scratch_buffer_grow (&s)) +- { +- retval = GLOB_NOSPACE; +- goto out; +- } +- } +- if (err == 0) +- { +- home_dir = strdup (p->pw_dir); +- malloc_home_dir = 1; +- } +- scratch_buffer_free (&s); +- if (err == 0 && home_dir == NULL) +- { +- retval = GLOB_NOSPACE; +- goto out; +- } ++ } ++ if (err != ERANGE) ++ break; ++ if (!scratch_buffer_grow (&s)) ++ { ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ } ++ if (err == 0) ++ { ++ home_dir = strdup (p->pw_dir); ++ malloc_home_dir = 1; ++ } ++ scratch_buffer_free (&s); ++ if (err == 0 && home_dir == NULL) ++ { ++ retval = GLOB_NOSPACE; ++ goto out; ++ } + #endif /* WINDOWS32 */ +- } +- if (home_dir == NULL || home_dir[0] == '\0') +- { +- if (__glibc_unlikely (malloc_home_dir)) +- free (home_dir); +- if (flags & GLOB_TILDE_CHECK) +- { +- retval = GLOB_NOMATCH; +- goto out; +- } +- else +- { +- home_dir = (char *) "~"; /* No luck. */ +- malloc_home_dir = 0; +- } +- } +- /* Now construct the full directory. */ +- if (dirname[1] == '\0') +- { +- if (__glibc_unlikely (malloc_dirname)) +- free (dirname); +- +- dirname = home_dir; +- dirlen = strlen (dirname); +- malloc_dirname = malloc_home_dir; +- } +- else +- { +- char *newp; +- size_t home_len = strlen (home_dir); +- int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen); +- if (use_alloca) +- newp = alloca_account (home_len + dirlen, alloca_used); +- else +- { +- newp = malloc (home_len + dirlen); +- if (newp == NULL) +- { +- if (__glibc_unlikely (malloc_home_dir)) +- free (home_dir); +- retval = GLOB_NOSPACE; +- goto out; +- } +- } +- +- mempcpy (mempcpy (newp, home_dir, home_len), +- &dirname[1], dirlen); +- +- if (__glibc_unlikely (malloc_dirname)) +- free (dirname); +- +- dirname = newp; +- dirlen += home_len - 1; +- malloc_dirname = !use_alloca; +- +- if (__glibc_unlikely (malloc_home_dir)) +- free (home_dir); +- } +- dirname_modified = 1; +- } ++ } ++ if (home_dir == NULL || home_dir[0] == '\0') ++ { ++ if (__glibc_unlikely (malloc_home_dir)) ++ free (home_dir); ++ if (flags & GLOB_TILDE_CHECK) ++ { ++ retval = GLOB_NOMATCH; ++ goto out; ++ } ++ else ++ { ++ home_dir = (char *) "~"; /* No luck. */ ++ malloc_home_dir = 0; ++ } ++ } ++ /* Now construct the full directory. */ ++ if (dirname[1] == '\0') ++ { ++ if (__glibc_unlikely (malloc_dirname)) ++ free (dirname); ++ ++ dirname = home_dir; ++ dirlen = strlen (dirname); ++ malloc_dirname = malloc_home_dir; ++ } ++ else ++ { ++ char *newp; ++ size_t home_len = strlen (home_dir); ++ int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen); ++ if (use_alloca) ++ newp = alloca_account (home_len + dirlen, alloca_used); ++ else ++ { ++ newp = malloc (home_len + dirlen); ++ if (newp == NULL) ++ { ++ if (__glibc_unlikely (malloc_home_dir)) ++ free (home_dir); ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ } ++ ++ mempcpy (mempcpy (newp, home_dir, home_len), ++ &dirname[1], dirlen); ++ ++ if (__glibc_unlikely (malloc_dirname)) ++ free (dirname); ++ ++ dirname = newp; ++ dirlen += home_len - 1; ++ malloc_dirname = !use_alloca; ++ ++ if (__glibc_unlikely (malloc_home_dir)) ++ free (home_dir); ++ } ++ dirname_modified = 1; ++ } + else +- { ++ { + #ifndef WINDOWS32 +- char *end_name = strchr (dirname, '/'); +- char *user_name; +- int malloc_user_name = 0; +- char *unescape = NULL; +- +- if (!(flags & GLOB_NOESCAPE)) +- { +- if (end_name == NULL) +- { +- unescape = strchr (dirname, '\\'); +- if (unescape) +- end_name = strchr (unescape, '\0'); +- } +- else +- unescape = memchr (dirname, '\\', end_name - dirname); +- } +- if (end_name == NULL) +- user_name = dirname + 1; +- else +- { +- char *newp; +- if (glob_use_alloca (alloca_used, end_name - dirname)) +- newp = alloca_account (end_name - dirname, alloca_used); +- else +- { +- newp = malloc (end_name - dirname); +- if (newp == NULL) +- { +- retval = GLOB_NOSPACE; +- goto out; +- } +- malloc_user_name = 1; +- } +- if (unescape != NULL) +- { +- char *p = mempcpy (newp, dirname + 1, +- unescape - dirname - 1); +- char *q = unescape; +- while (q != end_name) +- { +- if (*q == '\\') +- { +- if (q + 1 == end_name) +- { +- /* "~fo\\o\\" unescape to user_name "foo\\", +- but "~fo\\o\\/" unescape to user_name +- "foo". */ +- if (filename == NULL) +- *p++ = '\\'; +- break; +- } +- ++q; +- } +- *p++ = *q++; +- } +- *p = '\0'; +- } +- else +- *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1)) +- = '\0'; +- user_name = newp; +- } +- +- /* Look up specific user's home directory. */ +- { +- struct passwd *p; +- struct scratch_buffer pwtmpbuf; +- scratch_buffer_init (&pwtmpbuf); ++ /* Recognize ~user as a shorthand for the specified user's home ++ directory. */ ++ char *end_name = strchr (dirname, '/'); ++ char *user_name; ++ int malloc_user_name = 0; ++ char *unescape = NULL; ++ ++ if (!(flags & GLOB_NOESCAPE)) ++ { ++ if (end_name == NULL) ++ { ++ unescape = strchr (dirname, '\\'); ++ if (unescape) ++ end_name = strchr (unescape, '\0'); ++ } ++ else ++ unescape = memchr (dirname, '\\', end_name - dirname); ++ } ++ if (end_name == NULL) ++ user_name = dirname + 1; ++ else ++ { ++ char *newp; ++ if (glob_use_alloca (alloca_used, end_name - dirname)) ++ newp = alloca_account (end_name - dirname, alloca_used); ++ else ++ { ++ newp = malloc (end_name - dirname); ++ if (newp == NULL) ++ { ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ malloc_user_name = 1; ++ } ++ if (unescape != NULL) ++ { ++ char *p = mempcpy (newp, dirname + 1, ++ unescape - dirname - 1); ++ char *q = unescape; ++ while (q != end_name) ++ { ++ if (*q == '\\') ++ { ++ if (q + 1 == end_name) ++ { ++ /* "~fo\\o\\" unescape to user_name "foo\\", ++ but "~fo\\o\\/" unescape to user_name ++ "foo". */ ++ if (filename == NULL) ++ *p++ = '\\'; ++ break; ++ } ++ ++q; ++ } ++ *p++ = *q++; ++ } ++ *p = '\0'; ++ } ++ else ++ *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1)) ++ = '\0'; ++ user_name = newp; ++ } ++ ++ /* Look up specific user's home directory. */ ++ { ++ struct passwd *p; ++ struct scratch_buffer pwtmpbuf; ++ scratch_buffer_init (&pwtmpbuf); + + # if defined HAVE_GETPWNAM_R || defined _LIBC +- struct passwd pwbuf; ++ struct passwd pwbuf; + +- while (getpwnam_r (user_name, &pwbuf, +- pwtmpbuf.data, pwtmpbuf.length, &p) +- == ERANGE) +- { +- if (!scratch_buffer_grow (&pwtmpbuf)) +- { +- retval = GLOB_NOSPACE; +- goto out; +- } +- } ++ while (getpwnam_r (user_name, &pwbuf, ++ pwtmpbuf.data, pwtmpbuf.length, &p) ++ == ERANGE) ++ { ++ if (!scratch_buffer_grow (&pwtmpbuf)) ++ { ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ } + # else +- p = getpwnam (user_name); ++ p = getpwnam (user_name); + # endif + +- if (__glibc_unlikely (malloc_user_name)) +- free (user_name); ++ if (__glibc_unlikely (malloc_user_name)) ++ free (user_name); + +- /* If we found a home directory use this. */ +- if (p != NULL) +- { +- size_t home_len = strlen (p->pw_dir); +- size_t rest_len = end_name == NULL ? 0 : strlen (end_name); +- char *d, *newp; +- bool use_alloca = glob_use_alloca (alloca_used, +- home_len + rest_len + 1); +- +- if (use_alloca) +- newp = alloca_account (home_len + rest_len + 1, alloca_used); +- else +- { +- newp = malloc (home_len + rest_len + 1); +- if (newp == NULL) +- { +- scratch_buffer_free (&pwtmpbuf); +- retval = GLOB_NOSPACE; +- goto out; +- } +- } +- d = mempcpy (newp, p->pw_dir, home_len); +- if (end_name != NULL) +- d = mempcpy (d, end_name, rest_len); +- *d = '\0'; +- +- if (__glibc_unlikely (malloc_dirname)) +- free (dirname); +- dirname = newp; +- malloc_dirname = !use_alloca; +- +- dirlen = home_len + rest_len; +- dirname_modified = 1; +- } +- else +- { +- if (flags & GLOB_TILDE_CHECK) +- { +- /* We have to regard it as an error if we cannot find the +- home directory. */ +- retval = GLOB_NOMATCH; +- goto out; +- } +- } +- scratch_buffer_free (&pwtmpbuf); +- } +-#endif /* !WINDOWS32 */ +- } ++ /* If we found a home directory use this. */ ++ if (p != NULL) ++ { ++ size_t home_len = strlen (p->pw_dir); ++ size_t rest_len = end_name == NULL ? 0 : strlen (end_name); ++ /* dirname contains end_name; we can't free it now. */ ++ char *prev_dirname = ++ (__glibc_unlikely (malloc_dirname) ? dirname : NULL); ++ char *d; ++ ++ malloc_dirname = 0; ++ ++ if (glob_use_alloca (alloca_used, home_len + rest_len + 1)) ++ dirname = alloca_account (home_len + rest_len + 1, ++ alloca_used); ++ else ++ { ++ dirname = malloc (home_len + rest_len + 1); ++ if (dirname == NULL) ++ { ++ free (prev_dirname); ++ scratch_buffer_free (&pwtmpbuf); ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ malloc_dirname = 1; ++ } ++ d = mempcpy (dirname, p->pw_dir, home_len); ++ if (end_name != NULL) ++ d = mempcpy (d, end_name, rest_len); ++ *d = '\0'; ++ ++ free (prev_dirname); ++ ++ dirlen = home_len + rest_len; ++ dirname_modified = 1; ++ } ++ else ++ { ++ if (flags & GLOB_TILDE_CHECK) ++ { ++ /* We have to regard it as an error if we cannot find the ++ home directory. */ ++ retval = GLOB_NOMATCH; ++ goto out; ++ } ++ } ++ scratch_buffer_free (&pwtmpbuf); ++ } ++#else /* WINDOWS32 */ ++ /* On native Windows, access to a user's home directory ++ (via GetUserProfileDirectory) or to a user's environment ++ variables (via ExpandEnvironmentStringsForUser) requires ++ the credentials of the user. Therefore we cannot support ++ the ~user syntax on this platform. ++ Handling ~user specially (and treat it like plain ~) if ++ user is getenv ("USERNAME") would not be a good idea, ++ since it would make people think that ~user is supported ++ in general. */ ++ if (flags & GLOB_TILDE_CHECK) ++ { ++ retval = GLOB_NOMATCH; ++ goto out; ++ } ++#endif /* WINDOWS32 */ ++ } + } + + /* Now test whether we looked for "~" or "~NAME". In this case we + can give the answer now. */ + if (filename == NULL) + { +- size_t newcount = pglob->gl_pathc + pglob->gl_offs; +- char **new_gl_pathv; ++ size_t newcount = pglob->gl_pathc + pglob->gl_offs; ++ char **new_gl_pathv; ++ ++ if (newcount > SIZE_MAX / sizeof (char *) - 2) ++ { ++ nospace: ++ free (pglob->gl_pathv); ++ pglob->gl_pathv = NULL; ++ pglob->gl_pathc = 0; ++ retval = GLOB_NOSPACE; ++ goto out; ++ } + +- if (newcount > SIZE_MAX / sizeof (char *) - 2) +- { +- nospace: +- free (pglob->gl_pathv); +- pglob->gl_pathv = NULL; +- pglob->gl_pathc = 0; +- retval = GLOB_NOSPACE; +- goto out; +- } +- +- new_gl_pathv = realloc (pglob->gl_pathv, +- (newcount + 2) * sizeof (char *)); +- if (new_gl_pathv == NULL) +- goto nospace; +- pglob->gl_pathv = new_gl_pathv; +- +- if (flags & GLOB_MARK && is_dir (dirname, flags, pglob)) +- { +- char *p; +- pglob->gl_pathv[newcount] = malloc (dirlen + 2); +- if (pglob->gl_pathv[newcount] == NULL) +- goto nospace; +- p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen); +- p[0] = '/'; +- p[1] = '\0'; +- if (__glibc_unlikely (malloc_dirname)) +- free (dirname); +- } +- else +- { +- if (__glibc_unlikely (malloc_dirname)) +- pglob->gl_pathv[newcount] = dirname; +- else +- { +- pglob->gl_pathv[newcount] = strdup (dirname); +- if (pglob->gl_pathv[newcount] == NULL) +- goto nospace; +- } +- } +- pglob->gl_pathv[++newcount] = NULL; +- ++pglob->gl_pathc; +- pglob->gl_flags = flags; ++ new_gl_pathv = realloc (pglob->gl_pathv, ++ (newcount + 2) * sizeof (char *)); ++ if (new_gl_pathv == NULL) ++ goto nospace; ++ pglob->gl_pathv = new_gl_pathv; ++ ++ if (flags & GLOB_MARK && is_dir (dirname, flags, pglob)) ++ { ++ char *p; ++ pglob->gl_pathv[newcount] = malloc (dirlen + 2); ++ if (pglob->gl_pathv[newcount] == NULL) ++ goto nospace; ++ p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen); ++ p[0] = '/'; ++ p[1] = '\0'; ++ if (__glibc_unlikely (malloc_dirname)) ++ free (dirname); ++ } ++ else ++ { ++ if (__glibc_unlikely (malloc_dirname)) ++ pglob->gl_pathv[newcount] = dirname; ++ else ++ { ++ pglob->gl_pathv[newcount] = strdup (dirname); ++ if (pglob->gl_pathv[newcount] == NULL) ++ goto nospace; ++ } ++ } ++ pglob->gl_pathv[++newcount] = NULL; ++ ++pglob->gl_pathc; ++ pglob->gl_flags = flags; + +- return 0; ++ return 0; + } + + meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE)); +@@ -934,135 +969,135 @@ __glob (const char *pattern, int flags, + if (meta & (GLOBPAT_SPECIAL | GLOBPAT_BRACKET)) + { + /* The directory name contains metacharacters, so we +- have to glob for the directory, and then glob for +- the pattern in each directory found. */ ++ have to glob for the directory, and then glob for ++ the pattern in each directory found. */ + size_t i; + + if (!(flags & GLOB_NOESCAPE) && dirlen > 0 && dirname[dirlen - 1] == '\\') +- { +- /* "foo\\/bar". Remove the final backslash from dirname +- if it has not been quoted. */ +- char *p = (char *) &dirname[dirlen - 1]; +- +- while (p > dirname && p[-1] == '\\') --p; +- if ((&dirname[dirlen] - p) & 1) +- *(char *) &dirname[--dirlen] = '\0'; +- } ++ { ++ /* "foo\\/bar". Remove the final backslash from dirname ++ if it has not been quoted. */ ++ char *p = (char *) &dirname[dirlen - 1]; ++ ++ while (p > dirname && p[-1] == '\\') --p; ++ if ((&dirname[dirlen] - p) & 1) ++ *(char *) &dirname[--dirlen] = '\0'; ++ } + + if (__glibc_unlikely ((flags & GLOB_ALTDIRFUNC) != 0)) +- { +- /* Use the alternative access functions also in the recursive +- call. */ +- dirs.gl_opendir = pglob->gl_opendir; +- dirs.gl_readdir = pglob->gl_readdir; +- dirs.gl_closedir = pglob->gl_closedir; +- dirs.gl_stat = pglob->gl_stat; +- dirs.gl_lstat = pglob->gl_lstat; +- } ++ { ++ /* Use the alternative access functions also in the recursive ++ call. */ ++ dirs.gl_opendir = pglob->gl_opendir; ++ dirs.gl_readdir = pglob->gl_readdir; ++ dirs.gl_closedir = pglob->gl_closedir; ++ dirs.gl_stat = pglob->gl_stat; ++ dirs.gl_lstat = pglob->gl_lstat; ++ } + + status = __glob (dirname, +- ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC)) +- | GLOB_NOSORT | GLOB_ONLYDIR), +- errfunc, &dirs); ++ ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC)) ++ | GLOB_NOSORT | GLOB_ONLYDIR), ++ errfunc, &dirs); + if (status != 0) +- { +- if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH) +- { +- retval = status; +- goto out; +- } +- goto no_matches; +- } ++ { ++ if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH) ++ { ++ retval = status; ++ goto out; ++ } ++ goto no_matches; ++ } + + /* We have successfully globbed the preceding directory name. +- For each name we found, call glob_in_dir on it and FILENAME, +- appending the results to PGLOB. */ ++ For each name we found, call glob_in_dir on it and FILENAME, ++ appending the results to PGLOB. */ + for (i = 0; i < dirs.gl_pathc; ++i) +- { +- size_t old_pathc; ++ { ++ size_t old_pathc; + +- old_pathc = pglob->gl_pathc; +- status = glob_in_dir (filename, dirs.gl_pathv[i], +- ((flags | GLOB_APPEND) +- & ~(GLOB_NOCHECK | GLOB_NOMAGIC)), +- errfunc, pglob, alloca_used); +- if (status == GLOB_NOMATCH) +- /* No matches in this directory. Try the next. */ +- continue; +- +- if (status != 0) +- { +- globfree (&dirs); +- globfree (pglob); +- pglob->gl_pathc = 0; +- retval = status; +- goto out; +- } +- +- /* Stick the directory on the front of each name. */ +- if (prefix_array (dirs.gl_pathv[i], +- &pglob->gl_pathv[old_pathc + pglob->gl_offs], +- pglob->gl_pathc - old_pathc)) +- { +- globfree (&dirs); +- globfree (pglob); +- pglob->gl_pathc = 0; +- retval = GLOB_NOSPACE; +- goto out; +- } +- } ++ old_pathc = pglob->gl_pathc; ++ status = glob_in_dir (filename, dirs.gl_pathv[i], ++ ((flags | GLOB_APPEND) ++ & ~(GLOB_NOCHECK | GLOB_NOMAGIC)), ++ errfunc, pglob, alloca_used); ++ if (status == GLOB_NOMATCH) ++ /* No matches in this directory. Try the next. */ ++ continue; ++ ++ if (status != 0) ++ { ++ globfree (&dirs); ++ globfree (pglob); ++ pglob->gl_pathc = 0; ++ retval = status; ++ goto out; ++ } ++ ++ /* Stick the directory on the front of each name. */ ++ if (prefix_array (dirs.gl_pathv[i], ++ &pglob->gl_pathv[old_pathc + pglob->gl_offs], ++ pglob->gl_pathc - old_pathc)) ++ { ++ globfree (&dirs); ++ globfree (pglob); ++ pglob->gl_pathc = 0; ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ } + + flags |= GLOB_MAGCHAR; + + /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls. +- But if we have not found any matching entry and the GLOB_NOCHECK +- flag was set we must return the input pattern itself. */ ++ But if we have not found any matching entry and the GLOB_NOCHECK ++ flag was set we must return the input pattern itself. */ + if (pglob->gl_pathc + pglob->gl_offs == oldcount) +- { +- no_matches: +- /* No matches. */ +- if (flags & GLOB_NOCHECK) +- { +- size_t newcount = pglob->gl_pathc + pglob->gl_offs; +- char **new_gl_pathv; +- +- if (newcount > SIZE_MAX / sizeof (char *) - 2) +- { +- nospace2: +- globfree (&dirs); +- retval = GLOB_NOSPACE; +- goto out; +- } +- +- new_gl_pathv = realloc (pglob->gl_pathv, +- (newcount + 2) * sizeof (char *)); +- if (new_gl_pathv == NULL) +- goto nospace2; +- pglob->gl_pathv = new_gl_pathv; +- +- pglob->gl_pathv[newcount] = strdup (pattern); +- if (pglob->gl_pathv[newcount] == NULL) +- { +- globfree (&dirs); +- globfree (pglob); +- pglob->gl_pathc = 0; +- retval = GLOB_NOSPACE; +- goto out; +- } +- +- ++pglob->gl_pathc; +- ++newcount; +- +- pglob->gl_pathv[newcount] = NULL; +- pglob->gl_flags = flags; +- } +- else +- { +- globfree (&dirs); +- retval = GLOB_NOMATCH; +- goto out; +- } +- } ++ { ++ no_matches: ++ /* No matches. */ ++ if (flags & GLOB_NOCHECK) ++ { ++ size_t newcount = pglob->gl_pathc + pglob->gl_offs; ++ char **new_gl_pathv; ++ ++ if (newcount > SIZE_MAX / sizeof (char *) - 2) ++ { ++ nospace2: ++ globfree (&dirs); ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ ++ new_gl_pathv = realloc (pglob->gl_pathv, ++ (newcount + 2) * sizeof (char *)); ++ if (new_gl_pathv == NULL) ++ goto nospace2; ++ pglob->gl_pathv = new_gl_pathv; ++ ++ pglob->gl_pathv[newcount] = strdup (pattern); ++ if (pglob->gl_pathv[newcount] == NULL) ++ { ++ globfree (&dirs); ++ globfree (pglob); ++ pglob->gl_pathc = 0; ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ ++ ++pglob->gl_pathc; ++ ++newcount; ++ ++ pglob->gl_pathv[newcount] = NULL; ++ pglob->gl_flags = flags; ++ } ++ else ++ { ++ globfree (&dirs); ++ retval = GLOB_NOMATCH; ++ goto out; ++ } ++ } + + globfree (&dirs); + } +@@ -1072,57 +1107,57 @@ __glob (const char *pattern, int flags, + int orig_flags = flags; + + if (meta & GLOBPAT_BACKSLASH) +- { +- char *p = strchr (dirname, '\\'), *q; +- /* We need to unescape the dirname string. It is certainly +- allocated by alloca, as otherwise filename would be NULL +- or dirname wouldn't contain backslashes. */ +- q = p; +- do +- { +- if (*p == '\\') +- { +- *q = *++p; +- --dirlen; +- } +- else +- *q = *p; +- ++q; +- } +- while (*p++ != '\0'); +- dirname_modified = 1; +- } ++ { ++ char *p = strchr (dirname, '\\'), *q; ++ /* We need to unescape the dirname string. It is certainly ++ allocated by alloca, as otherwise filename would be NULL ++ or dirname wouldn't contain backslashes. */ ++ q = p; ++ do ++ { ++ if (*p == '\\') ++ { ++ *q = *++p; ++ --dirlen; ++ } ++ else ++ *q = *p; ++ ++q; ++ } ++ while (*p++ != '\0'); ++ dirname_modified = 1; ++ } + if (dirname_modified) +- flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); ++ flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); + status = glob_in_dir (filename, dirname, flags, errfunc, pglob, +- alloca_used); ++ alloca_used); + if (status != 0) +- { +- if (status == GLOB_NOMATCH && flags != orig_flags +- && pglob->gl_pathc + pglob->gl_offs == oldcount) +- { +- /* Make sure globfree (&dirs); is a nop. */ +- dirs.gl_pathv = NULL; +- flags = orig_flags; +- goto no_matches; +- } +- retval = status; +- goto out; +- } ++ { ++ if (status == GLOB_NOMATCH && flags != orig_flags ++ && pglob->gl_pathc + pglob->gl_offs == oldcount) ++ { ++ /* Make sure globfree (&dirs); is a nop. */ ++ dirs.gl_pathv = NULL; ++ flags = orig_flags; ++ goto no_matches; ++ } ++ retval = status; ++ goto out; ++ } + + if (dirlen > 0) +- { +- /* Stick the directory on the front of each name. */ +- if (prefix_array (dirname, +- &pglob->gl_pathv[old_pathc + pglob->gl_offs], +- pglob->gl_pathc - old_pathc)) +- { +- globfree (pglob); +- pglob->gl_pathc = 0; +- retval = GLOB_NOSPACE; +- goto out; +- } +- } ++ { ++ /* Stick the directory on the front of each name. */ ++ if (prefix_array (dirname, ++ &pglob->gl_pathv[old_pathc + pglob->gl_offs], ++ pglob->gl_pathc - old_pathc)) ++ { ++ globfree (pglob); ++ pglob->gl_pathc = 0; ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ } + } + + if (flags & GLOB_MARK) +@@ -1131,28 +1166,28 @@ __glob (const char *pattern, int flags, + size_t i; + + for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i) +- if (is_dir (pglob->gl_pathv[i], flags, pglob)) +- { +- size_t len = strlen (pglob->gl_pathv[i]) + 2; +- char *new = realloc (pglob->gl_pathv[i], len); +- if (new == NULL) +- { +- globfree (pglob); +- pglob->gl_pathc = 0; +- retval = GLOB_NOSPACE; +- goto out; +- } +- strcpy (&new[len - 2], "/"); +- pglob->gl_pathv[i] = new; +- } ++ if (is_dir (pglob->gl_pathv[i], flags, pglob)) ++ { ++ size_t len = strlen (pglob->gl_pathv[i]) + 2; ++ char *new = realloc (pglob->gl_pathv[i], len); ++ if (new == NULL) ++ { ++ globfree (pglob); ++ pglob->gl_pathc = 0; ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ strcpy (&new[len - 2], "/"); ++ pglob->gl_pathv[i] = new; ++ } + } + + if (!(flags & GLOB_NOSORT)) + { + /* Sort the vector. */ + qsort (&pglob->gl_pathv[oldcount], +- pglob->gl_pathc + pglob->gl_offs - oldcount, +- sizeof (char *), collated_compare); ++ pglob->gl_pathc + pglob->gl_offs - oldcount, ++ sizeof (char *), collated_compare); + } + + out: +@@ -1204,14 +1239,14 @@ prefix_array (const char *dirname, char + if (dirlen > 1) + { + if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':') +- /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ +- --dirlen; ++ /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ ++ --dirlen; + else if (dirname[dirlen - 1] == ':') +- { +- /* DIRNAME is "d:". Use ':' instead of '/'. */ +- --dirlen; +- dirsep_char = ':'; +- } ++ { ++ /* DIRNAME is "d:". Use ':' instead of '/'. */ ++ --dirlen; ++ dirsep_char = ':'; ++ } + } + #endif + +@@ -1220,16 +1255,16 @@ prefix_array (const char *dirname, char + size_t eltlen = strlen (array[i]) + 1; + char *new = malloc (dirlen + 1 + eltlen); + if (new == NULL) +- { +- while (i > 0) +- free (array[--i]); +- return 1; +- } ++ { ++ while (i > 0) ++ free (array[--i]); ++ return 1; ++ } + + { +- char *endp = mempcpy (new, dirname, dirlen); +- *endp++ = dirsep_char; +- mempcpy (endp, array[i], eltlen); ++ char *endp = mempcpy (new, dirname, dirlen); ++ *endp++ = dirsep_char; ++ mempcpy (endp, array[i], eltlen); + } + free (array[i]); + array[i] = new; +@@ -1244,11 +1279,13 @@ prefix_array (const char *dirname, char + The GLOB_APPEND flag is assumed to be set (always appends). */ + static int + glob_in_dir (const char *pattern, const char *directory, int flags, +- int (*errfunc) (const char *, int), +- glob_t *pglob, size_t alloca_used) ++ int (*errfunc) (const char *, int), ++ glob_t *pglob, size_t alloca_used) + { + size_t dirlen = strlen (directory); + void *stream = NULL; ++ struct scratch_buffer s; ++ scratch_buffer_init (&s); + # define GLOBNAMES_MEMBERS(nnames) \ + struct globnames *next; size_t count; char *name[nnames]; + struct globnames { GLOBNAMES_MEMBERS (FLEXIBLE_ARRAY_MEMBER) }; +@@ -1273,8 +1310,8 @@ glob_in_dir (const char *pattern, const + if (meta == GLOBPAT_NONE && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) + { + /* We need not do any tests. The PATTERN contains no meta +- characters and we must not return an error therefore the +- result will always contain exactly one name. */ ++ characters and we must not return an error therefore the ++ result will always contain exactly one name. */ + flags |= GLOB_NOCHECK; + } + else if (meta == GLOBPAT_NONE) +@@ -1288,102 +1325,127 @@ glob_in_dir (const char *pattern, const + if (alloca_fullname) + fullname = alloca_account (fullsize, alloca_used); + else +- { +- fullname = malloc (fullsize); +- if (fullname == NULL) +- return GLOB_NOSPACE; +- } ++ { ++ fullname = malloc (fullsize); ++ if (fullname == NULL) ++ return GLOB_NOSPACE; ++ } + + mempcpy (mempcpy (mempcpy (fullname, directory, dirlen), +- "/", 1), +- pattern, patlen + 1); ++ "/", 1), ++ pattern, patlen + 1); + if (glob_lstat (pglob, flags, fullname) == 0 +- || errno == EOVERFLOW) +- /* We found this file to be existing. Now tell the rest +- of the function to copy this name into the result. */ +- flags |= GLOB_NOCHECK; ++ || errno == EOVERFLOW) ++ /* We found this file to be existing. Now tell the rest ++ of the function to copy this name into the result. */ ++ flags |= GLOB_NOCHECK; + + if (__glibc_unlikely (!alloca_fullname)) +- free (fullname); ++ free (fullname); + } + else + { + stream = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) +- ? (*pglob->gl_opendir) (directory) +- : opendir (directory)); ++ ? (*pglob->gl_opendir) (directory) ++ : opendir (directory)); + if (stream == NULL) +- { +- if (errno != ENOTDIR +- && ((errfunc != NULL && (*errfunc) (directory, errno)) +- || (flags & GLOB_ERR))) +- return GLOB_ABORTED; +- } ++ { ++ if (errno != ENOTDIR ++ && ((errfunc != NULL && (*errfunc) (directory, errno)) ++ || (flags & GLOB_ERR))) ++ return GLOB_ABORTED; ++ } + else +- { +- int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) +- | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)); +- flags |= GLOB_MAGCHAR; +- +- while (1) +- { +- struct readdir_result d; +- { +- if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) +- d = convert_dirent (GL_READDIR (pglob, stream)); +- else +- { ++ { ++ int dfd = dirfd (stream); ++ int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) ++ | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)); ++ flags |= GLOB_MAGCHAR; ++ ++ while (1) ++ { ++ struct readdir_result d; ++ { ++ if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) ++ d = convert_dirent (GL_READDIR (pglob, stream)); ++ else ++ { + #ifdef COMPILE_GLOB64 +- d = convert_dirent (__readdir (stream)); ++ d = convert_dirent (__readdir (stream)); + #else +- d = convert_dirent64 (__readdir64 (stream)); ++ d = convert_dirent64 (__readdir64 (stream)); + #endif +- } +- } +- if (d.name == NULL) +- break; +- +- /* If we shall match only directories use the information +- provided by the dirent call if possible. */ +- if (flags & GLOB_ONLYDIR) +- switch (readdir_result_type (d)) +- { +- case DT_DIR: case DT_LNK: case DT_UNKNOWN: break; +- default: continue; +- } +- +- if (fnmatch (pattern, d.name, fnm_flags) == 0) +- { +- if (cur == names->count) +- { +- struct globnames *newnames; +- size_t count = names->count * 2; +- size_t nameoff = offsetof (struct globnames, name); +- size_t size = FLEXSIZEOF (struct globnames, name, +- count * sizeof (char *)); +- if ((SIZE_MAX - nameoff) / 2 / sizeof (char *) +- < names->count) +- goto memory_error; +- if (glob_use_alloca (alloca_used, size)) +- newnames = names_alloca +- = alloca_account (size, alloca_used); +- else if ((newnames = malloc (size)) +- == NULL) +- goto memory_error; +- newnames->count = count; +- newnames->next = names; +- names = newnames; +- cur = 0; +- } +- names->name[cur] = strdup (d.name); +- if (names->name[cur] == NULL) +- goto memory_error; +- ++cur; +- ++nfound; +- if (SIZE_MAX - pglob->gl_offs <= nfound) +- goto memory_error; +- } +- } +- } ++ } ++ } ++ if (d.name == NULL) ++ break; ++ ++ /* If we shall match only directories use the information ++ provided by the dirent call if possible. */ ++ if (flags & GLOB_ONLYDIR) ++ switch (readdir_result_type (d)) ++ { ++ default: continue; ++ case DT_DIR: break; ++ case DT_LNK: case DT_UNKNOWN: ++ /* The filesystem was too lazy to give us a hint, ++ so we have to do it the hard way. */ ++ if (__glibc_unlikely (dfd < 0 || flags & GLOB_ALTDIRFUNC)) ++ { ++ size_t namelen = strlen (d.name); ++ size_t need = dirlen + 1 + namelen + 1; ++ if (s.length < need ++ && !scratch_buffer_set_array_size (&s, need, 1)) ++ goto memory_error; ++ char *p = mempcpy (s.data, directory, dirlen); ++ *p = '/'; ++ p += p[-1] != '/'; ++ memcpy (p, d.name, namelen + 1); ++ if (! is_dir (s.data, flags, pglob)) ++ continue; ++ } ++ else ++ { ++ struct_stat64 st64; ++ if (! (GLOB_FSTATAT64 (dfd, d.name, &st64, 0) == 0 ++ && S_ISDIR (st64.st_mode))) ++ continue; ++ } ++ } ++ ++ if (fnmatch (pattern, d.name, fnm_flags) == 0) ++ { ++ if (cur == names->count) ++ { ++ struct globnames *newnames; ++ size_t count = names->count * 2; ++ size_t nameoff = offsetof (struct globnames, name); ++ size_t size = FLEXSIZEOF (struct globnames, name, ++ count * sizeof (char *)); ++ if ((SIZE_MAX - nameoff) / 2 / sizeof (char *) ++ < names->count) ++ goto memory_error; ++ if (glob_use_alloca (alloca_used, size)) ++ newnames = names_alloca ++ = alloca_account (size, alloca_used); ++ else if ((newnames = malloc (size)) ++ == NULL) ++ goto memory_error; ++ newnames->count = count; ++ newnames->next = names; ++ names = newnames; ++ cur = 0; ++ } ++ names->name[cur] = strdup (d.name); ++ if (names->name[cur] == NULL) ++ goto memory_error; ++ ++cur; ++ ++nfound; ++ if (SIZE_MAX - pglob->gl_offs <= nfound) ++ goto memory_error; ++ } ++ } ++ } + } + + if (nfound == 0 && (flags & GLOB_NOCHECK)) +@@ -1392,7 +1454,7 @@ glob_in_dir (const char *pattern, const + nfound = 1; + names->name[cur] = malloc (len + 1); + if (names->name[cur] == NULL) +- goto memory_error; ++ goto memory_error; + *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0'; + } + +@@ -1403,82 +1465,83 @@ glob_in_dir (const char *pattern, const + result = 0; + + if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc +- < pglob->gl_offs + nfound + 1) +- goto memory_error; ++ < pglob->gl_offs + nfound + 1) ++ goto memory_error; + + new_gl_pathv +- = realloc (pglob->gl_pathv, +- (pglob->gl_pathc + pglob->gl_offs + nfound + 1) +- * sizeof (char *)); ++ = realloc (pglob->gl_pathv, ++ (pglob->gl_pathc + pglob->gl_offs + nfound + 1) ++ * sizeof (char *)); + + if (new_gl_pathv == NULL) +- { +- memory_error: +- while (1) +- { +- struct globnames *old = names; +- for (size_t i = 0; i < cur; ++i) +- free (names->name[i]); +- names = names->next; +- /* NB: we will not leak memory here if we exit without +- freeing the current block assigned to OLD. At least +- the very first block is always allocated on the stack +- and this is the block assigned to OLD here. */ +- if (names == NULL) +- { +- assert (old == init_names); +- break; +- } +- cur = names->count; +- if (old == names_alloca) +- names_alloca = names; +- else +- free (old); +- } +- result = GLOB_NOSPACE; +- } ++ { ++ memory_error: ++ while (1) ++ { ++ struct globnames *old = names; ++ for (size_t i = 0; i < cur; ++i) ++ free (names->name[i]); ++ names = names->next; ++ /* NB: we will not leak memory here if we exit without ++ freeing the current block assigned to OLD. At least ++ the very first block is always allocated on the stack ++ and this is the block assigned to OLD here. */ ++ if (names == NULL) ++ { ++ assert (old == init_names); ++ break; ++ } ++ cur = names->count; ++ if (old == names_alloca) ++ names_alloca = names; ++ else ++ free (old); ++ } ++ result = GLOB_NOSPACE; ++ } + else +- { +- while (1) +- { +- struct globnames *old = names; +- for (size_t i = 0; i < cur; ++i) +- new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++] +- = names->name[i]; +- names = names->next; +- /* NB: we will not leak memory here if we exit without +- freeing the current block assigned to OLD. At least +- the very first block is always allocated on the stack +- and this is the block assigned to OLD here. */ +- if (names == NULL) +- { +- assert (old == init_names); +- break; +- } +- cur = names->count; +- if (old == names_alloca) +- names_alloca = names; +- else +- free (old); +- } ++ { ++ while (1) ++ { ++ struct globnames *old = names; ++ for (size_t i = 0; i < cur; ++i) ++ new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++] ++ = names->name[i]; ++ names = names->next; ++ /* NB: we will not leak memory here if we exit without ++ freeing the current block assigned to OLD. At least ++ the very first block is always allocated on the stack ++ and this is the block assigned to OLD here. */ ++ if (names == NULL) ++ { ++ assert (old == init_names); ++ break; ++ } ++ cur = names->count; ++ if (old == names_alloca) ++ names_alloca = names; ++ else ++ free (old); ++ } + +- pglob->gl_pathv = new_gl_pathv; ++ pglob->gl_pathv = new_gl_pathv; + +- pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; ++ pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + +- pglob->gl_flags = flags; +- } ++ pglob->gl_flags = flags; ++ } + } + + if (stream != NULL) + { + save = errno; + if (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)) +- (*pglob->gl_closedir) (stream); ++ (*pglob->gl_closedir) (stream); + else +- closedir (stream); ++ closedir (stream); + __set_errno (save); + } + ++ scratch_buffer_free (&s); + return result; + } +diff -rup a/sysdeps/gnu/glob-lstat-compat.c b/sysdeps/gnu/glob-lstat-compat.c +--- a/sysdeps/gnu/glob-lstat-compat.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/sysdeps/gnu/glob-lstat-compat.c 2022-05-02 17:51:04.167557574 -0400 +@@ -29,7 +29,8 @@ + #define GLOB_ATTRIBUTE attribute_compat_text_section + + /* Avoid calling gl_lstat with GLOB_ALTDIRFUNC. */ +-#define GLOB_NO_LSTAT ++#define GLOB_LSTAT gl_stat ++#define GLOB_LSTAT64 __stat64 + + #include + +diff -rup a/sysdeps/unix/sysv/linux/glob-lstat-compat.c b/sysdeps/unix/sysv/linux/glob-lstat-compat.c +--- a/sysdeps/unix/sysv/linux/glob-lstat-compat.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/glob-lstat-compat.c 2022-05-02 23:05:45.197297341 -0400 +@@ -30,7 +30,12 @@ + #define GLOB_ATTRIBUTE attribute_compat_text_section + + /* Avoid calling gl_lstat with GLOB_ALTDIRFUNC. */ +-#define GLOB_NO_LSTAT ++# define COMPILE_GLOB64 1 ++# define struct_stat struct stat ++# define struct_stat64 struct stat64 ++# define GLOB_LSTAT gl_stat ++# define GLOB_STAT64 __stat64 ++# define GLOB_LSTAT64 __stat64 + + #include + diff --git a/glibc-rh2065588-1.patch b/glibc-rh2065588-1.patch new file mode 100644 index 0000000..3b4db3f --- /dev/null +++ b/glibc-rh2065588-1.patch @@ -0,0 +1,253 @@ +commit 2a973ab7f1a6f6cd9be1c7257fd7b5d331515eab +Author: Adhemerval Zanella +Date: Wed Sep 12 10:30:46 2018 -0300 + + posix: Add internal symbols for posix_spawn interface + + This patch adds internal hidden definition for mostly of the posix_spawn + function so it can be used internally on both popen and system + implementations. + + Checked on x86_64-linux-gnu. + + * include/spawn.h (__posix_spawn, posix_spawn_file_actions_addclose, + __posix_spawn_file_actions_adddup2, __posix_spawn_file_actions_destroy, + __posix_spawn_file_actions_init, __posix_spawnattr_init, + __posix_spawnattr_destroy, __posix_spawnattr_setflags, + __posix_spawnattr_setsigdefault, __posix_spawnattr_setsigmask): New + prototype. + * posix/spawn.c (__posix_spawn): Add libc_hidden_def. + * posix/spawn_faction_addclose.c + (__posix_spawn_file_actions_addclose): Add hidden definition. + * posix/spawn_faction_adddup2.c + (__posix_spawn_file_actions_adddup2): Likewise. + * posix/spawn_faction_destroy.c + (__posix_spawn_file_actions_destroy): Likewise. + * posix/spawn_faction_init.c (__posix_spawn_file_actions_init): + Likewise. + * posix/spawnattr_destroy.c (__posix_spawnattr_destroy): Likewise. + * posix/spawnattr_init.c (__posix_spawnattr_init): Likewise. + * posix/spawnattr_setdefault.c (__posix_spawnattr_setsigdefault): + Likewise. + * posix/spawnattr_setflags.c (__posix_spawnattr_setflags): Likewise. + * posix/spawnattr_setsigmask.c (__posix_spawnattr_setsigmask): + Likewise. + +diff --git a/include/spawn.h b/include/spawn.h +index a6c7a8adc361927e..7fdd965bd780f8de 100644 +--- a/include/spawn.h ++++ b/include/spawn.h +@@ -1 +1,36 @@ ++#ifndef _SPAWN_H + #include ++ ++# ifndef _ISOMAC ++__typeof (posix_spawn) __posix_spawn; ++libc_hidden_proto (__posix_spawn) ++ ++__typeof (posix_spawn_file_actions_addclose) ++ __posix_spawn_file_actions_addclose attribute_hidden; ++ ++__typeof (posix_spawn_file_actions_adddup2) ++ __posix_spawn_file_actions_adddup2 attribute_hidden; ++ ++__typeof (posix_spawn_file_actions_destroy) ++ __posix_spawn_file_actions_destroy attribute_hidden; ++ ++__typeof (posix_spawn_file_actions_init) __posix_spawn_file_actions_init ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_init) __posix_spawnattr_init ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_destroy) __posix_spawnattr_destroy ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_setflags) __posix_spawnattr_setflags ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_setsigdefault) __posix_spawnattr_setsigdefault ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_setsigmask) __posix_spawnattr_setsigmask ++ attribute_hidden; ++ ++# endif /* !_ISOMAC */ ++#endif /* spawn.h */ +diff --git a/posix/spawn.c b/posix/spawn.c +index 51f67b2755bd4949..a82f1c84e299f018 100644 +--- a/posix/spawn.c ++++ b/posix/spawn.c +@@ -30,6 +30,7 @@ __posix_spawn (pid_t *pid, const char *path, + return __spawni (pid, path, file_actions, attrp, argv, envp, 0); + } + versioned_symbol (libc, __posix_spawn, posix_spawn, GLIBC_2_15); ++libc_hidden_def (__posix_spawn) + + + #if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15) +diff --git a/posix/spawn_faction_addclose.c b/posix/spawn_faction_addclose.c +index 21081e19b55db44c..e1fafe438cf15c91 100644 +--- a/posix/spawn_faction_addclose.c ++++ b/posix/spawn_faction_addclose.c +@@ -24,8 +24,8 @@ + /* Add an action to FILE-ACTIONS which tells the implementation to call + `close' for the given file descriptor during the `spawn' call. */ + int +-posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions, +- int fd) ++__posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions, ++ int fd) + { + struct __spawn_action *rec; + +@@ -48,3 +48,5 @@ posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions, + + return 0; + } ++weak_alias (__posix_spawn_file_actions_addclose, ++ posix_spawn_file_actions_addclose) +diff --git a/posix/spawn_faction_adddup2.c b/posix/spawn_faction_adddup2.c +index 363bc29ae502bd60..371b1de3e6f1979a 100644 +--- a/posix/spawn_faction_adddup2.c ++++ b/posix/spawn_faction_adddup2.c +@@ -24,8 +24,8 @@ + /* Add an action to FILE-ACTIONS which tells the implementation to call + `dup2' for the given file descriptors during the `spawn' call. */ + int +-posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions, +- int fd, int newfd) ++__posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions, ++ int fd, int newfd) + { + struct __spawn_action *rec; + +@@ -49,3 +49,5 @@ posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions, + + return 0; + } ++weak_alias (__posix_spawn_file_actions_adddup2, ++ posix_spawn_file_actions_adddup2) +diff --git a/posix/spawn_faction_destroy.c b/posix/spawn_faction_destroy.c +index 46061ee3473d4475..2a2de4e41d6bd6d0 100644 +--- a/posix/spawn_faction_destroy.c ++++ b/posix/spawn_faction_destroy.c +@@ -22,7 +22,7 @@ + + /* Deallocate the file actions. */ + int +-posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) ++__posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) + { + /* Free the paths in the open actions. */ + for (int i = 0; i < file_actions->__used; ++i) +@@ -44,3 +44,5 @@ posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) + free (file_actions->__actions); + return 0; + } ++weak_alias (__posix_spawn_file_actions_destroy, ++ posix_spawn_file_actions_destroy) +diff --git a/posix/spawn_faction_init.c b/posix/spawn_faction_init.c +index ddb42e6a77ba41ec..98432067c645021e 100644 +--- a/posix/spawn_faction_init.c ++++ b/posix/spawn_faction_init.c +@@ -45,9 +45,10 @@ __posix_spawn_file_actions_realloc (posix_spawn_file_actions_t *file_actions) + + /* Initialize data structure for file attribute for `spawn' call. */ + int +-posix_spawn_file_actions_init (posix_spawn_file_actions_t *file_actions) ++__posix_spawn_file_actions_init (posix_spawn_file_actions_t *file_actions) + { + /* Simply clear all the elements. */ + memset (file_actions, '\0', sizeof (*file_actions)); + return 0; + } ++weak_alias (__posix_spawn_file_actions_init, posix_spawn_file_actions_init) +diff --git a/posix/spawnattr_destroy.c b/posix/spawnattr_destroy.c +index 603e00fffefae2bf..043386778588913a 100644 +--- a/posix/spawnattr_destroy.c ++++ b/posix/spawnattr_destroy.c +@@ -19,8 +19,9 @@ + + /* Initialize data structure for file attribute for `spawn' call. */ + int +-posix_spawnattr_destroy (posix_spawnattr_t *attr) ++__posix_spawnattr_destroy (posix_spawnattr_t *attr) + { + /* Nothing to do in the moment. */ + return 0; + } ++weak_alias (__posix_spawnattr_destroy, posix_spawnattr_destroy) +diff --git a/posix/spawnattr_init.c b/posix/spawnattr_init.c +index bab464e62bdf7889..4e1218ab44e3f779 100644 +--- a/posix/spawnattr_init.c ++++ b/posix/spawnattr_init.c +@@ -20,7 +20,7 @@ + + /* Initialize data structure for file attribute for `spawn' call. */ + int +-posix_spawnattr_init (posix_spawnattr_t *attr) ++__posix_spawnattr_init (posix_spawnattr_t *attr) + { + /* All elements have to be initialized to the default values which + is generally zero. */ +@@ -28,3 +28,4 @@ posix_spawnattr_init (posix_spawnattr_t *attr) + + return 0; + } ++weak_alias (__posix_spawnattr_init, posix_spawnattr_init) +diff --git a/posix/spawnattr_setdefault.c b/posix/spawnattr_setdefault.c +index c77cda59be3dda20..174bcfa423dc5666 100644 +--- a/posix/spawnattr_setdefault.c ++++ b/posix/spawnattr_setdefault.c +@@ -20,11 +20,12 @@ + + /* Set signal mask for signals with default handling in ATTR to SIGDEFAULT. */ + int +-posix_spawnattr_setsigdefault (posix_spawnattr_t *attr, +- const sigset_t *sigdefault) ++__posix_spawnattr_setsigdefault (posix_spawnattr_t *attr, ++ const sigset_t *sigdefault) + { + /* Copy the sigset_t data to the user buffer. */ + memcpy (&attr->__sd, sigdefault, sizeof (sigset_t)); + + return 0; + } ++weak_alias (__posix_spawnattr_setsigdefault, posix_spawnattr_setsigdefault) +diff --git a/posix/spawnattr_setflags.c b/posix/spawnattr_setflags.c +index cf9a60181dc91ccd..0a42e94770224a94 100644 +--- a/posix/spawnattr_setflags.c ++++ b/posix/spawnattr_setflags.c +@@ -30,7 +30,7 @@ + + /* Store flags in the attribute structure. */ + int +-posix_spawnattr_setflags (posix_spawnattr_t *attr, short int flags) ++__posix_spawnattr_setflags (posix_spawnattr_t *attr, short int flags) + { + /* Check no invalid bits are set. */ + if (flags & ~ALL_FLAGS) +@@ -41,3 +41,4 @@ posix_spawnattr_setflags (posix_spawnattr_t *attr, short int flags) + + return 0; + } ++weak_alias (__posix_spawnattr_setflags, posix_spawnattr_setflags) +diff --git a/posix/spawnattr_setsigmask.c b/posix/spawnattr_setsigmask.c +index 7ae81ad47025db6f..12c0111af441dd13 100644 +--- a/posix/spawnattr_setsigmask.c ++++ b/posix/spawnattr_setsigmask.c +@@ -20,7 +20,7 @@ + + /* Set signal mask for the new process in ATTR to SIGMASK. */ + int +-posix_spawnattr_setsigmask (posix_spawnattr_t *attr, ++__posix_spawnattr_setsigmask (posix_spawnattr_t *attr, + const sigset_t *sigmask) + { + /* Copy the sigset_t data to the user buffer. */ +@@ -28,3 +28,4 @@ posix_spawnattr_setsigmask (posix_spawnattr_t *attr, + + return 0; + } ++weak_alias (__posix_spawnattr_setsigmask, posix_spawnattr_setsigmask) diff --git a/glibc-rh2065588-10.patch b/glibc-rh2065588-10.patch new file mode 100644 index 0000000..3016994 --- /dev/null +++ b/glibc-rh2065588-10.patch @@ -0,0 +1,21 @@ +commit 5fce0e095bc413f908f472074c2235198cd76bf4 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:36:23 2020 -0300 + + support/shell-container.c: Return 127 if execve fails + + Reviewed-by: DJ Delorie + +diff --git a/support/shell-container.c b/support/shell-container.c +index e87ac5cf1baa84e5..e9eea64bca7e949d 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -238,7 +238,7 @@ run_command_array (char **argv) + + fprintf (stderr, "sh: execing %s failed: %s", + argv[0], strerror (errno)); +- exit (1); ++ exit (127); + } + + waitpid (pid, &status, 0); diff --git a/glibc-rh2065588-11.patch b/glibc-rh2065588-11.patch new file mode 100644 index 0000000..a1ef4a7 --- /dev/null +++ b/glibc-rh2065588-11.patch @@ -0,0 +1,39 @@ +commit 5a5a3a3234bc220a5192d620e0cbc5360da46f14 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:40:36 2020 -0300 + + support/shell-container.c: Add builtin exit + + Reviewed-by: DJ Delorie + +diff --git a/support/shell-container.c b/support/shell-container.c +index e9eea64bca7e949d..aeaf6d2733abce61 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -135,6 +135,18 @@ copy_func (char **argv) + + } + ++/* Emulate the 'exit' builtin. The exit value is optional. */ ++static int ++exit_func (char **argv) ++{ ++ int exit_val = 0; ++ ++ if (argv[0] != 0) ++ exit_val = atoi (argv[0]) & 0xff; ++ exit (exit_val); ++ return 0; ++} ++ + /* This is a list of all the built-in commands we understand. */ + static struct { + const char *name; +@@ -143,6 +155,7 @@ static struct { + { "true", true_func }, + { "echo", echo_func }, + { "cp", copy_func }, ++ { "exit", exit_func }, + { NULL, NULL } + }; + diff --git a/glibc-rh2065588-12.patch b/glibc-rh2065588-12.patch new file mode 100644 index 0000000..7f4223f --- /dev/null +++ b/glibc-rh2065588-12.patch @@ -0,0 +1,60 @@ +commit 1c17100c43c0913ec94f3bcc966bf3792236c690 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:47:13 2020 -0300 + + support/shell-container.c: Add builtin kill + + No options supported. + + Reviewed-by: DJ Delorie + +diff --git a/support/shell-container.c b/support/shell-container.c +index aeaf6d2733abce61..3869e14683fb74dd 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -147,6 +147,25 @@ exit_func (char **argv) + return 0; + } + ++/* Emulate the "/bin/kill" command. Options are ignored. */ ++static int ++kill_func (char **argv) ++{ ++ int signum = SIGTERM; ++ int i; ++ ++ for (i = 0; argv[i]; i++) ++ { ++ pid_t pid; ++ if (strcmp (argv[i], "$$") == 0) ++ pid = getpid (); ++ else ++ pid = atoi (argv[i]); ++ kill (pid, signum); ++ } ++ return 0; ++} ++ + /* This is a list of all the built-in commands we understand. */ + static struct { + const char *name; +@@ -156,6 +175,7 @@ static struct { + { "echo", echo_func }, + { "cp", copy_func }, + { "exit", exit_func }, ++ { "kill", kill_func }, + { NULL, NULL } + }; + +@@ -264,6 +284,11 @@ run_command_array (char **argv) + if (rv) + exit (rv); + } ++ else if (WIFSIGNALED (status)) ++ { ++ int sig = WTERMSIG (status); ++ raise (sig); ++ } + else + exit (1); + } diff --git a/glibc-rh2065588-13.patch b/glibc-rh2065588-13.patch new file mode 100644 index 0000000..e4e9d70 --- /dev/null +++ b/glibc-rh2065588-13.patch @@ -0,0 +1,66 @@ +commit 75fe6d1a1620d84e0e487868feba9b2c0f109610 +Author: Siddhesh Poyarekar +Date: Wed May 12 10:13:41 2021 +0530 + + support: Close fds in copy_func + + copy_func may leave file descriptors open on error, so close them on + function exit. + +diff --git a/support/shell-container.c b/support/shell-container.c +index 3869e14683fb74dd..f0a9814ae230d167 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -93,8 +93,9 @@ copy_func (char **argv) + { + char *sname = argv[0]; + char *dname = argv[1]; +- int sfd, dfd; ++ int sfd = -1, dfd = -1; + struct stat st; ++ int ret = 1; + + sfd = open (sname, O_RDONLY); + if (sfd < 0) +@@ -108,7 +109,7 @@ copy_func (char **argv) + { + fprintf (stderr, "cp: unable to fstat %s: %s\n", + sname, strerror (errno)); +- return 1; ++ goto out; + } + + dfd = open (dname, O_WRONLY | O_TRUNC | O_CREAT, 0600); +@@ -116,22 +117,26 @@ copy_func (char **argv) + { + fprintf (stderr, "cp: unable to open %s for writing: %s\n", + dname, strerror (errno)); +- return 1; ++ goto out; + } + + if (support_copy_file_range (sfd, 0, dfd, 0, st.st_size, 0) != st.st_size) + { + fprintf (stderr, "cp: cannot copy file %s to %s: %s\n", + sname, dname, strerror (errno)); +- return 1; ++ goto out; + } + +- close (sfd); +- close (dfd); +- ++ ret = 0; + chmod (dname, st.st_mode & 0777); + +- return 0; ++out: ++ if (sfd >= 0) ++ close (sfd); ++ if (dfd >= 0) ++ close (dfd); ++ ++ return ret; + + } + diff --git a/glibc-rh2065588-2.patch b/glibc-rh2065588-2.patch new file mode 100644 index 0000000..c671cf9 --- /dev/null +++ b/glibc-rh2065588-2.patch @@ -0,0 +1,231 @@ +commit 14d0e87d9b8caaa2eca7ca81f1189596671fe4fb +Author: Adhemerval Zanella +Date: Wed Sep 12 10:32:05 2018 -0300 + + posix: Use posix_spawn on popen + + This patch uses posix_spawn on popen instead of fork and execl. On Linux + this has the advantage of much lower memory consumption (usually 32 Kb + minimum for the mmap stack area). + + Two issues are also fixed with this change: + + * BZ#17490: although POSIX pthread_atfork description only list 'fork' + as the function that should execute the atfork handlers, popen + description states that: + + '[...] shall be *as if* a child process were created within the popen() + call using the fork() function [...]' + + Other libc/system seems to follow the idea atfork handlers should not be + executed for popen: + + libc/system | run atfork handles | notes + ------------|----------------------|--------------------------------------- + Freebsd | no | uses vfork + Solaris 11 | no | + MacOSX 11 | no | implemented through posix_spawn syscall + ------------|----------------------|---------------------------------------- + + Similar to posix_spawn and system, popen idea is to spawn a different + binary so all the POSIX rationale to run the atfork handlers to avoid + internal process inconsistency is not really required and in some cases + might be unsafe. + + * BZ#22834: the described scenario, where the forked process might access + invalid memory due an inconsistent state in multithreaded environment, + should not happen because posix_spawn does not access the affected + data structure (proc_file_chain). + + Checked on x86_64-linux-gnu and i686-linux-gnu. + + [BZ #22834] + [BZ #17490] + * NEWS: Add new semantic for atfork with popen and system. + * libio/iopopen.c (_IO_new_proc_open): use posix_spawn instead of + fork and execl. + +diff --git a/libio/iopopen.c b/libio/iopopen.c +index 2eff45b4c80b5cd6..c768295180fdf809 100644 +--- a/libio/iopopen.c ++++ b/libio/iopopen.c +@@ -34,7 +34,8 @@ + #include + #include + #include +-#include ++#include ++#include + + struct _IO_proc_file + { +@@ -59,13 +60,60 @@ unlock (void *not_used) + } + #endif + ++/* POSIX states popen shall ensure that any streams from previous popen() ++ calls that remain open in the parent process should be closed in the new ++ child process. ++ To avoid a race-condition between checking which file descriptors need to ++ be close (by transversing the proc_file_chain list) and the insertion of a ++ new one after a successful posix_spawn this function should be called ++ with proc_file_chain_lock acquired. */ ++static bool ++spawn_process (posix_spawn_file_actions_t *fa, FILE *fp, const char *command, ++ int do_cloexec, int pipe_fds[2], int parent_end, int child_end, ++ int child_pipe_fd) ++{ ++ ++ for (struct _IO_proc_file *p = proc_file_chain; p; p = p->next) ++ { ++ int fd = _IO_fileno ((FILE *) p); ++ ++ /* If any stream from previous popen() calls has fileno ++ child_pipe_fd, it has been already closed by the adddup2 action ++ above. */ ++ if (fd != child_pipe_fd ++ && __posix_spawn_file_actions_addclose (fa, fd) != 0) ++ return false; ++ } ++ ++ if (__posix_spawn (&((_IO_proc_file *) fp)->pid, _PATH_BSHELL, fa, 0, ++ (char *const[]){ (char*) "sh", (char*) "-c", ++ (char *) command, NULL }, __environ) != 0) ++ return false; ++ ++ __close_nocancel (pipe_fds[child_end]); ++ ++ if (!do_cloexec) ++ /* Undo the effects of the pipe2 call which set the ++ close-on-exec flag. */ ++ __fcntl (pipe_fds[parent_end], F_SETFD, 0); ++ ++ _IO_fileno (fp) = pipe_fds[parent_end]; ++ ++ ((_IO_proc_file *) fp)->next = proc_file_chain; ++ proc_file_chain = (_IO_proc_file *) fp; ++ ++ return true; ++} ++ + FILE * + _IO_new_proc_open (FILE *fp, const char *command, const char *mode) + { + int read_or_write; ++ /* These are indexes for pipe_fds. */ + int parent_end, child_end; + int pipe_fds[2]; +- pid_t child_pid; ++ int child_pipe_fd; ++ bool spawn_ok; + + int do_read = 0; + int do_write = 0; +@@ -108,72 +156,62 @@ _IO_new_proc_open (FILE *fp, const char *command, const char *mode) + + if (do_read) + { +- parent_end = pipe_fds[0]; +- child_end = pipe_fds[1]; ++ parent_end = 0; ++ child_end = 1; + read_or_write = _IO_NO_WRITES; ++ child_pipe_fd = 1; + } + else + { +- parent_end = pipe_fds[1]; +- child_end = pipe_fds[0]; ++ parent_end = 1; ++ child_end = 0; + read_or_write = _IO_NO_READS; ++ child_pipe_fd = 0; + } + +- ((_IO_proc_file *) fp)->pid = child_pid = __fork (); +- if (child_pid == 0) +- { +- int child_std_end = do_read ? 1 : 0; +- struct _IO_proc_file *p; +- +- if (child_end != child_std_end) +- __dup2 (child_end, child_std_end); +- else +- /* The descriptor is already the one we will use. But it must +- not be marked close-on-exec. Undo the effects. */ +- __fcntl (child_end, F_SETFD, 0); +- /* POSIX.2: "popen() shall ensure that any streams from previous +- popen() calls that remain open in the parent process are closed +- in the new child process." */ +- for (p = proc_file_chain; p; p = p->next) +- { +- int fd = _IO_fileno ((FILE *) p); ++ posix_spawn_file_actions_t fa; ++ /* posix_spawn_file_actions_init does not fail. */ ++ __posix_spawn_file_actions_init (&fa); + +- /* If any stream from previous popen() calls has fileno +- child_std_end, it has been already closed by the dup2 syscall +- above. */ +- if (fd != child_std_end) +- __close_nocancel (fd); +- } +- +- execl ("/bin/sh", "sh", "-c", command, (char *) 0); +- _exit (127); +- } +- __close_nocancel (child_end); +- if (child_pid < 0) ++ /* The descriptor is already the one the child will use. In this case ++ it must be moved to another one otherwise, there is no safe way to ++ remove the close-on-exec flag in the child without creating a FD leak ++ race in the parent. */ ++ if (pipe_fds[child_end] == child_pipe_fd) + { +- __close_nocancel (parent_end); +- return NULL; ++ int tmp = __fcntl (child_pipe_fd, F_DUPFD_CLOEXEC, 0); ++ if (tmp < 0) ++ goto spawn_failure; ++ __close_nocancel (pipe_fds[child_end]); ++ pipe_fds[child_end] = tmp; + } + +- if (!do_cloexec) +- /* Undo the effects of the pipe2 call which set the +- close-on-exec flag. */ +- __fcntl (parent_end, F_SETFD, 0); ++ if (__posix_spawn_file_actions_adddup2 (&fa, pipe_fds[child_end], ++ child_pipe_fd) != 0) ++ goto spawn_failure; + +- _IO_fileno (fp) = parent_end; +- +- /* Link into proc_file_chain. */ + #ifdef _IO_MTSAFE_IO + _IO_cleanup_region_start_noarg (unlock); + _IO_lock_lock (proc_file_chain_lock); + #endif +- ((_IO_proc_file *) fp)->next = proc_file_chain; +- proc_file_chain = (_IO_proc_file *) fp; ++ spawn_ok = spawn_process (&fa, fp, command, do_cloexec, pipe_fds, ++ parent_end, child_end, child_pipe_fd); + #ifdef _IO_MTSAFE_IO + _IO_lock_unlock (proc_file_chain_lock); + _IO_cleanup_region_end (0); + #endif + ++ __posix_spawn_file_actions_destroy (&fa); ++ ++ if (!spawn_ok) ++ { ++ spawn_failure: ++ __close_nocancel (pipe_fds[child_end]); ++ __close_nocancel (pipe_fds[parent_end]); ++ __set_errno (ENOMEM); ++ return NULL; ++ } ++ + _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES); + return fp; + } diff --git a/glibc-rh2065588-3.patch b/glibc-rh2065588-3.patch new file mode 100644 index 0000000..d168d88 --- /dev/null +++ b/glibc-rh2065588-3.patch @@ -0,0 +1,527 @@ +commit 5fb7fc96350575c9adb1316833e48ca11553be49 +Author: Adhemerval Zanella +Date: Wed Oct 24 16:29:38 2018 -0300 + + posix: Use posix_spawn on system + + This patch uses posix_spawn on system implementation. On Linux this has + the advantage of much lower memory consumption (usually 32 Kb minimum for + the mmap stack area). + + Although POSIX does not require, glibc system implementation aims to be + thread and cancellation safe. The cancellation code is moved to generic + implementation and enabled iff SIGCANCEL is defined (similar on how the + cancellation handler is enabled on nptl-init.c). + + Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu, + arm-linux-gnueabihf, and powerpc64le-linux-gnu. + + * sysdeps/unix/sysv/linux/spawni.c (__spawni_child): Use + __sigismember instead of sigismember. + * sysdeps/posix/system.c [SIGCANCEL] (cancel_handler_args, + cancel_handler): New definitions. + (CLEANUP_HANDLER, CLEANUP_RESET): Likewise. + (DO_LOCK, DO_UNLOCK, INIT_LOCK, ADD_REF, SUB_REF): Remove. + (do_system): Use posix_spawn instead of fork and execl and remove + reentracy code. + * sysdeps/generic/not-errno.h (__kill_noerrno): New prototype. + * sysdeps/unix/sysv/linux/not-errno.h (__kill_noerrno): Likewise. + * sysdeps/unix/sysv/linux/ia64/system.c: Remove file. + * sysdeps/unix/sysv/linux/s390/system.c: Likewise. + * sysdeps/unix/sysv/linux/sparc/system.c: Likewise. + * sysdeps/unix/sysv/linux/system.c: Likewise. + +diff --git a/sysdeps/generic/not-errno.h b/sysdeps/generic/not-errno.h +index 93617a3266fd4aad..0fd66b5c5ed82315 100644 +--- a/sysdeps/generic/not-errno.h ++++ b/sysdeps/generic/not-errno.h +@@ -17,3 +17,5 @@ + . */ + + extern __typeof (__access) __access_noerrno attribute_hidden; ++ ++extern __typeof (__kill) __kill_noerrno attribute_hidden; +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index d7594436ed59906f..8a51a6b9919ec39b 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -17,20 +17,36 @@ + + #include + #include +-#include + #include + #include ++#include ++#include ++#include + #include + #include +-#include +-#include +-#include ++#include + ++#include ++#include ++#include ++#include + + #define SHELL_PATH "/bin/sh" /* Path of the shell. */ + #define SHELL_NAME "sh" /* Name to give it. */ + + ++/* This system implementation aims to be thread-safe, which requires to ++ restore the signal dispositions for SIGINT and SIGQUIT correctly and to ++ deal with cancellation by terminating the child process. ++ ++ The signal disposition restoration on the single-thread case is ++ straighfoward. For multithreaded case, a reference-counter with a lock ++ is used, so the first thread will set the SIGINT/SIGQUIT dispositions and ++ last thread will restore them. ++ ++ Cancellation handling is done with thread cancellation clean-up handlers ++ on waitpid call. */ ++ + #ifdef _LIBC_REENTRANT + static struct sigaction intr, quit; + static int sa_refcntr; +@@ -50,17 +66,45 @@ __libc_lock_define_initialized (static, lock); + #endif + + ++#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL) ++struct cancel_handler_args ++{ ++ struct sigaction *quit; ++ struct sigaction *intr; ++ pid_t pid; ++}; ++ ++static void ++cancel_handler (void *arg) ++{ ++ struct cancel_handler_args *args = (struct cancel_handler_args *) (arg); ++ ++ __kill_noerrno (args->pid, SIGKILL); ++ ++ TEMP_FAILURE_RETRY (__waitpid_nocancel (args->pid, NULL, 0)); ++ ++ DO_LOCK (); ++ if (SUB_REF () == 0) ++ { ++ __sigaction (SIGQUIT, args->quit, NULL); ++ __sigaction (SIGINT, args->intr, NULL); ++ } ++ DO_UNLOCK (); ++} ++#endif ++ + /* Execute LINE as a shell command, returning its status. */ + static int + do_system (const char *line) + { +- int status, save; ++ int status; + pid_t pid; + struct sigaction sa; + #ifndef _LIBC_REENTRANT + struct sigaction intr, quit; + #endif + sigset_t omask; ++ sigset_t reset; + + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; +@@ -69,105 +113,72 @@ do_system (const char *line) + DO_LOCK (); + if (ADD_REF () == 0) + { +- if (__sigaction (SIGINT, &sa, &intr) < 0) +- { +- (void) SUB_REF (); +- goto out; +- } +- if (__sigaction (SIGQUIT, &sa, &quit) < 0) +- { +- save = errno; +- (void) SUB_REF (); +- goto out_restore_sigint; +- } ++ /* sigaction can not fail with SIGINT/SIGQUIT used with SIG_IGN. */ ++ __sigaction (SIGINT, &sa, &intr); ++ __sigaction (SIGQUIT, &sa, &quit); + } + DO_UNLOCK (); + +- /* We reuse the bitmap in the 'sa' structure. */ + __sigaddset (&sa.sa_mask, SIGCHLD); +- save = errno; +- if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) ++ /* sigprocmask can not fail with SIG_BLOCK used with valid input ++ arguments. */ ++ __sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask); ++ ++ __sigemptyset (&reset); ++ if (intr.sa_handler != SIG_IGN) ++ __sigaddset(&reset, SIGINT); ++ if (quit.sa_handler != SIG_IGN) ++ __sigaddset(&reset, SIGQUIT); ++ ++ posix_spawnattr_t spawn_attr; ++ /* None of the posix_spawnattr_* function returns an error, including ++ posix_spawnattr_setflags for the follow specific usage (using valid ++ flags). */ ++ __posix_spawnattr_init (&spawn_attr); ++ __posix_spawnattr_setsigmask (&spawn_attr, &omask); ++ __posix_spawnattr_setsigdefault (&spawn_attr, &reset); ++ __posix_spawnattr_setflags (&spawn_attr, ++ POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK); ++ ++ status = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr, ++ (char *const[]){ (char*) SHELL_NAME, ++ (char*) "-c", ++ (char *) line, NULL }, ++ __environ); ++ __posix_spawnattr_destroy (&spawn_attr); ++ ++ if (status == 0) + { +-#ifndef _LIBC +- if (errno == ENOSYS) +- __set_errno (save); +- else +-#endif +- { +- DO_LOCK (); +- if (SUB_REF () == 0) +- { +- save = errno; +- (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); +- out_restore_sigint: +- (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); +- __set_errno (save); +- } +- out: +- DO_UNLOCK (); +- return -1; +- } +- } +- +-#ifdef CLEANUP_HANDLER +- CLEANUP_HANDLER; +-#endif +- +-#ifdef FORK +- pid = FORK (); +-#else +- pid = __fork (); ++ /* Cancellation results in cleanup handlers running as exceptions in ++ the block where they were installed, so it is safe to reference ++ stack variable allocate in the broader scope. */ ++#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL) ++ struct cancel_handler_args cancel_args = ++ { ++ .quit = &quit, ++ .intr = &intr, ++ .pid = pid ++ }; ++ __libc_cleanup_region_start (1, cancel_handler, &cancel_args); + #endif +- if (pid == (pid_t) 0) +- { +- /* Child side. */ +- const char *new_argv[4]; +- new_argv[0] = SHELL_NAME; +- new_argv[1] = "-c"; +- new_argv[2] = line; +- new_argv[3] = NULL; +- +- /* Restore the signals. */ +- (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); +- (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); +- (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL); +- INIT_LOCK (); +- +- /* Exec the shell. */ +- (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ); +- _exit (127); +- } +- else if (pid < (pid_t) 0) +- /* The fork failed. */ +- status = -1; +- else +- /* Parent side. */ +- { + /* Note the system() is a cancellation point. But since we call + waitpid() which itself is a cancellation point we do not + have to do anything here. */ + if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid) + status = -1; +- } +- +-#ifdef CLEANUP_HANDLER +- CLEANUP_RESET; ++#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL) ++ __libc_cleanup_region_end (0); + #endif ++ } + +- save = errno; + DO_LOCK (); +- if ((SUB_REF () == 0 +- && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL) +- | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0) +- || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0) ++ if (SUB_REF () == 0) + { +-#ifndef _LIBC +- /* glibc cannot be used on systems without waitpid. */ +- if (errno == ENOSYS) +- __set_errno (save); +- else +-#endif +- status = -1; ++ /* sigaction can not fail with SIGINT/SIGQUIT used with old ++ disposition. Same applies for sigprocmask. */ ++ __sigaction (SIGINT, &intr, NULL); ++ __sigaction (SIGQUIT, &quit, NULL); ++ __sigprocmask (SIG_SETMASK, &omask, NULL); + } + DO_UNLOCK (); + +diff --git a/sysdeps/unix/sysv/linux/ia64/system.c b/sysdeps/unix/sysv/linux/ia64/system.c +deleted file mode 100644 +index d09fefefe64753ab..0000000000000000 +--- a/sysdeps/unix/sysv/linux/ia64/system.c ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* Copyright (C) 2002-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 +- . */ +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#define FORK() \ +- INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \ +- &pid, NULL, NULL) +- +-#include +diff --git a/sysdeps/unix/sysv/linux/not-errno.h b/sysdeps/unix/sysv/linux/not-errno.h +index 106ba5c72e3d7dda..b2f72cfb3d412c56 100644 +--- a/sysdeps/unix/sysv/linux/not-errno.h ++++ b/sysdeps/unix/sysv/linux/not-errno.h +@@ -16,6 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + ++#include ++#include ++ + /* This function is used on maybe_enable_malloc_check (elf/dl-tunables.c) + and to avoid having to build/use multiple versions if stack protection + in enabled it is defined as inline. */ +@@ -33,3 +36,14 @@ __access_noerrno (const char *pathname, int mode) + return INTERNAL_SYSCALL_ERRNO (res, err); + return 0; + } ++ ++static inline int ++__kill_noerrno (pid_t pid, int sig) ++{ ++ int res; ++ INTERNAL_SYSCALL_DECL (err); ++ res = INTERNAL_SYSCALL_CALL (kill, err, pid, sig); ++ if (INTERNAL_SYSCALL_ERROR_P (res, err)) ++ return INTERNAL_SYSCALL_ERRNO (res, err); ++ return 0; ++} +diff --git a/sysdeps/unix/sysv/linux/s390/system.c b/sysdeps/unix/sysv/linux/s390/system.c +deleted file mode 100644 +index d8ef46133419dd89..0000000000000000 +--- a/sysdeps/unix/sysv/linux/s390/system.c ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* Copyright (C) 2003-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 +- . */ +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#define FORK() \ +- INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid) +- +-#include "../system.c" +diff --git a/sysdeps/unix/sysv/linux/sparc/system.c b/sysdeps/unix/sysv/linux/sparc/system.c +deleted file mode 100644 +index 1f65c83399f920d6..0000000000000000 +--- a/sysdeps/unix/sysv/linux/sparc/system.c ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* Copyright (C) 2003-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 +- . */ +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#define FORK() \ +- INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL) +- +-#include "../system.c" +diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c +index 85239cedbf2a5ab5..6a8bd2ed2e1c29b7 100644 +--- a/sysdeps/unix/sysv/linux/spawni.c ++++ b/sysdeps/unix/sysv/linux/spawni.c +@@ -138,11 +138,11 @@ __spawni_child (void *arguments) + for (int sig = 1; sig < _NSIG; ++sig) + { + if ((attr->__flags & POSIX_SPAWN_SETSIGDEF) +- && sigismember (&attr->__sd, sig)) ++ && __sigismember (&attr->__sd, sig)) + { + sa.sa_handler = SIG_DFL; + } +- else if (sigismember (&hset, sig)) ++ else if (__sigismember (&hset, sig)) + { + if (__is_internal_signal (sig)) + sa.sa_handler = SIG_IGN; +diff --git a/sysdeps/unix/sysv/linux/system.c b/sysdeps/unix/sysv/linux/system.c +deleted file mode 100644 +index 7cc68a1528ee8f99..0000000000000000 +--- a/sysdeps/unix/sysv/linux/system.c ++++ /dev/null +@@ -1,76 +0,0 @@ +-/* Copyright (C) 2002-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 +- . */ +- +-#include +-#include +-#include /* For the real memset prototype. */ +-#include +-#include +-#include +-#include +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#ifndef FORK +-# define FORK() \ +- INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid) +-#endif +- +-#ifdef _LIBC_REENTRANT +-static void cancel_handler (void *arg); +- +-# define CLEANUP_HANDLER \ +- __libc_cleanup_region_start (1, cancel_handler, &pid) +- +-# define CLEANUP_RESET \ +- __libc_cleanup_region_end (0) +-#endif +- +- +-/* Linux has waitpid(), so override the generic unix version. */ +-#include +- +- +-#ifdef _LIBC_REENTRANT +-/* The cancellation handler. */ +-static void +-cancel_handler (void *arg) +-{ +- pid_t child = *(pid_t *) arg; +- +- INTERNAL_SYSCALL_DECL (err); +- INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL); +- +- TEMP_FAILURE_RETRY (__waitpid (child, NULL, 0)); +- +- DO_LOCK (); +- +- if (SUB_REF () == 0) +- { +- (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); +- (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); +- } +- +- DO_UNLOCK (); +-} +-#endif diff --git a/glibc-rh2065588-4.patch b/glibc-rh2065588-4.patch new file mode 100644 index 0000000..33a0cce --- /dev/null +++ b/glibc-rh2065588-4.patch @@ -0,0 +1,194 @@ +commit f09542c584b121da0322fde4b55306d512b85d93 +Author: Adhemerval Zanella +Date: Mon Mar 23 15:23:20 2020 -0300 + + posix: Fix system error return value [BZ #25715] + + It fixes 5fb7fc9635 when posix_spawn fails. + + Checked on x86_64-linux-gnu and i686-linux-gnu. + + Reviewed-by: Carlos O'Donell + +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index d14839f3ec3a7bad..b61bd347df7ec46a 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -17,14 +17,128 @@ + . */ + + #include ++#include ++#include ++#include ++#include + ++#include ++#include ++#include ++#include ++ ++static char *tmpdir; ++static long int namemax; ++ ++static void ++do_prepare (int argc, char *argv[]) ++{ ++ tmpdir = support_create_temp_directory ("tst-system-"); ++ /* Include the last '/0'. */ ++ namemax = pathconf (tmpdir, _PC_NAME_MAX) + 1; ++ TEST_VERIFY_EXIT (namemax != -1); ++} ++#define PREPARE do_prepare ++ ++struct args ++{ ++ const char *command; ++ int exit_status; ++ int term_sig; ++ const char *path; ++}; ++ ++static void ++call_system (void *closure) ++{ ++ struct args *args = (struct args *) closure; ++ int ret; ++ ++ if (args->path != NULL) ++ TEST_COMPARE (setenv ("PATH", args->path, 1), 0); ++ ret = system (args->command); ++ if (args->term_sig == 0) ++ { ++ /* Expect regular termination. */ ++ TEST_VERIFY (WIFEXITED (ret) != 0); ++ TEST_COMPARE (WEXITSTATUS (ret), args->exit_status); ++ } ++ else ++ { ++ /* status_or_signal < 0. Expect termination by signal. */ ++ TEST_VERIFY (WIFSIGNALED (ret) != 0); ++ TEST_COMPARE (WTERMSIG (ret), args->term_sig); ++ } ++} + + static int + do_test (void) + { +- return system (":"); +-} ++ TEST_VERIFY (system (NULL) != 0); + ++ { ++ char cmd[namemax]; ++ memset (cmd, 'a', sizeof(cmd)); ++ cmd[sizeof(cmd) - 1] = '\0'; ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ cmd, 127, 0, tmpdir ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); ++ ++ char *returnerr = xasprintf ("%s: 1: %s: not found\n", ++ basename(_PATH_BSHELL), cmd); ++ TEST_COMPARE_STRING (result.err.buffer, returnerr); ++ free (returnerr); ++ } ++ ++ { ++ char cmd[namemax + 1]; ++ memset (cmd, 'a', sizeof(cmd)); ++ cmd[sizeof(cmd) - 1] = '\0'; ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ cmd, 127, 0, tmpdir ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); ++ ++ char *returnerr = xasprintf ("%s: 1: %s: File name too long\n", ++ basename(_PATH_BSHELL), cmd); ++ TEST_COMPARE_STRING (result.err.buffer, returnerr); ++ free (returnerr); ++ } ++ ++ { ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ "kill -USR1 $$", 0, SIGUSR1 ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_none); ++ } ++ ++ { ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { "echo ...", 0 }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_stdout); ++ TEST_COMPARE_STRING (result.out.buffer, "...\n"); ++ } ++ ++ { ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { "exit 1", 1 }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_none); ++ } ++ ++ TEST_COMPARE (system (":"), 0); ++ ++ return 0; ++} + +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index 8a51a6b9919ec39b..7db09a05c3fbca43 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -97,7 +97,8 @@ cancel_handler (void *arg) + static int + do_system (const char *line) + { +- int status; ++ int status = -1; ++ int ret; + pid_t pid; + struct sigaction sa; + #ifndef _LIBC_REENTRANT +@@ -140,14 +141,14 @@ do_system (const char *line) + __posix_spawnattr_setflags (&spawn_attr, + POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK); + +- status = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr, +- (char *const[]){ (char*) SHELL_NAME, +- (char*) "-c", +- (char *) line, NULL }, +- __environ); ++ ret = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr, ++ (char *const[]){ (char *) SHELL_NAME, ++ (char *) "-c", ++ (char *) line, NULL }, ++ __environ); + __posix_spawnattr_destroy (&spawn_attr); + +- if (status == 0) ++ if (ret == 0) + { + /* Cancellation results in cleanup handlers running as exceptions in + the block where they were installed, so it is safe to reference +@@ -182,6 +183,9 @@ do_system (const char *line) + } + DO_UNLOCK (); + ++ if (ret != 0) ++ __set_errno (ret); ++ + return status; + } + diff --git a/glibc-rh2065588-5.patch b/glibc-rh2065588-5.patch new file mode 100644 index 0000000..368e759 --- /dev/null +++ b/glibc-rh2065588-5.patch @@ -0,0 +1,64 @@ +commit 7a7226543611897103c7483bec160547294dcf0d +Author: Alexandra Hájková +Date: Sat Dec 26 20:44:34 2020 +0100 + + Add xfchmod to libsupport + +diff --git a/support/Makefile b/support/Makefile +index d2b95539403e416c..4875f52495ef292d 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -91,6 +91,7 @@ libsupport-routines = \ + xdlfcn \ + xdlmopen \ + xdup2 \ ++ xfchmod \ + xfclose \ + xfopen \ + xfork \ +diff --git a/support/xfchmod.c b/support/xfchmod.c +new file mode 100644 +index 0000000000000000..4323b9ca8e078c98 +--- /dev/null ++++ b/support/xfchmod.c +@@ -0,0 +1,28 @@ ++/* fchmod with error checking. ++ Copyright (C) 2021 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 ++ . */ ++ ++#include ++#include ++#include ++ ++void ++xfchmod (int fd, mode_t mode) ++{ ++ if (fchmod (fd, mode) != 0) ++ FAIL_EXIT1 ("fchmod (%d, 0%o): %m", fd, mode); ++} +diff --git a/support/xunistd.h b/support/xunistd.h +index 74fd2771d12c36fe..ced8cb1dd9ee356c 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -45,6 +45,7 @@ long long xlseek (int fd, long long offset, int whence); + void xftruncate (int fd, long long length); + void xsymlink (const char *target, const char *linkpath); + void xchdir (const char *path); ++void xfchmod (int fd, mode_t mode); + + /* Equivalent of "mkdir -p". */ + void xmkdirp (const char *, mode_t); diff --git a/glibc-rh2065588-6.patch b/glibc-rh2065588-6.patch new file mode 100644 index 0000000..16fdb47 --- /dev/null +++ b/glibc-rh2065588-6.patch @@ -0,0 +1,56 @@ +commit 7b9c3260bcca73781dda6bc2ddee84869bedfb8c +Author: Adhemerval Zanella +Date: Mon Dec 14 11:42:33 2020 -0300 + + support: Add xchmod wrapper + + Checked on x86_64-linux-gnu. + +diff --git a/support/xchmod.c b/support/xchmod.c +new file mode 100644 +index 0000000000000000..5e403c7cc2705aef +--- /dev/null ++++ b/support/xchmod.c +@@ -0,0 +1,30 @@ ++/* chmod with error checking. ++ Copyright (C) 2020 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 ++ . */ ++ ++#include ++#include ++ ++#include ++ ++void ++xchmod (const char *pathname, mode_t mode) ++{ ++ int r = chmod (pathname, mode); ++ if (r < 0) ++ FAIL_EXIT1 ("chmod (%s, %d): %m", pathname, mode); ++} +diff --git a/support/xunistd.h b/support/xunistd.h +index ced8cb1dd9ee356c..e92056c65efe8d6a 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -46,6 +46,7 @@ void xftruncate (int fd, long long length); + void xsymlink (const char *target, const char *linkpath); + void xchdir (const char *path); + void xfchmod (int fd, mode_t mode); ++void xchmod (const char *pathname, mode_t mode); + + /* Equivalent of "mkdir -p". */ + void xmkdirp (const char *, mode_t); diff --git a/glibc-rh2065588-7.patch b/glibc-rh2065588-7.patch new file mode 100644 index 0000000..b16b79e --- /dev/null +++ b/glibc-rh2065588-7.patch @@ -0,0 +1,73 @@ +commit 4eda036f5b897fa8bc20ddd2099b5a6ed4239dc9 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:48:34 2020 -0300 + + stdlib: Move tst-system to tests-container + + Fix some issues with different shell and error messages. + + Checked on x86_64-linux-gnu and i686-linux-gnu. + +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 01194bbf7cc96851..9d0edcf6a7749b28 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -70,7 +70,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ + test-canon test-canon2 tst-strtoll tst-environ \ + tst-xpg-basename tst-random tst-random2 tst-bsearch \ + tst-limits tst-rand48 bug-strtod tst-setcontext \ +- tst-setcontext2 test-a64l tst-qsort tst-system testmb2 \ ++ tst-setcontext2 test-a64l tst-qsort testmb2 \ + bug-strtod2 tst-atof1 tst-atof2 tst-strtod2 \ + tst-rand48-2 tst-makecontext tst-strtod5 \ + tst-qsort2 tst-makecontext2 tst-strtod6 tst-unsetenv1 \ +@@ -92,6 +92,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ + tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \ + tst-tls-atexit tst-tls-atexit-nodelete + tests-static := tst-secure-getenv ++tests-container := tst-system + + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-empty-env +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index b61bd347df7ec46a..194e09828dd5c206 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -88,7 +88,8 @@ do_test (void) + }); + support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); + +- char *returnerr = xasprintf ("%s: 1: %s: not found\n", ++ char *returnerr = xasprintf ("%s: execing %s failed: " ++ "No such file or directory", + basename(_PATH_BSHELL), cmd); + TEST_COMPARE_STRING (result.err.buffer, returnerr); + free (returnerr); +@@ -106,7 +107,8 @@ do_test (void) + }); + support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); + +- char *returnerr = xasprintf ("%s: 1: %s: File name too long\n", ++ char *returnerr = xasprintf ("%s: execing %s failed: " ++ "File name too long", + basename(_PATH_BSHELL), cmd); + TEST_COMPARE_STRING (result.err.buffer, returnerr); + free (returnerr); +@@ -116,7 +118,7 @@ do_test (void) + struct support_capture_subprocess result; + result = support_capture_subprocess (call_system, + &(struct args) { +- "kill -USR1 $$", 0, SIGUSR1 ++ "kill $$", 0, SIGTERM + }); + support_capture_subprocess_check (&result, "system", 0, sc_allow_none); + } +@@ -136,7 +138,7 @@ do_test (void) + support_capture_subprocess_check (&result, "system", 0, sc_allow_none); + } + +- TEST_COMPARE (system (":"), 0); ++ TEST_COMPARE (system (""), 0); + + return 0; + } diff --git a/glibc-rh2065588-8.patch b/glibc-rh2065588-8.patch new file mode 100644 index 0000000..102b72a --- /dev/null +++ b/glibc-rh2065588-8.patch @@ -0,0 +1,74 @@ +commit 42dda89dcb0407f6799dbfd0b9dab1529666ad51 +Author: Adhemerval Zanella +Date: Fri Dec 11 15:23:05 2020 -0300 + + posix: Fix return value of system if shell can not be executed [BZ #27053] + + POSIX states that system returned code for failure to execute the shell + shall be as if the shell had terminated using _exit(127). This + behaviour was removed with 5fb7fc96350575. + + Checked on x86_64-linux-gnu. + +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index 194e09828dd5c206..8681584f15ef3b47 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + static char *tmpdir; + static long int namemax; +@@ -138,6 +139,22 @@ do_test (void) + support_capture_subprocess_check (&result, "system", 0, sc_allow_none); + } + ++ { ++ struct stat64 st; ++ xstat (_PATH_BSHELL, &st); ++ mode_t mode = st.st_mode; ++ xchmod (_PATH_BSHELL, mode & ~(S_IXUSR | S_IXGRP | S_IXOTH)); ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ "exit 1", 127, 0 ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_none); ++ ++ xchmod (_PATH_BSHELL, st.st_mode); ++ } ++ + TEST_COMPARE (system (""), 0); + + return 0; +diff --git a/support/Makefile b/support/Makefile +index 4875f52495ef292d..09b41b0d57e9239a 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -86,6 +86,7 @@ libsupport-routines = \ + xchroot \ + xclone \ + xclose \ ++ xchmod \ + xconnect \ + xcopy_file_range \ + xdlfcn \ +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index 7db09a05c3fbca43..047ded4badfddcab 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -171,6 +171,10 @@ do_system (const char *line) + __libc_cleanup_region_end (0); + #endif + } ++ else ++ /* POSIX states that failure to execute the shell should return ++ as if the shell had terminated using _exit(127). */ ++ status = W_EXITCODE (127, 0); + + DO_LOCK (); + if (SUB_REF () == 0) diff --git a/glibc-rh2065588-9.patch b/glibc-rh2065588-9.patch new file mode 100644 index 0000000..6d259d8 --- /dev/null +++ b/glibc-rh2065588-9.patch @@ -0,0 +1,21 @@ +commit 542160f0b6a7c26758c9575a8876f6624a5dd65f +Author: Girish Joshi +Date: Mon Mar 2 15:19:29 2020 -0500 + + Fixed typo in run_command_array() in support/shell-container.c + + https://sourceware.org/bugzilla/show_bug.cgi?id=23991 + +diff --git a/support/shell-container.c b/support/shell-container.c +index 9bd90d3f60529079..e87ac5cf1baa84e5 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -228,7 +228,7 @@ run_command_array (char **argv) + if (new_stderr != 2) + { + dup2 (new_stderr, 2); +- close (new_stdout); ++ close (new_stderr); + } + + if (builtin_func != NULL) diff --git a/glibc-rh2072329.patch b/glibc-rh2072329.patch new file mode 100644 index 0000000..e26331e --- /dev/null +++ b/glibc-rh2072329.patch @@ -0,0 +1,86 @@ +commit 33e03f9cd2be4f2cd62f93fda539cc07d9c8130e +Author: Joan Bruguera +Date: Mon Apr 11 19:49:56 2022 +0200 + + misc: Fix rare fortify crash on wchar funcs. [BZ 29030] + + If `__glibc_objsize (__o) == (size_t) -1` (i.e. `__o` is unknown size), fortify + checks should pass, and `__whatever_alias` should be called. + + Previously, `__glibc_objsize (__o) == (size_t) -1` was explicitly checked, but + on commit a643f60c53876b, this was moved into `__glibc_safe_or_unknown_len`. + + A comment says the -1 case should work as: "The -1 check is redundant because + since it implies that __glibc_safe_len_cond is true.". But this fails when: + * `__s > 1` + * `__osz == -1` (i.e. unknown size at compile time) + * `__l` is big enough + * `__l * __s <= __osz` can be folded to a constant + (I only found this to be true for `mbsrtowcs` and other functions in wchar2.h) + + In this case `__l * __s <= __osz` is false, and `__whatever_chk_warn` will be + called by `__glibc_fortify` or `__glibc_fortify_n` and crash the program. + + This commit adds the explicit `__osz == -1` check again. + moc crashes on startup due to this, see: https://bugs.archlinux.org/task/74041 + + Minimal test case (test.c): + #include + + int main (void) + { + const char *hw = "HelloWorld"; + mbsrtowcs (NULL, &hw, (size_t)-1, NULL); + return 0; + } + + Build with: + gcc -O2 -Wp,-D_FORTIFY_SOURCE=2 test.c -o test && ./test + + Output: + *** buffer overflow detected ***: terminated + + Fixes: BZ #29030 + Signed-off-by: Joan Bruguera + Signed-off-by: Siddhesh Poyarekar + +diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c +index 1668294e48b5c63c..701bffd1d664f289 100644 +--- a/debug/tst-fortify.c ++++ b/debug/tst-fortify.c +@@ -1505,6 +1505,11 @@ do_test (void) + CHK_FAIL_END + #endif + ++ /* Bug 29030 regresion check */ ++ cp = "HelloWorld"; ++ if (mbsrtowcs (NULL, &cp, (size_t)-1, &s) != 10) ++ FAIL (); ++ + cp = "A"; + if (mbstowcs (wenough, cp, 10) != 1 + || wcscmp (wenough, L"A") != 0) +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index a17ae0ed87e6163f..404496c7d6da4fb3 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -143,13 +143,13 @@ + || (__builtin_constant_p (__l) && (__l) > 0)) + + /* Length is known to be safe at compile time if the __L * __S <= __OBJSZ +- condition can be folded to a constant and if it is true. The -1 check is +- redundant because since it implies that __glibc_safe_len_cond is true. */ ++ condition can be folded to a constant and if it is true, or unknown (-1) */ + #define __glibc_safe_or_unknown_len(__l, __s, __osz) \ +- (__glibc_unsigned_or_positive (__l) \ +- && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \ +- __s, __osz)) \ +- && __glibc_safe_len_cond ((__SIZE_TYPE__) (__l), __s, __osz)) ++ ((__osz) == (__SIZE_TYPE__) -1 \ ++ || (__glibc_unsigned_or_positive (__l) \ ++ && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \ ++ (__s), (__osz))) \ ++ && __glibc_safe_len_cond ((__SIZE_TYPE__) (__l), (__s), (__osz)))) + + /* Conversely, we know at compile time that the length is unsafe if the + __L * __S <= __OBJSZ condition can be folded to a constant and if it is diff --git a/glibc-rh2077835.patch b/glibc-rh2077835.patch new file mode 100644 index 0000000..7323d49 --- /dev/null +++ b/glibc-rh2077835.patch @@ -0,0 +1,211 @@ +commit 2376944b9e5c0364b9fb473e4d8dabca31b57167 +Author: Stefan Liebler +Date: Wed Apr 13 14:36:09 2022 +0200 + + S390: Add new s390 platform z16. + + The new IBM z16 is added to platform string array. + The macro _DL_PLATFORMS_COUNT is incremented. + + _dl_hwcaps_subdir is extended by "z16" if HWCAP_S390_VXRS_PDE2 + is set. HWCAP_S390_NNPA is not tested in _dl_hwcaps_subdirs_active + as those instructions may be replaced or removed in future. + + tst-glibc-hwcaps.c is extended in order to test z16 via new marker5. + + A fatal glibc error is dumped if glibc was build with architecture + level set for z16, but run on an older machine. (See dl-hwcap-check.h) + +Reworked for RHEL 8.7.0 + +diff -Nrup a/elf/Makefile b/elf/Makefile +--- a/elf/Makefile 2022-05-16 21:48:11.267916411 -0400 ++++ b/elf/Makefile 2022-05-16 21:48:56.106095151 -0400 +@@ -347,7 +347,8 @@ modules-names = testobj1 testobj2 testob + libmarkermod2-1 libmarkermod2-2 \ + libmarkermod3-1 libmarkermod3-2 libmarkermod3-3 \ + libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \ +- tst-tls20mod-bad tst-tls21mod \ ++ libmarkermod5-1 libmarkermod5-2 libmarkermod5-3 libmarkermod5-4 \ ++ libmarkermod5-5 tst-tls20mod-bad tst-tls21mod \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1782,6 +1783,7 @@ LDFLAGS-libmarkermod1-1.so += -Wl,-sonam + LDFLAGS-libmarkermod2-1.so += -Wl,-soname,libmarkermod2.so + LDFLAGS-libmarkermod3-1.so += -Wl,-soname,libmarkermod3.so + LDFLAGS-libmarkermod4-1.so += -Wl,-soname,libmarkermod4.so ++LDFLAGS-libmarkermod5-1.so += -Wl,-soname,libmarkermod5.so + $(objpfx)libmarkermod%.os : markermodMARKER-VALUE.c + $(compile-command.c) \ + -DMARKER=marker$(firstword $(subst -, ,$*)) \ +@@ -1794,6 +1796,8 @@ $(objpfx)libmarkermod3.so: $(objpfx)libm + cp $< $@ + $(objpfx)libmarkermod4.so: $(objpfx)libmarkermod4-1.so + cp $< $@ ++$(objpfx)libmarkermod5.so: $(objpfx)libmarkermod5-1.so ++ cp $< $@ + + # tst-glibc-hwcaps-prepend checks that --glibc-hwcaps-prepend is + # preferred over auto-detected subdirectories. +diff -Nrup a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script +--- a/elf/tst-glibc-hwcaps-cache.script 2022-05-16 21:48:11.053915558 -0400 ++++ b/elf/tst-glibc-hwcaps-cache.script 2022-05-16 21:48:56.107095155 -0400 +@@ -4,6 +4,7 @@ + cp $B/elf/libmarkermod2-1.so $L/libmarkermod2.so + cp $B/elf/libmarkermod3-1.so $L/libmarkermod3.so + cp $B/elf/libmarkermod4-1.so $L/libmarkermod4.so ++cp $B/elf/libmarkermod5-1.so $L/libmarkermod5.so + + mkdirp 0770 $L/glibc-hwcaps/power9 + cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/power9/libmarkermod2.so +@@ -20,6 +21,11 @@ mkdirp 0770 $L/glibc-hwcaps/z15 + cp $B/elf/libmarkermod4-2.so $L/glibc-hwcaps/z13/libmarkermod4.so + cp $B/elf/libmarkermod4-3.so $L/glibc-hwcaps/z14/libmarkermod4.so + cp $B/elf/libmarkermod4-4.so $L/glibc-hwcaps/z15/libmarkermod4.so ++mkdirp 0770 $L/glibc-hwcaps/z16 ++cp $B/elf/libmarkermod5-2.so $L/glibc-hwcaps/z13/libmarkermod5.so ++cp $B/elf/libmarkermod5-3.so $L/glibc-hwcaps/z14/libmarkermod5.so ++cp $B/elf/libmarkermod5-4.so $L/glibc-hwcaps/z15/libmarkermod5.so ++cp $B/elf/libmarkermod5-5.so $L/glibc-hwcaps/z16/libmarkermod5.so + + mkdirp 0770 $L/glibc-hwcaps/x86-64-v2 + cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so +diff -Nrup a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c +--- a/sysdeps/s390/dl-procinfo.c 2022-05-16 21:48:11.250916343 -0400 ++++ b/sysdeps/s390/dl-procinfo.c 2022-05-16 21:48:56.107095155 -0400 +@@ -64,11 +64,12 @@ PROCINFO_CLASS const char _dl_s390_cap_f + #if !defined PROCINFO_DECL && defined SHARED + ._dl_s390_platforms + #else +-PROCINFO_CLASS const char _dl_s390_platforms[10][7] ++PROCINFO_CLASS const char _dl_s390_platforms[11][7] + #endif + #ifndef PROCINFO_DECL + = { +- "g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14", "z15" ++ "g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14", "z15", ++ "z16" + } + #endif + #if !defined SHARED || defined PROCINFO_DECL +diff -Nrup a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +--- a/sysdeps/s390/dl-procinfo.h 2022-05-16 21:48:11.250916343 -0400 ++++ b/sysdeps/s390/dl-procinfo.h 2022-05-16 21:48:56.107095155 -0400 +@@ -23,7 +23,7 @@ + + #define _DL_HWCAP_COUNT 23 + +-#define _DL_PLATFORMS_COUNT 10 ++#define _DL_PLATFORMS_COUNT 11 + + /* The kernel provides up to 32 capability bits with elf_hwcap. */ + #define _DL_FIRST_PLATFORM 32 +diff -Nrup a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c +--- a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c 2022-05-16 21:48:11.053915558 -0400 ++++ b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c 2022-05-16 21:58:02.840301911 -0400 +@@ -19,8 +19,8 @@ + #include + #include + +-const char _dl_hwcaps_subdirs[] = "z15:z14:z13"; +-enum { subdirs_count = 3 }; /* Number of components in _dl_hwcaps_subdirs. */ ++const char _dl_hwcaps_subdirs[] = "z16:z15:z14:z13"; ++enum { subdirs_count = 4 }; /* Number of components in _dl_hwcaps_subdirs. */ + + uint32_t + _dl_hwcaps_subdirs_active (void) +@@ -50,5 +50,12 @@ _dl_hwcaps_subdirs_active (void) + return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); + ++active; + ++ /* z16. ++ Note: We do not list HWCAP_S390_NNPA here as, according to the Principles of ++ Operation, those instructions may be replaced or removed in future. */ ++ if (!(GLRO (dl_hwcap) & HWCAP_S390_VXRS_PDE2)) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ + return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); + } +diff -Nrup a/sysdeps/s390/s390-64/Makefile b/sysdeps/s390/s390-64/Makefile +--- a/sysdeps/s390/s390-64/Makefile 2022-05-16 21:48:11.053915558 -0400 ++++ b/sysdeps/s390/s390-64/Makefile 2022-05-16 21:54:08.832355745 -0400 +@@ -7,8 +7,11 @@ CFLAGS-rtld.c += -Wno-uninitialized -Wno + CFLAGS-dl-load.c += -Wno-unused + CFLAGS-dl-reloc.c += -Wno-unused + +-$(objpfx)tst-glibc-hwcaps: $(objpfx)libmarkermod2-1.so \ +- $(objpfx)libmarkermod3-1.so $(objpfx)libmarkermod4-1.so ++$(objpfx)tst-glibc-hwcaps: \ ++ $(objpfx)libmarkermod2-1.so \ ++ $(objpfx)libmarkermod3-1.so \ ++ $(objpfx)libmarkermod4-1.so \ ++ $(objpfx)libmarkermod5-1.so + $(objpfx)tst-glibc-hwcaps.out: \ + $(objpfx)libmarkermod2.so \ + $(objpfx)glibc-hwcaps/z13/libmarkermod2.so \ +@@ -19,6 +22,11 @@ $(objpfx)tst-glibc-hwcaps.out: \ + $(objpfx)glibc-hwcaps/z13/libmarkermod4.so \ + $(objpfx)glibc-hwcaps/z14/libmarkermod4.so \ + $(objpfx)glibc-hwcaps/z15/libmarkermod4.so \ ++ $(objpfx)libmarkermod5.so \ ++ $(objpfx)glibc-hwcaps/z13/libmarkermod5.so \ ++ $(objpfx)glibc-hwcaps/z14/libmarkermod5.so \ ++ $(objpfx)glibc-hwcaps/z15/libmarkermod5.so \ ++ $(objpfx)glibc-hwcaps/z16/libmarkermod5.so + + $(objpfx)glibc-hwcaps/z13/libmarkermod2.so: $(objpfx)libmarkermod2-2.so + $(make-target-directory) +@@ -38,6 +46,18 @@ $(objpfx)glibc-hwcaps/z14/libmarkermod4. + $(objpfx)glibc-hwcaps/z15/libmarkermod4.so: $(objpfx)libmarkermod4-4.so + $(make-target-directory) + cp $< $@ ++$(objpfx)glibc-hwcaps/z13/libmarkermod5.so: $(objpfx)libmarkermod5-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z14/libmarkermod5.so: $(objpfx)libmarkermod5-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z15/libmarkermod5.so: $(objpfx)libmarkermod5-4.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z16/libmarkermod5.so: $(objpfx)libmarkermod5-5.so ++ $(make-target-directory) ++ cp $< $@ + + ifeq (no,$(build-hardcoded-path-in-tests)) + # This is an ld.so.cache test, and RPATH/RUNPATH in the executable +diff -Nrup a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c +--- a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c 2022-05-16 21:48:11.053915558 -0400 ++++ b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c 2022-05-16 21:48:56.107095155 -0400 +@@ -25,6 +25,7 @@ + extern int marker2 (void); + extern int marker3 (void); + extern int marker4 (void); ++extern int marker5 (void); + + /* Return the arch level, 10 for the baseline libmarkermod*.so's. */ + static int +@@ -63,9 +64,13 @@ compute_level (void) + return 12; + if (strcmp (platform, "z15") == 0) + return 13; ++ if (strcmp (platform, "z16") == 0) ++ return 14; + printf ("warning: unrecognized AT_PLATFORM value: %s\n", platform); + /* Assume that the new platform supports z15. */ + return 13; ++ /* Assume that the new platform supports z16. */ ++ return 14; + } + + static int +@@ -76,6 +81,7 @@ do_test (void) + TEST_COMPARE (marker2 (), MIN (level - 9, 2)); + TEST_COMPARE (marker3 (), MIN (level - 9, 3)); + TEST_COMPARE (marker4 (), MIN (level - 9, 4)); ++ TEST_COMPARE (marker5 (), MIN (level - 9, 5)); + return 0; + } + diff --git a/glibc-rh2086853.patch b/glibc-rh2086853.patch new file mode 100644 index 0000000..d11e4cb --- /dev/null +++ b/glibc-rh2086853.patch @@ -0,0 +1,30 @@ +commit 61a87530108ec9181e1b18a9b727ec3cc3ba7532 +Author: Siddhesh Poyarekar +Date: Fri May 13 10:01:47 2022 +0530 + + fortify: Ensure that __glibc_fortify condition is a constant [BZ #29141] + + The fix c8ee1c85 introduced a -1 check for object size without also + checking that object size is a constant. Because of this, the tree + optimizer passes in gcc fail to fold away one of the branches in + __glibc_fortify and trips on a spurious Wstringop-overflow. The warning + itself is incorrect and the branch does go away eventually in DCE in the + rtl passes in gcc, but the constant check is a helpful hint to simplify + code early, so add it in. + + Resolves: BZ #29141 + Signed-off-by: Siddhesh Poyarekar + +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index 404496c7d6da4fb3..f3d7efdd2a9320f7 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -145,7 +145,7 @@ + /* Length is known to be safe at compile time if the __L * __S <= __OBJSZ + condition can be folded to a constant and if it is true, or unknown (-1) */ + #define __glibc_safe_or_unknown_len(__l, __s, __osz) \ +- ((__osz) == (__SIZE_TYPE__) -1 \ ++ ((__builtin_constant_p (__osz) && (__osz) == (__SIZE_TYPE__) -1) \ + || (__glibc_unsigned_or_positive (__l) \ + && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \ + (__s), (__osz))) \ diff --git a/glibc.spec b/glibc.spec index 96e229e..1355462 100644 --- a/glibc.spec +++ b/glibc.spec @@ -1,6 +1,6 @@ %define glibcsrcdir glibc-2.28 %define glibcversion 2.28 -%define glibcrelease 197%{?dist} +%define glibcrelease 203%{?dist} # Pre-release tarballs are pulled in from git using a command that is # effectively: # @@ -879,6 +879,24 @@ Patch684: glibc-rh2033684-12.patch Patch685: glibc-rh2063712.patch Patch686: glibc-rh2063042.patch Patch687: glibc-rh2071745.patch +Patch688: glibc-rh2065588-1.patch +Patch689: glibc-rh2065588-2.patch +Patch690: glibc-rh2065588-3.patch +Patch691: glibc-rh2065588-4.patch +Patch692: glibc-rh2065588-5.patch +Patch693: glibc-rh2065588-6.patch +Patch694: glibc-rh2065588-7.patch +Patch695: glibc-rh2065588-8.patch +Patch696: glibc-rh2065588-9.patch +Patch697: glibc-rh2065588-10.patch +Patch698: glibc-rh2065588-11.patch +Patch699: glibc-rh2065588-12.patch +Patch700: glibc-rh2065588-13.patch +Patch701: glibc-rh2072329.patch +Patch702: glibc-rh1982608.patch +Patch703: glibc-rh1961109.patch +Patch704: glibc-rh2086853.patch +Patch705: glibc-rh2077835.patch ############################################################################## # Continued list of core "glibc" package information: @@ -2709,6 +2727,24 @@ fi %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared %changelog +* Tue May 17 2022 Patsy Griffin - 2.28-203 +- 390x: Add support for IBM z16. (#2077835) + +* Mon May 16 2022 Siddhesh Poyarekar - 2.28-202 +- Ensure that condition in __glibc_fortify is a constant (#2086853) + +* Tue May 10 2022 Arjun Shankar - 2.28-201 +- Add missing MACRON to EBCDIC character sets (#1961109) + +* Wed May 4 2022 DJ Delorie - 2.28-200 +- Fix glob defects on certain XFS filesystems (#1982608) + +* Tue Apr 26 2022 Siddhesh Poyarekar - 2.28-199 +- Fix fortify false positive with mbsrtowcs and mbsnrtowcs (#2072329). + +* Fri Apr 22 2022 Carlos O'Donell - 2.28-198 +- Fix multi-threaded popen defect leading to segfault (#2065588) + * Tue Apr 05 2022 Arjun Shankar - 2.28-197 - timezone: Fix a test that causes occasional build failure (#2071745)