diff options
author | Yuuki Harano <masm+github@masm11.me> | 2021-01-30 23:37:19 +0900 |
---|---|---|
committer | Yuuki Harano <masm+github@masm11.me> | 2021-01-30 23:37:19 +0900 |
commit | 50c76b844bc79309b4f5d9e28a2386b9a6f735b7 (patch) | |
tree | 29f8273d8afccae1f16b723c36548cee150cb0bc /lib | |
parent | 563a0d94c379292bd88e83f18560ed21c497cea9 (diff) | |
parent | 96f20120c97a0a329fff81a0cc3747082a8a2c55 (diff) | |
download | emacs-50c76b844bc79309b4f5d9e28a2386b9a6f735b7.tar.gz emacs-50c76b844bc79309b4f5d9e28a2386b9a6f735b7.tar.bz2 emacs-50c76b844bc79309b4f5d9e28a2386b9a6f735b7.zip |
Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs into feature/pgtk
Diffstat (limited to 'lib')
38 files changed, 1575 insertions, 358 deletions
diff --git a/lib/_Noreturn.h b/lib/_Noreturn.h index 38afe1d5672..fb718bc0691 100644 --- a/lib/_Noreturn.h +++ b/lib/_Noreturn.h @@ -26,14 +26,16 @@ AIX system header files and several gnulib header files use precisely this syntax with 'extern'. */ # define _Noreturn [[noreturn]] -# elif ((!defined __cplusplus || defined __clang__) \ - && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \ - || 4 < __GNUC__ + (7 <= __GNUC_MINOR__) \ - || (defined __apple_build_version__ \ - ? 6000000 <= __apple_build_version__ \ - : 3 < __clang_major__ + (5 <= __clang_minor__)))) +# elif ((!defined __cplusplus || defined __clang__) \ + && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \ + || (!defined __STRICT_ANSI__ \ + && (__4 < __GNUC__ + (7 <= __GNUC_MINOR__) \ + || (defined __apple_build_version__ \ + ? 6000000 <= __apple_build_version__ \ + : 3 < __clang_major__ + (5 <= __clang_minor__)))))) /* _Noreturn works as-is. */ -# elif 2 < __GNUC__ + (8 <= __GNUC_MINOR__) || 0x5110 <= __SUNPRO_C +# elif (2 < __GNUC__ + (8 <= __GNUC_MINOR__) || defined __clang__ \ + || 0x5110 <= __SUNPRO_C) # define _Noreturn __attribute__ ((__noreturn__)) # elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0) # define _Noreturn __declspec (noreturn) diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c index b6dc3a447ab..b7dba08994d 100644 --- a/lib/canonicalize-lgpl.c +++ b/lib/canonicalize-lgpl.c @@ -85,10 +85,6 @@ # define IF_LINT(Code) /* empty */ #endif -/* True if adding two valid object sizes might overflow idx_t. - As a practical matter, this cannot happen on 64-bit machines. */ -enum { NARROW_ADDRESSES = IDX_MAX >> 31 >> 31 == 0 }; - #ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT # define DOUBLE_SLASH_IS_DISTINCT_ROOT false #endif @@ -145,11 +141,11 @@ suffix_requires_dir_check (char const *end) macOS 10.13 <https://bugs.gnu.org/30350>, and should also work on platforms like AIX 7.2 that need at least "/.". */ -#if defined _LIBC || defined LSTAT_FOLLOWS_SLASHED_SYMLINK +# if defined _LIBC || defined LSTAT_FOLLOWS_SLASHED_SYMLINK static char const dir_suffix[] = "/"; -#else +# else static char const dir_suffix[] = "/./"; -#endif +# endif /* Return true if DIR is a searchable dir, false (setting errno) otherwise. DIREND points to the NUL byte at the end of the DIR string. @@ -191,13 +187,13 @@ get_path_max (void) to pacify GCC is known; even an explicit #pragma does not pacify GCC. When the GCC bug is fixed this workaround should be limited to the broken GCC versions. */ -#if __GNUC_PREREQ (10, 1) -# if defined GCC_LINT || defined lint +# if __GNUC_PREREQ (10, 1) +# if defined GCC_LINT || defined lint __attribute__ ((__noinline__)) -# elif __OPTIMIZE__ && !__NO_INLINE__ -# define GCC_BOGUS_WRETURN_LOCAL_ADDR +# elif __OPTIMIZE__ && !__NO_INLINE__ +# define GCC_BOGUS_WRETURN_LOCAL_ADDR +# endif # endif -#endif static char * realpath_stk (const char *name, char *resolved, struct scratch_buffer *rname_buf) @@ -343,7 +339,7 @@ realpath_stk (const char *name, char *resolved, if (end_in_extra_buffer) end_idx = end - extra_buf; size_t len = strlen (end); - if (NARROW_ADDRESSES && INT_ADD_OVERFLOW (len, n)) + if (INT_ADD_OVERFLOW (len, n)) { __set_errno (ENOMEM); goto error_nomem; @@ -443,7 +439,8 @@ __realpath (const char *name, char *resolved) } libc_hidden_def (__realpath) versioned_symbol (libc, __realpath, realpath, GLIBC_2_3); -#endif /* !FUNC_REALPATH_WORKS || defined _LIBC */ + +#endif /* defined _LIBC || !FUNC_REALPATH_WORKS */ #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3) diff --git a/lib/cdefs.h b/lib/cdefs.h index 2a3dc9666b9..17a0919cd83 100644 --- a/lib/cdefs.h +++ b/lib/cdefs.h @@ -25,7 +25,7 @@ /* The GNU libc does not support any K&R compilers or the traditional mode of ISO C compilers anymore. Check for some of the combinations not - anymore supported. */ + supported anymore. */ #if defined __GNUC__ && !defined __STDC__ # error "You need a ISO C conforming compiler to use the glibc headers" #endif @@ -34,31 +34,26 @@ #undef __P #undef __PMT -/* Compilers that are not clang may object to - #if defined __clang__ && __has_attribute(...) - even though they do not need to evaluate the right-hand side of the &&. */ -#if defined __clang__ && defined __has_attribute -# define __glibc_clang_has_attribute(name) __has_attribute (name) +/* Compilers that lack __has_attribute may object to + #if defined __has_attribute && __has_attribute (...) + even though they do not need to evaluate the right-hand side of the &&. + Similarly for __has_builtin, etc. */ +#if (defined __has_attribute \ + && (!defined __clang_minor__ \ + || 3 < __clang_major__ + (5 <= __clang_minor__))) +# define __glibc_has_attribute(attr) __has_attribute (attr) #else -# define __glibc_clang_has_attribute(name) 0 +# define __glibc_has_attribute(attr) 0 #endif - -/* Compilers that are not clang may object to - #if defined __clang__ && __has_builtin(...) - even though they do not need to evaluate the right-hand side of the &&. */ -#if defined __clang__ && defined __has_builtin -# define __glibc_clang_has_builtin(name) __has_builtin (name) +#ifdef __has_builtin +# define __glibc_has_builtin(name) __has_builtin (name) #else -# define __glibc_clang_has_builtin(name) 0 +# define __glibc_has_builtin(name) 0 #endif - -/* Compilers that are not clang may object to - #if defined __clang__ && __has_extension(...) - even though they do not need to evaluate the right-hand side of the &&. */ -#if defined __clang__ && defined __has_extension -# define __glibc_clang_has_extension(ext) __has_extension (ext) +#ifdef __has_extension +# define __glibc_has_extension(ext) __has_extension (ext) #else -# define __glibc_clang_has_extension(ext) 0 +# define __glibc_has_extension(ext) 0 #endif #if defined __GNUC__ || defined __clang__ @@ -74,22 +69,26 @@ # endif /* GCC can always grok prototypes. For C++ programs we add throw() - to help it optimize the function calls. But this works only with + to help it optimize the function calls. But this only works with gcc 2.8.x and egcs. For gcc 3.4 and up we even mark C functions as non-throwing using a function attribute since programs can use the -fexceptions options for C code as well. */ # if !defined __cplusplus \ - && (__GNUC_PREREQ (3, 4) || __glibc_clang_has_attribute (__nothrow__)) + && (__GNUC_PREREQ (3, 4) || __glibc_has_attribute (__nothrow__)) # define __THROW __attribute__ ((__nothrow__ __LEAF)) # define __THROWNL __attribute__ ((__nothrow__)) # define __NTH(fct) __attribute__ ((__nothrow__ __LEAF)) fct # define __NTHNL(fct) __attribute__ ((__nothrow__)) fct # else # if defined __cplusplus && (__GNUC_PREREQ (2,8) || __clang_major >= 4) -# define __THROW throw () -# define __THROWNL throw () -# define __NTH(fct) __LEAF_ATTR fct throw () -# define __NTHNL(fct) fct throw () +# if __cplusplus >= 201103L +# define __THROW noexcept (true) +# else +# define __THROW throw () +# endif +# define __THROWNL __THROW +# define __NTH(fct) __LEAF_ATTR fct __THROW +# define __NTHNL(fct) fct __THROW # else # define __THROW # define __THROWNL @@ -142,24 +141,20 @@ #define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1) #define __bos0(ptr) __builtin_object_size (ptr, 0) +/* Use __builtin_dynamic_object_size at _FORTIFY_SOURCE=3 when available. */ +#if __USE_FORTIFY_LEVEL == 3 && __glibc_clang_prereq (9, 0) +# define __glibc_objsize0(__o) __builtin_dynamic_object_size (__o, 0) +# define __glibc_objsize(__o) __builtin_dynamic_object_size (__o, 1) +#else +# define __glibc_objsize0(__o) __bos0 (__o) +# define __glibc_objsize(__o) __bos (__o) +#endif + #if __GNUC_PREREQ (4,3) -# define __warndecl(name, msg) \ - extern void name (void) __attribute__((__warning__ (msg))) # define __warnattr(msg) __attribute__((__warning__ (msg))) # define __errordecl(name, msg) \ extern void name (void) __attribute__((__error__ (msg))) -#elif __glibc_clang_has_attribute (__diagnose_if__) && 0 -/* These definitions are not enabled, because they produce bogus warnings - in the glibc Fortify functions. These functions are written in a style - that works with GCC. In order to work with clang, these functions would - need to be modified. */ -# define __warndecl(name, msg) \ - extern void name (void) __attribute__((__diagnose_if__ (1, msg, "warning"))) -# define __warnattr(msg) __attribute__((__diagnose_if__ (1, msg, "warning"))) -# define __errordecl(name, msg) \ - extern void name (void) __attribute__((__diagnose_if__ (1, msg, "error"))) #else -# define __warndecl(name, msg) extern void name (void) # define __warnattr(msg) # define __errordecl(name, msg) extern void name (void) #endif @@ -233,7 +228,7 @@ /* At some point during the gcc 2.96 development the `malloc' attribute for functions was introduced. We don't want to use it unconditionally (although this would be possible) since it generates warnings. */ -#if __GNUC_PREREQ (2,96) || __glibc_clang_has_attribute (__malloc__) +#if __GNUC_PREREQ (2,96) || __glibc_has_attribute (__malloc__) # define __attribute_malloc__ __attribute__ ((__malloc__)) #else # define __attribute_malloc__ /* Ignore */ @@ -251,23 +246,31 @@ /* At some point during the gcc 2.96 development the `pure' attribute for functions was introduced. We don't want to use it unconditionally (although this would be possible) since it generates warnings. */ -#if __GNUC_PREREQ (2,96) || __glibc_clang_has_attribute (__pure__) +#if __GNUC_PREREQ (2,96) || __glibc_has_attribute (__pure__) # define __attribute_pure__ __attribute__ ((__pure__)) #else # define __attribute_pure__ /* Ignore */ #endif /* This declaration tells the compiler that the value is constant. */ -#if __GNUC_PREREQ (2,5) || __glibc_clang_has_attribute (__const__) +#if __GNUC_PREREQ (2,5) || __glibc_has_attribute (__const__) # define __attribute_const__ __attribute__ ((__const__)) #else # define __attribute_const__ /* Ignore */ #endif +#if defined __STDC_VERSION__ && 201710L < __STDC_VERSION__ +# define __attribute_maybe_unused__ [[__maybe_unused__]] +#elif __GNUC_PREREQ (2,7) || __glibc_has_attribute (__unused__) +# define __attribute_maybe_unused__ __attribute__ ((__unused__)) +#else +# define __attribute_maybe_unused__ /* Ignore */ +#endif + /* At some point during the gcc 3.1 development the `used' attribute for functions was introduced. We don't want to use it unconditionally (although this would be possible) since it generates warnings. */ -#if __GNUC_PREREQ (3,1) || __glibc_clang_has_attribute (__used__) +#if __GNUC_PREREQ (3,1) || __glibc_has_attribute (__used__) # define __attribute_used__ __attribute__ ((__used__)) # define __attribute_noinline__ __attribute__ ((__noinline__)) #else @@ -276,7 +279,7 @@ #endif /* Since version 3.2, gcc allows marking deprecated functions. */ -#if __GNUC_PREREQ (3,2) || __glibc_clang_has_attribute (__deprecated__) +#if __GNUC_PREREQ (3,2) || __glibc_has_attribute (__deprecated__) # define __attribute_deprecated__ __attribute__ ((__deprecated__)) #else # define __attribute_deprecated__ /* Ignore */ @@ -285,8 +288,8 @@ /* Since version 4.5, gcc also allows one to specify the message printed when a deprecated function is used. clang claims to be gcc 4.2, but may also support this feature. */ -#if __GNUC_PREREQ (4,5) || \ - __glibc_clang_has_extension (__attribute_deprecated_with_message__) +#if __GNUC_PREREQ (4,5) \ + || __glibc_has_extension (__attribute_deprecated_with_message__) # define __attribute_deprecated_msg__(msg) \ __attribute__ ((__deprecated__ (msg))) #else @@ -299,7 +302,7 @@ If several `format_arg' attributes are given for the same function, in gcc-3.0 and older, all but the last one are ignored. In newer gccs, all designated arguments are considered. */ -#if __GNUC_PREREQ (2,8) || __glibc_clang_has_attribute (__format_arg__) +#if __GNUC_PREREQ (2,8) || __glibc_has_attribute (__format_arg__) # define __attribute_format_arg__(x) __attribute__ ((__format_arg__ (x))) #else # define __attribute_format_arg__(x) /* Ignore */ @@ -309,7 +312,7 @@ attribute for functions was introduced. We don't want to use it unconditionally (although this would be possible) since it generates warnings. */ -#if __GNUC_PREREQ (2,97) || __glibc_clang_has_attribute (__format__) +#if __GNUC_PREREQ (2,97) || __glibc_has_attribute (__format__) # define __attribute_format_strfmon__(a,b) \ __attribute__ ((__format__ (__strfmon__, a, b))) #else @@ -317,19 +320,21 @@ #endif /* The nonnull function attribute marks pointer parameters that - must not be NULL. Do not define __nonnull if it is already defined, - for portability when this file is used in Gnulib. */ + must not be NULL. */ #ifndef __nonnull -# if __GNUC_PREREQ (3,3) || __glibc_clang_has_attribute (__nonnull__) +# if __GNUC_PREREQ (3,3) || __glibc_has_attribute (__nonnull__) # define __nonnull(params) __attribute__ ((__nonnull__ params)) # else # define __nonnull(params) # endif +#elif !defined __GLIBC__ +# undef __nonnull +# define __nonnull(params) _GL_ATTRIBUTE_NONNULL (params) #endif /* If fortification mode, we warn about unused results of certain function calls which can lead to problems. */ -#if __GNUC_PREREQ (3,4) || __glibc_clang_has_attribute (__warn_unused_result__) +#if __GNUC_PREREQ (3,4) || __glibc_has_attribute (__warn_unused_result__) # define __attribute_warn_unused_result__ \ __attribute__ ((__warn_unused_result__)) # if defined __USE_FORTIFY_LEVEL && __USE_FORTIFY_LEVEL > 0 @@ -343,7 +348,7 @@ #endif /* Forces a function to be always inlined. */ -#if __GNUC_PREREQ (3,2) || __glibc_clang_has_attribute (__always_inline__) +#if __GNUC_PREREQ (3,2) || __glibc_has_attribute (__always_inline__) /* The Linux kernel defines __always_inline in stddef.h (283d7573), and it conflicts with this definition. Therefore undefine it first to allow either header to be included first. */ @@ -356,7 +361,7 @@ /* Associate error messages with the source location of the call site rather than with the source location inside the function. */ -#if __GNUC_PREREQ (4,3) || __glibc_clang_has_attribute (__artificial__) +#if __GNUC_PREREQ (4,3) || __glibc_has_attribute (__artificial__) # define __attribute_artificial__ __attribute__ ((__artificial__)) #else # define __attribute_artificial__ /* Ignore */ @@ -433,7 +438,7 @@ # endif #endif -#if (__GNUC__ >= 3) || __glibc_clang_has_builtin (__builtin_expect) +#if (__GNUC__ >= 3) || __glibc_has_builtin (__builtin_expect) # define __glibc_unlikely(cond) __builtin_expect ((cond), 0) # define __glibc_likely(cond) __builtin_expect ((cond), 1) #else @@ -441,12 +446,6 @@ # define __glibc_likely(cond) (cond) #endif -#ifdef __has_attribute -# define __glibc_has_attribute(attr) __has_attribute (attr) -#else -# define __glibc_has_attribute(attr) 0 -#endif - #if (!defined _Noreturn \ && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \ && !(__GNUC_PREREQ (4,7) \ @@ -467,6 +466,16 @@ # define __attribute_nonstring__ #endif +/* Undefine (also defined in libc-symbols.h). */ +#undef __attribute_copy__ +#if __GNUC_PREREQ (9, 0) +/* Copies attributes from the declaration or type referenced by + the argument. */ +# define __attribute_copy__(arg) __attribute__ ((__copy__ (arg))) +#else +# define __attribute_copy__(arg) +#endif + #if (!defined _Static_assert && !defined __cplusplus \ && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \ && (!(__GNUC_PREREQ (4, 6) || __clang_major__ >= 4) \ @@ -483,7 +492,37 @@ # include <bits/long-double.h> #endif -#if defined __LONG_DOUBLE_MATH_OPTIONAL && defined __NO_LONG_DOUBLE_MATH +#if __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 +# ifdef __REDIRECT + +/* Alias name defined automatically. */ +# define __LDBL_REDIR(name, proto) ... unused__ldbl_redir +# define __LDBL_REDIR_DECL(name) \ + extern __typeof (name) name __asm (__ASMNAME ("__" #name "ieee128")); + +/* Alias name defined automatically, with leading underscores. */ +# define __LDBL_REDIR2_DECL(name) \ + extern __typeof (__##name) __##name \ + __asm (__ASMNAME ("__" #name "ieee128")); + +/* Alias name defined manually. */ +# define __LDBL_REDIR1(name, proto, alias) ... unused__ldbl_redir1 +# define __LDBL_REDIR1_DECL(name, alias) \ + extern __typeof (name) name __asm (__ASMNAME (#alias)); + +# define __LDBL_REDIR1_NTH(name, proto, alias) \ + __REDIRECT_NTH (name, proto, alias) +# define __REDIRECT_NTH_LDBL(name, proto, alias) \ + __LDBL_REDIR1_NTH (name, proto, __##alias##ieee128) + +/* Unused. */ +# define __REDIRECT_LDBL(name, proto, alias) ... unused__redirect_ldbl +# define __LDBL_REDIR_NTH(name, proto) ... unused__ldbl_redir_nth + +# else +_Static_assert (0, "IEEE 128-bits long double requires redirection on this platform"); +# endif +#elif defined __LONG_DOUBLE_MATH_OPTIONAL && defined __NO_LONG_DOUBLE_MATH # define __LDBL_COMPAT 1 # ifdef __REDIRECT # define __LDBL_REDIR1(name, proto, alias) __REDIRECT (name, proto, alias) @@ -492,6 +531,8 @@ # define __LDBL_REDIR1_NTH(name, proto, alias) __REDIRECT_NTH (name, proto, alias) # define __LDBL_REDIR_NTH(name, proto) \ __LDBL_REDIR1_NTH (name, proto, __nldbl_##name) +# define __LDBL_REDIR2_DECL(name) \ + extern __typeof (__##name) __##name __asm (__ASMNAME ("__nldbl___" #name)); # define __LDBL_REDIR1_DECL(name, alias) \ extern __typeof (name) name __asm (__ASMNAME (#alias)); # define __LDBL_REDIR_DECL(name) \ @@ -502,11 +543,13 @@ __LDBL_REDIR1_NTH (name, proto, __nldbl_##alias) # endif #endif -#if !defined __LDBL_COMPAT || !defined __REDIRECT +#if (!defined __LDBL_COMPAT && __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 0) \ + || !defined __REDIRECT # define __LDBL_REDIR1(name, proto, alias) name proto # define __LDBL_REDIR(name, proto) name proto # define __LDBL_REDIR1_NTH(name, proto, alias) name proto __THROW # define __LDBL_REDIR_NTH(name, proto) name proto __THROW +# define __LDBL_REDIR2_DECL(name) # define __LDBL_REDIR_DECL(name) # ifdef __REDIRECT # define __REDIRECT_LDBL(name, proto, alias) __REDIRECT (name, proto, alias) @@ -537,7 +580,7 @@ check is required to enable the use of generic selection. */ #if !defined __cplusplus \ && (__GNUC_PREREQ (4, 9) \ - || __glibc_clang_has_extension (c_generic_selections) \ + || __glibc_has_extension (c_generic_selections) \ || (!defined __GNUC__ && defined __STDC_VERSION__ \ && __STDC_VERSION__ >= 201112L)) # define __HAVE_GENERIC_SELECTION 1 @@ -545,4 +588,23 @@ # define __HAVE_GENERIC_SELECTION 0 #endif +#if __GNUC_PREREQ (10, 0) +/* Designates a 1-based positional argument ref-index of pointer type + that can be used to access size-index elements of the pointed-to + array according to access mode, or at least one element when + size-index is not provided: + access (access-mode, <ref-index> [, <size-index>]) */ +#define __attr_access(x) __attribute__ ((__access__ x)) +#else +# define __attr_access(x) +#endif + +/* Specify that a function such as setjmp or vfork may return + twice. */ +#if __GNUC_PREREQ (4, 1) +# define __attribute_returns_twice__ __attribute__ ((__returns_twice__)) +#else +# define __attribute_returns_twice__ /* Ignore. */ +#endif + #endif /* sys/cdefs.h */ diff --git a/lib/dirent.in.h b/lib/dirent.in.h index 2e2c5119a11..4666972b150 100644 --- a/lib/dirent.in.h +++ b/lib/dirent.in.h @@ -154,7 +154,8 @@ _GL_WARN_ON_USE (closedir, "closedir is not portable - " /* Return the file descriptor associated with the given directory stream, or -1 if none exists. */ # if @REPLACE_DIRFD@ -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +/* On kLIBC, dirfd() is a macro that does not work. Undefine it. */ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) || defined dirfd # undef dirfd # define dirfd rpl_dirfd # endif diff --git a/lib/dynarray.h b/lib/dynarray.h new file mode 100644 index 00000000000..6da3e87e55f --- /dev/null +++ b/lib/dynarray.h @@ -0,0 +1,31 @@ +/* Type-safe arrays which grow dynamically. + Copyright 2021 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Paul Eggert, 2021. */ + +#ifndef _GL_DYNARRAY_H +#define _GL_DYNARRAY_H + +#include <libc-config.h> + +#define __libc_dynarray_at_failure gl_dynarray_at_failure +#define __libc_dynarray_emplace_enlarge gl_dynarray_emplace_enlarge +#define __libc_dynarray_finalize gl_dynarray_finalize +#define __libc_dynarray_resize_clear gl_dynarray_resize_clear +#define __libc_dynarray_resize gl_dynarray_resize +#include <malloc/dynarray.h> + +#endif /* _GL_DYNARRAY_H */ diff --git a/lib/explicit_bzero.c b/lib/explicit_bzero.c index feea4446c06..f50ed0875d7 100644 --- a/lib/explicit_bzero.c +++ b/lib/explicit_bzero.c @@ -54,11 +54,21 @@ explicit_bzero (void *s, size_t len) explicit_memset (s, '\0', len); #elif HAVE_MEMSET_S (void) memset_s (s, len, '\0', len); -#else +#elif defined __GNUC__ && !defined __clang__ memset (s, '\0', len); -# if defined __GNUC__ && !defined __clang__ /* Compiler barrier. */ asm volatile ("" ::: "memory"); -# endif +#elif defined __clang__ + memset (s, '\0', len); + /* Compiler barrier. */ + /* With asm ("" ::: "memory") LLVM analyzes uses of 's' and finds that the + whole thing is dead and eliminates it. Use 'g' to work around this + problem. See <https://bugs.llvm.org/show_bug.cgi?id=15495#c11>. */ + __asm__ volatile ("" : : "g"(s) : "memory"); +#else + /* Invoke memset through a volatile function pointer. This defeats compiler + optimizations. */ + void * (* const volatile volatile_memset) (void *, int, size_t) = memset; + (void) volatile_memset (s, '\0', len); #endif } diff --git a/lib/fchmodat.c b/lib/fchmodat.c index d27c0d7734a..eb6e2242fdd 100644 --- a/lib/fchmodat.c +++ b/lib/fchmodat.c @@ -38,6 +38,7 @@ orig_fchmodat (int dir, char const *file, mode_t mode, int flags) #include <fcntl.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> #ifdef __osf__ @@ -63,6 +64,22 @@ orig_fchmodat (int dir, char const *file, mode_t mode, int flags) int fchmodat (int dir, char const *file, mode_t mode, int flags) { +# if HAVE_NEARLY_WORKING_FCHMODAT + /* Correct the trailing slash handling. */ + size_t len = strlen (file); + if (len && file[len - 1] == '/') + { + struct stat st; + if (fstatat (dir, file, &st, flags & AT_SYMLINK_NOFOLLOW) < 0) + return -1; + if (!S_ISDIR (st.st_mode)) + { + errno = ENOTDIR; + return -1; + } + } +# endif + # if NEED_FCHMODAT_NONSYMLINK_FIX if (flags == AT_SYMLINK_NOFOLLOW) { diff --git a/lib/free.c b/lib/free.c index 135c3eb16bc..5c89787aba1 100644 --- a/lib/free.c +++ b/lib/free.c @@ -27,7 +27,21 @@ void rpl_free (void *p) #undef free { +#if defined __GNUC__ && !defined __clang__ + /* An invalid GCC optimization + <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98396> + would optimize away the assignments in the code below, when link-time + optimization (LTO) is enabled. Make the code more complicated, so that + GCC does not grok how to optimize it. */ + int err[2]; + err[0] = errno; + err[1] = errno; + errno = 0; + free (p); + errno = err[errno == 0]; +#else int err = errno; free (p); errno = err; +#endif } diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index c457ac61209..07736f9b8bc 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -516,6 +516,7 @@ GNULIB_SYMLINK = @GNULIB_SYMLINK@ GNULIB_SYMLINKAT = @GNULIB_SYMLINKAT@ GNULIB_SYSTEM_POSIX = @GNULIB_SYSTEM_POSIX@ GNULIB_TIMEGM = @GNULIB_TIMEGM@ +GNULIB_TIMESPEC_GET = @GNULIB_TIMESPEC_GET@ GNULIB_TIME_R = @GNULIB_TIME_R@ GNULIB_TIME_RZ = @GNULIB_TIME_RZ@ GNULIB_TMPFILE = @GNULIB_TMPFILE@ @@ -746,6 +747,7 @@ HAVE_SYS_SELECT_H = @HAVE_SYS_SELECT_H@ HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@ HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@ HAVE_TIMEGM = @HAVE_TIMEGM@ +HAVE_TIMESPEC_GET = @HAVE_TIMESPEC_GET@ HAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@ HAVE_TYPE_VOLATILE_SIG_ATOMIC_T = @HAVE_TYPE_VOLATILE_SIG_ATOMIC_T@ HAVE_UNISTD_H = @HAVE_UNISTD_H@ @@ -949,6 +951,7 @@ REPLACE_FCNTL = @REPLACE_FCNTL@ REPLACE_FDOPEN = @REPLACE_FDOPEN@ REPLACE_FDOPENDIR = @REPLACE_FDOPENDIR@ REPLACE_FFLUSH = @REPLACE_FFLUSH@ +REPLACE_FFSLL = @REPLACE_FFSLL@ REPLACE_FOPEN = @REPLACE_FOPEN@ REPLACE_FPRINTF = @REPLACE_FPRINTF@ REPLACE_FPURGE = @REPLACE_FPURGE@ @@ -989,7 +992,9 @@ REPLACE_MEMCHR = @REPLACE_MEMCHR@ REPLACE_MEMMEM = @REPLACE_MEMMEM@ REPLACE_MKDIR = @REPLACE_MKDIR@ REPLACE_MKFIFO = @REPLACE_MKFIFO@ +REPLACE_MKFIFOAT = @REPLACE_MKFIFOAT@ REPLACE_MKNOD = @REPLACE_MKNOD@ +REPLACE_MKNODAT = @REPLACE_MKNODAT@ REPLACE_MKSTEMP = @REPLACE_MKSTEMP@ REPLACE_MKTIME = @REPLACE_MKTIME@ REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@ @@ -1087,6 +1092,7 @@ SYSTEM_TYPE = @SYSTEM_TYPE@ SYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@ TERMCAP_OBJ = @TERMCAP_OBJ@ TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@ +TIME_H_DEFINES_TIME_UTC = @TIME_H_DEFINES_TIME_UTC@ TOOLKIT_LIBW = @TOOLKIT_LIBW@ UINT32_MAX_LT_UINTMAX_MAX = @UINT32_MAX_LT_UINTMAX_MAX@ UINT64_MAX_EQ_ULONG_MAX = @UINT64_MAX_EQ_ULONG_MAX@ @@ -1171,6 +1177,7 @@ gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1 = @gl_GNULIB_ENABLED_a9786850 gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36 = @gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36@ gl_GNULIB_ENABLED_cloexec = @gl_GNULIB_ENABLED_cloexec@ gl_GNULIB_ENABLED_dirfd = @gl_GNULIB_ENABLED_dirfd@ +gl_GNULIB_ENABLED_dynarray = @gl_GNULIB_ENABLED_dynarray@ gl_GNULIB_ENABLED_euidaccess = @gl_GNULIB_ENABLED_euidaccess@ gl_GNULIB_ENABLED_getdtablesize = @gl_GNULIB_ENABLED_getdtablesize@ gl_GNULIB_ENABLED_getgroups = @gl_GNULIB_ENABLED_getgroups@ @@ -1584,6 +1591,20 @@ EXTRA_libgnu_a_SOURCES += dup2.c endif ## end gnulib module dup2 +## begin gnulib module dynarray +ifeq (,$(OMIT_GNULIB_MODULE_dynarray)) + +ifneq (,$(gl_GNULIB_ENABLED_dynarray)) +libgnu_a_SOURCES += malloc/dynarray_at_failure.c malloc/dynarray_emplace_enlarge.c malloc/dynarray_finalize.c malloc/dynarray_resize.c malloc/dynarray_resize_clear.c + +endif +EXTRA_DIST += dynarray.h malloc/dynarray-skeleton.c malloc/dynarray.h + +EXTRA_libgnu_a_SOURCES += malloc/dynarray-skeleton.c + +endif +## end gnulib module dynarray + ## begin gnulib module eloop-threshold ifeq (,$(OMIT_GNULIB_MODULE_eloop-threshold)) @@ -3036,6 +3057,7 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H -e 's|@''HAVE_SIGDESCR_NP''@|$(HAVE_SIGDESCR_NP)|g' \ -e 's|@''HAVE_DECL_STRSIGNAL''@|$(HAVE_DECL_STRSIGNAL)|g' \ -e 's|@''HAVE_STRVERSCMP''@|$(HAVE_STRVERSCMP)|g' \ + -e 's|@''REPLACE_FFSLL''@|$(REPLACE_FFSLL)|g' \ -e 's|@''REPLACE_MEMCHR''@|$(REPLACE_MEMCHR)|g' \ -e 's|@''REPLACE_MEMMEM''@|$(REPLACE_MEMMEM)|g' \ -e 's|@''REPLACE_STPNCPY''@|$(REPLACE_STPNCPY)|g' \ @@ -3237,7 +3259,9 @@ sys/stat.h: sys_stat.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNU -e 's|@''REPLACE_LSTAT''@|$(REPLACE_LSTAT)|g' \ -e 's|@''REPLACE_MKDIR''@|$(REPLACE_MKDIR)|g' \ -e 's|@''REPLACE_MKFIFO''@|$(REPLACE_MKFIFO)|g' \ + -e 's|@''REPLACE_MKFIFOAT''@|$(REPLACE_MKFIFOAT)|g' \ -e 's|@''REPLACE_MKNOD''@|$(REPLACE_MKNOD)|g' \ + -e 's|@''REPLACE_MKNODAT''@|$(REPLACE_MKNODAT)|g' \ -e 's|@''REPLACE_STAT''@|$(REPLACE_STAT)|g' \ -e 's|@''REPLACE_UTIMENSAT''@|$(REPLACE_UTIMENSAT)|g' \ -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ @@ -3350,6 +3374,7 @@ time.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_STRFTIME''@/$(GNULIB_STRFTIME)/g' \ -e 's/@''GNULIB_STRPTIME''@/$(GNULIB_STRPTIME)/g' \ -e 's/@''GNULIB_TIMEGM''@/$(GNULIB_TIMEGM)/g' \ + -e 's/@''GNULIB_TIMESPEC_GET''@/$(GNULIB_TIMESPEC_GET)/g' \ -e 's/@''GNULIB_TIME_R''@/$(GNULIB_TIME_R)/g' \ -e 's/@''GNULIB_TIME_RZ''@/$(GNULIB_TIME_RZ)/g' \ -e 's/@''GNULIB_TZSET''@/$(GNULIB_TZSET)/g' \ @@ -3358,6 +3383,7 @@ time.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''HAVE_NANOSLEEP''@|$(HAVE_NANOSLEEP)|g' \ -e 's|@''HAVE_STRPTIME''@|$(HAVE_STRPTIME)|g' \ -e 's|@''HAVE_TIMEGM''@|$(HAVE_TIMEGM)|g' \ + -e 's|@''HAVE_TIMESPEC_GET''@|$(HAVE_TIMESPEC_GET)|g' \ -e 's|@''HAVE_TIMEZONE_T''@|$(HAVE_TIMEZONE_T)|g' \ -e 's|@''REPLACE_CTIME''@|$(REPLACE_CTIME)|g' \ -e 's|@''REPLACE_GMTIME''@|$(REPLACE_GMTIME)|g' \ @@ -3372,6 +3398,7 @@ time.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''SYS_TIME_H_DEFINES_STRUCT_TIMESPEC''@|$(SYS_TIME_H_DEFINES_STRUCT_TIMESPEC)|g' \ -e 's|@''TIME_H_DEFINES_STRUCT_TIMESPEC''@|$(TIME_H_DEFINES_STRUCT_TIMESPEC)|g' \ -e 's|@''UNISTD_H_DEFINES_STRUCT_TIMESPEC''@|$(UNISTD_H_DEFINES_STRUCT_TIMESPEC)|g' \ + -e 's|@''TIME_H_DEFINES_TIME_UTC''@|$(TIME_H_DEFINES_TIME_UTC)|g' \ -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ diff --git a/lib/libc-config.h b/lib/libc-config.h index d4e29951f35..c0eac707cfd 100644 --- a/lib/libc-config.h +++ b/lib/libc-config.h @@ -71,107 +71,112 @@ # endif #endif - -/* Prepare to include <cdefs.h>, which is our copy of glibc - <sys/cdefs.h>. */ +#ifndef __attribute_maybe_unused__ +/* <sys/cdefs.h> either does not exist, or is too old for Gnulib. + Prepare to include <cdefs.h>, which is Gnulib's version of a + more-recent glibc <sys/cdefs.h>. */ /* Define _FEATURES_H so that <cdefs.h> does not include <features.h>. */ -#ifndef _FEATURES_H -# define _FEATURES_H 1 -#endif +# ifndef _FEATURES_H +# define _FEATURES_H 1 +# endif /* Define __WORDSIZE so that <cdefs.h> does not attempt to include nonexistent files. Make it a syntax error, since Gnulib does not use __WORDSIZE now, and if Gnulib uses it later the syntax error will let us know that __WORDSIZE needs configuring. */ -#ifndef __WORDSIZE -# define __WORDSIZE %%% -#endif +# ifndef __WORDSIZE +# define __WORDSIZE %%% +# endif /* Undef the macros unconditionally defined by our copy of glibc <sys/cdefs.h>, so that they do not clash with any system-defined versions. */ -#undef _SYS_CDEFS_H -#undef __ASMNAME -#undef __ASMNAME2 -#undef __BEGIN_DECLS -#undef __CONCAT -#undef __END_DECLS -#undef __HAVE_GENERIC_SELECTION -#undef __LDBL_COMPAT -#undef __LDBL_REDIR -#undef __LDBL_REDIR1 -#undef __LDBL_REDIR1_DECL -#undef __LDBL_REDIR1_NTH -#undef __LDBL_REDIR_DECL -#undef __LDBL_REDIR_NTH -#undef __LEAF -#undef __LEAF_ATTR -#undef __NTH -#undef __NTHNL -#undef __P -#undef __PMT -#undef __REDIRECT -#undef __REDIRECT_LDBL -#undef __REDIRECT_NTH -#undef __REDIRECT_NTHNL -#undef __REDIRECT_NTH_LDBL -#undef __STRING -#undef __THROW -#undef __THROWNL -#undef __always_inline -#undef __attribute__ -#undef __attribute_alloc_size__ -#undef __attribute_artificial__ -#undef __attribute_const__ -#undef __attribute_deprecated__ -#undef __attribute_deprecated_msg__ -#undef __attribute_format_arg__ -#undef __attribute_format_strfmon__ -#undef __attribute_malloc__ -#undef __attribute_noinline__ -#undef __attribute_nonstring__ -#undef __attribute_pure__ -#undef __attribute_used__ -#undef __attribute_warn_unused_result__ -#undef __bos -#undef __bos0 -#undef __errordecl -#undef __extension__ -#undef __extern_always_inline -#undef __extern_inline -#undef __flexarr -#undef __fortify_function -#undef __glibc_c99_flexarr_available -#undef __glibc_clang_has_extension -#undef __glibc_likely -#undef __glibc_macro_warning -#undef __glibc_macro_warning1 -#undef __glibc_unlikely -#undef __inline -#undef __ptr_t -#undef __restrict -#undef __restrict_arr -#undef __va_arg_pack -#undef __va_arg_pack_len -#undef __warnattr -#undef __warndecl +# undef _SYS_CDEFS_H +# undef __ASMNAME +# undef __ASMNAME2 +# undef __BEGIN_DECLS +# undef __CONCAT +# undef __END_DECLS +# undef __HAVE_GENERIC_SELECTION +# undef __LDBL_COMPAT +# undef __LDBL_REDIR +# undef __LDBL_REDIR1 +# undef __LDBL_REDIR1_DECL +# undef __LDBL_REDIR1_NTH +# undef __LDBL_REDIR2_DECL +# undef __LDBL_REDIR_DECL +# undef __LDBL_REDIR_NTH +# undef __LEAF +# undef __LEAF_ATTR +# undef __NTH +# undef __NTHNL +# undef __REDIRECT +# undef __REDIRECT_LDBL +# undef __REDIRECT_NTH +# undef __REDIRECT_NTHNL +# undef __REDIRECT_NTH_LDBL +# undef __STRING +# undef __THROW +# undef __THROWNL +# undef __attr_access +# undef __attribute__ +# undef __attribute_alloc_size__ +# undef __attribute_artificial__ +# undef __attribute_const__ +# undef __attribute_deprecated__ +# undef __attribute_deprecated_msg__ +# undef __attribute_format_arg__ +# undef __attribute_format_strfmon__ +# undef __attribute_malloc__ +# undef __attribute_noinline__ +# undef __attribute_nonstring__ +# undef __attribute_pure__ +# undef __attribute_returns_twice__ +# undef __attribute_used__ +# undef __attribute_warn_unused_result__ +# undef __bos +# undef __bos0 +# undef __errordecl +# undef __extension__ +# undef __extern_always_inline +# undef __extern_inline +# undef __flexarr +# undef __fortify_function +# undef __glibc_c99_flexarr_available +# undef __glibc_has_attribute +# undef __glibc_has_builtin +# undef __glibc_has_extension +# undef __glibc_macro_warning +# undef __glibc_macro_warning1 +# undef __glibc_objsize +# undef __glibc_objsize0 +# undef __glibc_unlikely +# undef __inline +# undef __ptr_t +# undef __restrict +# undef __restrict_arr +# undef __va_arg_pack +# undef __va_arg_pack_len +# undef __warnattr /* Include our copy of glibc <sys/cdefs.h>. */ -#include <cdefs.h> +# include <cdefs.h> /* <cdefs.h> __inline is too pessimistic for non-GCC. */ -#undef __inline -#ifndef HAVE___INLINE -# if 199901 <= __STDC_VERSION__ || defined inline -# define __inline inline -# else -# define __inline +# undef __inline +# ifndef HAVE___INLINE +# if 199901 <= __STDC_VERSION__ || defined inline +# define __inline inline +# else +# define __inline +# endif # endif -#endif + +#endif /* defined __glibc_likely */ /* A substitute for glibc <libc-symbols.h>, good enough for Gnulib. */ #define attribute_hidden -#define libc_hidden_proto(name, ...) +#define libc_hidden_proto(name) #define libc_hidden_def(name) #define libc_hidden_weak(name) #define libc_hidden_ver(local, name) diff --git a/lib/malloc/dynarray-skeleton.c b/lib/malloc/dynarray-skeleton.c new file mode 100644 index 00000000000..4995fd1c049 --- /dev/null +++ b/lib/malloc/dynarray-skeleton.c @@ -0,0 +1,525 @@ +/* Type-safe arrays which grow dynamically. + Copyright (C) 2017-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 General Public + License as published by the Free Software Foundation; either + version 3 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +/* Pre-processor macros which act as parameters: + + DYNARRAY_STRUCT + The struct tag of dynamic array to be defined. + DYNARRAY_ELEMENT + The type name of the element type. Elements are copied + as if by memcpy, and can change address as the dynamic + array grows. + DYNARRAY_PREFIX + The prefix of the functions which are defined. + + The following parameters are optional: + + DYNARRAY_ELEMENT_FREE + DYNARRAY_ELEMENT_FREE (E) is evaluated to deallocate the + contents of elements. E is of type DYNARRAY_ELEMENT *. + DYNARRAY_ELEMENT_INIT + DYNARRAY_ELEMENT_INIT (E) is evaluated to initialize a new + element. E is of type DYNARRAY_ELEMENT *. + If DYNARRAY_ELEMENT_FREE but not DYNARRAY_ELEMENT_INIT is + defined, new elements are automatically zero-initialized. + Otherwise, new elements have undefined contents. + DYNARRAY_INITIAL_SIZE + The size of the statically allocated array (default: + at least 2, more elements if they fit into 128 bytes). + Must be a preprocessor constant. If DYNARRAY_INITIAL_SIZE is 0, + there is no statically allocated array at, and all non-empty + arrays are heap-allocated. + DYNARRAY_FINAL_TYPE + The name of the type which holds the final array. If not + defined, is PREFIX##finalize not provided. DYNARRAY_FINAL_TYPE + must be a struct type, with members of type DYNARRAY_ELEMENT and + size_t at the start (in this order). + + These macros are undefined after this header file has been + included. + + The following types are provided (their members are private to the + dynarray implementation): + + struct DYNARRAY_STRUCT + + The following functions are provided: + + void DYNARRAY_PREFIX##init (struct DYNARRAY_STRUCT *); + void DYNARRAY_PREFIX##free (struct DYNARRAY_STRUCT *); + bool DYNARRAY_PREFIX##has_failed (const struct DYNARRAY_STRUCT *); + void DYNARRAY_PREFIX##mark_failed (struct DYNARRAY_STRUCT *); + size_t DYNARRAY_PREFIX##size (const struct DYNARRAY_STRUCT *); + DYNARRAY_ELEMENT *DYNARRAY_PREFIX##begin (const struct DYNARRAY_STRUCT *); + DYNARRAY_ELEMENT *DYNARRAY_PREFIX##end (const struct DYNARRAY_STRUCT *); + DYNARRAY_ELEMENT *DYNARRAY_PREFIX##at (struct DYNARRAY_STRUCT *, size_t); + void DYNARRAY_PREFIX##add (struct DYNARRAY_STRUCT *, DYNARRAY_ELEMENT); + DYNARRAY_ELEMENT *DYNARRAY_PREFIX##emplace (struct DYNARRAY_STRUCT *); + bool DYNARRAY_PREFIX##resize (struct DYNARRAY_STRUCT *, size_t); + void DYNARRAY_PREFIX##remove_last (struct DYNARRAY_STRUCT *); + void DYNARRAY_PREFIX##clear (struct DYNARRAY_STRUCT *); + + The following functions are provided are provided if the + prerequisites are met: + + bool DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *, + DYNARRAY_FINAL_TYPE *); + (if DYNARRAY_FINAL_TYPE is defined) + DYNARRAY_ELEMENT *DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *, + size_t *); + (if DYNARRAY_FINAL_TYPE is not defined) +*/ + +#include <malloc/dynarray.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#ifndef DYNARRAY_STRUCT +# error "DYNARRAY_STRUCT must be defined" +#endif + +#ifndef DYNARRAY_ELEMENT +# error "DYNARRAY_ELEMENT must be defined" +#endif + +#ifndef DYNARRAY_PREFIX +# error "DYNARRAY_PREFIX must be defined" +#endif + +#ifdef DYNARRAY_INITIAL_SIZE +# if DYNARRAY_INITIAL_SIZE < 0 +# error "DYNARRAY_INITIAL_SIZE must be non-negative" +# endif +# if DYNARRAY_INITIAL_SIZE > 0 +# define DYNARRAY_HAVE_SCRATCH 1 +# else +# define DYNARRAY_HAVE_SCRATCH 0 +# endif +#else +/* Provide a reasonable default which limits the size of + DYNARRAY_STRUCT. */ +# define DYNARRAY_INITIAL_SIZE \ + (sizeof (DYNARRAY_ELEMENT) > 64 ? 2 : 128 / sizeof (DYNARRAY_ELEMENT)) +# define DYNARRAY_HAVE_SCRATCH 1 +#endif + +/* Public type definitions. */ + +/* All fields of this struct are private to the implementation. */ +struct DYNARRAY_STRUCT +{ + union + { + struct dynarray_header dynarray_abstract; + struct + { + /* These fields must match struct dynarray_header. */ + size_t used; + size_t allocated; + DYNARRAY_ELEMENT *array; + } dynarray_header; + } u; + +#if DYNARRAY_HAVE_SCRATCH + /* Initial inline allocation. */ + DYNARRAY_ELEMENT scratch[DYNARRAY_INITIAL_SIZE]; +#endif +}; + +/* Internal use only: Helper macros. */ + +/* Ensure macro-expansion of DYNARRAY_PREFIX. */ +#define DYNARRAY_CONCAT0(prefix, name) prefix##name +#define DYNARRAY_CONCAT1(prefix, name) DYNARRAY_CONCAT0(prefix, name) +#define DYNARRAY_NAME(name) DYNARRAY_CONCAT1(DYNARRAY_PREFIX, name) + +/* Use DYNARRAY_FREE instead of DYNARRAY_NAME (free), + so that Gnulib does not change 'free' to 'rpl_free'. */ +#define DYNARRAY_FREE DYNARRAY_CONCAT1 (DYNARRAY_NAME (f), ree) + +/* Address of the scratch buffer if any. */ +#if DYNARRAY_HAVE_SCRATCH +# define DYNARRAY_SCRATCH(list) (list)->scratch +#else +# define DYNARRAY_SCRATCH(list) NULL +#endif + +/* Internal use only: Helper functions. */ + +/* Internal function. Call DYNARRAY_ELEMENT_FREE with the array + elements. Name mangling needed due to the DYNARRAY_ELEMENT_FREE + macro expansion. */ +static inline void +DYNARRAY_NAME (free__elements__) (DYNARRAY_ELEMENT *__dynarray_array, + size_t __dynarray_used) +{ +#ifdef DYNARRAY_ELEMENT_FREE + for (size_t __dynarray_i = 0; __dynarray_i < __dynarray_used; ++__dynarray_i) + DYNARRAY_ELEMENT_FREE (&__dynarray_array[__dynarray_i]); +#endif /* DYNARRAY_ELEMENT_FREE */ +} + +/* Internal function. Free the non-scratch array allocation. */ +static inline void +DYNARRAY_NAME (free__array__) (struct DYNARRAY_STRUCT *list) +{ +#if DYNARRAY_HAVE_SCRATCH + if (list->u.dynarray_header.array != list->scratch) + free (list->u.dynarray_header.array); +#else + free (list->u.dynarray_header.array); +#endif +} + +/* Public functions. */ + +/* Initialize a dynamic array object. This must be called before any + use of the object. */ +__nonnull ((1)) +static void +DYNARRAY_NAME (init) (struct DYNARRAY_STRUCT *list) +{ + list->u.dynarray_header.used = 0; + list->u.dynarray_header.allocated = DYNARRAY_INITIAL_SIZE; + list->u.dynarray_header.array = DYNARRAY_SCRATCH (list); +} + +/* Deallocate the dynamic array and its elements. */ +__attribute_maybe_unused__ __nonnull ((1)) +static void +DYNARRAY_FREE (struct DYNARRAY_STRUCT *list) +{ + DYNARRAY_NAME (free__elements__) + (list->u.dynarray_header.array, list->u.dynarray_header.used); + DYNARRAY_NAME (free__array__) (list); + DYNARRAY_NAME (init) (list); +} + +/* Return true if the dynamic array is in an error state. */ +__nonnull ((1)) +static inline bool +DYNARRAY_NAME (has_failed) (const struct DYNARRAY_STRUCT *list) +{ + return list->u.dynarray_header.allocated == __dynarray_error_marker (); +} + +/* Mark the dynamic array as failed. All elements are deallocated as + a side effect. */ +__nonnull ((1)) +static void +DYNARRAY_NAME (mark_failed) (struct DYNARRAY_STRUCT *list) +{ + DYNARRAY_NAME (free__elements__) + (list->u.dynarray_header.array, list->u.dynarray_header.used); + DYNARRAY_NAME (free__array__) (list); + list->u.dynarray_header.array = DYNARRAY_SCRATCH (list); + list->u.dynarray_header.used = 0; + list->u.dynarray_header.allocated = __dynarray_error_marker (); +} + +/* Return the number of elements which have been added to the dynamic + array. */ +__nonnull ((1)) +static inline size_t +DYNARRAY_NAME (size) (const struct DYNARRAY_STRUCT *list) +{ + return list->u.dynarray_header.used; +} + +/* Return a pointer to the array element at INDEX. Terminate the + process if INDEX is out of bounds. */ +__nonnull ((1)) +static inline DYNARRAY_ELEMENT * +DYNARRAY_NAME (at) (struct DYNARRAY_STRUCT *list, size_t index) +{ + if (__glibc_unlikely (index >= DYNARRAY_NAME (size) (list))) + __libc_dynarray_at_failure (DYNARRAY_NAME (size) (list), index); + return list->u.dynarray_header.array + index; +} + +/* Return a pointer to the first array element, if any. For a + zero-length array, the pointer can be NULL even though the dynamic + array has not entered the failure state. */ +__nonnull ((1)) +static inline DYNARRAY_ELEMENT * +DYNARRAY_NAME (begin) (struct DYNARRAY_STRUCT *list) +{ + return list->u.dynarray_header.array; +} + +/* Return a pointer one element past the last array element. For a + zero-length array, the pointer can be NULL even though the dynamic + array has not entered the failure state. */ +__nonnull ((1)) +static inline DYNARRAY_ELEMENT * +DYNARRAY_NAME (end) (struct DYNARRAY_STRUCT *list) +{ + return list->u.dynarray_header.array + list->u.dynarray_header.used; +} + +/* Internal function. Slow path for the add function below. */ +static void +DYNARRAY_NAME (add__) (struct DYNARRAY_STRUCT *list, DYNARRAY_ELEMENT item) +{ + if (__glibc_unlikely + (!__libc_dynarray_emplace_enlarge (&list->u.dynarray_abstract, + DYNARRAY_SCRATCH (list), + sizeof (DYNARRAY_ELEMENT)))) + { + DYNARRAY_NAME (mark_failed) (list); + return; + } + + /* Copy the new element and increase the array length. */ + list->u.dynarray_header.array[list->u.dynarray_header.used++] = item; +} + +/* Add ITEM at the end of the array, enlarging it by one element. + Mark *LIST as failed if the dynamic array allocation size cannot be + increased. */ +__nonnull ((1)) +static inline void +DYNARRAY_NAME (add) (struct DYNARRAY_STRUCT *list, DYNARRAY_ELEMENT item) +{ + /* Do nothing in case of previous error. */ + if (DYNARRAY_NAME (has_failed) (list)) + return; + + /* Enlarge the array if necessary. */ + if (__glibc_unlikely (list->u.dynarray_header.used + == list->u.dynarray_header.allocated)) + { + DYNARRAY_NAME (add__) (list, item); + return; + } + + /* Copy the new element and increase the array length. */ + list->u.dynarray_header.array[list->u.dynarray_header.used++] = item; +} + +/* Internal function. Building block for the emplace functions below. + Assumes space for one more element in *LIST. */ +static inline DYNARRAY_ELEMENT * +DYNARRAY_NAME (emplace__tail__) (struct DYNARRAY_STRUCT *list) +{ + DYNARRAY_ELEMENT *result + = &list->u.dynarray_header.array[list->u.dynarray_header.used]; + ++list->u.dynarray_header.used; +#if defined (DYNARRAY_ELEMENT_INIT) + DYNARRAY_ELEMENT_INIT (result); +#elif defined (DYNARRAY_ELEMENT_FREE) + memset (result, 0, sizeof (*result)); +#endif + return result; +} + +/* Internal function. Slow path for the emplace function below. */ +static DYNARRAY_ELEMENT * +DYNARRAY_NAME (emplace__) (struct DYNARRAY_STRUCT *list) +{ + if (__glibc_unlikely + (!__libc_dynarray_emplace_enlarge (&list->u.dynarray_abstract, + DYNARRAY_SCRATCH (list), + sizeof (DYNARRAY_ELEMENT)))) + { + DYNARRAY_NAME (mark_failed) (list); + return NULL; + } + return DYNARRAY_NAME (emplace__tail__) (list); +} + +/* Allocate a place for a new element in *LIST and return a pointer to + it. The pointer can be NULL if the dynamic array cannot be + enlarged due to a memory allocation failure. */ +__attribute_maybe_unused__ __attribute_warn_unused_result__ __nonnull ((1)) +static +/* Avoid inlining with the larger initialization code. */ +#if !(defined (DYNARRAY_ELEMENT_INIT) || defined (DYNARRAY_ELEMENT_FREE)) +inline +#endif +DYNARRAY_ELEMENT * +DYNARRAY_NAME (emplace) (struct DYNARRAY_STRUCT *list) +{ + /* Do nothing in case of previous error. */ + if (DYNARRAY_NAME (has_failed) (list)) + return NULL; + + /* Enlarge the array if necessary. */ + if (__glibc_unlikely (list->u.dynarray_header.used + == list->u.dynarray_header.allocated)) + return (DYNARRAY_NAME (emplace__) (list)); + return DYNARRAY_NAME (emplace__tail__) (list); +} + +/* Change the size of *LIST to SIZE. If SIZE is larger than the + existing size, new elements are added (which can be initialized). + Otherwise, the list is truncated, and elements are freed. Return + false on memory allocation failure (and mark *LIST as failed). */ +__attribute_maybe_unused__ __nonnull ((1)) +static bool +DYNARRAY_NAME (resize) (struct DYNARRAY_STRUCT *list, size_t size) +{ + if (size > list->u.dynarray_header.used) + { + bool ok; +#if defined (DYNARRAY_ELEMENT_INIT) + /* The new elements have to be initialized. */ + size_t old_size = list->u.dynarray_header.used; + ok = __libc_dynarray_resize (&list->u.dynarray_abstract, + size, DYNARRAY_SCRATCH (list), + sizeof (DYNARRAY_ELEMENT)); + if (ok) + for (size_t i = old_size; i < size; ++i) + { + DYNARRAY_ELEMENT_INIT (&list->u.dynarray_header.array[i]); + } +#elif defined (DYNARRAY_ELEMENT_FREE) + /* Zero initialization is needed so that the elements can be + safely freed. */ + ok = __libc_dynarray_resize_clear + (&list->u.dynarray_abstract, size, + DYNARRAY_SCRATCH (list), sizeof (DYNARRAY_ELEMENT)); +#else + ok = __libc_dynarray_resize (&list->u.dynarray_abstract, + size, DYNARRAY_SCRATCH (list), + sizeof (DYNARRAY_ELEMENT)); +#endif + if (__glibc_unlikely (!ok)) + DYNARRAY_NAME (mark_failed) (list); + return ok; + } + else + { + /* The list has shrunk in size. Free the removed elements. */ + DYNARRAY_NAME (free__elements__) + (list->u.dynarray_header.array + size, + list->u.dynarray_header.used - size); + list->u.dynarray_header.used = size; + return true; + } +} + +/* Remove the last element of LIST if it is present. */ +__attribute_maybe_unused__ __nonnull ((1)) +static void +DYNARRAY_NAME (remove_last) (struct DYNARRAY_STRUCT *list) +{ + /* used > 0 implies that the array is the non-failed state. */ + if (list->u.dynarray_header.used > 0) + { + size_t new_length = list->u.dynarray_header.used - 1; +#ifdef DYNARRAY_ELEMENT_FREE + DYNARRAY_ELEMENT_FREE (&list->u.dynarray_header.array[new_length]); +#endif + list->u.dynarray_header.used = new_length; + } +} + +/* Remove all elements from the list. The elements are freed, but the + list itself is not. */ +__attribute_maybe_unused__ __nonnull ((1)) +static void +DYNARRAY_NAME (clear) (struct DYNARRAY_STRUCT *list) +{ + /* free__elements__ does nothing if the list is in the failed + state. */ + DYNARRAY_NAME (free__elements__) + (list->u.dynarray_header.array, list->u.dynarray_header.used); + list->u.dynarray_header.used = 0; +} + +#ifdef DYNARRAY_FINAL_TYPE +/* Transfer the dynamic array to a permanent location at *RESULT. + Returns true on success on false on allocation failure. In either + case, *LIST is re-initialized and can be reused. A NULL pointer is + stored in *RESULT if LIST refers to an empty list. On success, the + pointer in *RESULT is heap-allocated and must be deallocated using + free. */ +__attribute_maybe_unused__ __attribute_warn_unused_result__ __nonnull ((1, 2)) +static bool +DYNARRAY_NAME (finalize) (struct DYNARRAY_STRUCT *list, + DYNARRAY_FINAL_TYPE *result) +{ + struct dynarray_finalize_result res; + if (__libc_dynarray_finalize (&list->u.dynarray_abstract, + DYNARRAY_SCRATCH (list), + sizeof (DYNARRAY_ELEMENT), &res)) + { + /* On success, the result owns all the data. */ + DYNARRAY_NAME (init) (list); + *result = (DYNARRAY_FINAL_TYPE) { res.array, res.length }; + return true; + } + else + { + /* On error, we need to free all data. */ + DYNARRAY_FREE (list); + errno = ENOMEM; + return false; + } +} +#else /* !DYNARRAY_FINAL_TYPE */ +/* Transfer the dynamic array to a heap-allocated array and return a + pointer to it. The pointer is NULL if memory allocation fails, or + if the array is empty, so this function should be used only for + arrays which are known not be empty (usually because they always + have a sentinel at the end). If LENGTHP is not NULL, the array + length is written to *LENGTHP. *LIST is re-initialized and can be + reused. */ +__attribute_maybe_unused__ __attribute_warn_unused_result__ __nonnull ((1)) +static DYNARRAY_ELEMENT * +DYNARRAY_NAME (finalize) (struct DYNARRAY_STRUCT *list, size_t *lengthp) +{ + struct dynarray_finalize_result res; + if (__libc_dynarray_finalize (&list->u.dynarray_abstract, + DYNARRAY_SCRATCH (list), + sizeof (DYNARRAY_ELEMENT), &res)) + { + /* On success, the result owns all the data. */ + DYNARRAY_NAME (init) (list); + if (lengthp != NULL) + *lengthp = res.length; + return res.array; + } + else + { + /* On error, we need to free all data. */ + DYNARRAY_FREE (list); + errno = ENOMEM; + return NULL; + } +} +#endif /* !DYNARRAY_FINAL_TYPE */ + +/* Undo macro definitions. */ + +#undef DYNARRAY_CONCAT0 +#undef DYNARRAY_CONCAT1 +#undef DYNARRAY_NAME +#undef DYNARRAY_SCRATCH +#undef DYNARRAY_HAVE_SCRATCH + +#undef DYNARRAY_STRUCT +#undef DYNARRAY_ELEMENT +#undef DYNARRAY_PREFIX +#undef DYNARRAY_ELEMENT_FREE +#undef DYNARRAY_ELEMENT_INIT +#undef DYNARRAY_INITIAL_SIZE +#undef DYNARRAY_FINAL_TYPE diff --git a/lib/malloc/dynarray.h b/lib/malloc/dynarray.h new file mode 100644 index 00000000000..84e4394bf32 --- /dev/null +++ b/lib/malloc/dynarray.h @@ -0,0 +1,178 @@ +/* Type-safe arrays which grow dynamically. Shared definitions. + Copyright (C) 2017-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 General Public + License as published by the Free Software Foundation; either + version 3 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +/* To use the dynarray facility, you need to include + <malloc/dynarray-skeleton.c> and define the parameter macros + documented in that file. + + A minimal example which provides a growing list of integers can be + defined like this: + + struct int_array + { + // Pointer to result array followed by its length, + // as required by DYNARRAY_FINAL_TYPE. + int *array; + size_t length; + }; + + #define DYNARRAY_STRUCT dynarray_int + #define DYNARRAY_ELEMENT int + #define DYNARRAY_PREFIX dynarray_int_ + #define DYNARRAY_FINAL_TYPE struct int_array + #include <malloc/dynarray-skeleton.c> + + To create a three-element array with elements 1, 2, 3, use this + code: + + struct dynarray_int dyn; + dynarray_int_init (&dyn); + for (int i = 1; i <= 3; ++i) + { + int *place = dynarray_int_emplace (&dyn); + assert (place != NULL); + *place = i; + } + struct int_array result; + bool ok = dynarray_int_finalize (&dyn, &result); + assert (ok); + assert (result.length == 3); + assert (result.array[0] == 1); + assert (result.array[1] == 2); + assert (result.array[2] == 3); + free (result.array); + + If the elements contain resources which must be freed, define + DYNARRAY_ELEMENT_FREE appropriately, like this: + + struct str_array + { + char **array; + size_t length; + }; + + #define DYNARRAY_STRUCT dynarray_str + #define DYNARRAY_ELEMENT char * + #define DYNARRAY_ELEMENT_FREE(ptr) free (*ptr) + #define DYNARRAY_PREFIX dynarray_str_ + #define DYNARRAY_FINAL_TYPE struct str_array + #include <malloc/dynarray-skeleton.c> + + Compared to scratch buffers, dynamic arrays have the following + features: + + - They have an element type, and are not just an untyped buffer of + bytes. + + - When growing, previously stored elements are preserved. (It is + expected that scratch_buffer_grow_preserve and + scratch_buffer_set_array_size eventually go away because all + current users are moved to dynamic arrays.) + + - Scratch buffers have a more aggressive growth policy because + growing them typically means a retry of an operation (across an + NSS service module boundary), which is expensive. + + - For the same reason, scratch buffers have a much larger initial + stack allocation. */ + +#ifndef _DYNARRAY_H +#define _DYNARRAY_H + +#include <stdbool.h> +#include <stddef.h> +#include <string.h> + +struct dynarray_header +{ + size_t used; + size_t allocated; + void *array; +}; + +/* Marker used in the allocated member to indicate that an error was + encountered. */ +static inline size_t +__dynarray_error_marker (void) +{ + return -1; +} + +/* Internal function. See the has_failed function in + dynarray-skeleton.c. */ +static inline bool +__dynarray_error (struct dynarray_header *list) +{ + return list->allocated == __dynarray_error_marker (); +} + +/* Internal function. Enlarge the dynamically allocated area of the + array to make room for one more element. SCRATCH is a pointer to + the scratch area (which is not heap-allocated and must not be + freed). ELEMENT_SIZE is the size, in bytes, of one element. + Return false on failure, true on success. */ +bool __libc_dynarray_emplace_enlarge (struct dynarray_header *, + void *scratch, size_t element_size); + +/* Internal function. Enlarge the dynamically allocated area of the + array to make room for at least SIZE elements (which must be larger + than the existing used part of the dynamic array). SCRATCH is a + pointer to the scratch area (which is not heap-allocated and must + not be freed). ELEMENT_SIZE is the size, in bytes, of one element. + Return false on failure, true on success. */ +bool __libc_dynarray_resize (struct dynarray_header *, size_t size, + void *scratch, size_t element_size); + +/* Internal function. Like __libc_dynarray_resize, but clear the new + part of the dynamic array. */ +bool __libc_dynarray_resize_clear (struct dynarray_header *, size_t size, + void *scratch, size_t element_size); + +/* Internal type. */ +struct dynarray_finalize_result +{ + void *array; + size_t length; +}; + +/* Internal function. Copy the dynamically-allocated area to an + explicitly-sized heap allocation. SCRATCH is a pointer to the + embedded scratch space. ELEMENT_SIZE is the size, in bytes, of the + element type. On success, true is returned, and pointer and length + are written to *RESULT. On failure, false is returned. The caller + has to take care of some of the memory management; this function is + expected to be called from dynarray-skeleton.c. */ +bool __libc_dynarray_finalize (struct dynarray_header *list, void *scratch, + size_t element_size, + struct dynarray_finalize_result *result); + + +/* Internal function. Terminate the process after an index error. + SIZE is the number of elements of the dynamic array. INDEX is the + lookup index which triggered the failure. */ +_Noreturn void __libc_dynarray_at_failure (size_t size, size_t index); + +#ifndef _ISOMAC +libc_hidden_proto (__libc_dynarray_emplace_enlarge) +libc_hidden_proto (__libc_dynarray_resize) +libc_hidden_proto (__libc_dynarray_resize_clear) +libc_hidden_proto (__libc_dynarray_finalize) +libc_hidden_proto (__libc_dynarray_at_failure) +#endif + +#endif /* _DYNARRAY_H */ diff --git a/lib/malloc/dynarray_at_failure.c b/lib/malloc/dynarray_at_failure.c new file mode 100644 index 00000000000..a4424593748 --- /dev/null +++ b/lib/malloc/dynarray_at_failure.c @@ -0,0 +1,35 @@ +/* Report an dynamic array index out of bounds condition. + Copyright (C) 2017-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 General Public + License as published by the Free Software Foundation; either + version 3 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <dynarray.h> +#include <stdio.h> +#include <stdlib.h> + +void +__libc_dynarray_at_failure (size_t size, size_t index) +{ +#ifdef _LIBC + char buf[200]; + __snprintf (buf, sizeof (buf), "Fatal glibc error: " + "array index %zu not less than array length %zu\n", + index, size); +#else + abort (); +#endif +} +libc_hidden_def (__libc_dynarray_at_failure) diff --git a/lib/malloc/dynarray_emplace_enlarge.c b/lib/malloc/dynarray_emplace_enlarge.c new file mode 100644 index 00000000000..7ac4b6db403 --- /dev/null +++ b/lib/malloc/dynarray_emplace_enlarge.c @@ -0,0 +1,73 @@ +/* Increase the size of a dynamic array in preparation of an emplace operation. + Copyright (C) 2017-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 General Public + License as published by the Free Software Foundation; either + version 3 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <dynarray.h> +#include <errno.h> +#include <intprops.h> +#include <stdlib.h> +#include <string.h> + +bool +__libc_dynarray_emplace_enlarge (struct dynarray_header *list, + void *scratch, size_t element_size) +{ + size_t new_allocated; + if (list->allocated == 0) + { + /* No scratch buffer provided. Choose a reasonable default + size. */ + if (element_size < 4) + new_allocated = 16; + else if (element_size < 8) + new_allocated = 8; + else + new_allocated = 4; + } + else + /* Increase the allocated size, using an exponential growth + policy. */ + { + new_allocated = list->allocated + list->allocated / 2 + 1; + if (new_allocated <= list->allocated) + { + /* Overflow. */ + __set_errno (ENOMEM); + return false; + } + } + + size_t new_size; + if (INT_MULTIPLY_WRAPV (new_allocated, element_size, &new_size)) + return false; + void *new_array; + if (list->array == scratch) + { + /* The previous array was not heap-allocated. */ + new_array = malloc (new_size); + if (new_array != NULL && list->array != NULL) + memcpy (new_array, list->array, list->used * element_size); + } + else + new_array = realloc (list->array, new_size); + if (new_array == NULL) + return false; + list->array = new_array; + list->allocated = new_allocated; + return true; +} +libc_hidden_def (__libc_dynarray_emplace_enlarge) diff --git a/lib/malloc/dynarray_finalize.c b/lib/malloc/dynarray_finalize.c new file mode 100644 index 00000000000..be9441e313d --- /dev/null +++ b/lib/malloc/dynarray_finalize.c @@ -0,0 +1,62 @@ +/* Copy the dynamically-allocated area to an explicitly-sized heap allocation. + Copyright (C) 2017-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 General Public + License as published by the Free Software Foundation; either + version 3 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <dynarray.h> +#include <stdlib.h> +#include <string.h> + +bool +__libc_dynarray_finalize (struct dynarray_header *list, + void *scratch, size_t element_size, + struct dynarray_finalize_result *result) +{ + if (__dynarray_error (list)) + /* The caller will reported the deferred error. */ + return false; + + size_t used = list->used; + + /* Empty list. */ + if (used == 0) + { + /* An empty list could still be backed by a heap-allocated + array. Free it if necessary. */ + if (list->array != scratch) + free (list->array); + *result = (struct dynarray_finalize_result) { NULL, 0 }; + return true; + } + + size_t allocation_size = used * element_size; + void *heap_array = malloc (allocation_size); + if (heap_array != NULL) + { + /* The new array takes ownership of the strings. */ + if (list->array != NULL) + memcpy (heap_array, list->array, allocation_size); + if (list->array != scratch) + free (list->array); + *result = (struct dynarray_finalize_result) + { .array = heap_array, .length = used }; + return true; + } + else + /* The caller will perform the freeing operation. */ + return false; +} +libc_hidden_def (__libc_dynarray_finalize) diff --git a/lib/malloc/dynarray_resize.c b/lib/malloc/dynarray_resize.c new file mode 100644 index 00000000000..92bbddd4461 --- /dev/null +++ b/lib/malloc/dynarray_resize.c @@ -0,0 +1,64 @@ +/* Increase the size of a dynamic array. + Copyright (C) 2017-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 General Public + License as published by the Free Software Foundation; either + version 3 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <dynarray.h> +#include <errno.h> +#include <intprops.h> +#include <stdlib.h> +#include <string.h> + +bool +__libc_dynarray_resize (struct dynarray_header *list, size_t size, + void *scratch, size_t element_size) +{ + /* The existing allocation provides sufficient room. */ + if (size <= list->allocated) + { + list->used = size; + return true; + } + + /* Otherwise, use size as the new allocation size. The caller is + expected to provide the final size of the array, so there is no + over-allocation here. */ + + size_t new_size_bytes; + if (INT_MULTIPLY_WRAPV (size, element_size, &new_size_bytes)) + { + /* Overflow. */ + __set_errno (ENOMEM); + return false; + } + void *new_array; + if (list->array == scratch) + { + /* The previous array was not heap-allocated. */ + new_array = malloc (new_size_bytes); + if (new_array != NULL && list->array != NULL) + memcpy (new_array, list->array, list->used * element_size); + } + else + new_array = realloc (list->array, new_size_bytes); + if (new_array == NULL) + return false; + list->array = new_array; + list->allocated = size; + list->used = size; + return true; +} +libc_hidden_def (__libc_dynarray_resize) diff --git a/lib/malloc/dynarray_resize_clear.c b/lib/malloc/dynarray_resize_clear.c new file mode 100644 index 00000000000..99c2cc87c31 --- /dev/null +++ b/lib/malloc/dynarray_resize_clear.c @@ -0,0 +1,35 @@ +/* Increase the size of a dynamic array and clear the new part. + Copyright (C) 2017-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 General Public + License as published by the Free Software Foundation; either + version 3 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <dynarray.h> +#include <string.h> + +bool +__libc_dynarray_resize_clear (struct dynarray_header *list, size_t size, + void *scratch, size_t element_size) +{ + size_t old_size = list->used; + if (!__libc_dynarray_resize (list, size, scratch, element_size)) + return false; + /* __libc_dynarray_resize already checked for overflow. */ + char *array = list->array; + memset (array + (old_size * element_size), 0, + (size - old_size) * element_size); + return true; +} +libc_hidden_def (__libc_dynarray_resize_clear) diff --git a/lib/malloc/scratch_buffer_grow.c b/lib/malloc/scratch_buffer_grow.c index 41befe3d65f..e7606d81cd7 100644 --- a/lib/malloc/scratch_buffer_grow.c +++ b/lib/malloc/scratch_buffer_grow.c @@ -1,5 +1,5 @@ /* Variable-sized buffer with on-stack default allocation. - Copyright (C) 2015-2020 Free Software Foundation, Inc. + Copyright (C) 2015-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 diff --git a/lib/malloc/scratch_buffer_grow_preserve.c b/lib/malloc/scratch_buffer_grow_preserve.c index aef232938d5..59f8c710001 100644 --- a/lib/malloc/scratch_buffer_grow_preserve.c +++ b/lib/malloc/scratch_buffer_grow_preserve.c @@ -1,5 +1,5 @@ /* Variable-sized buffer with on-stack default allocation. - Copyright (C) 2015-2020 Free Software Foundation, Inc. + Copyright (C) 2015-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 diff --git a/lib/malloc/scratch_buffer_set_array_size.c b/lib/malloc/scratch_buffer_set_array_size.c index 5f5e4c24f5a..e2b9f31211a 100644 --- a/lib/malloc/scratch_buffer_set_array_size.c +++ b/lib/malloc/scratch_buffer_set_array_size.c @@ -1,5 +1,5 @@ /* Variable-sized buffer with on-stack default allocation. - Copyright (C) 2015-2020 Free Software Foundation, Inc. + Copyright (C) 2015-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 diff --git a/lib/mini-gmp.c b/lib/mini-gmp.c index d34fe525e4c..de061e673ac 100644 --- a/lib/mini-gmp.c +++ b/lib/mini-gmp.c @@ -4521,7 +4521,7 @@ mpz_export (void *r, size_t *countp, int order, size_t size, int endian, mp_size_t un; if (nails != 0) - gmp_die ("mpz_import: Nails not supported."); + gmp_die ("mpz_export: Nails not supported."); assert (order == 1 || order == -1); assert (endian >= -1 && endian <= 1); diff --git a/lib/mktime-internal.h b/lib/mktime-internal.h index b765a37ee34..9c447bd7b05 100644 --- a/lib/mktime-internal.h +++ b/lib/mktime-internal.h @@ -1,5 +1,5 @@ /* Internals of mktime and related functions - Copyright 2016-2020 Free Software Foundation, Inc. + Copyright 2016-2021 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Paul Eggert <eggert@cs.ucla.edu>. diff --git a/lib/nstrftime.c b/lib/nstrftime.c index 8ba6975552b..2f5e4fbe639 100644 --- a/lib/nstrftime.c +++ b/lib/nstrftime.c @@ -19,7 +19,7 @@ # define USE_IN_EXTENDED_LOCALE_MODEL 1 # define HAVE_STRUCT_ERA_ENTRY 1 # define HAVE_TM_GMTOFF 1 -# define HAVE_TM_ZONE 1 +# define HAVE_STRUCT_TM_TM_ZONE 1 # define HAVE_TZNAME 1 # include "../locale/localeinfo.h" #else @@ -499,7 +499,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) #endif zone = NULL; -#if HAVE_TM_ZONE +#if HAVE_STRUCT_TM_TM_ZONE /* The POSIX test suite assumes that setting the environment variable TZ to a new value before calling strftime() will influence the result (the %Z format) even if the information in @@ -516,7 +516,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) } else { -# if !HAVE_TM_ZONE +# if !HAVE_STRUCT_TM_TM_ZONE /* Infer the zone name from *TZ instead of from TZNAME. */ tzname_vec = tz->tzname_copy; # endif diff --git a/lib/regex.c b/lib/regex.c index 88173bb1052..f76a416b3b5 100644 --- a/lib/regex.c +++ b/lib/regex.c @@ -1,5 +1,5 @@ /* Extended regular expression matching and search library. - Copyright (C) 2002-2020 Free Software Foundation, Inc. + Copyright (C) 2002-2021 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. diff --git a/lib/regex_internal.h b/lib/regex_internal.h index be2fa4fe78e..4c634edcbfa 100644 --- a/lib/regex_internal.h +++ b/lib/regex_internal.h @@ -32,6 +32,7 @@ #include <stdbool.h> #include <stdint.h> +#include <dynarray.h> #include <intprops.h> #include <verify.h> @@ -444,25 +445,6 @@ typedef struct re_dfa_t re_dfa_t; #define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) #define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) -#if defined _LIBC || HAVE_ALLOCA -# include <alloca.h> -#endif - -#ifndef _LIBC -# if HAVE_ALLOCA -/* The OS usually guarantees only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - allocate anything larger than 4096 bytes. Also care for the possibility - of a few compiler-allocated temporary stack slots. */ -# define __libc_use_alloca(n) ((n) < 4032) -# else -/* alloca is implemented with malloc, so just use malloc. */ -# define __libc_use_alloca(n) 0 -# undef alloca -# define alloca(n) malloc (n) -# endif -#endif - #ifdef _LIBC # define MALLOC_0_IS_NONNULL 1 #elif !defined MALLOC_0_IS_NONNULL @@ -848,12 +830,14 @@ re_string_elem_size_at (const re_string_t *pstr, Idx idx) } #endif /* RE_ENABLE_I18N */ -#ifndef FALLTHROUGH -# if (__GNUC__ >= 7) || (__clang_major__ >= 10) +#ifdef _LIBC +# if __GNUC__ >= 7 # define FALLTHROUGH __attribute__ ((__fallthrough__)) # else # define FALLTHROUGH ((void) 0) # endif +#else +# include "attribute.h" #endif #endif /* _REGEX_INTERNAL_H */ diff --git a/lib/regexec.c b/lib/regexec.c index 395e37db591..15dc57bd0e6 100644 --- a/lib/regexec.c +++ b/lib/regexec.c @@ -1,5 +1,5 @@ /* Extended regular expression matching and search library. - Copyright (C) 2002-2020 Free Software Foundation, Inc. + Copyright (C) 2002-2021 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. @@ -1355,6 +1355,12 @@ pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx, Idx nregs, return fs->stack[num].node; } + +#define DYNARRAY_STRUCT regmatch_list +#define DYNARRAY_ELEMENT regmatch_t +#define DYNARRAY_PREFIX regmatch_list_ +#include <malloc/dynarray-skeleton.c> + /* Set the positions where the subexpressions are starts/ends to registers PMATCH. Note: We assume that pmatch[0] is already set, and @@ -1370,8 +1376,8 @@ set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, re_node_set eps_via_nodes; struct re_fail_stack_t *fs; struct re_fail_stack_t fs_body = { 0, 2, NULL }; - regmatch_t *prev_idx_match; - bool prev_idx_match_malloced = false; + struct regmatch_list prev_match; + regmatch_list_init (&prev_match); DEBUG_ASSERT (nmatch > 1); DEBUG_ASSERT (mctx->state_log != NULL); @@ -1388,18 +1394,13 @@ set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, cur_node = dfa->init_node; re_node_set_init_empty (&eps_via_nodes); - if (__libc_use_alloca (nmatch * sizeof (regmatch_t))) - prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t)); - else + if (!regmatch_list_resize (&prev_match, nmatch)) { - prev_idx_match = re_malloc (regmatch_t, nmatch); - if (prev_idx_match == NULL) - { - free_fail_stack_return (fs); - return REG_ESPACE; - } - prev_idx_match_malloced = true; + regmatch_list_free (&prev_match); + free_fail_stack_return (fs); + return REG_ESPACE; } + regmatch_t *prev_idx_match = regmatch_list_begin (&prev_match); memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) @@ -1417,8 +1418,7 @@ set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, if (reg_idx == nmatch) { re_node_set_free (&eps_via_nodes); - if (prev_idx_match_malloced) - re_free (prev_idx_match); + regmatch_list_free (&prev_match); return free_fail_stack_return (fs); } cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, @@ -1427,8 +1427,7 @@ set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, else { re_node_set_free (&eps_via_nodes); - if (prev_idx_match_malloced) - re_free (prev_idx_match); + regmatch_list_free (&prev_match); return REG_NOERROR; } } @@ -1442,8 +1441,7 @@ set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, if (__glibc_unlikely (cur_node == -2)) { re_node_set_free (&eps_via_nodes); - if (prev_idx_match_malloced) - re_free (prev_idx_match); + regmatch_list_free (&prev_match); free_fail_stack_return (fs); return REG_ESPACE; } @@ -1453,15 +1451,13 @@ set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, else { re_node_set_free (&eps_via_nodes); - if (prev_idx_match_malloced) - re_free (prev_idx_match); + regmatch_list_free (&prev_match); return REG_NOMATCH; } } } re_node_set_free (&eps_via_nodes); - if (prev_idx_match_malloced) - re_free (prev_idx_match); + regmatch_list_free (&prev_match); return free_fail_stack_return (fs); } @@ -3251,7 +3247,7 @@ expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes, /* Build transition table for the state. Return true if successful. */ -static bool +static bool __attribute_noinline__ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) { reg_errcode_t err; @@ -3259,36 +3255,20 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) int ch; bool need_word_trtable = false; bitset_word_t elem, mask; - bool dests_node_malloced = false; - bool dest_states_malloced = false; Idx ndests; /* Number of the destination states from 'state'. */ re_dfastate_t **trtable; - re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl; - re_node_set follows, *dests_node; - bitset_t *dests_ch; + re_dfastate_t *dest_states[SBC_MAX]; + re_dfastate_t *dest_states_word[SBC_MAX]; + re_dfastate_t *dest_states_nl[SBC_MAX]; + re_node_set follows; bitset_t acceptable; - struct dests_alloc - { - re_node_set dests_node[SBC_MAX]; - bitset_t dests_ch[SBC_MAX]; - } *dests_alloc; - /* We build DFA states which corresponds to the destination nodes from 'state'. 'dests_node[i]' represents the nodes which i-th destination state contains, and 'dests_ch[i]' represents the characters which i-th destination state accepts. */ - if (__libc_use_alloca (sizeof (struct dests_alloc))) - dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc)); - else - { - dests_alloc = re_malloc (struct dests_alloc, 1); - if (__glibc_unlikely (dests_alloc == NULL)) - return false; - dests_node_malloced = true; - } - dests_node = dests_alloc->dests_node; - dests_ch = dests_alloc->dests_ch; + re_node_set dests_node[SBC_MAX]; + bitset_t dests_ch[SBC_MAX]; /* Initialize transition table. */ state->word_trtable = state->trtable = NULL; @@ -3298,8 +3278,6 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch); if (__glibc_unlikely (ndests <= 0)) { - if (dests_node_malloced) - re_free (dests_alloc); /* Return false in case of an error, true otherwise. */ if (ndests == 0) { @@ -3314,38 +3292,14 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) err = re_node_set_alloc (&follows, ndests + 1); if (__glibc_unlikely (err != REG_NOERROR)) - goto out_free; - - /* Avoid arithmetic overflow in size calculation. */ - size_t ndests_max - = ((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX) - / (3 * sizeof (re_dfastate_t *))); - if (__glibc_unlikely (ndests_max < ndests)) - goto out_free; - - if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX - + ndests * 3 * sizeof (re_dfastate_t *))) - dest_states = (re_dfastate_t **) - alloca (ndests * 3 * sizeof (re_dfastate_t *)); - else { - dest_states = re_malloc (re_dfastate_t *, ndests * 3); - if (__glibc_unlikely (dest_states == NULL)) - { -out_free: - if (dest_states_malloced) - re_free (dest_states); - re_node_set_free (&follows); - for (i = 0; i < ndests; ++i) - re_node_set_free (dests_node + i); - if (dests_node_malloced) - re_free (dests_alloc); - return false; - } - dest_states_malloced = true; + out_free: + re_node_set_free (&follows); + for (i = 0; i < ndests; ++i) + re_node_set_free (dests_node + i); + return false; } - dest_states_word = dest_states + ndests; - dest_states_nl = dest_states_word + ndests; + bitset_empty (acceptable); /* Then build the states for all destinations. */ @@ -3470,16 +3424,9 @@ out_free: } } - if (dest_states_malloced) - re_free (dest_states); - re_node_set_free (&follows); for (i = 0; i < ndests; ++i) re_node_set_free (dests_node + i); - - if (dests_node_malloced) - re_free (dests_alloc); - return true; } diff --git a/lib/scratch_buffer.h b/lib/scratch_buffer.h index 3e2b5ef27db..603b0d65d0a 100644 --- a/lib/scratch_buffer.h +++ b/lib/scratch_buffer.h @@ -21,6 +21,7 @@ #include <libc-config.h> +#define __libc_scratch_buffer_dupfree gl_scratch_buffer_dupfree #define __libc_scratch_buffer_grow gl_scratch_buffer_grow #define __libc_scratch_buffer_grow_preserve gl_scratch_buffer_grow_preserve #define __libc_scratch_buffer_set_array_size gl_scratch_buffer_set_array_size diff --git a/lib/stddef.in.h b/lib/stddef.in.h index ba7195a9102..0f506a5b18b 100644 --- a/lib/stddef.in.h +++ b/lib/stddef.in.h @@ -49,6 +49,23 @@ # ifndef _@GUARD_PREFIX@_STDDEF_H +/* On AIX 7.2, with xlc in 64-bit mode, <stddef.h> defines max_align_t to a + type with alignment 4, but 'long' has alignment 8. */ +# if defined _AIX && defined _ARCH_PPC64 +# if !GNULIB_defined_max_align_t +# ifdef _MAX_ALIGN_T +/* /usr/include/stddef.h has already defined max_align_t. Override it. */ +typedef long rpl_max_align_t; +# define max_align_t rpl_max_align_t +# else +/* Prevent /usr/include/stddef.h from defining max_align_t. */ +typedef long max_align_t; +# define _MAX_ALIGN_T +# endif +# define GNULIB_defined_max_align_t 1 +# endif +# endif + /* The include_next requires a split double-inclusion guard. */ # @INCLUDE_NEXT@ @NEXT_STDDEF_H@ @@ -86,8 +103,10 @@ we are currently compiling with gcc. On MSVC, max_align_t is defined only in C++ mode, after <cstddef> was included. Its definition is good since it has an alignment of 8 (on x86 - and x86_64). */ -#if defined _MSC_VER && defined __cplusplus + and x86_64). + Similarly on OS/2 kLIBC. */ +#if (defined _MSC_VER || (defined __KLIBC__ && !defined __LIBCN__)) \ + && defined __cplusplus # include <cstddef> #else # if ! (@HAVE_MAX_ALIGN_T@ || defined _GCC_MAX_ALIGN_T) diff --git a/lib/string.in.h b/lib/string.in.h index 9f68e77c767..c76c1820b36 100644 --- a/lib/string.in.h +++ b/lib/string.in.h @@ -69,6 +69,14 @@ # include <unistd.h> #endif +/* AIX 7.2 declares ffsl and ffsll in <strings.h>, not in <string.h>. */ +/* But in any case avoid namespace pollution on glibc systems. */ +#if ((@GNULIB_FFSL@ || @GNULIB_FFSLL@ || defined GNULIB_POSIXCHECK) \ + && defined _AIX) \ + && ! defined __GLIBC__ +# include <strings.h> +#endif + /* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ /* The definition of _GL_ARG_NONNULL is copied here. */ @@ -110,10 +118,18 @@ _GL_WARN_ON_USE (ffsl, "ffsl is not portable - use the ffsl module"); /* Find the index of the least-significant set bit. */ #if @GNULIB_FFSLL@ -# if !@HAVE_FFSLL@ +# if @REPLACE_FFSLL@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# define ffsll rpl_ffsll +# endif +_GL_FUNCDECL_RPL (ffsll, int, (long long int i)); +_GL_CXXALIAS_RPL (ffsll, int, (long long int i)); +# else +# if !@HAVE_FFSLL@ _GL_FUNCDECL_SYS (ffsll, int, (long long int i)); -# endif +# endif _GL_CXXALIAS_SYS (ffsll, int, (long long int i)); +# endif _GL_CXXALIASWARN (ffsll); #elif defined GNULIB_POSIXCHECK # undef ffsll diff --git a/lib/sys_stat.in.h b/lib/sys_stat.in.h index ccdb5cbd143..13d12943cd0 100644 --- a/lib/sys_stat.in.h +++ b/lib/sys_stat.in.h @@ -713,11 +713,21 @@ _GL_WARN_ON_USE (mkfifo, "mkfifo is not portable - " #if @GNULIB_MKFIFOAT@ -# if !@HAVE_MKFIFOAT@ +# if @REPLACE_MKFIFOAT@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef mkfifoat +# define mkfifoat rpl_mkfifoat +# endif +_GL_FUNCDECL_RPL (mkfifoat, int, (int fd, char const *file, mode_t mode) + _GL_ARG_NONNULL ((2))); +_GL_CXXALIAS_RPL (mkfifoat, int, (int fd, char const *file, mode_t mode)); +# else +# if !@HAVE_MKFIFOAT@ _GL_FUNCDECL_SYS (mkfifoat, int, (int fd, char const *file, mode_t mode) _GL_ARG_NONNULL ((2))); -# endif +# endif _GL_CXXALIAS_SYS (mkfifoat, int, (int fd, char const *file, mode_t mode)); +# endif _GL_CXXALIASWARN (mkfifoat); #elif defined GNULIB_POSIXCHECK # undef mkfifoat @@ -756,13 +766,25 @@ _GL_WARN_ON_USE (mknod, "mknod is not portable - " #if @GNULIB_MKNODAT@ -# if !@HAVE_MKNODAT@ +# if @REPLACE_MKNODAT@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef mknodat +# define mknodat rpl_mknodat +# endif +_GL_FUNCDECL_RPL (mknodat, int, + (int fd, char const *file, mode_t mode, dev_t dev) + _GL_ARG_NONNULL ((2))); +_GL_CXXALIAS_RPL (mknodat, int, + (int fd, char const *file, mode_t mode, dev_t dev)); +# else +# if !@HAVE_MKNODAT@ _GL_FUNCDECL_SYS (mknodat, int, (int fd, char const *file, mode_t mode, dev_t dev) _GL_ARG_NONNULL ((2))); -# endif +# endif _GL_CXXALIAS_SYS (mknodat, int, (int fd, char const *file, mode_t mode, dev_t dev)); +# endif _GL_CXXALIASWARN (mknodat); #elif defined GNULIB_POSIXCHECK # undef mknodat diff --git a/lib/tempname.c b/lib/tempname.c index 3d91deef1e1..e243483eaf8 100644 --- a/lib/tempname.c +++ b/lib/tempname.c @@ -22,6 +22,7 @@ #include <sys/types.h> #include <assert.h> +#include <stdbool.h> #include <errno.h> @@ -61,7 +62,8 @@ # define __gen_tempname gen_tempname # define __mkdir mkdir # define __open open -# define __lxstat64(version, file, buf) lstat (file, buf) +# define __lstat64(file, buf) lstat (file, buf) +# define __stat64(file, buf) stat (file, buf) # define __getrandom getrandom # define __clock_gettime64 clock_gettime # define __timespec64 timespec @@ -76,13 +78,14 @@ typedef uint_fast64_t random_value; #define BASE_62_POWER (62LL * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62) static random_value -random_bits (random_value var) +random_bits (random_value var, bool use_getrandom) { random_value r; - if (__getrandom (&r, sizeof r, 0) == sizeof r) + /* Without GRND_NONBLOCK it can be blocked for minutes on some systems. */ + if (use_getrandom && __getrandom (&r, sizeof r, GRND_NONBLOCK) == sizeof r) return r; #if _LIBC || (defined CLOCK_MONOTONIC && HAVE_CLOCK_GETTIME) - /* Add entropy if getrandom is not supported. */ + /* Add entropy if getrandom did not work. */ struct __timespec64 tv; __clock_gettime64 (CLOCK_MONOTONIC, &tv); var ^= tv.tv_nsec; @@ -96,7 +99,7 @@ static int direxists (const char *dir) { struct_stat64 buf; - return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode); + return __stat64 (dir, &buf) == 0 && S_ISDIR (buf.st_mode); } /* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is @@ -188,7 +191,7 @@ try_nocreate (char *tmpl, void *flags _GL_UNUSED) { struct_stat64 st; - if (__lxstat64 (_STAT_VER, tmpl, &st) == 0 || errno == EOVERFLOW) + if (__lstat64 (tmpl, &st) == 0 || errno == EOVERFLOW) __set_errno (EEXIST); return errno == ENOENT ? 0 : -1; } @@ -267,6 +270,13 @@ try_tempname_len (char *tmpl, int suffixlen, void *args, /* How many random base-62 digits can currently be extracted from V. */ int vdigits = 0; + /* Whether to consume entropy when acquiring random bits. On the + first try it's worth the entropy cost with __GT_NOCREATE, which + is inherently insecure and can use the entropy to make it a bit + less secure. On the (rare) second and later attempts it might + help against DoS attacks. */ + bool use_getrandom = tryfunc == try_nocreate; + /* Least unfair value for V. If V is less than this, V can generate BASE_62_DIGITS digits fairly. Otherwise it might be biased. */ random_value const unfair_min @@ -290,7 +300,10 @@ try_tempname_len (char *tmpl, int suffixlen, void *args, if (vdigits == 0) { do - v = random_bits (v); + { + v = random_bits (v, use_getrandom); + use_getrandom = true; + } while (unfair_min <= v); vdigits = BASE_62_DIGITS; diff --git a/lib/time-internal.h b/lib/time-internal.h index 63a3f9e3db1..067ee729eda 100644 --- a/lib/time-internal.h +++ b/lib/time-internal.h @@ -24,7 +24,7 @@ struct tm_zone members are zero. */ struct tm_zone *next; -#if HAVE_TZNAME && !HAVE_TM_ZONE +#if HAVE_TZNAME && !HAVE_STRUCT_TM_TM_ZONE /* Copies of recent strings taken from tzname[0] and tzname[1]. The copies are in ABBRS, so that they survive tzset. Null if unknown. */ char *tzname_copy[2]; diff --git a/lib/time.in.h b/lib/time.in.h index 958dc0bd292..1385980cdf5 100644 --- a/lib/time.in.h +++ b/lib/time.in.h @@ -101,6 +101,25 @@ struct __time_t_must_be_integral { # define GNULIB_defined_struct_time_t_must_be_integral 1 # endif +/* Define TIME_UTC, a positive integer constant used for timespec_get(). */ +# if ! @TIME_H_DEFINES_TIME_UTC@ +# if !GNULIB_defined_TIME_UTC +# define TIME_UTC 1 +# define GNULIB_defined_TIME_UTC 1 +# endif +# endif + +/* Set *TS to the current time, and return BASE. + Upon failure, return 0. */ +# if @GNULIB_TIMESPEC_GET@ +# if ! @HAVE_TIMESPEC_GET@ +_GL_FUNCDECL_SYS (timespec_get, int, (struct timespec *ts, int base) + _GL_ARG_NONNULL ((1))); +# endif +_GL_CXXALIAS_SYS (timespec_get, int, (struct timespec *ts, int base)); +_GL_CXXALIASWARN (timespec_get); +# endif + /* Sleep for at least RQTP seconds unless interrupted, If interrupted, return -1 and store the remaining time into RMTP. See <https://pubs.opengroup.org/onlinepubs/9699919799/functions/nanosleep.html>. */ diff --git a/lib/time_rz.c b/lib/time_rz.c index 65e20cc5661..3ac053c6219 100644 --- a/lib/time_rz.c +++ b/lib/time_rz.c @@ -71,7 +71,7 @@ tzalloc (char const *name) if (tz) { tz->next = NULL; -#if HAVE_TZNAME && !HAVE_TM_ZONE +#if HAVE_TZNAME && !HAVE_STRUCT_TM_TM_ZONE tz->tzname_copy[0] = tz->tzname_copy[1] = NULL; #endif tz->tz_is_set = !!name; @@ -83,13 +83,13 @@ tzalloc (char const *name) } /* Save into TZ any nontrivial time zone abbreviation used by TM, and - update *TM (if HAVE_TM_ZONE) or *TZ (if !HAVE_TM_ZONE && - HAVE_TZNAME) if they use the abbreviation. Return true if - successful, false (setting errno) otherwise. */ + update *TM (if HAVE_STRUCT_TM_TM_ZONE) or *TZ (if + !HAVE_STRUCT_TM_TM_ZONE && HAVE_TZNAME) if they use the abbreviation. + Return true if successful, false (setting errno) otherwise. */ static bool save_abbr (timezone_t tz, struct tm *tm) { -#if HAVE_TM_ZONE || HAVE_TZNAME +#if HAVE_STRUCT_TM_TM_ZONE || HAVE_TZNAME char const *zone = NULL; char *zone_copy = (char *) ""; @@ -97,7 +97,7 @@ save_abbr (timezone_t tz, struct tm *tm) int tzname_index = -1; # endif -# if HAVE_TM_ZONE +# if HAVE_STRUCT_TM_TM_ZONE zone = tm->tm_zone; # endif @@ -145,7 +145,7 @@ save_abbr (timezone_t tz, struct tm *tm) } /* Replace the zone name so that its lifetime matches that of TZ. */ -# if HAVE_TM_ZONE +# if HAVE_STRUCT_TM_TM_ZONE tm->tm_zone = zone_copy; # else if (0 <= tzname_index) @@ -303,7 +303,7 @@ mktime_z (timezone_t tz, struct tm *tm) tm_1.tm_isdst = tm->tm_isdst; time_t t = mktime (&tm_1); bool ok = 0 <= tm_1.tm_yday; -#if HAVE_TM_ZONE || HAVE_TZNAME +#if HAVE_STRUCT_TM_TM_ZONE || HAVE_TZNAME ok = ok && save_abbr (tz, &tm_1); #endif if (revert_tz (old_tz) && ok) diff --git a/lib/timegm.c b/lib/timegm.c index fa30943084d..e4127e71c0b 100644 --- a/lib/timegm.c +++ b/lib/timegm.c @@ -1,6 +1,6 @@ /* Convert UTC calendar time to simple time. Like mktime but assumes UTC. - Copyright (C) 1994-2020 Free Software Foundation, Inc. + Copyright (C) 1994-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 diff --git a/lib/utimens.c b/lib/utimens.c index 5bbae058132..44d1ea003e2 100644 --- a/lib/utimens.c +++ b/lib/utimens.c @@ -27,6 +27,7 @@ #include <errno.h> #include <fcntl.h> #include <stdbool.h> +#include <string.h> #include <sys/stat.h> #include <sys/time.h> #include <unistd.h> @@ -52,7 +53,9 @@ /* Avoid recursion with rpl_futimens or rpl_utimensat. */ #undef futimens -#undef utimensat +#if !HAVE_NEARLY_WORKING_UTIMENSAT +# undef utimensat +#endif /* Solaris 9 mistakenly succeeds when given a non-directory with a trailing slash. Force the use of rpl_stat for a fix. */ @@ -246,6 +249,20 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2]) # if HAVE_UTIMENSAT if (fd < 0) { +# if defined __APPLE__ && defined __MACH__ + size_t len = strlen (file); + if (len > 0 && file[len - 1] == '/') + { + struct stat statbuf; + if (stat (file, &statbuf) < 0) + return -1; + if (!S_ISDIR (statbuf.st_mode)) + { + errno = ENOTDIR; + return -1; + } + } +# endif result = utimensat (AT_FDCWD, file, ts, 0); # ifdef __linux__ /* Work around a kernel bug: diff --git a/lib/utimensat.c b/lib/utimensat.c index 2cea64f6982..9fdecd681f6 100644 --- a/lib/utimensat.c +++ b/lib/utimensat.c @@ -24,14 +24,40 @@ #include <errno.h> #include <fcntl.h> #include <stdlib.h> +#include <string.h> +#include <sys/stat.h> #include "stat-time.h" #include "timespec.h" #include "utimens.h" -#if HAVE_UTIMENSAT +#if HAVE_NEARLY_WORKING_UTIMENSAT +/* Use the original utimensat(), but correct the trailing slash handling. */ +int +rpl_utimensat (int fd, char const *file, struct timespec const times[2], + int flag) # undef utimensat +{ + size_t len = strlen (file); + if (len && file[len - 1] == '/') + { + struct stat st; + if (fstatat (fd, file, &st, flag & AT_SYMLINK_NOFOLLOW) < 0) + return -1; + if (!S_ISDIR (st.st_mode)) + { + errno = ENOTDIR; + return -1; + } + } + + return utimensat (fd, file, times, flag); +} + +#else + +# if HAVE_UTIMENSAT /* If we have a native utimensat, but are compiling this file, then utimensat was defined to rpl_utimensat by our replacement @@ -42,24 +68,25 @@ local_utimensat provides the fallback manipulation. */ static int local_utimensat (int, char const *, struct timespec const[2], int); -# define AT_FUNC_NAME local_utimensat +# define AT_FUNC_NAME local_utimensat /* Like utimensat, but work around native bugs. */ int rpl_utimensat (int fd, char const *file, struct timespec const times[2], int flag) +# undef utimensat { -# if defined __linux__ || defined __sun +# if defined __linux__ || defined __sun struct timespec ts[2]; -# endif +# endif /* See comments in utimens.c for details. */ static int utimensat_works_really; /* 0 = unknown, 1 = yes, -1 = no. */ if (0 <= utimensat_works_really) { int result; -# if defined __linux__ || defined __sun +# if defined __linux__ || defined __sun struct stat st; /* As recently as Linux kernel 2.6.32 (Dec 2009), several file systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT, @@ -90,7 +117,7 @@ rpl_utimensat (int fd, char const *file, struct timespec const times[2], ts[1] = times[1]; times = ts; } -# ifdef __hppa__ +# ifdef __hppa__ /* Linux kernel 2.6.22.19 on hppa does not reject invalid tv_nsec values. */ else if (times @@ -104,8 +131,36 @@ rpl_utimensat (int fd, char const *file, struct timespec const times[2], errno = EINVAL; return -1; } +# endif +# endif +# if defined __APPLE__ && defined __MACH__ + /* macOS 10.13 does not reject invalid tv_nsec values either. */ + if (times + && ((times[0].tv_nsec != UTIME_OMIT + && times[0].tv_nsec != UTIME_NOW + && ! (0 <= times[0].tv_nsec + && times[0].tv_nsec < TIMESPEC_HZ)) + || (times[1].tv_nsec != UTIME_OMIT + && times[1].tv_nsec != UTIME_NOW + && ! (0 <= times[1].tv_nsec + && times[1].tv_nsec < TIMESPEC_HZ)))) + { + errno = EINVAL; + return -1; + } + size_t len = strlen (file); + if (len > 0 && file[len - 1] == '/') + { + struct stat statbuf; + if (fstatat (fd, file, &statbuf, 0) < 0) + return -1; + if (!S_ISDIR (statbuf.st_mode)) + { + errno = ENOTDIR; + return -1; + } + } # endif -# endif result = utimensat (fd, file, times, flag); /* Linux kernel 2.6.25 has a bug where it returns EINVAL for UTIME_NOW or UTIME_OMIT with non-zero tv_sec, which @@ -129,11 +184,11 @@ rpl_utimensat (int fd, char const *file, struct timespec const times[2], return local_utimensat (fd, file, times, flag); } -#else /* !HAVE_UTIMENSAT */ +# else /* !HAVE_UTIMENSAT */ -# define AT_FUNC_NAME utimensat +# define AT_FUNC_NAME utimensat -#endif /* !HAVE_UTIMENSAT */ +# endif /* !HAVE_UTIMENSAT */ /* Set the access and modification timestamps of FILE to be TIMESPEC[0] and TIMESPEC[1], respectively; relative to directory @@ -146,15 +201,17 @@ rpl_utimensat (int fd, char const *file, struct timespec const times[2], Return 0 on success, -1 (setting errno) on failure. */ /* AT_FUNC_NAME is now utimensat or local_utimensat. */ -#define AT_FUNC_F1 lutimens -#define AT_FUNC_F2 utimens -#define AT_FUNC_USE_F1_COND AT_SYMLINK_NOFOLLOW -#define AT_FUNC_POST_FILE_PARAM_DECLS , struct timespec const ts[2], int flag -#define AT_FUNC_POST_FILE_ARGS , ts -#include "at-func.c" -#undef AT_FUNC_NAME -#undef AT_FUNC_F1 -#undef AT_FUNC_F2 -#undef AT_FUNC_USE_F1_COND -#undef AT_FUNC_POST_FILE_PARAM_DECLS -#undef AT_FUNC_POST_FILE_ARGS +# define AT_FUNC_F1 lutimens +# define AT_FUNC_F2 utimens +# define AT_FUNC_USE_F1_COND AT_SYMLINK_NOFOLLOW +# define AT_FUNC_POST_FILE_PARAM_DECLS , struct timespec const ts[2], int flag +# define AT_FUNC_POST_FILE_ARGS , ts +# include "at-func.c" +# undef AT_FUNC_NAME +# undef AT_FUNC_F1 +# undef AT_FUNC_F2 +# undef AT_FUNC_USE_F1_COND +# undef AT_FUNC_POST_FILE_PARAM_DECLS +# undef AT_FUNC_POST_FILE_ARGS + +#endif /* !HAVE_NEARLY_WORKING_UTIMENSAT */ diff --git a/lib/verify.h b/lib/verify.h index 3cdcdca5671..65514c34b9e 100644 --- a/lib/verify.h +++ b/lib/verify.h @@ -22,16 +22,10 @@ /* Define _GL_HAVE__STATIC_ASSERT to 1 if _Static_assert (R, DIAGNOSTIC) - works as per C11. This is supported by GCC 4.6.0 and later, in C - mode, and by clang (also in C++ mode). + works as per C11. This is supported by GCC 4.6.0+ and by clang 4+. Define _GL_HAVE__STATIC_ASSERT1 to 1 if _Static_assert (R) works as - per C2X. This is supported by GCC 9.1 and later, and by clang in - C++1z mode. - - Define _GL_HAVE_STATIC_ASSERT1 if static_assert (R) works as per - C++17. This is supported by GCC 9.1 and later, and by clang in - C++1z mode. + per C2X. This is supported by GCC 9.1+. Support compilers claiming conformance to the relevant standard, and also support GCC when not pedantic. If we were willing to slow @@ -47,18 +41,6 @@ || (!defined __STRICT_ANSI__ && 9 <= __GNUC__)) # define _GL_HAVE__STATIC_ASSERT1 1 # endif -#else -# if 4 <= __clang_major__ -# define _GL_HAVE__STATIC_ASSERT 1 -# endif -# if 4 <= __clang_major__ && 201411 <= __cpp_static_assert -# define _GL_HAVE__STATIC_ASSERT1 1 -# endif -# if 201703L <= __cplusplus \ - || 9 <= __GNUC__ \ - || (4 <= __clang_major__ && 201411 <= __cpp_static_assert) -# define _GL_HAVE_STATIC_ASSERT1 1 -# endif #endif /* FreeBSD 9.1 <sys/cdefs.h>, included by <stddef.h> and lots of other @@ -225,7 +207,9 @@ template <int w> Unfortunately, unlike C11, this implementation must appear as an ordinary declaration, and cannot appear inside struct { ... }. */ -#if defined _GL_HAVE__STATIC_ASSERT +#if 200410 <= __cpp_static_assert +# define _GL_VERIFY(R, DIAGNOSTIC, ...) static_assert (R, DIAGNOSTIC) +#elif defined _GL_HAVE__STATIC_ASSERT # define _GL_VERIFY(R, DIAGNOSTIC, ...) _Static_assert (R, DIAGNOSTIC) #else # define _GL_VERIFY(R, DIAGNOSTIC, ...) \ @@ -239,7 +223,7 @@ template <int w> # define _Static_assert(...) \ _GL_VERIFY (__VA_ARGS__, "static assertion failed", -) # endif -# if !defined _GL_HAVE_STATIC_ASSERT1 && !defined static_assert +# if __cpp_static_assert < 201411 && !defined static_assert # define static_assert _Static_assert /* C11 requires this #define. */ # endif #endif |