aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel F. T. Gomes <gabriel@inconstante.eti.br>2017-12-19 15:18:07 -0200
committerGabriel F. T. Gomes <gabriel@inconstante.eti.br>2017-12-19 15:18:07 -0200
commit567785e2b50321d02d7682aae085f19dc3404f3d (patch)
tree53e82c7e00c5a2e7674eeee7627ba17477316c58
parent0f0074a4f1a3ebddb4d5acbbf71ba7c9a2182a47 (diff)
parentc5b38f2ecec6facf818e3c50ad014be05b52c179 (diff)
downloadglibc-ibm/2.24/master.tar
glibc-ibm/2.24/master.tar.gz
glibc-ibm/2.24/master.tar.bz2
glibc-ibm/2.24/master.zip
Merge branch release/2.24/master into ibm/2.24/masteribm/2.24/master
-rw-r--r--ChangeLog296
-rw-r--r--NEWS29
-rw-r--r--conform/Makefile6
-rw-r--r--elf/dl-load.c27
-rw-r--r--grp/grp-merge.c18
-rw-r--r--include/array_length.h36
-rw-r--r--misc/regexp.c9
-rw-r--r--nis/nss_nisplus/nisplus-alias.c2
-rw-r--r--posix/Makefile13
-rw-r--r--posix/flexmember.h45
-rw-r--r--posix/glob.c780
-rw-r--r--posix/glob64.c6
-rw-r--r--posix/glob_internal.h57
-rw-r--r--posix/glob_pattern_p.c33
-rw-r--r--posix/globfree.c41
-rw-r--r--posix/globfree64.c31
-rw-r--r--posix/tst-glob-tilde.c143
-rw-r--r--sunrpc/Makefile14
-rw-r--r--sunrpc/bug20790.x1
-rw-r--r--sunrpc/clnt_udp.c2
-rw-r--r--sunrpc/rpc_parse.c2
-rw-r--r--sunrpc/tst-udp-error.c62
-rw-r--r--sysdeps/aarch64/dl-machine.h4
-rw-r--r--sysdeps/gnu/glob64.c3
-rw-r--r--sysdeps/gnu/globfree64.c10
-rw-r--r--sysdeps/ieee754/dbl-64/e_pow.c8
-rw-r--r--sysdeps/unix/sysv/linux/Makefile2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/glob.c4
-rw-r--r--sysdeps/unix/sysv/linux/alpha/globfree.c37
-rw-r--r--sysdeps/unix/sysv/linux/i386/glob64.c36
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c1
-rw-r--r--sysdeps/unix/sysv/linux/oldglob.c42
-rw-r--r--sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym32
-rw-r--r--sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym32
-rw-r--r--sysdeps/unix/sysv/linux/sh/sys/ucontext.h70
-rw-r--r--sysdeps/unix/sysv/linux/wordsize-64/globfree64.c2
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/x32/globfree.c1
-rw-r--r--sysdeps/wordsize-64/glob.c2
-rw-r--r--sysdeps/wordsize-64/globfree.c5
-rw-r--r--sysdeps/wordsize-64/globfree64.c1
-rw-r--r--sysdeps/x86/cpu-features-offsets.sym1
-rw-r--r--sysdeps/x86/cpu-features.c80
-rw-r--r--sysdeps/x86/cpu-features.h23
-rw-r--r--sysdeps/x86_64/Makefile24
-rw-r--r--sysdeps/x86_64/dl-machine.h38
-rw-r--r--sysdeps/x86_64/dl-tls.c53
-rw-r--r--sysdeps/x86_64/dl-tls.h5
-rw-r--r--sysdeps/x86_64/dl-trampoline.S87
-rw-r--r--sysdeps/x86_64/dl-trampoline.h265
-rw-r--r--sysdeps/x86_64/rtld-offsets.sym6
-rw-r--r--sysdeps/x86_64/tls_get_addr.S61
-rw-r--r--sysdeps/x86_64/tlsdesc.sym3
-rw-r--r--sysdeps/x86_64/tst-avx-aux.c47
-rw-r--r--sysdeps/x86_64/tst-avx.c49
-rw-r--r--sysdeps/x86_64/tst-avx512-aux.c48
-rw-r--r--sysdeps/x86_64/tst-avx512.c57
-rw-r--r--sysdeps/x86_64/tst-avx512mod.c48
-rw-r--r--sysdeps/x86_64/tst-avxmod.c48
-rw-r--r--sysdeps/x86_64/tst-sse.c46
-rw-r--r--sysdeps/x86_64/tst-ssemod.c46
60 files changed, 2119 insertions, 861 deletions
diff --git a/ChangeLog b/ChangeLog
index d96bbeccb6..488789649b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,299 @@
+2017-12-14 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #22607]
+ CVE-2017-1000409
+ * elf/dl-load.c (_dl_init_paths): Compute number of components in
+ the expanded path string.
+
+2017-12-14 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #22606]
+ CVE-2017-1000408
+ * elf/dl-load.c (system_dirs): Update comment.
+ (nsystem_dirs_len): Use array_length.
+ (_dl_init_paths): Use nsystem_dirs_len to compute the array size.
+
+2017-11-02 Florian Weimer <fweimer@redhat.com>
+
+ Add array_length and array_end macros.
+ * include/array_length.h: New file.
+
+2017-11-02 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #22332]
+ * posix/tst-glob-tilde.c (do_noescape): New variable.
+ (one_test): Process it.
+ (do_test): Set do_noescape. Add unescaping test case.
+
+2017-10-22 Paul Eggert <eggert@cs.ucla.edu>
+
+ [BZ #22332]
+ * posix/glob.c (__glob): Fix buffer overflow during GLOB_TILDE
+ unescaping.
+
+2017-10-21 Florian Weimer <fweimer@redhat.com>
+
+ * posix/Makefile (tests): Add tst-glob-tilde.
+ (tests-special): Add tst-glob-tilde-mem.out
+ (tst-glob-tilde-ENV): Set MALLOC_TRACE.
+ (tst-glob-tilde-mem.out): Add mtrace check.
+ * posix/tst-glob-tilde.c: New file.
+
+2017-10-20 Paul Eggert <eggert@cs.ucla.edu>
+
+ [BZ #22320]
+ CVE-2017-15670
+ * posix/glob.c (__glob): Fix one-byte overflow.
+
+2017-09-08 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ [BZ #1062]
+ CVE-2017-15671
+ * posix/Makefile (routines): Add globfree, globfree64, and
+ glob_pattern_p.
+ * posix/flexmember.h: New file.
+ * posix/glob_internal.h: Likewise.
+ * posix/glob_pattern_p.c: Likewise.
+ * posix/globfree.c: Likewise.
+ * posix/globfree64.c: Likewise.
+ * sysdeps/gnu/globfree64.c: Likewise.
+ * sysdeps/unix/sysv/linux/alpha/globfree.c: Likewise.
+ * sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c: Likewise.
+ * sysdeps/unix/sysv/linux/oldglob.c: Likewise.
+ * sysdeps/unix/sysv/linux/wordsize-64/globfree64.c: Likewise.
+ * sysdeps/unix/sysv/linux/x86_64/x32/globfree.c: Likewise.
+ * sysdeps/wordsize-64/globfree.c: Likewise.
+ * sysdeps/wordsize-64/globfree64.c: Likewise.
+ * posix/glob.c (HAVE_CONFIG_H): Use !_LIBC instead.
+ [NDEBUG): Remove comments.
+ (GLOB_ONLY_P, _AMIGA, VMS): Remove define.
+ (dirent_type): New type. Use uint_fast8_t not
+ uint8_t, as C99 does not require uint8_t.
+ (DT_UNKNOWN, DT_DIR, DT_LNK): New macros.
+ (struct readdir_result): Use dirent_type. Do not define skip_entry
+ unless it is needed; this saves a byte on platforms lacking d_ino.
+ (readdir_result_type, readdir_result_skip_entry):
+ New functions, replacing ...
+ (readdir_result_might_be_symlink, readdir_result_might_be_dir):
+ these functions, which were removed. This makes the callers
+ easier to read. All callers changed.
+ (D_INO_TO_RESULT): Now empty if there is no d_ino.
+ (size_add_wrapv, glob_use_alloca): New static functions.
+ (glob, glob_in_dir): Check for size_t overflow in several places,
+ and fix some size_t checks that were not quite right.
+ Remove old code using SHELL since Bash no longer
+ uses this.
+ (glob, prefix_array): Separate MS code better.
+ (glob_in_dir): Remove old Amiga and VMS code.
+ (globfree, __glob_pattern_type, __glob_pattern_p): Move to
+ separate files.
+ (glob_in_dir): Do not rely on undefined behavior in accessing
+ struct members beyond their bounds. Use a flexible array member
+ instead
+ (link_stat): Rename from link_exists2_p and return -1/0 instead of
+ 0/1. Caller changed.
+ (glob): Fix memory leaks.
+ * posix/glob64 (globfree64): Move to separate file.
+ * sysdeps/gnu/glob64.c (NO_GLOB_PATTERN_P): Remove define.
+ (globfree64): Remove hidden alias.
+ * sysdeps/unix/sysv/linux/Makefile (sysdeps_routines): Add
+ oldglob.
+ * sysdeps/unix/sysv/linux/alpha/glob.c (__new_globfree): Move to
+ separate file.
+ * sysdeps/unix/sysv/linux/i386/glob64.c (NO_GLOB_PATTERN_P): Remove
+ define.
+ Move compat code to separate file.
+ * sysdeps/wordsize-64/glob.c (globfree): Move definitions to
+ separate file.
+
+2017-08-20 H.J. Lu <hongjiu.lu@intel.com>
+
+ [BZ #18822]
+ * sysdeps/unix/sysv/linux/i386/glob64.c (__old_glob64): Add
+ libc_hidden_proto and libc_hidden_def.
+
+2017-10-22 H.J. Lu <hongjiu.lu@intel.com>
+
+ [BZ #21265]
+ * sysdeps/x86/cpu-features-offsets.sym (XSAVE_STATE_SIZE_OFFSET):
+ New.
+ * sysdeps/x86/cpu-features.c: Include <libc-internal.h>.
+ (get_common_indeces): Set xsave_state_size and
+ bit_arch_XSAVEC_Usable if needed.
+ (init_cpu_features): Remove bit_arch_Use_dl_runtime_resolve_slow
+ and bit_arch_Use_dl_runtime_resolve_opt.
+ * sysdeps/x86/cpu-features.h (bit_arch_Use_dl_runtime_resolve_opt):
+ Removed.
+ (bit_arch_Use_dl_runtime_resolve_slow): Likewise.
+ (bit_arch_Prefer_No_AVX512): Updated.
+ (bit_arch_MathVec_Prefer_No_AVX512): Likewise.
+ (bit_arch_XSAVEC_Usable): New.
+ (STATE_SAVE_OFFSET): Likewise.
+ (STATE_SAVE_MASK): Likewise.
+ [__ASSEMBLER__]: Include <cpu-features-offsets.h>.
+ (cpu_features): Add xsave_state_size.
+ (index_arch_Use_dl_runtime_resolve_opt): Removed.
+ (index_arch_Use_dl_runtime_resolve_slow): Likewise.
+ (index_arch_XSAVEC_Usable): New.
+ * sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup):
+ Replace _dl_runtime_resolve_sse, _dl_runtime_resolve_avx,
+ _dl_runtime_resolve_avx_slow, _dl_runtime_resolve_avx_opt,
+ _dl_runtime_resolve_avx512 and _dl_runtime_resolve_avx512_opt
+ with _dl_runtime_resolve_fxsave, _dl_runtime_resolve_xsave and
+ _dl_runtime_resolve_xsavec.
+ * sysdeps/x86_64/dl-trampoline.S (DL_RUNTIME_UNALIGNED_VEC_SIZE):
+ Removed.
+ (DL_RUNTIME_RESOLVE_REALIGN_STACK): Check STATE_SAVE_ALIGNMENT
+ instead of VEC_SIZE.
+ (REGISTER_SAVE_BND0): Removed.
+ (REGISTER_SAVE_BND1): Likewise.
+ (REGISTER_SAVE_BND3): Likewise.
+ (REGISTER_SAVE_RAX): Always defined to 0.
+ (VMOV): Removed.
+ (_dl_runtime_resolve_avx): Likewise.
+ (_dl_runtime_resolve_avx_slow): Likewise.
+ (_dl_runtime_resolve_avx_opt): Likewise.
+ (_dl_runtime_resolve_avx512): Likewise.
+ (_dl_runtime_resolve_avx512_opt): Likewise.
+ (_dl_runtime_resolve_sse): Likewise.
+ (_dl_runtime_resolve_sse_vex): Likewise.
+ (USE_FXSAVE): New.
+ (_dl_runtime_resolve_fxsave): Likewise.
+ (USE_XSAVE): Likewise.
+ (_dl_runtime_resolve_xsave): Likewise.
+ (USE_XSAVEC): Likewise.
+ (_dl_runtime_resolve_xsavec): Likewise.
+ * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_avx512):
+ Removed.
+ (_dl_runtime_resolve_avx512_opt): Likewise.
+ (_dl_runtime_resolve_avx): Likewise.
+ (_dl_runtime_resolve_avx_opt): Likewise.
+ (_dl_runtime_resolve_sse): Likewise.
+ (_dl_runtime_resolve_sse_vex): Likewise.
+ (_dl_runtime_resolve_fxsave): New.
+ (_dl_runtime_resolve_xsave): Likewise.
+ (_dl_runtime_resolve_xsavec): Likewise.
+
+2017-10-19 H.J. Lu <hongjiu.lu@intel.com>
+
+ * sysdeps/x86_64/Makefile (tests): Add tst-sse, tst-avx and
+ tst-avx512.
+ (test-extras): Add tst-avx-aux and tst-avx512-aux.
+ (extra-test-objs): Add tst-avx-aux.o and tst-avx512-aux.o.
+ (modules-names): Add tst-ssemod, tst-avxmod and tst-avx512mod.
+ ($(objpfx)tst-sse): New rule.
+ ($(objpfx)tst-avx): Likewise.
+ ($(objpfx)tst-avx512): Likewise.
+ (CFLAGS-tst-avx-aux.c): New.
+ (CFLAGS-tst-avxmod.c): Likewise.
+ (CFLAGS-tst-avx512-aux.c): Likewise.
+ (CFLAGS-tst-avx512mod.c): Likewise.
+ * sysdeps/x86_64/tst-avx-aux.c: New file.
+ * sysdeps/x86_64/tst-avx.c: Likewise.
+ * sysdeps/x86_64/tst-avx512-aux.c: Likewise.
+ * sysdeps/x86_64/tst-avx512.c: Likewise.
+ * sysdeps/x86_64/tst-avx512mod.c: Likewise.
+ * sysdeps/x86_64/tst-avxmod.c: Likewise.
+ * sysdeps/x86_64/tst-sse.c: Likewise.
+ * sysdeps/x86_64/tst-ssemod.c: Likewise.
+
+2017-10-19 H.J. Lu <hongjiu.lu@intel.com>
+
+ * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve): Don't
+ adjust CFA when allocating register save area on re-aligned
+ stack.
+
+2016-12-21 Joseph Myers <joseph@codesourcery.com>
+
+ [BZ #20978]
+ * nis/nss_nisplus/nisplus-alias.c (_nss_nisplus_getaliasbyname_r):
+ Compare name == NULL, not name != NULL.
+
+2016-11-08 Joseph Myers <joseph@codesourcery.com>
+
+ [BZ #20790]
+ * sunrpc/rpc_parse.c (get_prog_declaration): Increase buffer size
+ to MAXLINESIZE.
+ * sunrpc/bug20790.x: New file.
+ * sunrpc/Makefile [$(run-built-tests) = yes] (rpcgen-tests): New
+ variable.
+ [$(run-built-tests) = yes] (tests-special): Add $(rpcgen-tests).
+ [$(run-built-tests) = yes] ($(rpcgen-tests)): New rule.
+
+2016-10-14 Steve Ellcey <sellcey@caviumnetworks.com>
+
+ * sysdeps/ieee754/dbl-64/e_pow.c (checkint) Make conditions explicitly
+ boolean.
+
+2017-07-19 DJ Delorie <dj@delorie.com>
+
+ [BZ #21654]
+ * grp/grp-merge.c (libc_hidden_def): Fix cast-after-dereference.
+
+2017-07-14 DJ Delorie <dj@redhat.com>
+
+ [BZ #21654]
+ * grp/grp_merge.c (__copy_grp): Align char** to minimum pointer
+ alignment not char alignment.
+ (__merge_grp): Likewise.
+
+2017-08-06 H.J. Lu <hongjiu.lu@intel.com>
+
+ [BZ #21871]
+ * sysdeps/x86/cpu-features.c (init_cpu_features): Set
+ bit_arch_Use_dl_runtime_resolve_opt only with AVX512F.
+
+2017-02-27 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #21115]
+ * sunrpc/clnt_udp.c (clntudp_call): Free ancillary data later.
+ * sunrpc/Makefile (tests): Add tst-udp-error.
+ (tst-udp-error): Link against libc.so explicitly.
+ * sunrpc/tst-udp-error: New file.
+
+2017-01-24 James Clarke <jrtc27@jrtc27.com>
+
+ * sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym: Use new REG_R*
+ constants instead of the old R* ones.
+ * sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym: Likewise.
+ * sysdeps/unix/sysv/linux/sh/sys/ucontext.h (NGPREG): Rename...
+ (NGREG): ... to this, to fit in with other architectures.
+ (gpregset_t): Use new NGREG macro.
+ [__USE_GNU]: Remove condition; all architectures other than tile
+ are unconditional.
+ (R*): Rename to REG_R*.
+
+2017-07-26 H.J. Lu <hongjiu.lu@intel.com>
+
+ [BZ #21666]
+ * misc/regexp.c (loc1): Add __attribute__ ((nocommon));
+ (loc2): Likewise.
+ (locs): Likewise.
+
+2017-07-12 Szabolcs Nagy <szabolcs.nagy@arm.com>
+
+ * sysdeps/aarch64/dl-machine.h (RTLD_START_1): Change _dl_argv to the
+ hidden __GI__dl_argv symbol.
+
+2016-09-05 Aurelien Jarno <aurelien@aurel32.net>
+
+ * conform/Makefile (conformtest-header-tests): Pass -I. to $(PERL).
+ (linknamespace-symlists-tests): Likewise.
+ (linknamespace-header-tests): Likewise.
+
+2017-07-06 Florian Weimer <fweimer@redhat.com>
+ H.J. Lu <hongjiu.lu@intel.com>
+
+ [BZ #21609]
+ * sysdeps/x86_64/Makefile (sysdep-dl-routines): Add tls_get_addr.
+ (gen-as-const-headers): Add rtld-offsets.sym.
+ * sysdeps/x86_64/dl-tls.c: New file.
+ * sysdeps/x86_64/rtld-offsets.sym: Likwise.
+ * sysdeps/x86_64/tls_get_addr.S: Likewise.
+ * sysdeps/x86_64/dl-tls.h: Add multiple inclusion guards.
+ * sysdeps/x86_64/tlsdesc.sym (TI_MODULE_OFFSET): New.
+ (TI_OFFSET_OFFSET): Likwise.
+
2017-06-14 Florian Weimer <fweimer@redhat.com>
* sysdeps/i386/i686/multiarch/strcspn-c.c: Add IS_IN (libc) guard.
diff --git a/NEWS b/NEWS
index c4c082b415..9e20117a81 100644
--- a/NEWS
+++ b/NEWS
@@ -21,12 +21,41 @@ Security related changes:
question type which is outside the range of valid question type values.
(CVE-2015-5180)
+* CVE-2017-15670: The glob function, when invoked with GLOB_TILDE, suffered
+ from a one-byte overflow during ~ operator processing (either on the stack
+ or the heap, depending on the length of the user name).
+
+* CVE-2017-15671: The glob function, when invoked with GLOB_TILDE,
+ would sometimes fail to free memory allocated during ~ operator
+ processing, leading to a memory leak and, potentially, to a denial
+ of service.
+
+* CVE-2017-15804: The glob function, when invoked with GLOB_TILDE and
+ without GLOB_NOESCAPE, could write past the end of a buffer while
+ unescaping user names. Reported by Tim Rühsen.
+
+* CVE-2017-1000408: Incorrect array size computation in _dl_init_paths leads
+ to the allocation of too much memory. (This is not a security bug per se,
+ it is mentioned here only because of the CVE assignment.) Reported by
+ Qualys.
+
+* CVE-2017-1000409: Buffer overflow in _dl_init_paths due to miscomputation
+ of the number of search path components. (This is not a security
+ vulnerability per se because no trust boundary is crossed if the fix for
+ CVE-2017-1000366 has been applied, but it is mentioned here only because
+ of the CVE assignment.) Reported by Qualys.
+
The following bugs are resolved with this release:
+ [20790] Fix rpcgen buffer overrun
+ [20978] Fix strlen on null pointer in nss_nisplus
[21209] Ignore and remove LD_HWCAP_MASK for AT_SECURE programs
+ [21265] x86-64: Use fxsave/xsave/xsavec in _dl_runtime_resolve
[21289] Fix symbol redirect for fts_set
[21386] Assertion in fork for distinct parent PID is incorrect
+ [21609] x86-64: Align the stack in __tls_get_addr
[21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366)
+ [21654] nss: Fix invalid cast in group merging
Version 2.24
diff --git a/conform/Makefile b/conform/Makefile
index 762aac98fc..7883624c81 100644
--- a/conform/Makefile
+++ b/conform/Makefile
@@ -196,13 +196,13 @@ $(conformtest-header-tests): $(objpfx)%/conform.out: \
conformtest.pl $(conformtest-headers-data)
(set -e; std_hdr=$*; std=$${std_hdr%%/*}; hdr=$${std_hdr#*/}; \
mkdir -p $(@D)/scratch; \
- $(PERL) conformtest.pl --tmpdir=$(@D)/scratch --cc='$(CC)' \
+ $(PERL) -I. conformtest.pl --tmpdir=$(@D)/scratch --cc='$(CC)' \
--flags='$(conformtest-cc-flags)' --standard=$$std \
--headers=$$hdr > $@); \
$(evaluate-test)
$(linknamespace-symlists-tests): $(objpfx)symlist-%: list-header-symbols.pl
- $(PERL) -w $< --tmpdir=$(objpfx) --cc='$(CC)' \
+ $(PERL) -I. -w $< --tmpdir=$(objpfx) --cc='$(CC)' \
--flags='$(conformtest-cc-flags)' --standard=$* \
--headers="$(strip $(conformtest-headers-$*))" \
> $@ 2> $@.err; \
@@ -233,7 +233,7 @@ $(linknamespace-header-tests): $(objpfx)%/linknamespace.out: \
$(linknamespace-symlist-stdlibs-tests)
(set -e; std_hdr=$*; std=$${std_hdr%%/*}; hdr=$${std_hdr#*/}; \
mkdir -p $(@D)/scratch; \
- $(PERL) -w $< --tmpdir=$(@D)/scratch --cc='$(CC)' \
+ $(PERL) -I. -w $< --tmpdir=$(@D)/scratch --cc='$(CC)' \
--flags='$(conformtest-cc-flags)' --standard=$$std \
--stdsyms=$(objpfx)symlist-$$std --header=$$hdr \
--libsyms=$(objpfx)symlist-stdlibs-$$std \
diff --git a/elf/dl-load.c b/elf/dl-load.c
index c0d6249373..64f55145a2 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -37,6 +37,7 @@
#include <sysdep.h>
#include <stap-probe.h>
#include <libc-internal.h>
+#include <array_length.h>
#include <dl-dst.h>
#include <dl-load.h>
@@ -103,7 +104,9 @@ static size_t ncapstr attribute_relro;
static size_t max_capstrlen attribute_relro;
-/* Get the generated information about the trusted directories. */
+/* Get the generated information about the trusted directories. Use
+ an array of concatenated strings to avoid relocations. See
+ gen-trusted-dirs.awk. */
#include "trusted-dirs.h"
static const char system_dirs[] = SYSTEM_DIRS;
@@ -111,9 +114,7 @@ static const size_t system_dirs_len[] =
{
SYSTEM_DIRS_LEN
};
-#define nsystem_dirs_len \
- (sizeof (system_dirs_len) / sizeof (system_dirs_len[0]))
-
+#define nsystem_dirs_len array_length (system_dirs_len)
static bool
is_trusted_path (const char *path, size_t len)
@@ -688,9 +689,8 @@ _dl_init_paths (const char *llp)
+ ncapstr * sizeof (enum r_dir_status))
/ sizeof (struct r_search_path_elem));
- rtld_search_dirs.dirs[0] = (struct r_search_path_elem *)
- malloc ((sizeof (system_dirs) / sizeof (system_dirs[0]))
- * round_size * sizeof (struct r_search_path_elem));
+ rtld_search_dirs.dirs[0] = malloc (nsystem_dirs_len * round_size
+ * sizeof (*rtld_search_dirs.dirs[0]));
if (rtld_search_dirs.dirs[0] == NULL)
{
errstring = N_("cannot create cache for search path");
@@ -776,8 +776,6 @@ _dl_init_paths (const char *llp)
if (llp != NULL && *llp != '\0')
{
- size_t nllp;
- const char *cp = llp;
char *llp_tmp;
#ifdef SHARED
@@ -800,13 +798,10 @@ _dl_init_paths (const char *llp)
/* Decompose the LD_LIBRARY_PATH contents. First determine how many
elements it has. */
- nllp = 1;
- while (*cp)
- {
- if (*cp == ':' || *cp == ';')
- ++nllp;
- ++cp;
- }
+ size_t nllp = 1;
+ for (const char *cp = llp_tmp; *cp != '\0'; ++cp)
+ if (*cp == ':' || *cp == ';')
+ ++nllp;
env_path_list.dirs = (struct r_search_path_elem **)
malloc ((nllp + 1) * sizeof (struct r_search_path_elem *));
diff --git a/grp/grp-merge.c b/grp/grp-merge.c
index 0a1eb38d2c..5f79755798 100644
--- a/grp/grp-merge.c
+++ b/grp/grp-merge.c
@@ -85,6 +85,14 @@ __copy_grp (const struct group srcgrp, const size_t buflen,
}
members[i] = NULL;
+ /* Align for pointers. We can't simply align C because we need to
+ align destbuf[c]. */
+ if ((((uintptr_t)destbuf + c) & (__alignof__(char **) - 1)) != 0)
+ {
+ uintptr_t mis_align = ((uintptr_t)destbuf + c) & (__alignof__(char **) - 1);
+ c += __alignof__(char **) - mis_align;
+ }
+
/* Copy the pointers from the members array into the buffer and assign them
to the gr_mem member of destgrp. */
destgrp->gr_mem = (char **) &destbuf[c];
@@ -129,7 +137,7 @@ __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
/* Get the count of group members from the last sizeof (size_t) bytes in the
mergegrp buffer. */
- savedmemcount = (size_t) *(savedend - sizeof (size_t));
+ savedmemcount = *(size_t *) (savedend - sizeof (size_t));
/* Get the count of new members to add. */
for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++)
@@ -168,6 +176,14 @@ __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
/* Add the NULL-terminator. */
members[savedmemcount + memcount] = NULL;
+ /* Align for pointers. We can't simply align C because we need to
+ align savedbuf[c]. */
+ if ((((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1)) != 0)
+ {
+ uintptr_t mis_align = ((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1);
+ c += __alignof__(char **) - mis_align;
+ }
+
/* Copy the member array back into the buffer after the member list and free
the member array. */
savedgrp->gr_mem = (char **) &savedbuf[c];
diff --git a/include/array_length.h b/include/array_length.h
new file mode 100644
index 0000000000..cb4a8b2a56
--- /dev/null
+++ b/include/array_length.h
@@ -0,0 +1,36 @@
+/* The array_length and array_end macros.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _ARRAY_LENGTH_H
+#define _ARRAY_LENGTH_H
+
+/* array_length (VAR) is the number of elements in the array VAR. VAR
+ must evaluate to an array, not a pointer. */
+#define array_length(var) \
+ __extension__ ({ \
+ _Static_assert (!__builtin_types_compatible_p \
+ (__typeof (var), __typeof (&(var)[0])), \
+ "argument must be an array"); \
+ sizeof (var) / sizeof ((var)[0]); \
+ })
+
+/* array_end (VAR) is a pointer one past the end of the array VAR.
+ VAR must evaluate to an array, not a pointer. */
+#define array_end(var) (&(var)[array_length (var)])
+
+#endif /* _ARRAY_LENGTH_H */
diff --git a/misc/regexp.c b/misc/regexp.c
index 3b3668272f..b2a2c6e636 100644
--- a/misc/regexp.c
+++ b/misc/regexp.c
@@ -29,14 +29,15 @@
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_23)
-/* Define the variables used for the interface. */
-char *loc1;
-char *loc2;
+/* Define the variables used for the interface. Avoid .symver on common
+ symbol, which just creates a new common symbol, not an alias. */
+char *loc1 __attribute__ ((nocommon));
+char *loc2 __attribute__ ((nocommon));
compat_symbol (libc, loc1, loc1, GLIBC_2_0);
compat_symbol (libc, loc2, loc2, GLIBC_2_0);
/* Although we do not support the use we define this variable as well. */
-char *locs;
+char *locs __attribute__ ((nocommon));
compat_symbol (libc, locs, locs, GLIBC_2_0);
diff --git a/nis/nss_nisplus/nisplus-alias.c b/nis/nss_nisplus/nisplus-alias.c
index 7f698b4e6d..cb5acce01d 100644
--- a/nis/nss_nisplus/nisplus-alias.c
+++ b/nis/nss_nisplus/nisplus-alias.c
@@ -291,7 +291,7 @@ _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias,
return status;
}
- if (name != NULL)
+ if (name == NULL)
{
*errnop = EINVAL;
return NSS_STATUS_UNAVAIL;
diff --git a/posix/Makefile b/posix/Makefile
index 5b0e298f75..82a4020c76 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -43,7 +43,7 @@ routines := \
getpgid setpgid getpgrp bsd-getpgrp setpgrp getsid setsid \
getresuid getresgid setresuid setresgid \
pathconf sysconf fpathconf \
- glob glob64 fnmatch regex \
+ glob glob64 globfree globfree64 glob_pattern_p fnmatch regex \
confstr \
getopt getopt1 getopt_init \
sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax \
@@ -90,7 +90,7 @@ tests := tstgetopt testfnm runtests runptests \
bug-getopt5 tst-getopt_long1 bug-regex34 bug-regex35 \
tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \
tst-fnmatch3 bug-regex36 tst-getaddrinfo5 \
- tst-posix_spawn-fd
+ tst-posix_spawn-fd tst-glob-tilde
xtests := bug-ga2
ifeq (yes,$(build-shared))
test-srcs := globtest
@@ -133,7 +133,8 @@ tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \
$(objpfx)tst-rxspencer-no-utf8-mem.out $(objpfx)tst-pcre-mem.out \
$(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \
$(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \
- $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out
+ $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out \
+ $(objpfx)tst-glob-tilde-mem.out
xtests-special += $(objpfx)bug-ga2-mem.out
endif
@@ -340,6 +341,12 @@ $(objpfx)bug-glob2-mem.out: $(objpfx)bug-glob2.out
$(common-objpfx)malloc/mtrace $(objpfx)bug-glob2.mtrace > $@; \
$(evaluate-test)
+tst-glob-tilde-ENV = MALLOC_TRACE=$(objpfx)tst-glob-tilde.mtrace
+
+$(objpfx)tst-glob-tilde-mem.out: $(objpfx)tst-glob-tilde.out
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-glob-tilde.mtrace > $@; \
+ $(evaluate-test)
+
$(inst_libexecdir)/getconf: $(inst_bindir)/getconf \
$(objpfx)getconf.speclist FORCE
$(addprefix $(..)./scripts/mkinstalldirs ,\
diff --git a/posix/flexmember.h b/posix/flexmember.h
new file mode 100644
index 0000000000..107c1f09e9
--- /dev/null
+++ b/posix/flexmember.h
@@ -0,0 +1,45 @@
+/* Sizes of structs with flexible array members.
+
+ Copyright 2016-2017 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>.
+
+ Written by Paul Eggert. */
+
+#include <stddef.h>
+
+/* Nonzero multiple of alignment of TYPE, suitable for FLEXSIZEOF below.
+ On older platforms without _Alignof, use a pessimistic bound that is
+ safe in practice even if FLEXIBLE_ARRAY_MEMBER is 1.
+ On newer platforms, use _Alignof to get a tighter bound. */
+
+#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112
+# define FLEXALIGNOF(type) (sizeof (type) & ~ (sizeof (type) - 1))
+#else
+# define FLEXALIGNOF(type) _Alignof (type)
+#endif
+
+/* Upper bound on the size of a struct of type TYPE with a flexible
+ array member named MEMBER that is followed by N bytes of other data.
+ This is not simply sizeof (TYPE) + N, since it may require
+ alignment on unusually picky C11 platforms, and
+ FLEXIBLE_ARRAY_MEMBER may be 1 on pre-C11 platforms.
+ Yield a value less than N if and only if arithmetic overflow occurs. */
+
+#define FLEXSIZEOF(type, member, n) \
+ ((offsetof (type, member) + FLEXALIGNOF (type) - 1 + (n)) \
+ & ~ (FLEXALIGNOF (type) - 1))
diff --git a/posix/glob.c b/posix/glob.c
index ea4b0b61eb..f3fa807700 100644
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -15,7 +15,7 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#ifdef HAVE_CONFIG_H
+#ifndef _LIBC
# include <config.h>
#endif
@@ -27,29 +27,15 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
-
-/* Outcomment the following line for production quality code. */
-/* #define NDEBUG 1 */
#include <assert.h>
+#include <unistd.h>
-#include <stdio.h> /* Needed on stupid SunOS for assert. */
-
-#if !defined _LIBC || !defined GLOB_ONLY_P
-#if defined HAVE_UNISTD_H || defined _LIBC
-# include <unistd.h>
-# ifndef POSIX
-# ifdef _POSIX_VERSION
-# define POSIX
-# endif
-# endif
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# define WINDOWS32
#endif
-#include <pwd.h>
-
-#if defined HAVE_STDINT_H || defined _LIBC
-# include <stdint.h>
-#elif !defined UINTPTR_MAX
-# define UINTPTR_MAX (~((size_t) 0))
+#ifndef WINDOWS32
+# include <pwd.h>
#endif
#include <errno.h>
@@ -57,24 +43,7 @@
# define __set_errno(val) errno = (val)
#endif
-#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
-# include <dirent.h>
-#else
-# define dirent direct
-# ifdef HAVE_SYS_NDIR_H
-# include <sys/ndir.h>
-# endif
-# ifdef HAVE_SYS_DIR_H
-# include <sys/dir.h>
-# endif
-# ifdef HAVE_NDIR_H
-# include <ndir.h>
-# endif
-# ifdef HAVE_VMSDIR_H
-# include "vmsdir.h"
-# endif /* HAVE_VMSDIR_H */
-#endif
-
+#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <alloca.h>
@@ -87,27 +56,29 @@
# define opendir(name) __opendir (name)
# define readdir(str) __readdir64 (str)
# define getpwnam_r(name, bufp, buf, len, res) \
- __getpwnam_r (name, bufp, buf, len, res)
+ __getpwnam_r (name, bufp, buf, len, res)
# ifndef __stat64
# define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf)
# endif
# define struct_stat64 struct stat64
+# define FLEXIBLE_ARRAY_MEMBER
#else /* !_LIBC */
-# include "getlogin_r.h"
-# include "mempcpy.h"
-# include "stat-macros.h"
-# include "strdup.h"
-# define __stat64(fname, buf) stat (fname, buf)
-# define struct_stat64 struct stat
-# define __stat(fname, buf) stat (fname, buf)
-# define __alloca alloca
-# define __readdir readdir
-# define __readdir64 readdir64
-# define __glob_pattern_p glob_pattern_p
+# define __getlogin_r(buf, len) getlogin_r (buf, len)
+# define __stat64(fname, buf) stat (fname, buf)
+# define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag)
+# define struct_stat64 struct stat
+# ifndef __MVS__
+# define __alloca alloca
+# endif
+# define __readdir readdir
+# define COMPILE_GLOB64
#endif /* _LIBC */
#include <fnmatch.h>
+#include <flexmember.h>
+#include <glob_internal.h>
+
#ifdef _SC_GETPW_R_SIZE_MAX
# define GETPW_R_SIZE_MAX() sysconf (_SC_GETPW_R_SIZE_MAX)
#else
@@ -121,61 +92,59 @@
static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
+typedef uint_fast8_t dirent_type;
+
+#if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE
+/* Any distinct values will do here.
+ Undef any existing macros out of the way. */
+# undef DT_UNKNOWN
+# undef DT_DIR
+# undef DT_LNK
+# define DT_UNKNOWN 0
+# define DT_DIR 1
+# define DT_LNK 2
+#endif
+
/* A representation of a directory entry which does not depend on the
layout of struct dirent, or the size of ino_t. */
struct readdir_result
{
const char *name;
-# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
- uint8_t type;
-# endif
+#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+ dirent_type type;
+#endif
+#if defined _LIBC || defined D_INO_IN_DIRENT
bool skip_entry;
+#endif
};
-# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
-/* Initializer based on the d_type member of struct dirent. */
-# define D_TYPE_TO_RESULT(source) (source)->d_type,
-
-/* True if the directory entry D might be a symbolic link. */
-static bool
-readdir_result_might_be_symlink (struct readdir_result d)
-{
- return d.type == DT_UNKNOWN || d.type == DT_LNK;
-}
-
-/* True if the directory entry D might be a directory. */
-static bool
-readdir_result_might_be_dir (struct readdir_result d)
-{
- return d.type == DT_DIR || readdir_result_might_be_symlink (d);
-}
-# else /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
-# define D_TYPE_TO_RESULT(source)
-
-/* If we do not have type information, symbolic links and directories
- are always a possibility. */
-
-static bool
-readdir_result_might_be_symlink (struct readdir_result d)
+/* Initialize and return type member of struct readdir_result. */
+static dirent_type
+readdir_result_type (struct readdir_result d)
{
- return true;
+#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+# define D_TYPE_TO_RESULT(source) (source)->d_type,
+ return d.type;
+#else
+# define D_TYPE_TO_RESULT(source)
+ return DT_UNKNOWN;
+#endif
}
+/* Initialize and return skip_entry member of struct readdir_result. */
static bool
-readdir_result_might_be_dir (struct readdir_result d)
+readdir_result_skip_entry (struct readdir_result d)
{
- return true;
-}
-
-# endif /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
-
-# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
/* Initializer for skip_entry. POSIX does not require that the d_ino
field be present, and some systems do not provide it. */
-# define D_INO_TO_RESULT(source) false,
-# else
-# define D_INO_TO_RESULT(source) (source)->d_ino == 0,
-# endif
+#if defined _LIBC || defined D_INO_IN_DIRENT
+# define D_INO_TO_RESULT(source) (source)->d_ino == 0,
+ return d.skip_entry;
+#else
+# define D_INO_TO_RESULT(source)
+ return false;
+#endif
+}
/* Construct an initializer for a struct readdir_result object from a
struct dirent *. No copy of the name is made. */
@@ -186,8 +155,6 @@ readdir_result_might_be_dir (struct readdir_result d)
D_INO_TO_RESULT (source) \
}
-#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
-
/* Call gl_readdir on STREAM. This macro can be overridden to reduce
type safety if an old interface version needs to be supported. */
#ifndef GL_READDIR
@@ -225,18 +192,55 @@ convert_dirent64 (const struct dirent64 *source)
}
#endif
+#ifndef _LIBC
+/* The results of opendir() in this file are not used with dirfd and fchdir,
+ and we do not leak fds to any single-threaded code that could use stdio,
+ therefore save some unnecessary recursion in fchdir.c and opendir_safer.c.
+ FIXME - if the kernel ever adds support for multi-thread safety for
+ avoiding standard fds, then we should use opendir_safer. */
+# ifdef GNULIB_defined_opendir
+# undef opendir
+# endif
+# ifdef GNULIB_defined_closedir
+# undef closedir
+# endif
-#ifndef attribute_hidden
-# define attribute_hidden
+/* Just use malloc. */
+# define __libc_use_alloca(n) false
+# define alloca_account(len, avar) ((void) (len), (void) (avar), (void *) 0)
+# define extend_alloca_account(buf, len, newlen, avar) \
+ ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0)
#endif
+/* Set *R = A + B. Return true if the answer is mathematically
+ incorrect due to overflow; in this case, *R is the low order
+ bits of the correct answer. */
+
+static bool
+size_add_wrapv (size_t a, size_t b, size_t *r)
+{
+#if 5 <= __GNUC__ && !defined __ICC
+ return __builtin_add_overflow (a, b, r);
+#else
+ *r = a + b;
+ return *r < a;
+#endif
+}
+
+static bool
+glob_use_alloca (size_t alloca_used, size_t len)
+{
+ size_t size;
+ return (!size_add_wrapv (alloca_used, len, &size)
+ && __libc_use_alloca (size));
+}
+
static int glob_in_dir (const char *pattern, const char *directory,
int flags, int (*errfunc) (const char *, int),
glob_t *pglob, size_t alloca_used);
extern int __glob_pattern_type (const char *pattern, int quote)
attribute_hidden;
-#if !defined _LIBC || !defined GLOB_ONLY_P
static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL;
static int collated_compare (const void *, const void *) __THROWNL;
@@ -265,16 +269,15 @@ next_brace_sub (const char *cp, int flags)
return *cp != '\0' ? cp : NULL;
}
-#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
/* Do glob searching for PATTERN, placing results in PGLOB.
The bits defined above may be set in FLAGS.
If a directory cannot be opened or read and ERRFUNC is not nil,
it is called with the pathname that caused the error, and the
- `errno' value from the failing call; if it returns non-zero
- `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
+ 'errno' value from the failing call; if it returns non-zero
+ 'glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
- Otherwise, `glob' returns zero. */
+ Otherwise, 'glob' returns zero. */
int
#ifdef GLOB_ATTRIBUTE
GLOB_ATTRIBUTE
@@ -292,9 +295,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
int malloc_dirname = 0;
glob_t dirs;
int retval = 0;
-#ifdef _LIBC
size_t alloca_used = 0;
-#endif
if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
{
@@ -308,7 +309,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
flags |= GLOB_ONLYDIR;
if (!(flags & GLOB_DOOFFS))
- /* Have to do this so `globfree' knows where to start freeing. It
+ /* Have to do this so 'globfree' knows where to start freeing. It
also makes all the code that uses gl_offs simpler. */
pglob->gl_offs = 0;
@@ -350,14 +351,12 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
size_t rest_len;
char *onealt;
size_t pattern_len = strlen (pattern) - 1;
-#ifdef _LIBC
- int alloca_onealt = __libc_use_alloca (alloca_used + pattern_len);
+ int alloca_onealt = glob_use_alloca (alloca_used, pattern_len);
if (alloca_onealt)
onealt = alloca_account (pattern_len, alloca_used);
else
-#endif
{
- onealt = (char *) malloc (pattern_len);
+ onealt = malloc (pattern_len);
if (onealt == NULL)
{
if (!(flags & GLOB_APPEND))
@@ -377,11 +376,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
next = next_brace_sub (begin + 1, flags);
if (next == NULL)
{
- /* It is an illegal expression. */
+ /* It is an invalid expression. */
illegal_brace:
-#ifdef _LIBC
if (__glibc_unlikely (!alloca_onealt))
-#endif
free (onealt);
return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
}
@@ -429,9 +426,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
/* If we got an error, return it. */
if (result && result != GLOB_NOMATCH)
{
-#ifdef _LIBC
if (__glibc_unlikely (!alloca_onealt))
-#endif
free (onealt);
if (!(flags & GLOB_APPEND))
{
@@ -450,9 +445,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
assert (next != NULL);
}
-#ifdef _LIBC
if (__glibc_unlikely (!alloca_onealt))
-#endif
free (onealt);
if (pglob->gl_pathc != firstc)
@@ -489,14 +482,16 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
/* Find the filename. */
filename = strrchr (pattern, '/');
+
#if defined __MSDOS__ || defined WINDOWS32
- /* The case of "d:pattern". Since `:' is not allowed in
+ /* The case of "d:pattern". Since ':' is not allowed in
file names, we can safely assume that wherever it
happens in pattern, it signals the filename part. This
is so we could some day support patterns like "[a-z]:foo". */
if (filename == NULL)
filename = strchr (pattern, ':');
#endif /* __MSDOS__ || WINDOWS32 */
+
dirname_modified = 0;
if (filename == NULL)
{
@@ -521,11 +516,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
}
filename = pattern;
-#ifdef _AMIGA
- dirname = (char *) "";
-#else
dirname = (char *) ".";
-#endif
dirlen = 0;
}
}
@@ -549,22 +540,21 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
char *drive_spec;
++dirlen;
- drive_spec = (char *) __alloca (dirlen + 1);
+ drive_spec = __alloca (dirlen + 1);
*((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
/* For now, disallow wildcards in the drive spec, to
prevent infinite recursion in glob. */
if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
return GLOB_NOMATCH;
- /* If this is "d:pattern", we need to copy `:' to DIRNAME
+ /* If this is "d:pattern", we need to copy ':' to DIRNAME
as well. If it's "d:/pattern", don't remove the slash
from "d:/", since "d:" and "d:/" are not the same.*/
}
#endif
-#ifdef _LIBC
- if (__libc_use_alloca (alloca_used + dirlen + 1))
+
+ if (glob_use_alloca (alloca_used, dirlen + 1))
newp = alloca_account (dirlen + 1, alloca_used);
else
-#endif
{
newp = malloc (dirlen + 1);
if (newp == NULL)
@@ -575,14 +565,17 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
dirname = newp;
++filename;
- if (filename[0] == '\0'
#if defined __MSDOS__ || defined WINDOWS32
- && dirname[dirlen - 1] != ':'
- && (dirlen < 3 || dirname[dirlen - 2] != ':'
- || dirname[dirlen - 1] != '/')
+ bool drive_root = (dirlen > 1
+ && (dirname[dirlen - 1] == ':'
+ || (dirlen > 2 && dirname[dirlen - 2] == ':'
+ && dirname[dirlen - 1] == '/')));
+#else
+ bool drive_root = false;
#endif
- && dirlen > 1)
- /* "pattern/". Expand "pattern", appending slashes. */
+
+ if (filename[0] == '\0' && dirlen > 1 && !drive_root)
+ /* "pattern/". Expand "pattern", appending slashes. */
{
int orig_flags = flags;
if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\')
@@ -615,7 +608,6 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
}
}
-#ifndef VMS
if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
{
if (dirname[1] == '\0' || dirname[1] == '/'
@@ -625,100 +617,127 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
/* Look up home directory. */
char *home_dir = getenv ("HOME");
int malloc_home_dir = 0;
-# ifdef _AMIGA
- if (home_dir == NULL || home_dir[0] == '\0')
- home_dir = "SYS:";
-# else
-# ifdef WINDOWS32
- if (home_dir == NULL || home_dir[0] == '\0')
- home_dir = "c:/users/default"; /* poor default */
-# else
if (home_dir == NULL || home_dir[0] == '\0')
{
+#ifdef WINDOWS32
+ /* Windows NT defines HOMEDRIVE and HOMEPATH. But give
+ preference to HOME, because the user can change HOME. */
+ const char *home_drive = getenv ("HOMEDRIVE");
+ const char *home_path = getenv ("HOMEPATH");
+
+ if (home_drive != NULL && home_path != NULL)
+ {
+ size_t home_drive_len = strlen (home_drive);
+ size_t home_path_len = strlen (home_path);
+ char *mem = alloca (home_drive_len + home_path_len + 1);
+
+ memcpy (mem, home_drive, home_drive_len);
+ memcpy (mem + home_drive_len, home_path, home_path_len + 1);
+ home_dir = mem;
+ }
+ else
+ home_dir = "c:/users/default"; /* poor default */
+#else
int success;
char *name;
+ int malloc_name = 0;
size_t buflen = GET_LOGIN_NAME_MAX () + 1;
if (buflen == 0)
- /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try
+ /* 'sysconf' does not support _SC_LOGIN_NAME_MAX. Try
a moderate value. */
buflen = 20;
- name = alloca_account (buflen, alloca_used);
+ if (glob_use_alloca (alloca_used, buflen))
+ name = alloca_account (buflen, alloca_used);
+ else
+ {
+ name = malloc (buflen);
+ if (name == NULL)
+ {
+ retval = GLOB_NOSPACE;
+ goto out;
+ }
+ malloc_name = 1;
+ }
success = __getlogin_r (name, buflen) == 0;
if (success)
{
struct passwd *p;
-# if defined HAVE_GETPWNAM_R || defined _LIBC
- long int pwbuflen = GETPW_R_SIZE_MAX ();
+ char *malloc_pwtmpbuf = NULL;
char *pwtmpbuf;
+# if defined HAVE_GETPWNAM_R || defined _LIBC
+ long int pwbuflenmax = GETPW_R_SIZE_MAX ();
+ size_t pwbuflen = pwbuflenmax;
struct passwd pwbuf;
- int malloc_pwtmpbuf = 0;
int save = errno;
-# ifndef _LIBC
- if (pwbuflen == -1)
- /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
+# ifndef _LIBC
+ if (! (0 < pwbuflenmax && pwbuflenmax <= SIZE_MAX))
+ /* 'sysconf' does not support _SC_GETPW_R_SIZE_MAX.
Try a moderate value. */
pwbuflen = 1024;
-# endif
- if (__libc_use_alloca (alloca_used + pwbuflen))
+# endif
+ if (glob_use_alloca (alloca_used, pwbuflen))
pwtmpbuf = alloca_account (pwbuflen, alloca_used);
else
{
pwtmpbuf = malloc (pwbuflen);
if (pwtmpbuf == NULL)
{
+ if (__glibc_unlikely (malloc_name))
+ free (name);
retval = GLOB_NOSPACE;
goto out;
}
- malloc_pwtmpbuf = 1;
+ malloc_pwtmpbuf = pwtmpbuf;
}
while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
!= 0)
{
+ size_t newlen;
+ bool v;
if (errno != ERANGE)
{
p = NULL;
break;
}
-
- if (!malloc_pwtmpbuf
- && __libc_use_alloca (alloca_used
- + 2 * pwbuflen))
+ v = size_add_wrapv (pwbuflen, pwbuflen, &newlen);
+ if (!v && malloc_pwtmpbuf == NULL
+ && glob_use_alloca (alloca_used, newlen))
pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen,
- 2 * pwbuflen,
- alloca_used);
+ newlen, alloca_used);
else
{
- char *newp = realloc (malloc_pwtmpbuf
- ? pwtmpbuf : NULL,
- 2 * pwbuflen);
+ char *newp = (v ? NULL
+ : realloc (malloc_pwtmpbuf, newlen));
if (newp == NULL)
{
- if (__glibc_unlikely (malloc_pwtmpbuf))
- free (pwtmpbuf);
+ free (malloc_pwtmpbuf);
+ if (__glibc_unlikely (malloc_name))
+ free (name);
retval = GLOB_NOSPACE;
goto out;
}
- pwtmpbuf = newp;
- pwbuflen = 2 * pwbuflen;
- malloc_pwtmpbuf = 1;
+ malloc_pwtmpbuf = pwtmpbuf = newp;
}
+ pwbuflen = newlen;
__set_errno (save);
}
-# else
+# else
p = getpwnam (name);
-# endif
+# endif
+ if (__glibc_unlikely (malloc_name))
+ free (name);
if (p != NULL)
{
- if (!malloc_pwtmpbuf)
+ if (malloc_pwtmpbuf == NULL)
home_dir = p->pw_dir;
else
{
size_t home_dir_len = strlen (p->pw_dir) + 1;
- if (__libc_use_alloca (alloca_used + home_dir_len))
+ if (glob_use_alloca (alloca_used, home_dir_len))
home_dir = alloca_account (home_dir_len,
alloca_used);
else
@@ -733,26 +752,32 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
malloc_home_dir = 1;
}
memcpy (home_dir, p->pw_dir, home_dir_len);
-
- free (pwtmpbuf);
}
}
+ free (malloc_pwtmpbuf);
}
+ else
+ {
+ if (__glibc_unlikely (malloc_name))
+ free (name);
+ }
+#endif /* WINDOWS32 */
}
if (home_dir == NULL || home_dir[0] == '\0')
{
+ if (__glibc_unlikely (malloc_home_dir))
+ free (home_dir);
if (flags & GLOB_TILDE_CHECK)
{
- if (__glibc_unlikely (malloc_home_dir))
- free (home_dir);
retval = GLOB_NOMATCH;
goto out;
}
else
- home_dir = (char *) "~"; /* No luck. */
+ {
+ home_dir = (char *) "~"; /* No luck. */
+ malloc_home_dir = 0;
+ }
}
-# endif /* WINDOWS32 */
-# endif
/* Now construct the full directory. */
if (dirname[1] == '\0')
{
@@ -767,8 +792,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
{
char *newp;
size_t home_len = strlen (home_dir);
- int use_alloca = __libc_use_alloca (alloca_used
- + home_len + dirlen);
+ int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen);
if (use_alloca)
newp = alloca_account (home_len + dirlen, alloca_used);
else
@@ -792,12 +816,15 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
dirname = newp;
dirlen += home_len - 1;
malloc_dirname = !use_alloca;
+
+ if (__glibc_unlikely (malloc_home_dir))
+ free (home_dir);
}
dirname_modified = 1;
}
-# if !defined _AMIGA && !defined WINDOWS32
else
{
+#ifndef WINDOWS32
char *end_name = strchr (dirname, '/');
char *user_name;
int malloc_user_name = 0;
@@ -819,7 +846,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
else
{
char *newp;
- if (__libc_use_alloca (alloca_used + (end_name - dirname)))
+ if (glob_use_alloca (alloca_used, end_name - dirname))
newp = alloca_account (end_name - dirname, alloca_used);
else
{
@@ -836,11 +863,11 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
char *p = mempcpy (newp, dirname + 1,
unescape - dirname - 1);
char *q = unescape;
- while (*q != '\0')
+ while (q != end_name)
{
if (*q == '\\')
{
- if (q[1] == '\0')
+ if (q + 1 == end_name)
{
/* "~fo\\o\\" unescape to user_name "foo\\",
but "~fo\\o\\/" unescape to user_name
@@ -856,7 +883,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
*p = '\0';
}
else
- *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
+ *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1))
= '\0';
user_name = newp;
}
@@ -864,20 +891,21 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
/* Look up specific user's home directory. */
{
struct passwd *p;
+ char *malloc_pwtmpbuf = NULL;
# if defined HAVE_GETPWNAM_R || defined _LIBC
- long int buflen = GETPW_R_SIZE_MAX ();
+ long int buflenmax = GETPW_R_SIZE_MAX ();
+ size_t buflen = buflenmax;
char *pwtmpbuf;
- int malloc_pwtmpbuf = 0;
struct passwd pwbuf;
int save = errno;
# ifndef _LIBC
- if (buflen == -1)
- /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a
+ if (! (0 <= buflenmax && buflenmax <= SIZE_MAX))
+ /* Perhaps 'sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a
moderate value. */
buflen = 1024;
# endif
- if (__libc_use_alloca (alloca_used + buflen))
+ if (glob_use_alloca (alloca_used, buflen))
pwtmpbuf = alloca_account (buflen, alloca_used);
else
{
@@ -890,32 +918,32 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
retval = GLOB_NOSPACE;
goto out;
}
- malloc_pwtmpbuf = 1;
+ malloc_pwtmpbuf = pwtmpbuf;
}
while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
{
+ size_t newlen;
+ bool v;
if (errno != ERANGE)
{
p = NULL;
break;
}
- if (!malloc_pwtmpbuf
- && __libc_use_alloca (alloca_used + 2 * buflen))
+ v = size_add_wrapv (buflen, buflen, &newlen);
+ if (!v && malloc_pwtmpbuf == NULL
+ && glob_use_alloca (alloca_used, newlen))
pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen,
- 2 * buflen, alloca_used);
+ newlen, alloca_used);
else
{
- char *newp = realloc (malloc_pwtmpbuf ? pwtmpbuf : NULL,
- 2 * buflen);
+ char *newp = v ? NULL : realloc (malloc_pwtmpbuf, newlen);
if (newp == NULL)
{
- if (__glibc_unlikely (malloc_pwtmpbuf))
- free (pwtmpbuf);
+ free (malloc_pwtmpbuf);
goto nomem_getpw;
}
- pwtmpbuf = newp;
- malloc_pwtmpbuf = 1;
+ malloc_pwtmpbuf = pwtmpbuf = newp;
}
__set_errno (save);
}
@@ -936,7 +964,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
free (dirname);
malloc_dirname = 0;
- if (__libc_use_alloca (alloca_used + home_len + rest_len + 1))
+ if (glob_use_alloca (alloca_used, home_len + rest_len + 1))
dirname = alloca_account (home_len + rest_len + 1,
alloca_used);
else
@@ -944,8 +972,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
dirname = malloc (home_len + rest_len + 1);
if (dirname == NULL)
{
- if (__glibc_unlikely (malloc_pwtmpbuf))
- free (pwtmpbuf);
+ free (malloc_pwtmpbuf);
retval = GLOB_NOSPACE;
goto out;
}
@@ -957,24 +984,24 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
dirlen = home_len + rest_len;
dirname_modified = 1;
- if (__glibc_unlikely (malloc_pwtmpbuf))
- free (pwtmpbuf);
+ free (malloc_pwtmpbuf);
}
else
{
- if (__glibc_unlikely (malloc_pwtmpbuf))
- free (pwtmpbuf);
+ free (malloc_pwtmpbuf);
if (flags & GLOB_TILDE_CHECK)
- /* We have to regard it as an error if we cannot find the
- home directory. */
- return GLOB_NOMATCH;
+ {
+ /* We have to regard it as an error if we cannot find the
+ home directory. */
+ retval = GLOB_NOMATCH;
+ goto out;
+ }
}
}
+#endif /* !WINDOWS32 */
}
-# endif /* Not Amiga && not WINDOWS32. */
}
-#endif /* Not VMS. */
/* Now test whether we looked for "~" or "~NAME". In this case we
can give the answer now. */
@@ -993,19 +1020,18 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
size_t newcount = pglob->gl_pathc + pglob->gl_offs;
char **new_gl_pathv;
- if (newcount > UINTPTR_MAX - (1 + 1)
- || newcount + 1 + 1 > ~((size_t) 0) / sizeof (char *))
+ if (newcount > SIZE_MAX / sizeof (char *) - 2)
{
nospace:
free (pglob->gl_pathv);
pglob->gl_pathv = NULL;
pglob->gl_pathc = 0;
- return GLOB_NOSPACE;
+ retval = GLOB_NOSPACE;
+ goto out;
}
- new_gl_pathv
- = (char **) realloc (pglob->gl_pathv,
- (newcount + 1 + 1) * sizeof (char *));
+ new_gl_pathv = realloc (pglob->gl_pathv,
+ (newcount + 2) * sizeof (char *));
if (new_gl_pathv == NULL)
goto nospace;
pglob->gl_pathv = new_gl_pathv;
@@ -1019,12 +1045,19 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen);
p[0] = '/';
p[1] = '\0';
+ if (__glibc_unlikely (malloc_dirname))
+ free (dirname);
}
else
{
- pglob->gl_pathv[newcount] = strdup (dirname);
- if (pglob->gl_pathv[newcount] == NULL)
- goto nospace;
+ if (__glibc_unlikely (malloc_dirname))
+ pglob->gl_pathv[newcount] = dirname;
+ else
+ {
+ pglob->gl_pathv[newcount] = strdup (dirname);
+ if (pglob->gl_pathv[newcount] == NULL)
+ goto nospace;
+ }
}
pglob->gl_pathv[++newcount] = NULL;
++pglob->gl_pathc;
@@ -1034,7 +1067,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
}
/* Not found. */
- return GLOB_NOMATCH;
+ retval = GLOB_NOMATCH;
+ goto out;
}
meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE));
@@ -1080,7 +1114,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
if (status != 0)
{
if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
- return status;
+ {
+ retval = status;
+ goto out;
+ }
goto no_matches;
}
@@ -1091,19 +1128,6 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
{
size_t old_pathc;
-#ifdef SHELL
- {
- /* Make globbing interruptible in the bash shell. */
- extern int interrupt_state;
-
- if (interrupt_state)
- {
- globfree (&dirs);
- return GLOB_ABORTED;
- }
- }
-#endif /* SHELL. */
-
old_pathc = pglob->gl_pathc;
status = glob_in_dir (filename, dirs.gl_pathv[i],
((flags | GLOB_APPEND)
@@ -1118,7 +1142,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
globfree (&dirs);
globfree (pglob);
pglob->gl_pathc = 0;
- return status;
+ retval = status;
+ goto out;
}
/* Stick the directory on the front of each name. */
@@ -1129,13 +1154,14 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
globfree (&dirs);
globfree (pglob);
pglob->gl_pathc = 0;
- return GLOB_NOSPACE;
+ retval = GLOB_NOSPACE;
+ goto out;
}
}
flags |= GLOB_MAGCHAR;
- /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
+ /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls.
But if we have not found any matching entry and the GLOB_NOCHECK
flag was set we must return the input pattern itself. */
if (pglob->gl_pathc + pglob->gl_offs == oldcount)
@@ -1147,28 +1173,28 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
size_t newcount = pglob->gl_pathc + pglob->gl_offs;
char **new_gl_pathv;
- if (newcount > UINTPTR_MAX - 2
- || newcount + 2 > ~((size_t) 0) / sizeof (char *))
+ if (newcount > SIZE_MAX / sizeof (char *) - 2)
{
nospace2:
globfree (&dirs);
- return GLOB_NOSPACE;
+ retval = GLOB_NOSPACE;
+ goto out;
}
- new_gl_pathv = (char **) realloc (pglob->gl_pathv,
- (newcount + 2)
- * sizeof (char *));
+ new_gl_pathv = realloc (pglob->gl_pathv,
+ (newcount + 2) * sizeof (char *));
if (new_gl_pathv == NULL)
goto nospace2;
pglob->gl_pathv = new_gl_pathv;
- pglob->gl_pathv[newcount] = __strdup (pattern);
+ pglob->gl_pathv[newcount] = strdup (pattern);
if (pglob->gl_pathv[newcount] == NULL)
{
globfree (&dirs);
globfree (pglob);
pglob->gl_pathc = 0;
- return GLOB_NOSPACE;
+ retval = GLOB_NOSPACE;
+ goto out;
}
++pglob->gl_pathc;
@@ -1180,7 +1206,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
else
{
globfree (&dirs);
- return GLOB_NOMATCH;
+ retval = GLOB_NOMATCH;
+ goto out;
}
}
@@ -1226,7 +1253,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
flags = orig_flags;
goto no_matches;
}
- return status;
+ retval = status;
+ goto out;
}
if (dirlen > 0)
@@ -1238,7 +1266,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
{
globfree (pglob);
pglob->gl_pathc = 0;
- return GLOB_NOSPACE;
+ retval = GLOB_NOSPACE;
+ goto out;
}
}
}
@@ -1263,7 +1292,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
{
globfree (pglob);
pglob->gl_pathc = 0;
- return GLOB_NOSPACE;
+ retval = GLOB_NOSPACE;
+ goto out;
}
strcpy (&new[len - 2], "/");
pglob->gl_pathv[i] = new;
@@ -1289,32 +1319,12 @@ libc_hidden_def (glob)
#endif
-#if !defined _LIBC || !defined GLOB_ONLY_P
-
-/* Free storage allocated in PGLOB by a previous `glob' call. */
-void
-globfree (glob_t *pglob)
-{
- if (pglob->gl_pathv != NULL)
- {
- size_t i;
- for (i = 0; i < pglob->gl_pathc; ++i)
- free (pglob->gl_pathv[pglob->gl_offs + i]);
- free (pglob->gl_pathv);
- pglob->gl_pathv = NULL;
- }
-}
-#if defined _LIBC && !defined globfree
-libc_hidden_def (globfree)
-#endif
-
-
/* Do a collated comparison of A and B. */
static int
collated_compare (const void *a, const void *b)
{
- const char *const s1 = *(const char *const * const) a;
- const char *const s2 = *(const char *const * const) b;
+ char *const *ps1 = a; char *s1 = *ps1;
+ char *const *ps2 = b; char *s2 = *ps2;
if (s1 == s2)
return 0;
@@ -1335,28 +1345,24 @@ prefix_array (const char *dirname, char **array, size_t n)
{
size_t i;
size_t dirlen = strlen (dirname);
-#if defined __MSDOS__ || defined WINDOWS32
- int sep_char = '/';
-# define DIRSEP_CHAR sep_char
-#else
-# define DIRSEP_CHAR '/'
-#endif
+ char dirsep_char = '/';
if (dirlen == 1 && dirname[0] == '/')
/* DIRNAME is just "/", so normal prepending would get us "//foo".
We want "/foo" instead, so don't prepend any chars from DIRNAME. */
dirlen = 0;
+
#if defined __MSDOS__ || defined WINDOWS32
- else if (dirlen > 1)
+ if (dirlen > 1)
{
if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
/* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */
--dirlen;
else if (dirname[dirlen - 1] == ':')
{
- /* DIRNAME is "d:". Use `:' instead of `/'. */
+ /* DIRNAME is "d:". Use ':' instead of '/'. */
--dirlen;
- sep_char = ':';
+ dirsep_char = ':';
}
}
#endif
@@ -1364,7 +1370,7 @@ prefix_array (const char *dirname, char **array, size_t n)
for (i = 0; i < n; ++i)
{
size_t eltlen = strlen (array[i]) + 1;
- char *new = (char *) malloc (dirlen + 1 + eltlen);
+ char *new = malloc (dirlen + 1 + eltlen);
if (new == NULL)
{
while (i > 0)
@@ -1374,7 +1380,7 @@ prefix_array (const char *dirname, char **array, size_t n)
{
char *endp = mempcpy (new, dirname, dirlen);
- *endp++ = DIRSEP_CHAR;
+ *endp++ = dirsep_char;
mempcpy (endp, array[i], eltlen);
}
free (array[i]);
@@ -1384,103 +1390,57 @@ prefix_array (const char *dirname, char **array, size_t n)
return 0;
}
-
-/* We must not compile this function twice. */
-#if !defined _LIBC || !defined NO_GLOB_PATTERN_P
-int
-__glob_pattern_type (const char *pattern, int quote)
-{
- const char *p;
- int ret = 0;
-
- for (p = pattern; *p != '\0'; ++p)
- switch (*p)
- {
- case '?':
- case '*':
- return 1;
-
- case '\\':
- if (quote)
- {
- if (p[1] != '\0')
- ++p;
- ret |= 2;
- }
- break;
-
- case '[':
- ret |= 4;
- break;
-
- case ']':
- if (ret & 4)
- return 1;
- break;
- }
-
- return ret;
-}
-
-/* Return nonzero if PATTERN contains any metacharacters.
- Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
-int
-__glob_pattern_p (const char *pattern, int quote)
-{
- return __glob_pattern_type (pattern, quote) == 1;
-}
-# ifdef _LIBC
-weak_alias (__glob_pattern_p, glob_pattern_p)
-# endif
-#endif
-
-#endif /* !GLOB_ONLY_P */
-
-
/* We put this in a separate function mainly to allow the memory
allocated with alloca to be recycled. */
-#if !defined _LIBC || !defined GLOB_ONLY_P
static int
__attribute_noinline__
-link_exists2_p (const char *dir, size_t dirlen, const char *fname,
- glob_t *pglob
-# ifndef _LIBC
- , int flags
+link_stat (const char *dir, size_t dirlen, const char *fname,
+ glob_t *pglob
+# if !defined _LIBC && !HAVE_FSTATAT
+ , int flags
# endif
- )
+ )
{
size_t fnamelen = strlen (fname);
- char *fullname = (char *) __alloca (dirlen + 1 + fnamelen + 1);
+ char *fullname = __alloca (dirlen + 1 + fnamelen + 1);
struct stat st;
-# ifndef _LIBC
- struct_stat64 st64;
-# endif
mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1),
fname, fnamelen + 1);
-# ifdef _LIBC
- return (*pglob->gl_stat) (fullname, &st) == 0;
-# else
- return ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
- ? (*pglob->gl_stat) (fullname, &st)
- : __stat64 (fullname, &st64)) == 0);
+# if !defined _LIBC && !HAVE_FSTATAT
+ if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) == 0, 1))
+ {
+ struct_stat64 st64;
+ return __stat64 (fullname, &st64);
+ }
# endif
+ return (*pglob->gl_stat) (fullname, &st);
}
-# ifdef _LIBC
-# define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \
- (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) \
- ? link_exists2_p (dirname, dirnamelen, fname, pglob) \
- : ({ struct stat64 st64; \
- __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0) == 0; }))
+
+/* Return true if DIR/FNAME exists. */
+static int
+link_exists_p (int dfd, const char *dir, size_t dirlen, const char *fname,
+ glob_t *pglob, int flags)
+{
+ int status;
+# if defined _LIBC || HAVE_FSTATAT
+ if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+ status = link_stat (dir, dirlen, fname, pglob);
+ else
+ {
+ /* dfd cannot be -1 here, because dirfd never returns -1 on
+ glibc, or on hosts that have fstatat. */
+ struct_stat64 st64;
+ status = __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0);
+ }
# else
-# define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \
- link_exists2_p (dirname, dirnamelen, fname, pglob, flags)
+ status = link_stat (dir, dirlen, fname, pglob, flags);
# endif
-#endif
-
+ return status == 0 || errno == EOVERFLOW;
+}
-/* Like `glob', but PATTERN is a final pathname component,
+/* Like 'glob', but PATTERN is a final pathname component,
and matches are searched for in DIRECTORY.
The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done.
The GLOB_APPEND flag is assumed to be set (always appends). */
@@ -1491,25 +1451,25 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
{
size_t dirlen = strlen (directory);
void *stream = NULL;
- struct globnames
- {
- struct globnames *next;
- size_t count;
- char *name[64];
- };
-#define INITIAL_COUNT sizeof (init_names.name) / sizeof (init_names.name[0])
- struct globnames init_names;
- struct globnames *names = &init_names;
- struct globnames *names_alloca = &init_names;
+# define GLOBNAMES_MEMBERS(nnames) \
+ struct globnames *next; size_t count; char *name[nnames];
+ struct globnames { GLOBNAMES_MEMBERS (FLEXIBLE_ARRAY_MEMBER) };
+ struct { GLOBNAMES_MEMBERS (64) } init_names_buf;
+ struct globnames *init_names = (struct globnames *) &init_names_buf;
+ struct globnames *names = init_names;
+ struct globnames *names_alloca = init_names;
size_t nfound = 0;
size_t cur = 0;
int meta;
int save;
+ int result;
- alloca_used += sizeof (init_names);
+ alloca_used += sizeof init_names_buf;
- init_names.next = NULL;
- init_names.count = INITIAL_COUNT;
+ init_names->next = NULL;
+ init_names->count = ((sizeof init_names_buf
+ - offsetof (struct globnames, name))
+ / sizeof init_names->name[0]);
meta = __glob_pattern_type (pattern, !(flags & GLOB_NOESCAPE));
if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
@@ -1529,14 +1489,16 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
struct_stat64 st64;
} ust;
size_t patlen = strlen (pattern);
- int alloca_fullname = __libc_use_alloca (alloca_used
- + dirlen + 1 + patlen + 1);
+ size_t fullsize;
+ bool alloca_fullname
+ = (! size_add_wrapv (dirlen + 1, patlen + 1, &fullsize)
+ && glob_use_alloca (alloca_used, fullsize));
char *fullname;
if (alloca_fullname)
- fullname = alloca_account (dirlen + 1 + patlen + 1, alloca_used);
+ fullname = alloca_account (fullsize, alloca_used);
else
{
- fullname = malloc (dirlen + 1 + patlen + 1);
+ fullname = malloc (fullsize);
if (fullname == NULL)
return GLOB_NOSPACE;
}
@@ -1544,9 +1506,11 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
"/", 1),
pattern, patlen + 1);
- if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+ if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
? (*pglob->gl_stat) (fullname, &ust.st)
- : __stat64 (fullname, &ust.st64)) == 0)
+ : __stat64 (fullname, &ust.st64))
+ == 0)
+ || errno == EOVERFLOW)
/* We found this file to be existing. Now tell the rest
of the function to copy this name into the result. */
flags |= GLOB_NOCHECK;
@@ -1568,16 +1532,10 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
}
else
{
-#ifdef _LIBC
int dfd = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
? -1 : dirfd ((DIR *) stream));
-#endif
int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
- | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
-#if defined _AMIGA || defined VMS
- | FNM_CASEFOLD
-#endif
- );
+ | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0));
flags |= GLOB_MAGCHAR;
while (1)
@@ -1597,19 +1555,24 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
}
if (d.name == NULL)
break;
- if (d.skip_entry)
+ if (readdir_result_skip_entry (d))
continue;
/* If we shall match only directories use the information
provided by the dirent call if possible. */
- if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d))
- continue;
+ if (flags & GLOB_ONLYDIR)
+ switch (readdir_result_type (d))
+ {
+ case DT_DIR: case DT_LNK: case DT_UNKNOWN: break;
+ default: continue;
+ }
if (fnmatch (pattern, d.name, fnm_flags) == 0)
{
/* If the file we found is a symlink we have to
make sure the target file exists. */
- if (!readdir_result_might_be_symlink (d)
+ dirent_type type = readdir_result_type (d);
+ if (! (type == DT_LNK || type == DT_UNKNOWN)
|| link_exists_p (dfd, directory, dirlen, d.name,
pglob, flags))
{
@@ -1617,10 +1580,13 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
{
struct globnames *newnames;
size_t count = names->count * 2;
- size_t size = (sizeof (struct globnames)
- + ((count - INITIAL_COUNT)
- * sizeof (char *)));
- if (__libc_use_alloca (alloca_used + size))
+ size_t nameoff = offsetof (struct globnames, name);
+ size_t size = FLEXSIZEOF (struct globnames, name,
+ count * sizeof (char *));
+ if ((SIZE_MAX - nameoff) / 2 / sizeof (char *)
+ < names->count)
+ goto memory_error;
+ if (glob_use_alloca (alloca_used, size))
newnames = names_alloca
= alloca_account (size, alloca_used);
else if ((newnames = malloc (size))
@@ -1636,6 +1602,8 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
goto memory_error;
++cur;
++nfound;
+ if (SIZE_MAX - pglob->gl_offs <= nfound)
+ goto memory_error;
}
}
}
@@ -1646,29 +1614,27 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
{
size_t len = strlen (pattern);
nfound = 1;
- names->name[cur] = (char *) malloc (len + 1);
+ names->name[cur] = malloc (len + 1);
if (names->name[cur] == NULL)
goto memory_error;
*((char *) mempcpy (names->name[cur++], pattern, len)) = '\0';
}
- int result = GLOB_NOMATCH;
+ result = GLOB_NOMATCH;
if (nfound != 0)
{
+ char **new_gl_pathv;
result = 0;
- if (pglob->gl_pathc > UINTPTR_MAX - pglob->gl_offs
- || pglob->gl_pathc + pglob->gl_offs > UINTPTR_MAX - nfound
- || pglob->gl_pathc + pglob->gl_offs + nfound > UINTPTR_MAX - 1
- || (pglob->gl_pathc + pglob->gl_offs + nfound + 1
- > UINTPTR_MAX / sizeof (char *)))
+ if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc
+ < pglob->gl_offs + nfound + 1)
goto memory_error;
- char **new_gl_pathv;
new_gl_pathv
- = (char **) realloc (pglob->gl_pathv,
- (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
- * sizeof (char *));
+ = realloc (pglob->gl_pathv,
+ (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
+ * sizeof (char *));
+
if (new_gl_pathv == NULL)
{
memory_error:
@@ -1684,7 +1650,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
and this is the block assigned to OLD here. */
if (names == NULL)
{
- assert (old == &init_names);
+ assert (old == init_names);
break;
}
cur = names->count;
@@ -1710,7 +1676,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
and this is the block assigned to OLD here. */
if (names == NULL)
{
- assert (old == &init_names);
+ assert (old == init_names);
break;
}
cur = names->count;
diff --git a/posix/glob64.c b/posix/glob64.c
index a5f5a7f9e2..39e54afe8b 100644
--- a/posix/glob64.c
+++ b/posix/glob64.c
@@ -43,10 +43,4 @@ glob64 (const char *pattern, int flags,
}
libc_hidden_def (glob64)
-void
-globfree64 (glob64_t *pglob)
-{
-}
-libc_hidden_def (globfree64)
-
stub_warning (glob64)
diff --git a/posix/glob_internal.h b/posix/glob_internal.h
new file mode 100644
index 0000000000..12c93660b7
--- /dev/null
+++ b/posix/glob_internal.h
@@ -0,0 +1,57 @@
+/* Shared definition for glob and glob_pattern_p.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef GLOB_INTERNAL_H
+# define GLOB_INTERNAL_H
+
+static inline int
+__glob_pattern_type (const char *pattern, int quote)
+{
+ const char *p;
+ int ret = 0;
+
+ for (p = pattern; *p != '\0'; ++p)
+ switch (*p)
+ {
+ case '?':
+ case '*':
+ return 1;
+
+ case '\\':
+ if (quote)
+ {
+ if (p[1] != '\0')
+ ++p;
+ ret |= 2;
+ }
+ break;
+
+ case '[':
+ ret |= 4;
+ break;
+
+ case ']':
+ if (ret & 4)
+ return 1;
+ break;
+ }
+
+ return ret;
+}
+
+#endif /* GLOB_INTERNAL_H */
diff --git a/posix/glob_pattern_p.c b/posix/glob_pattern_p.c
new file mode 100644
index 0000000000..a17d337182
--- /dev/null
+++ b/posix/glob_pattern_p.c
@@ -0,0 +1,33 @@
+/* Return nonzero if PATTERN contains any metacharacters.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _LIBC
+# include <config.h>
+#endif
+
+#include <glob.h>
+#include "glob_internal.h"
+
+/* Return nonzero if PATTERN contains any metacharacters.
+ Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
+int
+__glob_pattern_p (const char *pattern, int quote)
+{
+ return __glob_pattern_type (pattern, quote) == 1;
+}
+weak_alias (__glob_pattern_p, glob_pattern_p)
diff --git a/posix/globfree.c b/posix/globfree.c
new file mode 100644
index 0000000000..042e29d9b0
--- /dev/null
+++ b/posix/globfree.c
@@ -0,0 +1,41 @@
+/* Frees the dynamically allocated storage from an earlier call to glob.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _LIBC
+# include <config.h>
+#endif
+
+#include <glob.h>
+#include <stdlib.h>
+
+/* Free storage allocated in PGLOB by a previous `glob' call. */
+void
+globfree (glob_t *pglob)
+{
+ if (pglob->gl_pathv != NULL)
+ {
+ size_t i;
+ for (i = 0; i < pglob->gl_pathc; ++i)
+ free (pglob->gl_pathv[pglob->gl_offs + i]);
+ free (pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ }
+}
+#ifndef globfree
+libc_hidden_def (globfree)
+#endif
diff --git a/posix/globfree64.c b/posix/globfree64.c
new file mode 100644
index 0000000000..c9f8908a4e
--- /dev/null
+++ b/posix/globfree64.c
@@ -0,0 +1,31 @@
+/* Frees the dynamically allocated storage from an earlier call to glob.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _LIBC
+# include <config.h>
+#endif
+
+#include <glob.h>
+#include <stdlib.h>
+
+/* Free storage allocated in PGLOB by a previous `glob' call. */
+void
+globfree64 (glob64_t *pglob)
+{
+}
+libc_hidden_def (globfree64)
diff --git a/posix/tst-glob-tilde.c b/posix/tst-glob-tilde.c
new file mode 100644
index 0000000000..6886f4371f
--- /dev/null
+++ b/posix/tst-glob-tilde.c
@@ -0,0 +1,143 @@
+/* Check for GLOB_TIDLE heap allocation issues (bugs 22320, 22325, 22332).
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <glob.h>
+#include <mcheck.h>
+#include <nss.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+
+/* Flag which indicates whether to pass the GLOB_ONLYDIR flag. */
+static int do_onlydir;
+
+/* Flag which indicates whether to pass the GLOB_NOCHECK flag. */
+static int do_nocheck;
+
+/* Flag which indicates whether to pass the GLOB_MARK flag. */
+static int do_mark;
+
+/* Flag which indicates whether to pass the GLOB_NOESCAPE flag. */
+static int do_noescape;
+
+static void
+one_test (const char *prefix, const char *middle, const char *suffix)
+{
+ char *pattern = xasprintf ("%s%s%s", prefix, middle, suffix);
+ int flags = GLOB_TILDE;
+ if (do_onlydir)
+ flags |= GLOB_ONLYDIR;
+ if (do_nocheck)
+ flags |= GLOB_NOCHECK;
+ if (do_mark)
+ flags |= GLOB_MARK;
+ if (do_noescape)
+ flags |= GLOB_NOESCAPE;
+ glob_t gl;
+ /* This glob call might result in crashes or memory leaks. */
+ if (glob (pattern, flags, NULL, &gl) == 0)
+ globfree (&gl);
+ free (pattern);
+}
+
+enum
+ {
+ /* The largest base being tested. */
+ largest_base_size = 500000,
+
+ /* The actual size is the base size plus a variable whose absolute
+ value is not greater than this. This helps malloc to trigger
+ overflows. */
+ max_size_skew = 16,
+
+ /* The maximum string length supported by repeating_string
+ below. */
+ repeat_size = largest_base_size + max_size_skew,
+ };
+
+/* Used to construct strings which repeat a single character 'x'. */
+static char *repeat;
+
+/* Return a string of SIZE characters. */
+const char *
+repeating_string (int size)
+{
+ TEST_VERIFY (size >= 0);
+ TEST_VERIFY (size <= repeat_size);
+ const char *repeated_shifted = repeat + repeat_size - size;
+ TEST_VERIFY (strlen (repeated_shifted) == size);
+ return repeated_shifted;
+}
+
+static int
+do_test (void)
+{
+ /* Avoid network-based NSS modules and initialize nss_files with a
+ dummy lookup. This has to come before mtrace because NSS does
+ not free all memory. */
+ __nss_configure_lookup ("passwd", "files");
+ (void) getpwnam ("root");
+
+ mtrace ();
+
+ repeat = xmalloc (repeat_size + 1);
+ memset (repeat, 'x', repeat_size);
+ repeat[repeat_size] = '\0';
+
+ /* These numbers control the size of the user name. The values
+ cover the minimum (0), a typical size (8), a large
+ stack-allocated size (100000), and a somewhat large
+ heap-allocated size (largest_base_size). */
+ static const int base_sizes[] = { 0, 8, 100, 100000, largest_base_size, -1 };
+
+ for (do_onlydir = 0; do_onlydir < 2; ++do_onlydir)
+ for (do_nocheck = 0; do_nocheck < 2; ++do_nocheck)
+ for (do_mark = 0; do_mark < 2; ++do_mark)
+ for (do_noescape = 0; do_noescape < 2; ++do_noescape)
+ for (int base_idx = 0; base_sizes[base_idx] >= 0; ++base_idx)
+ {
+ for (int size_skew = -max_size_skew; size_skew <= max_size_skew;
+ ++size_skew)
+ {
+ int size = base_sizes[base_idx] + size_skew;
+ if (size < 0)
+ continue;
+
+ const char *user_name = repeating_string (size);
+ one_test ("~", user_name, "/a/b");
+ one_test ("~", user_name, "x\\x\\x////x\\a");
+ }
+
+ const char *user_name = repeating_string (base_sizes[base_idx]);
+ one_test ("~", user_name, "");
+ one_test ("~", user_name, "/");
+ one_test ("~", user_name, "/a");
+ one_test ("~", user_name, "/*/*");
+ one_test ("~", user_name, "\\/");
+ one_test ("/~", user_name, "");
+ one_test ("*/~", user_name, "/a/b");
+ }
+
+ free (repeat);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sunrpc/Makefile b/sunrpc/Makefile
index 789ef423e5..1e91905011 100644
--- a/sunrpc/Makefile
+++ b/sunrpc/Makefile
@@ -96,13 +96,18 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \
extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
others += rpcgen
-tests = tst-xdrmem tst-xdrmem2 test-rpcent
+tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error
xtests := tst-getmyaddr
ifeq ($(have-thread-library),yes)
xtests += thrsvc
endif
+ifeq ($(run-built-tests),yes)
+rpcgen-tests := $(objpfx)bug20790.out
+tests-special += $(rpcgen-tests)
+endif
+
headers += $(rpcsvc:%.x=rpcsvc/%.h)
extra-libs := librpcsvc
extra-libs-others := librpcsvc # Make it in `others' pass, not `lib' pass.
@@ -153,6 +158,7 @@ BUILD_CPPFLAGS += $(sunrpc-CPPFLAGS)
$(objpfx)tst-getmyaddr: $(common-objpfx)linkobj/libc.so
$(objpfx)tst-xdrmem: $(common-objpfx)linkobj/libc.so
$(objpfx)tst-xdrmem2: $(common-objpfx)linkobj/libc.so
+$(objpfx)tst-udp-error: $(common-objpfx)linkobj/libc.so
$(objpfx)rpcgen: $(addprefix $(objpfx),$(rpcgen-objs))
@@ -225,3 +231,9 @@ endif
endif
$(objpfx)thrsvc: $(common-objpfx)linkobj/libc.so $(shared-thread-library)
+
+ifeq ($(run-built-tests),yes)
+$(rpcgen-tests): $(objpfx)%.out: %.x $(objpfx)rpcgen
+ $(built-program-cmd) -c $< -o $@; \
+ $(evaluate-test)
+endif
diff --git a/sunrpc/bug20790.x b/sunrpc/bug20790.x
new file mode 100644
index 0000000000..a00c9b3830
--- /dev/null
+++ b/sunrpc/bug20790.x
@@ -0,0 +1 @@
+program TPROG { version TVERS { int FUNC(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) = 1; } = 1; } = 1;
diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c
index 4d9acb1e6a..1de25cb771 100644
--- a/sunrpc/clnt_udp.c
+++ b/sunrpc/clnt_udp.c
@@ -421,9 +421,9 @@ send_again:
cmsg = CMSG_NXTHDR (&msg, cmsg))
if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
{
- free (cbuf);
e = (struct sock_extended_err *) CMSG_DATA(cmsg);
cu->cu_error.re_errno = e->ee_errno;
+ free (cbuf);
return (cu->cu_error.re_status = RPC_CANTRECV);
}
free (cbuf);
diff --git a/sunrpc/rpc_parse.c b/sunrpc/rpc_parse.c
index 1a1df6d8c2..505a6554cf 100644
--- a/sunrpc/rpc_parse.c
+++ b/sunrpc/rpc_parse.c
@@ -521,7 +521,7 @@ static void
get_prog_declaration (declaration * dec, defkind dkind, int num /* arg number */ )
{
token tok;
- char name[10]; /* argument name */
+ char name[MAXLINESIZE]; /* argument name */
if (dkind == DEF_PROGRAM)
{
diff --git a/sunrpc/tst-udp-error.c b/sunrpc/tst-udp-error.c
new file mode 100644
index 0000000000..1efc02f5c6
--- /dev/null
+++ b/sunrpc/tst-udp-error.c
@@ -0,0 +1,62 @@
+/* Check for use-after-free in clntudp_call (bug 21115).
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <netinet/in.h>
+#include <rpc/clnt.h>
+#include <rpc/svc.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/xsocket.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ support_become_root ();
+ support_enter_network_namespace ();
+
+ /* Obtain a likely-unused port number. */
+ struct sockaddr_in sin =
+ {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
+ };
+ {
+ int fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ xbind (fd, (struct sockaddr *) &sin, sizeof (sin));
+ socklen_t sinlen = sizeof (sin);
+ xgetsockname (fd, (struct sockaddr *) &sin, &sinlen);
+ /* Close the socket, so that we will receive an error below. */
+ close (fd);
+ }
+
+ int sock = RPC_ANYSOCK;
+ CLIENT *clnt = clntudp_create
+ (&sin, 1, 2, (struct timeval) { 1, 0 }, &sock);
+ TEST_VERIFY_EXIT (clnt != NULL);
+ TEST_VERIFY (clnt_call (clnt, 3,
+ (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_void, NULL,
+ ((struct timeval) { 3, 0 }))
+ == RPC_CANTRECV);
+ clnt_destroy (clnt);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
index 282805e396..e86d8b5b63 100644
--- a/sysdeps/aarch64/dl-machine.h
+++ b/sysdeps/aarch64/dl-machine.h
@@ -172,8 +172,8 @@ _dl_start_user: \n\
cmp x0, #0 \n\
bne 1b \n\
// Update _dl_argv \n\
- adrp x3, _dl_argv \n\
- str x2, [x3, #:lo12:_dl_argv] \n\
+ adrp x3, __GI__dl_argv \n\
+ str x2, [x3, #:lo12:__GI__dl_argv] \n\
.L_done_stack_adjust: \n\
// compute envp \n\
add x3, x2, x1, lsl #3 \n\
diff --git a/sysdeps/gnu/glob64.c b/sysdeps/gnu/glob64.c
index d1e4e6f0d5..52e97e2f6a 100644
--- a/sysdeps/gnu/glob64.c
+++ b/sysdeps/gnu/glob64.c
@@ -15,11 +15,8 @@
#undef __stat
#define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
-#define NO_GLOB_PATTERN_P 1
-
#define COMPILE_GLOB64 1
#include <posix/glob.c>
libc_hidden_def (glob64)
-libc_hidden_def (globfree64)
diff --git a/sysdeps/gnu/globfree64.c b/sysdeps/gnu/globfree64.c
new file mode 100644
index 0000000000..f092d0bf8b
--- /dev/null
+++ b/sysdeps/gnu/globfree64.c
@@ -0,0 +1,10 @@
+#include <dirent.h>
+#include <glob.h>
+#include <sys/stat.h>
+
+#define glob_t glob64_t
+#define globfree(pglob) globfree64 (pglob)
+
+#include <posix/globfree.c>
+
+libc_hidden_def (globfree64)
diff --git a/sysdeps/ieee754/dbl-64/e_pow.c b/sysdeps/ieee754/dbl-64/e_pow.c
index 663fa392c2..bd758b5979 100644
--- a/sysdeps/ieee754/dbl-64/e_pow.c
+++ b/sysdeps/ieee754/dbl-64/e_pow.c
@@ -466,15 +466,15 @@ checkint (double x)
return (n & 1) ? -1 : 1; /* odd or even */
if (k > 20)
{
- if (n << (k - 20))
+ if (n << (k - 20) != 0)
return 0; /* if not integer */
- return (n << (k - 21)) ? -1 : 1;
+ return (n << (k - 21) != 0) ? -1 : 1;
}
if (n)
return 0; /*if not integer */
if (k == 20)
return (m & 1) ? -1 : 1;
- if (m << (k + 12))
+ if (m << (k + 12) != 0)
return 0;
- return (m << (k + 11)) ? -1 : 1;
+ return (m << (k + 11) != 0) ? -1 : 1;
}
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 35e1ed48d2..32beaa67d0 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -140,7 +140,7 @@ endif
ifeq ($(subdir),posix)
sysdep_headers += bits/initspin.h
-sysdep_routines += sched_getcpu
+sysdep_routines += sched_getcpu oldglob
tests += tst-affinity tst-affinity-pid
diff --git a/sysdeps/unix/sysv/linux/alpha/glob.c b/sysdeps/unix/sysv/linux/alpha/glob.c
index c5dfb85468..19eb9b1c07 100644
--- a/sysdeps/unix/sysv/linux/alpha/glob.c
+++ b/sysdeps/unix/sysv/linux/alpha/glob.c
@@ -42,10 +42,6 @@ extern void __new_globfree (glob_t *__pglob);
#undef globfree64
versioned_symbol (libc, __new_glob, glob, GLIBC_2_1);
-versioned_symbol (libc, __new_globfree, globfree, GLIBC_2_1);
libc_hidden_ver (__new_glob, glob)
-libc_hidden_ver (__new_globfree, globfree)
weak_alias (__new_glob, glob64)
-weak_alias (__new_globfree, globfree64)
-libc_hidden_ver (__new_globfree, globfree64)
diff --git a/sysdeps/unix/sysv/linux/alpha/globfree.c b/sysdeps/unix/sysv/linux/alpha/globfree.c
new file mode 100644
index 0000000000..98cf1c200b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/alpha/globfree.c
@@ -0,0 +1,37 @@
+/* Compat globfree. Linux/alpha version.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#define globfree64 __no_globfree64_decl
+#include <sys/types.h>
+#include <glob.h>
+#include <shlib-compat.h>
+
+#define globfree(pglob) \
+ __new_globfree (pglob)
+
+extern void __new_globfree (glob_t *__pglob);
+
+#include <posix/globfree.c>
+
+#undef globfree64
+
+versioned_symbol (libc, __new_globfree, globfree, GLIBC_2_1);
+libc_hidden_ver (__new_globfree, globfree)
+
+weak_alias (__new_globfree, globfree64)
+libc_hidden_ver (__new_globfree, globfree64)
diff --git a/sysdeps/unix/sysv/linux/i386/glob64.c b/sysdeps/unix/sysv/linux/i386/glob64.c
index 802c957d6c..c2cc85741f 100644
--- a/sysdeps/unix/sysv/linux/i386/glob64.c
+++ b/sysdeps/unix/sysv/linux/i386/glob64.c
@@ -19,6 +19,7 @@
#include <dirent.h>
#include <glob.h>
#include <sys/stat.h>
+#include <shlib-compat.h>
#define dirent dirent64
#define __readdir(dirp) __readdir64 (dirp)
@@ -33,44 +34,9 @@
#undef __stat
#define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
-#define NO_GLOB_PATTERN_P 1
-
#define COMPILE_GLOB64 1
#include <posix/glob.c>
-#include "shlib-compat.h"
-
-libc_hidden_def (globfree64)
-
versioned_symbol (libc, __glob64, glob64, GLIBC_2_2);
libc_hidden_ver (__glob64, glob64)
-
-#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
-
-#include <sysdeps/unix/sysv/linux/i386/olddirent.h>
-
-int __old_glob64 (const char *__pattern, int __flags,
- int (*__errfunc) (const char *, int),
- glob64_t *__pglob);
-
-#undef dirent
-#define dirent __old_dirent64
-#undef GL_READDIR
-# define GL_READDIR(pglob, stream) \
- ((struct __old_dirent64 *) (pglob)->gl_readdir (stream))
-#undef __readdir
-#define __readdir(dirp) __old_readdir64 (dirp)
-#undef glob
-#define glob(pattern, flags, errfunc, pglob) \
- __old_glob64 (pattern, flags, errfunc, pglob)
-#define convert_dirent __old_convert_dirent
-#define glob_in_dir __old_glob_in_dir
-#define GLOB_ATTRIBUTE attribute_compat_text_section
-
-#define GLOB_ONLY_P 1
-
-#include <posix/glob.c>
-
-compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1);
-#endif
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c
new file mode 100644
index 0000000000..abc35fdd2b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c
@@ -0,0 +1 @@
+/* glob64 is in globfree64.c */
diff --git a/sysdeps/unix/sysv/linux/oldglob.c b/sysdeps/unix/sysv/linux/oldglob.c
new file mode 100644
index 0000000000..8233e57ce9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/oldglob.c
@@ -0,0 +1,42 @@
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
+
+#include <dirent.h>
+#include <glob.h>
+#include <sys/stat.h>
+
+#include <sysdeps/unix/sysv/linux/i386/olddirent.h>
+
+int __old_glob64 (const char *__pattern, int __flags,
+ int (*__errfunc) (const char *, int),
+ glob64_t *__pglob);
+libc_hidden_proto (__old_glob64);
+
+#define dirent __old_dirent64
+#define GL_READDIR(pglob, stream) \
+ ((struct __old_dirent64 *) (pglob)->gl_readdir (stream))
+#undef __readdir
+#define __readdir(dirp) __old_readdir64 (dirp)
+
+#define glob_t glob64_t
+#define glob(pattern, flags, errfunc, pglob) \
+ __old_glob64 (pattern, flags, errfunc, pglob)
+#define globfree(pglob) globfree64(pglob)
+
+#define convert_dirent __old_convert_dirent
+#define glob_in_dir __old_glob_in_dir
+
+#undef stat
+#define stat stat64
+#undef __stat
+#define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
+
+#define GLOB_ATTRIBUTE attribute_compat_text_section
+
+#include <posix/glob.c>
+
+libc_hidden_def (__old_glob64);
+
+compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1);
+#endif
diff --git a/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym b/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym
index 17397c5511..25f914a93b 100644
--- a/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym
+++ b/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym
@@ -13,22 +13,22 @@ SIG_SETMASK
oLINK ucontext (uc_link)
oSS_SP ucontext (uc_stack.ss_sp)
oSS_SIZE ucontext (uc_stack.ss_size)
-oR0 mcontext (gregs[R0])
-oR1 mcontext (gregs[R1])
-oR2 mcontext (gregs[R2])
-oR3 mcontext (gregs[R3])
-oR4 mcontext (gregs[R4])
-oR5 mcontext (gregs[R5])
-oR6 mcontext (gregs[R6])
-oR7 mcontext (gregs[R7])
-oR8 mcontext (gregs[R8])
-oR9 mcontext (gregs[R9])
-oR10 mcontext (gregs[R10])
-oR11 mcontext (gregs[R11])
-oR12 mcontext (gregs[R12])
-oR13 mcontext (gregs[R13])
-oR14 mcontext (gregs[R14])
-oR15 mcontext (gregs[R15])
+oR0 mcontext (gregs[REG_R0])
+oR1 mcontext (gregs[REG_R1])
+oR2 mcontext (gregs[REG_R2])
+oR3 mcontext (gregs[REG_R3])
+oR4 mcontext (gregs[REG_R4])
+oR5 mcontext (gregs[REG_R5])
+oR6 mcontext (gregs[REG_R6])
+oR7 mcontext (gregs[REG_R7])
+oR8 mcontext (gregs[REG_R8])
+oR9 mcontext (gregs[REG_R9])
+oR10 mcontext (gregs[REG_R10])
+oR11 mcontext (gregs[REG_R11])
+oR12 mcontext (gregs[REG_R12])
+oR13 mcontext (gregs[REG_R13])
+oR14 mcontext (gregs[REG_R14])
+oR15 mcontext (gregs[REG_R15])
oPC mcontext (pc)
oPR mcontext (pr)
oSR mcontext (sr)
diff --git a/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym b/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym
index 65633fbcf4..130f60cd96 100644
--- a/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym
+++ b/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym
@@ -13,22 +13,22 @@ SIG_SETMASK
oLINK ucontext (uc_link)
oSS_SP ucontext (uc_stack.ss_sp)
oSS_SIZE ucontext (uc_stack.ss_size)
-oR0 mcontext (gregs[R0])
-oR1 mcontext (gregs[R1])
-oR2 mcontext (gregs[R2])
-oR3 mcontext (gregs[R3])
-oR4 mcontext (gregs[R4])
-oR5 mcontext (gregs[R5])
-oR6 mcontext (gregs[R6])
-oR7 mcontext (gregs[R7])
-oR8 mcontext (gregs[R8])
-oR9 mcontext (gregs[R9])
-oR10 mcontext (gregs[R10])
-oR11 mcontext (gregs[R11])
-oR12 mcontext (gregs[R12])
-oR13 mcontext (gregs[R13])
-oR14 mcontext (gregs[R14])
-oR15 mcontext (gregs[R15])
+oR0 mcontext (gregs[REG_R0])
+oR1 mcontext (gregs[REG_R1])
+oR2 mcontext (gregs[REG_R2])
+oR3 mcontext (gregs[REG_R3])
+oR4 mcontext (gregs[REG_R4])
+oR5 mcontext (gregs[REG_R5])
+oR6 mcontext (gregs[REG_R6])
+oR7 mcontext (gregs[REG_R7])
+oR8 mcontext (gregs[REG_R8])
+oR9 mcontext (gregs[REG_R9])
+oR10 mcontext (gregs[REG_R10])
+oR11 mcontext (gregs[REG_R11])
+oR12 mcontext (gregs[REG_R12])
+oR13 mcontext (gregs[REG_R13])
+oR14 mcontext (gregs[REG_R14])
+oR15 mcontext (gregs[REG_R15])
oPC mcontext (pc)
oPR mcontext (pr)
oSR mcontext (sr)
diff --git a/sysdeps/unix/sysv/linux/sh/sys/ucontext.h b/sysdeps/unix/sysv/linux/sh/sys/ucontext.h
index ab9a7e66bf..037fbb73e8 100644
--- a/sysdeps/unix/sysv/linux/sh/sys/ucontext.h
+++ b/sysdeps/unix/sysv/linux/sh/sys/ucontext.h
@@ -31,49 +31,47 @@
typedef int greg_t;
/* Number of general registers. */
-#define NGPREG 16
+#define NGREG 16
/* Container for all general registers. */
-typedef greg_t gregset_t[NGPREG];
+typedef greg_t gregset_t[NGREG];
-#ifdef __USE_GNU
/* Number of each register is the `gregset_t' array. */
enum
{
- R0 = 0,
-#define R0 R0
- R1 = 1,
-#define R1 R1
- R2 = 2,
-#define R2 R2
- R3 = 3,
-#define R3 R3
- R4 = 4,
-#define R4 R4
- R5 = 5,
-#define R5 R5
- R6 = 6,
-#define R6 R6
- R7 = 7,
-#define R7 R7
- R8 = 8,
-#define R8 R8
- R9 = 9,
-#define R9 R9
- R10 = 10,
-#define R10 R10
- R11 = 11,
-#define R11 R11
- R12 = 12,
-#define R12 R12
- R13 = 13,
-#define R13 R13
- R14 = 14,
-#define R14 R14
- R15 = 15,
-#define R15 R15
+ REG_R0 = 0,
+#define REG_R0 REG_R0
+ REG_R1 = 1,
+#define REG_R1 REG_R1
+ REG_R2 = 2,
+#define REG_R2 REG_R2
+ REG_R3 = 3,
+#define REG_R3 REG_R3
+ REG_R4 = 4,
+#define REG_R4 REG_R4
+ REG_R5 = 5,
+#define REG_R5 REG_R5
+ REG_R6 = 6,
+#define REG_R6 REG_R6
+ REG_R7 = 7,
+#define REG_R7 REG_R7
+ REG_R8 = 8,
+#define REG_R8 REG_R8
+ REG_R9 = 9,
+#define REG_R9 REG_R9
+ REG_R10 = 10,
+#define REG_R10 REG_R10
+ REG_R11 = 11,
+#define REG_R11 REG_R11
+ REG_R12 = 12,
+#define REG_R12 REG_R12
+ REG_R13 = 13,
+#define REG_R13 REG_R13
+ REG_R14 = 14,
+#define REG_R14 REG_R14
+ REG_R15 = 15,
+#define REG_R15 REG_R15
};
-#endif
#if (defined(__SH4__) || defined(__SH4A__))
typedef int freg_t;
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c b/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c
new file mode 100644
index 0000000000..af035e1514
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c
@@ -0,0 +1,2 @@
+/* This file is here so sysdeps/gnu/glob64.c doesn't take precedence. */
+#include <sysdeps/wordsize-64/globfree64.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c b/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c
new file mode 100644
index 0000000000..b76a761c17
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c
@@ -0,0 +1 @@
+#include <sysdeps/wordsize-64/globfree.c>
diff --git a/sysdeps/wordsize-64/glob.c b/sysdeps/wordsize-64/glob.c
index 082faf1c70..954e8d37e2 100644
--- a/sysdeps/wordsize-64/glob.c
+++ b/sysdeps/wordsize-64/glob.c
@@ -4,5 +4,3 @@
#undef glob64
#undef globfree64
weak_alias (glob, glob64)
-weak_alias (globfree, globfree64)
-libc_hidden_ver (globfree, globfree64)
diff --git a/sysdeps/wordsize-64/globfree.c b/sysdeps/wordsize-64/globfree.c
new file mode 100644
index 0000000000..ec8c35b489
--- /dev/null
+++ b/sysdeps/wordsize-64/globfree.c
@@ -0,0 +1,5 @@
+#define globfree64 __no_globfree64_decl
+#include <posix/globfree.c>
+#undef globfree64
+weak_alias (globfree, globfree64)
+libc_hidden_ver (globfree, globfree64)
diff --git a/sysdeps/wordsize-64/globfree64.c b/sysdeps/wordsize-64/globfree64.c
new file mode 100644
index 0000000000..a0f57ff4b3
--- /dev/null
+++ b/sysdeps/wordsize-64/globfree64.c
@@ -0,0 +1 @@
+/* globfree64 is in globfree.c */
diff --git a/sysdeps/x86/cpu-features-offsets.sym b/sysdeps/x86/cpu-features-offsets.sym
index f6739fae81..33dd094e37 100644
--- a/sysdeps/x86/cpu-features-offsets.sym
+++ b/sysdeps/x86/cpu-features-offsets.sym
@@ -15,6 +15,7 @@ CPUID_ECX_OFFSET offsetof (struct cpuid_registers, ecx)
CPUID_EDX_OFFSET offsetof (struct cpuid_registers, edx)
FAMILY_OFFSET offsetof (struct cpu_features, family)
MODEL_OFFSET offsetof (struct cpu_features, model)
+XSAVE_STATE_SIZE_OFFSET offsetof (struct cpu_features, xsave_state_size)
FEATURE_OFFSET offsetof (struct cpu_features, feature)
FEATURE_SIZE sizeof (unsigned int)
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index d1ee922290..9eca98817d 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -18,6 +18,7 @@
#include <cpuid.h>
#include <cpu-features.h>
+#include <libc-internal.h>
static void
get_common_indeces (struct cpu_features *cpu_features,
@@ -88,6 +89,71 @@ get_common_indeces (struct cpu_features *cpu_features,
cpu_features->feature[index_arch_FMA_Usable]
|= bit_arch_FMA_Usable;
}
+
+ /* For _dl_runtime_resolve, set xsave_state_size to xsave area
+ size + integer register save size and align it to 64 bytes. */
+ if (cpu_features->max_cpuid >= 0xd)
+ {
+ unsigned int eax, ebx, ecx, edx;
+
+ __cpuid_count (0xd, 0, eax, ebx, ecx, edx);
+ if (ebx != 0)
+ {
+ cpu_features->xsave_state_size
+ = ALIGN_UP (ebx + STATE_SAVE_OFFSET, 64);
+
+ __cpuid_count (0xd, 1, eax, ebx, ecx, edx);
+
+ /* Check if XSAVEC is available. */
+ if ((eax & (1 << 1)) != 0)
+ {
+ unsigned int xstate_comp_offsets[32];
+ unsigned int xstate_comp_sizes[32];
+ unsigned int i;
+
+ xstate_comp_offsets[0] = 0;
+ xstate_comp_offsets[1] = 160;
+ xstate_comp_offsets[2] = 576;
+ xstate_comp_sizes[0] = 160;
+ xstate_comp_sizes[1] = 256;
+
+ for (i = 2; i < 32; i++)
+ {
+ if ((STATE_SAVE_MASK & (1 << i)) != 0)
+ {
+ __cpuid_count (0xd, i, eax, ebx, ecx, edx);
+ xstate_comp_sizes[i] = eax;
+ }
+ else
+ {
+ ecx = 0;
+ xstate_comp_sizes[i] = 0;
+ }
+
+ if (i > 2)
+ {
+ xstate_comp_offsets[i]
+ = (xstate_comp_offsets[i - 1]
+ + xstate_comp_sizes[i -1]);
+ if ((ecx & (1 << 1)) != 0)
+ xstate_comp_offsets[i]
+ = ALIGN_UP (xstate_comp_offsets[i], 64);
+ }
+ }
+
+ /* Use XSAVEC. */
+ unsigned int size
+ = xstate_comp_offsets[31] + xstate_comp_sizes[31];
+ if (size)
+ {
+ cpu_features->xsave_state_size
+ = ALIGN_UP (size + STATE_SAVE_OFFSET, 64);
+ cpu_features->feature[index_arch_XSAVEC_Usable]
+ |= bit_arch_XSAVEC_Usable;
+ }
+ }
+ }
+ }
}
}
@@ -213,20 +279,6 @@ init_cpu_features (struct cpu_features *cpu_features)
else
cpu_features->feature[index_arch_Prefer_No_AVX512]
|= bit_arch_Prefer_No_AVX512;
-
- /* To avoid SSE transition penalty, use _dl_runtime_resolve_slow.
- If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt. */
- cpu_features->feature[index_arch_Use_dl_runtime_resolve_slow]
- |= bit_arch_Use_dl_runtime_resolve_slow;
- if (cpu_features->max_cpuid >= 0xd)
- {
- unsigned int eax;
-
- __cpuid_count (0xd, 1, eax, ebx, ecx, edx);
- if ((eax & (1 << 2)) != 0)
- cpu_features->feature[index_arch_Use_dl_runtime_resolve_opt]
- |= bit_arch_Use_dl_runtime_resolve_opt;
- }
}
/* This spells out "AuthenticAMD". */
else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65)
diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h
index 2609ac0999..507a141414 100644
--- a/sysdeps/x86/cpu-features.h
+++ b/sysdeps/x86/cpu-features.h
@@ -37,9 +37,8 @@
#define bit_arch_Prefer_No_VZEROUPPER (1 << 17)
#define bit_arch_Fast_Unaligned_Copy (1 << 18)
#define bit_arch_Prefer_ERMS (1 << 19)
-#define bit_arch_Use_dl_runtime_resolve_opt (1 << 20)
-#define bit_arch_Use_dl_runtime_resolve_slow (1 << 21)
-#define bit_arch_Prefer_No_AVX512 (1 << 22)
+#define bit_arch_Prefer_No_AVX512 (1 << 20)
+#define bit_arch_XSAVEC_Usable (1 << 21)
/* CPUID Feature flags. */
@@ -82,6 +81,15 @@
/* The current maximum size of the feature integer bit array. */
#define FEATURE_INDEX_MAX 1
+/* Offset for fxsave/xsave area used by _dl_runtime_resolve. Also need
+ space to preserve RCX, RDX, RSI, RDI, R8, R9 and RAX. It must be
+ aligned to 16 bytes for fxsave and 64 bytes for xsave. */
+#define STATE_SAVE_OFFSET (8 * 7 + 8)
+
+/* Save SSE, AVX, AVX512, mask and bound registers. */
+#define STATE_SAVE_MASK \
+ ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7))
+
#ifdef __ASSEMBLER__
# include <cpu-features-offsets.h>
@@ -206,6 +214,12 @@ struct cpu_features
} cpuid[COMMON_CPUID_INDEX_MAX];
unsigned int family;
unsigned int model;
+ /* The type must be unsigned long int so that we use
+
+ sub xsave_state_size_offset(%rip) %RSP_LP
+
+ in _dl_runtime_resolve. */
+ unsigned long int xsave_state_size;
unsigned int feature[FEATURE_INDEX_MAX];
};
@@ -298,9 +312,8 @@ extern const struct cpu_features *__get_cpu_features (void)
# define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_1
# define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_1
# define index_arch_Prefer_ERMS FEATURE_INDEX_1
-# define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1
-# define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1
# define index_arch_Prefer_No_AVX512 FEATURE_INDEX_1
+# define index_arch_XSAVEC_Usable FEATURE_INDEX_1
#endif /* !__ASSEMBLER__ */
diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
index 6d99284cd0..cc990a9685 100644
--- a/sysdeps/x86_64/Makefile
+++ b/sysdeps/x86_64/Makefile
@@ -27,7 +27,7 @@ ifeq ($(subdir),elf)
CFLAGS-.os += $(if $(filter $(@F),$(patsubst %,%.os,$(all-rtld-routines))),\
-mno-mmx)
-sysdep-dl-routines += tlsdesc dl-tlsdesc
+sysdep-dl-routines += tlsdesc dl-tlsdesc tls_get_addr
tests += ifuncmain8
modules-names += ifuncmod8
@@ -49,9 +49,12 @@ extra-test-objs += tst-quadmod1pie.o tst-quadmod2pie.o
$(objpfx)tst-quad1pie: $(objpfx)tst-quadmod1pie.o
$(objpfx)tst-quad2pie: $(objpfx)tst-quadmod2pie.o
-tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 tst-audit10
-test-extras += tst-audit4-aux tst-audit10-aux
-extra-test-objs += tst-audit4-aux.o tst-audit10-aux.o
+tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 \
+ tst-audit10 tst-sse tst-avx tst-avx512
+test-extras += tst-audit4-aux tst-audit10-aux \
+ tst-avx-aux tst-avx512-aux
+extra-test-objs += tst-audit4-aux.o tst-audit10-aux.o \
+ tst-avx-aux.o tst-avx512-aux.o
tests += tst-split-dynreloc
LDFLAGS-tst-split-dynreloc = -Wl,-T,$(..)sysdeps/x86_64/tst-split-dynreloc.lds
@@ -62,7 +65,8 @@ modules-names += tst-auditmod3a tst-auditmod3b \
tst-auditmod5a tst-auditmod5b \
tst-auditmod6a tst-auditmod6b tst-auditmod6c \
tst-auditmod7a tst-auditmod7b \
- tst-auditmod10a tst-auditmod10b
+ tst-auditmod10a tst-auditmod10b \
+ tst-ssemod tst-avxmod tst-avx512mod
$(objpfx)tst-audit3: $(objpfx)tst-auditmod3a.so
$(objpfx)tst-audit3.out: $(objpfx)tst-auditmod3b.so
@@ -89,6 +93,10 @@ $(objpfx)tst-audit10: $(objpfx)tst-audit10-aux.o $(objpfx)tst-auditmod10a.so
$(objpfx)tst-audit10.out: $(objpfx)tst-auditmod10b.so
tst-audit10-ENV = LD_AUDIT=$(objpfx)tst-auditmod10b.so
+$(objpfx)tst-sse: $(objpfx)tst-ssemod.so
+$(objpfx)tst-avx: $(objpfx)tst-avx-aux.o $(objpfx)tst-avxmod.so
+$(objpfx)tst-avx512: $(objpfx)tst-avx512-aux.o $(objpfx)tst-avx512mod.so
+
AVX-CFLAGS=-mavx -mno-vzeroupper
CFLAGS-tst-audit4-aux.c += $(AVX-CFLAGS)
CFLAGS-tst-auditmod4a.c += $(AVX-CFLAGS)
@@ -96,14 +104,18 @@ CFLAGS-tst-auditmod4b.c += $(AVX-CFLAGS)
CFLAGS-tst-auditmod6b.c += $(AVX-CFLAGS)
CFLAGS-tst-auditmod6c.c += $(AVX-CFLAGS)
CFLAGS-tst-auditmod7b.c += $(AVX-CFLAGS)
+CFLAGS-tst-avx-aux.c += $(AVX-CFLAGS)
+CFLAGS-tst-avxmod.c += $(AVX-CFLAGS)
ifeq (yes,$(config-cflags-avx512))
AVX512-CFLAGS = -mavx512f
CFLAGS-tst-audit10-aux.c += $(AVX512-CFLAGS)
CFLAGS-tst-auditmod10a.c += $(AVX512-CFLAGS)
CFLAGS-tst-auditmod10b.c += $(AVX512-CFLAGS)
+CFLAGS-tst-avx512-aux.c += $(AVX512-CFLAGS)
+CFLAGS-tst-avx512mod.c += $(AVX512-CFLAGS)
endif
endif
ifeq ($(subdir),csu)
-gen-as-const-headers += tlsdesc.sym
+gen-as-const-headers += tlsdesc.sym rtld-offsets.sym
endif
diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
index c0f0fa16a2..8355432dfc 100644
--- a/sysdeps/x86_64/dl-machine.h
+++ b/sysdeps/x86_64/dl-machine.h
@@ -66,12 +66,9 @@ static inline int __attribute__ ((unused, always_inline))
elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
{
Elf64_Addr *got;
- extern void _dl_runtime_resolve_sse (ElfW(Word)) attribute_hidden;
- extern void _dl_runtime_resolve_avx (ElfW(Word)) attribute_hidden;
- extern void _dl_runtime_resolve_avx_slow (ElfW(Word)) attribute_hidden;
- extern void _dl_runtime_resolve_avx_opt (ElfW(Word)) attribute_hidden;
- extern void _dl_runtime_resolve_avx512 (ElfW(Word)) attribute_hidden;
- extern void _dl_runtime_resolve_avx512_opt (ElfW(Word)) attribute_hidden;
+ extern void _dl_runtime_resolve_fxsave (ElfW(Word)) attribute_hidden;
+ extern void _dl_runtime_resolve_xsave (ElfW(Word)) attribute_hidden;
+ extern void _dl_runtime_resolve_xsavec (ElfW(Word)) attribute_hidden;
extern void _dl_runtime_profile_sse (ElfW(Word)) attribute_hidden;
extern void _dl_runtime_profile_avx (ElfW(Word)) attribute_hidden;
extern void _dl_runtime_profile_avx512 (ElfW(Word)) attribute_hidden;
@@ -120,29 +117,14 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
/* This function will get called to fix up the GOT entry
indicated by the offset on the stack, and then jump to
the resolved address. */
- if (HAS_ARCH_FEATURE (AVX512F_Usable))
- {
- if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_opt))
- *(ElfW(Addr) *) (got + 2)
- = (ElfW(Addr)) &_dl_runtime_resolve_avx512_opt;
- else
- *(ElfW(Addr) *) (got + 2)
- = (ElfW(Addr)) &_dl_runtime_resolve_avx512;
- }
- else if (HAS_ARCH_FEATURE (AVX_Usable))
- {
- if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_opt))
- *(ElfW(Addr) *) (got + 2)
- = (ElfW(Addr)) &_dl_runtime_resolve_avx_opt;
- else if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_slow))
- *(ElfW(Addr) *) (got + 2)
- = (ElfW(Addr)) &_dl_runtime_resolve_avx_slow;
- else
- *(ElfW(Addr) *) (got + 2)
- = (ElfW(Addr)) &_dl_runtime_resolve_avx;
- }
+ if (GLRO(dl_x86_cpu_features).xsave_state_size != 0)
+ *(ElfW(Addr) *) (got + 2)
+ = (HAS_ARCH_FEATURE (XSAVEC_Usable)
+ ? (ElfW(Addr)) &_dl_runtime_resolve_xsavec
+ : (ElfW(Addr)) &_dl_runtime_resolve_xsave);
else
- *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_resolve_sse;
+ *(ElfW(Addr) *) (got + 2)
+ = (ElfW(Addr)) &_dl_runtime_resolve_fxsave;
}
}
diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c
new file mode 100644
index 0000000000..3584805c8e
--- /dev/null
+++ b/sysdeps/x86_64/dl-tls.c
@@ -0,0 +1,53 @@
+/* Thread-local storage handling in the ELF dynamic linker. x86-64 version.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef SHARED
+/* Work around GCC PR58066, due to which __tls_get_addr may be called
+ with an unaligned stack. The compat implementation is in
+ tls_get_addr-compat.S. */
+
+# include <dl-tls.h>
+
+/* Define __tls_get_addr within elf/dl-tls.c under a different
+ name. */
+extern __typeof__ (__tls_get_addr) ___tls_get_addr;
+
+# define __tls_get_addr ___tls_get_addr
+# include <elf/dl-tls.c>
+# undef __tls_get_addr
+
+hidden_ver (___tls_get_addr, __tls_get_addr)
+
+/* Only handle slow paths for __tls_get_addr. */
+attribute_hidden
+void *
+__tls_get_addr_slow (GET_ADDR_ARGS)
+{
+ dtv_t *dtv = THREAD_DTV ();
+
+ if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation)))
+ return update_get_addr (GET_ADDR_PARAM);
+
+ return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL);
+}
+#else
+
+/* No compatibility symbol needed. */
+# include <elf/dl-tls.c>
+
+#endif
diff --git a/sysdeps/x86_64/dl-tls.h b/sysdeps/x86_64/dl-tls.h
index cf6c107f54..fa5bf6cd93 100644
--- a/sysdeps/x86_64/dl-tls.h
+++ b/sysdeps/x86_64/dl-tls.h
@@ -16,6 +16,9 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#ifndef _X86_64_DL_TLS_H
+#define _X86_64_DL_TLS_H
+
#include <stdint.h>
/* Type used for the representation of TLS information in the GOT. */
@@ -27,3 +30,5 @@ typedef struct dl_tls_index
extern void *__tls_get_addr (tls_index *ti);
+
+#endif /* _X86_64_DL_TLS_H */
diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S
index 50b23633e3..b4cda0f535 100644
--- a/sysdeps/x86_64/dl-trampoline.S
+++ b/sysdeps/x86_64/dl-trampoline.S
@@ -34,41 +34,24 @@
# define DL_STACK_ALIGNMENT 8
#endif
-#ifndef DL_RUNTIME_UNALIGNED_VEC_SIZE
-/* The maximum size in bytes of unaligned vector load and store in the
- dynamic linker. Since SSE optimized memory/string functions with
- aligned SSE register load and store are used in the dynamic linker,
- we must set this to 8 so that _dl_runtime_resolve_sse will align the
- stack before calling _dl_fixup. */
-# define DL_RUNTIME_UNALIGNED_VEC_SIZE 8
-#endif
-
-/* True if _dl_runtime_resolve should align stack to VEC_SIZE bytes. */
+/* True if _dl_runtime_resolve should align stack for STATE_SAVE or align
+ stack to 16 bytes before calling _dl_fixup. */
#define DL_RUNTIME_RESOLVE_REALIGN_STACK \
- (VEC_SIZE > DL_STACK_ALIGNMENT \
- && VEC_SIZE > DL_RUNTIME_UNALIGNED_VEC_SIZE)
-
-/* Align vector register save area to 16 bytes. */
-#define REGISTER_SAVE_VEC_OFF 0
+ (STATE_SAVE_ALIGNMENT > DL_STACK_ALIGNMENT \
+ || 16 > DL_STACK_ALIGNMENT)
/* Area on stack to save and restore registers used for parameter
passing when calling _dl_fixup. */
#ifdef __ILP32__
-# define REGISTER_SAVE_RAX (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 8)
# define PRESERVE_BND_REGS_PREFIX
#else
-/* Align bound register save area to 16 bytes. */
-# define REGISTER_SAVE_BND0 (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 8)
-# define REGISTER_SAVE_BND1 (REGISTER_SAVE_BND0 + 16)
-# define REGISTER_SAVE_BND2 (REGISTER_SAVE_BND1 + 16)
-# define REGISTER_SAVE_BND3 (REGISTER_SAVE_BND2 + 16)
-# define REGISTER_SAVE_RAX (REGISTER_SAVE_BND3 + 16)
# ifdef HAVE_MPX_SUPPORT
# define PRESERVE_BND_REGS_PREFIX bnd
# else
# define PRESERVE_BND_REGS_PREFIX .byte 0xf2
# endif
#endif
+#define REGISTER_SAVE_RAX 0
#define REGISTER_SAVE_RCX (REGISTER_SAVE_RAX + 8)
#define REGISTER_SAVE_RDX (REGISTER_SAVE_RCX + 8)
#define REGISTER_SAVE_RSI (REGISTER_SAVE_RDX + 8)
@@ -80,68 +63,56 @@
#define VEC_SIZE 64
#define VMOVA vmovdqa64
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT
-# define VMOV vmovdqa64
-#else
-# define VMOV vmovdqu64
-#endif
#define VEC(i) zmm##i
-#define _dl_runtime_resolve _dl_runtime_resolve_avx512
#define _dl_runtime_profile _dl_runtime_profile_avx512
#include "dl-trampoline.h"
-#undef _dl_runtime_resolve
#undef _dl_runtime_profile
#undef VEC
-#undef VMOV
#undef VMOVA
#undef VEC_SIZE
#define VEC_SIZE 32
#define VMOVA vmovdqa
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT
-# define VMOV vmovdqa
-#else
-# define VMOV vmovdqu
-#endif
#define VEC(i) ymm##i
-#define _dl_runtime_resolve _dl_runtime_resolve_avx
-#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx_opt
#define _dl_runtime_profile _dl_runtime_profile_avx
#include "dl-trampoline.h"
-#undef _dl_runtime_resolve
-#undef _dl_runtime_resolve_opt
#undef _dl_runtime_profile
#undef VEC
-#undef VMOV
#undef VMOVA
#undef VEC_SIZE
/* movaps/movups is 1-byte shorter. */
#define VEC_SIZE 16
#define VMOVA movaps
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT
-# define VMOV movaps
-#else
-# define VMOV movups
-#endif
#define VEC(i) xmm##i
-#define _dl_runtime_resolve _dl_runtime_resolve_sse
#define _dl_runtime_profile _dl_runtime_profile_sse
#undef RESTORE_AVX
#include "dl-trampoline.h"
-#undef _dl_runtime_resolve
#undef _dl_runtime_profile
-#undef VMOV
+#undef VEC
#undef VMOVA
+#undef VEC_SIZE
-/* Used by _dl_runtime_resolve_avx_opt/_dl_runtime_resolve_avx512_opt
- to preserve the full vector registers with zero upper bits. */
-#define VMOVA vmovdqa
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT
-# define VMOV vmovdqa
-#else
-# define VMOV vmovdqu
-#endif
-#define _dl_runtime_resolve _dl_runtime_resolve_sse_vex
-#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx512_opt
+#define USE_FXSAVE
+#define STATE_SAVE_ALIGNMENT 16
+#define _dl_runtime_resolve _dl_runtime_resolve_fxsave
+#include "dl-trampoline.h"
+#undef _dl_runtime_resolve
+#undef USE_FXSAVE
+#undef STATE_SAVE_ALIGNMENT
+
+#define USE_XSAVE
+#define STATE_SAVE_ALIGNMENT 64
+#define _dl_runtime_resolve _dl_runtime_resolve_xsave
+#include "dl-trampoline.h"
+#undef _dl_runtime_resolve
+#undef USE_XSAVE
+#undef STATE_SAVE_ALIGNMENT
+
+#define USE_XSAVEC
+#define STATE_SAVE_ALIGNMENT 64
+#define _dl_runtime_resolve _dl_runtime_resolve_xsavec
#include "dl-trampoline.h"
+#undef _dl_runtime_resolve
+#undef USE_XSAVEC
+#undef STATE_SAVE_ALIGNMENT
diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h
index 32ad3af202..b9c2f1796f 100644
--- a/sysdeps/x86_64/dl-trampoline.h
+++ b/sysdeps/x86_64/dl-trampoline.h
@@ -16,140 +16,47 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#undef REGISTER_SAVE_AREA_RAW
-#ifdef __ILP32__
-/* X32 saves RCX, RDX, RSI, RDI, R8 and R9 plus RAX as well as VEC0 to
- VEC7. */
-# define REGISTER_SAVE_AREA_RAW (8 * 7 + VEC_SIZE * 8)
-#else
-/* X86-64 saves RCX, RDX, RSI, RDI, R8 and R9 plus RAX as well as
- BND0, BND1, BND2, BND3 and VEC0 to VEC7. */
-# define REGISTER_SAVE_AREA_RAW (8 * 7 + 16 * 4 + VEC_SIZE * 8)
-#endif
+ .text
+#ifdef _dl_runtime_resolve
-#undef REGISTER_SAVE_AREA
-#undef LOCAL_STORAGE_AREA
-#undef BASE
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK
-# define REGISTER_SAVE_AREA (REGISTER_SAVE_AREA_RAW + 8)
-/* Local stack area before jumping to function address: RBX. */
-# define LOCAL_STORAGE_AREA 8
-# define BASE rbx
-# if (REGISTER_SAVE_AREA % VEC_SIZE) != 0
-# error REGISTER_SAVE_AREA must be multples of VEC_SIZE
-# endif
-#else
-# define REGISTER_SAVE_AREA REGISTER_SAVE_AREA_RAW
-/* Local stack area before jumping to function address: All saved
- registers. */
-# define LOCAL_STORAGE_AREA REGISTER_SAVE_AREA
-# define BASE rsp
-# if (REGISTER_SAVE_AREA % 16) != 8
-# error REGISTER_SAVE_AREA must be odd multples of 8
+# undef REGISTER_SAVE_AREA
+# undef LOCAL_STORAGE_AREA
+# undef BASE
+
+# if (STATE_SAVE_ALIGNMENT % 16) != 0
+# error STATE_SAVE_ALIGNMENT must be multples of 16
# endif
-#endif
- .text
-#ifdef _dl_runtime_resolve_opt
-/* Use the smallest vector registers to preserve the full YMM/ZMM
- registers to avoid SSE transition penalty. */
-
-# if VEC_SIZE == 32
-/* Check if the upper 128 bits in %ymm0 - %ymm7 registers are non-zero
- and preserve %xmm0 - %xmm7 registers with the zero upper bits. Since
- there is no SSE transition penalty on AVX512 processors which don't
- support XGETBV with ECX == 1, _dl_runtime_resolve_avx512_slow isn't
- provided. */
- .globl _dl_runtime_resolve_avx_slow
- .hidden _dl_runtime_resolve_avx_slow
- .type _dl_runtime_resolve_avx_slow, @function
- .align 16
-_dl_runtime_resolve_avx_slow:
- cfi_startproc
- cfi_adjust_cfa_offset(16) # Incorporate PLT
- vorpd %ymm0, %ymm1, %ymm8
- vorpd %ymm2, %ymm3, %ymm9
- vorpd %ymm4, %ymm5, %ymm10
- vorpd %ymm6, %ymm7, %ymm11
- vorpd %ymm8, %ymm9, %ymm9
- vorpd %ymm10, %ymm11, %ymm10
- vpcmpeqd %xmm8, %xmm8, %xmm8
- vorpd %ymm9, %ymm10, %ymm10
- vptest %ymm10, %ymm8
- # Preserve %ymm0 - %ymm7 registers if the upper 128 bits of any
- # %ymm0 - %ymm7 registers aren't zero.
- PRESERVE_BND_REGS_PREFIX
- jnc _dl_runtime_resolve_avx
- # Use vzeroupper to avoid SSE transition penalty.
- vzeroupper
- # Preserve %xmm0 - %xmm7 registers with the zero upper 128 bits
- # when the upper 128 bits of %ymm0 - %ymm7 registers are zero.
- PRESERVE_BND_REGS_PREFIX
- jmp _dl_runtime_resolve_sse_vex
- cfi_adjust_cfa_offset(-16) # Restore PLT adjustment
- cfi_endproc
- .size _dl_runtime_resolve_avx_slow, .-_dl_runtime_resolve_avx_slow
+# if (STATE_SAVE_OFFSET % STATE_SAVE_ALIGNMENT) != 0
+# error STATE_SAVE_OFFSET must be multples of STATE_SAVE_ALIGNMENT
# endif
-/* Use XGETBV with ECX == 1 to check which bits in vector registers are
- non-zero and only preserve the non-zero lower bits with zero upper
- bits. */
- .globl _dl_runtime_resolve_opt
- .hidden _dl_runtime_resolve_opt
- .type _dl_runtime_resolve_opt, @function
- .align 16
-_dl_runtime_resolve_opt:
- cfi_startproc
- cfi_adjust_cfa_offset(16) # Incorporate PLT
- pushq %rax
- cfi_adjust_cfa_offset(8)
- cfi_rel_offset(%rax, 0)
- pushq %rcx
- cfi_adjust_cfa_offset(8)
- cfi_rel_offset(%rcx, 0)
- pushq %rdx
- cfi_adjust_cfa_offset(8)
- cfi_rel_offset(%rdx, 0)
- movl $1, %ecx
- xgetbv
- movl %eax, %r11d
- popq %rdx
- cfi_adjust_cfa_offset(-8)
- cfi_restore (%rdx)
- popq %rcx
- cfi_adjust_cfa_offset(-8)
- cfi_restore (%rcx)
- popq %rax
- cfi_adjust_cfa_offset(-8)
- cfi_restore (%rax)
-# if VEC_SIZE == 32
- # For YMM registers, check if YMM state is in use.
- andl $bit_YMM_state, %r11d
- # Preserve %xmm0 - %xmm7 registers with the zero upper 128 bits if
- # YMM state isn't in use.
- PRESERVE_BND_REGS_PREFIX
- jz _dl_runtime_resolve_sse_vex
-# elif VEC_SIZE == 16
- # For ZMM registers, check if YMM state and ZMM state are in
- # use.
- andl $(bit_YMM_state | bit_ZMM0_15_state), %r11d
- cmpl $bit_YMM_state, %r11d
- # Preserve %zmm0 - %zmm7 registers if ZMM state is in use.
- PRESERVE_BND_REGS_PREFIX
- jg _dl_runtime_resolve_avx512
- # Preserve %ymm0 - %ymm7 registers with the zero upper 256 bits if
- # ZMM state isn't in use.
- PRESERVE_BND_REGS_PREFIX
- je _dl_runtime_resolve_avx
- # Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if
- # neither YMM state nor ZMM state are in use.
+# if DL_RUNTIME_RESOLVE_REALIGN_STACK
+/* Local stack area before jumping to function address: RBX. */
+# define LOCAL_STORAGE_AREA 8
+# define BASE rbx
+# ifdef USE_FXSAVE
+/* Use fxsave to save XMM registers. */
+# define REGISTER_SAVE_AREA (512 + STATE_SAVE_OFFSET)
+# if (REGISTER_SAVE_AREA % 16) != 0
+# error REGISTER_SAVE_AREA must be multples of 16
+# endif
+# endif
# else
-# error Unsupported VEC_SIZE!
+# ifndef USE_FXSAVE
+# error USE_FXSAVE must be defined
+# endif
+/* Use fxsave to save XMM registers. */
+# define REGISTER_SAVE_AREA (512 + STATE_SAVE_OFFSET + 8)
+/* Local stack area before jumping to function address: All saved
+ registers. */
+# define LOCAL_STORAGE_AREA REGISTER_SAVE_AREA
+# define BASE rsp
+# if (REGISTER_SAVE_AREA % 16) != 8
+# error REGISTER_SAVE_AREA must be odd multples of 8
+# endif
# endif
- cfi_adjust_cfa_offset(-16) # Restore PLT adjustment
- cfi_endproc
- .size _dl_runtime_resolve_opt, .-_dl_runtime_resolve_opt
-#endif
+
.globl _dl_runtime_resolve
.hidden _dl_runtime_resolve
.type _dl_runtime_resolve, @function
@@ -157,19 +64,30 @@ _dl_runtime_resolve_opt:
cfi_startproc
_dl_runtime_resolve:
cfi_adjust_cfa_offset(16) # Incorporate PLT
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK
-# if LOCAL_STORAGE_AREA != 8
-# error LOCAL_STORAGE_AREA must be 8
-# endif
+# if DL_RUNTIME_RESOLVE_REALIGN_STACK
+# if LOCAL_STORAGE_AREA != 8
+# error LOCAL_STORAGE_AREA must be 8
+# endif
pushq %rbx # push subtracts stack by 8.
cfi_adjust_cfa_offset(8)
cfi_rel_offset(%rbx, 0)
mov %RSP_LP, %RBX_LP
cfi_def_cfa_register(%rbx)
- and $-VEC_SIZE, %RSP_LP
-#endif
+ and $-STATE_SAVE_ALIGNMENT, %RSP_LP
+# endif
+# ifdef REGISTER_SAVE_AREA
sub $REGISTER_SAVE_AREA, %RSP_LP
+# if !DL_RUNTIME_RESOLVE_REALIGN_STACK
cfi_adjust_cfa_offset(REGISTER_SAVE_AREA)
+# endif
+# else
+ # Allocate stack space of the required size to save the state.
+# if IS_IN (rtld)
+ sub _rtld_local_ro+RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET+XSAVE_STATE_SIZE_OFFSET(%rip), %RSP_LP
+# else
+ sub _dl_x86_cpu_features+XSAVE_STATE_SIZE_OFFSET(%rip), %RSP_LP
+# endif
+# endif
# Preserve registers otherwise clobbered.
movq %rax, REGISTER_SAVE_RAX(%rsp)
movq %rcx, REGISTER_SAVE_RCX(%rsp)
@@ -178,59 +96,42 @@ _dl_runtime_resolve:
movq %rdi, REGISTER_SAVE_RDI(%rsp)
movq %r8, REGISTER_SAVE_R8(%rsp)
movq %r9, REGISTER_SAVE_R9(%rsp)
- VMOV %VEC(0), (REGISTER_SAVE_VEC_OFF)(%rsp)
- VMOV %VEC(1), (REGISTER_SAVE_VEC_OFF + VEC_SIZE)(%rsp)
- VMOV %VEC(2), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 2)(%rsp)
- VMOV %VEC(3), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 3)(%rsp)
- VMOV %VEC(4), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 4)(%rsp)
- VMOV %VEC(5), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 5)(%rsp)
- VMOV %VEC(6), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 6)(%rsp)
- VMOV %VEC(7), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 7)(%rsp)
-#ifndef __ILP32__
- # We also have to preserve bound registers. These are nops if
- # Intel MPX isn't available or disabled.
-# ifdef HAVE_MPX_SUPPORT
- bndmov %bnd0, REGISTER_SAVE_BND0(%rsp)
- bndmov %bnd1, REGISTER_SAVE_BND1(%rsp)
- bndmov %bnd2, REGISTER_SAVE_BND2(%rsp)
- bndmov %bnd3, REGISTER_SAVE_BND3(%rsp)
+# ifdef USE_FXSAVE
+ fxsave STATE_SAVE_OFFSET(%rsp)
# else
-# if REGISTER_SAVE_BND0 == 0
- .byte 0x66,0x0f,0x1b,0x04,0x24
+ movl $STATE_SAVE_MASK, %eax
+ xorl %edx, %edx
+ # Clear the XSAVE Header.
+# ifdef USE_XSAVE
+ movq %rdx, (STATE_SAVE_OFFSET + 512)(%rsp)
+ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8)(%rsp)
+# endif
+ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 2)(%rsp)
+ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 3)(%rsp)
+ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 4)(%rsp)
+ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 5)(%rsp)
+ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 6)(%rsp)
+ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 7)(%rsp)
+# ifdef USE_XSAVE
+ xsave STATE_SAVE_OFFSET(%rsp)
# else
- .byte 0x66,0x0f,0x1b,0x44,0x24,REGISTER_SAVE_BND0
+ xsavec STATE_SAVE_OFFSET(%rsp)
# endif
- .byte 0x66,0x0f,0x1b,0x4c,0x24,REGISTER_SAVE_BND1
- .byte 0x66,0x0f,0x1b,0x54,0x24,REGISTER_SAVE_BND2
- .byte 0x66,0x0f,0x1b,0x5c,0x24,REGISTER_SAVE_BND3
# endif
-#endif
# Copy args pushed by PLT in register.
# %rdi: link_map, %rsi: reloc_index
mov (LOCAL_STORAGE_AREA + 8)(%BASE), %RSI_LP
mov LOCAL_STORAGE_AREA(%BASE), %RDI_LP
call _dl_fixup # Call resolver.
mov %RAX_LP, %R11_LP # Save return value
-#ifndef __ILP32__
- # Restore bound registers. These are nops if Intel MPX isn't
- # avaiable or disabled.
-# ifdef HAVE_MPX_SUPPORT
- bndmov REGISTER_SAVE_BND3(%rsp), %bnd3
- bndmov REGISTER_SAVE_BND2(%rsp), %bnd2
- bndmov REGISTER_SAVE_BND1(%rsp), %bnd1
- bndmov REGISTER_SAVE_BND0(%rsp), %bnd0
+ # Get register content back.
+# ifdef USE_FXSAVE
+ fxrstor STATE_SAVE_OFFSET(%rsp)
# else
- .byte 0x66,0x0f,0x1a,0x5c,0x24,REGISTER_SAVE_BND3
- .byte 0x66,0x0f,0x1a,0x54,0x24,REGISTER_SAVE_BND2
- .byte 0x66,0x0f,0x1a,0x4c,0x24,REGISTER_SAVE_BND1
-# if REGISTER_SAVE_BND0 == 0
- .byte 0x66,0x0f,0x1a,0x04,0x24
-# else
- .byte 0x66,0x0f,0x1a,0x44,0x24,REGISTER_SAVE_BND0
-# endif
+ movl $STATE_SAVE_MASK, %eax
+ xorl %edx, %edx
+ xrstor STATE_SAVE_OFFSET(%rsp)
# endif
-#endif
- # Get register content back.
movq REGISTER_SAVE_R9(%rsp), %r9
movq REGISTER_SAVE_R8(%rsp), %r8
movq REGISTER_SAVE_RDI(%rsp), %rdi
@@ -238,20 +139,12 @@ _dl_runtime_resolve:
movq REGISTER_SAVE_RDX(%rsp), %rdx
movq REGISTER_SAVE_RCX(%rsp), %rcx
movq REGISTER_SAVE_RAX(%rsp), %rax
- VMOV (REGISTER_SAVE_VEC_OFF)(%rsp), %VEC(0)
- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE)(%rsp), %VEC(1)
- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 2)(%rsp), %VEC(2)
- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 3)(%rsp), %VEC(3)
- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 4)(%rsp), %VEC(4)
- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 5)(%rsp), %VEC(5)
- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 6)(%rsp), %VEC(6)
- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 7)(%rsp), %VEC(7)
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK
+# if DL_RUNTIME_RESOLVE_REALIGN_STACK
mov %RBX_LP, %RSP_LP
cfi_def_cfa_register(%rsp)
movq (%rsp), %rbx
cfi_restore(%rbx)
-#endif
+# endif
# Adjust stack(PLT did 2 pushes)
add $(LOCAL_STORAGE_AREA + 16), %RSP_LP
cfi_adjust_cfa_offset(-(LOCAL_STORAGE_AREA + 16))
@@ -260,11 +153,9 @@ _dl_runtime_resolve:
jmp *%r11 # Jump to function address.
cfi_endproc
.size _dl_runtime_resolve, .-_dl_runtime_resolve
+#endif
-/* To preserve %xmm0 - %xmm7 registers, dl-trampoline.h is included
- twice, for _dl_runtime_resolve_sse and _dl_runtime_resolve_sse_vex.
- But we don't need another _dl_runtime_profile for XMM registers. */
#if !defined PROF && defined _dl_runtime_profile
# if (LR_VECTOR_OFFSET % VEC_SIZE) != 0
# error LR_VECTOR_OFFSET must be multples of VEC_SIZE
diff --git a/sysdeps/x86_64/rtld-offsets.sym b/sysdeps/x86_64/rtld-offsets.sym
new file mode 100644
index 0000000000..fd41b51521
--- /dev/null
+++ b/sysdeps/x86_64/rtld-offsets.sym
@@ -0,0 +1,6 @@
+#define SHARED
+#include <ldsodefs.h>
+
+--
+
+GL_TLS_GENERATION_OFFSET offsetof (struct rtld_global, _dl_tls_generation)
diff --git a/sysdeps/x86_64/tls_get_addr.S b/sysdeps/x86_64/tls_get_addr.S
new file mode 100644
index 0000000000..9d38fb3be5
--- /dev/null
+++ b/sysdeps/x86_64/tls_get_addr.S
@@ -0,0 +1,61 @@
+/* Stack-aligning implementation of __tls_get_addr. x86-64 version.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef SHARED
+
+# include <sysdep.h>
+# include "tlsdesc.h"
+# include "rtld-offsets.h"
+
+/* See __tls_get_addr and __tls_get_addr_slow in dl-tls.c. This function
+ call __tls_get_addr_slow on both slow paths. It realigns the stack
+ before the call to work around GCC PR58066. */
+
+ENTRY (__tls_get_addr)
+ mov %fs:DTV_OFFSET, %RDX_LP
+ mov GL_TLS_GENERATION_OFFSET+_rtld_local(%rip), %RAX_LP
+ /* GL(dl_tls_generation) == dtv[0].counter */
+ cmp %RAX_LP, (%rdx)
+ jne 1f
+ mov TI_MODULE_OFFSET(%rdi), %RAX_LP
+ /* dtv[ti->ti_module] */
+# ifdef __LP64__
+ salq $4, %rax
+ movq (%rdx,%rax), %rax
+# else
+ movl (%rdx,%rax, 8), %eax
+# endif
+ cmp $-1, %RAX_LP
+ je 1f
+ add TI_OFFSET_OFFSET(%rdi), %RAX_LP
+ ret
+1:
+ /* On the slow path, align the stack. */
+ pushq %rbp
+ cfi_def_cfa_offset (16)
+ cfi_offset (%rbp, -16)
+ mov %RSP_LP, %RBP_LP
+ cfi_def_cfa_register (%rbp)
+ and $-16, %RSP_LP
+ call __tls_get_addr_slow
+ mov %RBP_LP, %RSP_LP
+ popq %rbp
+ cfi_def_cfa (%rsp, 8)
+ ret
+END (__tls_get_addr)
+#endif /* SHARED */
diff --git a/sysdeps/x86_64/tlsdesc.sym b/sysdeps/x86_64/tlsdesc.sym
index 33854975d0..fc897ab4b5 100644
--- a/sysdeps/x86_64/tlsdesc.sym
+++ b/sysdeps/x86_64/tlsdesc.sym
@@ -15,3 +15,6 @@ TLSDESC_ARG offsetof(struct tlsdesc, arg)
TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count)
TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module)
TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset)
+
+TI_MODULE_OFFSET offsetof(tls_index, ti_module)
+TI_OFFSET_OFFSET offsetof(tls_index, ti_offset)
diff --git a/sysdeps/x86_64/tst-avx-aux.c b/sysdeps/x86_64/tst-avx-aux.c
new file mode 100644
index 0000000000..e3807de7bb
--- /dev/null
+++ b/sysdeps/x86_64/tst-avx-aux.c
@@ -0,0 +1,47 @@
+/* Test case for preserved AVX registers in dynamic linker, -mavx part.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <immintrin.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+tst_avx_aux (void)
+{
+#ifdef __AVX__
+ extern __m256i avx_test (__m256i, __m256i, __m256i, __m256i,
+ __m256i, __m256i, __m256i, __m256i);
+
+ __m256i ymm0 = _mm256_set1_epi32 (0);
+ __m256i ymm1 = _mm256_set1_epi32 (1);
+ __m256i ymm2 = _mm256_set1_epi32 (2);
+ __m256i ymm3 = _mm256_set1_epi32 (3);
+ __m256i ymm4 = _mm256_set1_epi32 (4);
+ __m256i ymm5 = _mm256_set1_epi32 (5);
+ __m256i ymm6 = _mm256_set1_epi32 (6);
+ __m256i ymm7 = _mm256_set1_epi32 (7);
+ __m256i ret = avx_test (ymm0, ymm1, ymm2, ymm3,
+ ymm4, ymm5, ymm6, ymm7);
+ ymm0 = _mm256_set1_epi32 (0x12349876);
+ if (memcmp (&ymm0, &ret, sizeof (ret)))
+ abort ();
+ return 0;
+#else /* __AVX__ */
+ return 77;
+#endif /* __AVX__ */
+}
diff --git a/sysdeps/x86_64/tst-avx.c b/sysdeps/x86_64/tst-avx.c
new file mode 100644
index 0000000000..ec2e3a79ff
--- /dev/null
+++ b/sysdeps/x86_64/tst-avx.c
@@ -0,0 +1,49 @@
+/* Test case for preserved AVX registers in dynamic linker.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <cpuid.h>
+
+int tst_avx_aux (void);
+
+static int
+avx_enabled (void)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ if (__get_cpuid (1, &eax, &ebx, &ecx, &edx) == 0
+ || (ecx & (bit_AVX | bit_OSXSAVE)) != (bit_AVX | bit_OSXSAVE))
+ return 0;
+
+ /* Check the OS has AVX and SSE saving enabled. */
+ asm ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0));
+
+ return (eax & 6) == 6;
+}
+
+static int
+do_test (void)
+{
+ /* Run AVX test only if AVX is supported. */
+ if (avx_enabled ())
+ return tst_avx_aux ();
+ else
+ return 77;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../../test-skeleton.c"
diff --git a/sysdeps/x86_64/tst-avx512-aux.c b/sysdeps/x86_64/tst-avx512-aux.c
new file mode 100644
index 0000000000..6cebc523f2
--- /dev/null
+++ b/sysdeps/x86_64/tst-avx512-aux.c
@@ -0,0 +1,48 @@
+/* Test case for preserved AVX512 registers in dynamic linker,
+ -mavx512 part.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <immintrin.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+tst_avx512_aux (void)
+{
+#ifdef __AVX512F__
+ extern __m512i avx512_test (__m512i, __m512i, __m512i, __m512i,
+ __m512i, __m512i, __m512i, __m512i);
+
+ __m512i zmm0 = _mm512_set1_epi32 (0);
+ __m512i zmm1 = _mm512_set1_epi32 (1);
+ __m512i zmm2 = _mm512_set1_epi32 (2);
+ __m512i zmm3 = _mm512_set1_epi32 (3);
+ __m512i zmm4 = _mm512_set1_epi32 (4);
+ __m512i zmm5 = _mm512_set1_epi32 (5);
+ __m512i zmm6 = _mm512_set1_epi32 (6);
+ __m512i zmm7 = _mm512_set1_epi32 (7);
+ __m512i ret = avx512_test (zmm0, zmm1, zmm2, zmm3,
+ zmm4, zmm5, zmm6, zmm7);
+ zmm0 = _mm512_set1_epi32 (0x12349876);
+ if (memcmp (&zmm0, &ret, sizeof (ret)))
+ abort ();
+ return 0;
+#else /* __AVX512F__ */
+ return 77;
+#endif /* __AVX512F__ */
+}
diff --git a/sysdeps/x86_64/tst-avx512.c b/sysdeps/x86_64/tst-avx512.c
new file mode 100644
index 0000000000..a8e42ef553
--- /dev/null
+++ b/sysdeps/x86_64/tst-avx512.c
@@ -0,0 +1,57 @@
+/* Test case for preserved AVX512 registers in dynamic linker.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <cpuid.h>
+
+int tst_avx512_aux (void);
+
+static int
+avx512_enabled (void)
+{
+#ifdef bit_AVX512F
+ unsigned int eax, ebx, ecx, edx;
+
+ if (__get_cpuid (1, &eax, &ebx, &ecx, &edx) == 0
+ || (ecx & (bit_AVX | bit_OSXSAVE)) != (bit_AVX | bit_OSXSAVE))
+ return 0;
+
+ __cpuid_count (7, 0, eax, ebx, ecx, edx);
+ if (!(ebx & bit_AVX512F))
+ return 0;
+
+ asm ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0));
+
+ /* Verify that ZMM, YMM and XMM states are enabled. */
+ return (eax & 0xe6) == 0xe6;
+#else
+ return 0;
+#endif
+}
+
+static int
+do_test (void)
+{
+ /* Run AVX512 test only if AVX512 is supported. */
+ if (avx512_enabled ())
+ return tst_avx512_aux ();
+ else
+ return 77;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../../test-skeleton.c"
diff --git a/sysdeps/x86_64/tst-avx512mod.c b/sysdeps/x86_64/tst-avx512mod.c
new file mode 100644
index 0000000000..4cfb3a2c3d
--- /dev/null
+++ b/sysdeps/x86_64/tst-avx512mod.c
@@ -0,0 +1,48 @@
+/* Test case for x86-64 preserved AVX512 registers in dynamic linker. */
+
+#ifdef __AVX512F__
+#include <stdlib.h>
+#include <string.h>
+#include <immintrin.h>
+
+__m512i
+avx512_test (__m512i x0, __m512i x1, __m512i x2, __m512i x3,
+ __m512i x4, __m512i x5, __m512i x6, __m512i x7)
+{
+ __m512i zmm;
+
+ zmm = _mm512_set1_epi32 (0);
+ if (memcmp (&zmm, &x0, sizeof (zmm)))
+ abort ();
+
+ zmm = _mm512_set1_epi32 (1);
+ if (memcmp (&zmm, &x1, sizeof (zmm)))
+ abort ();
+
+ zmm = _mm512_set1_epi32 (2);
+ if (memcmp (&zmm, &x2, sizeof (zmm)))
+ abort ();
+
+ zmm = _mm512_set1_epi32 (3);
+ if (memcmp (&zmm, &x3, sizeof (zmm)))
+ abort ();
+
+ zmm = _mm512_set1_epi32 (4);
+ if (memcmp (&zmm, &x4, sizeof (zmm)))
+ abort ();
+
+ zmm = _mm512_set1_epi32 (5);
+ if (memcmp (&zmm, &x5, sizeof (zmm)))
+ abort ();
+
+ zmm = _mm512_set1_epi32 (6);
+ if (memcmp (&zmm, &x6, sizeof (zmm)))
+ abort ();
+
+ zmm = _mm512_set1_epi32 (7);
+ if (memcmp (&zmm, &x7, sizeof (zmm)))
+ abort ();
+
+ return _mm512_set1_epi32 (0x12349876);
+}
+#endif
diff --git a/sysdeps/x86_64/tst-avxmod.c b/sysdeps/x86_64/tst-avxmod.c
new file mode 100644
index 0000000000..6e5b154997
--- /dev/null
+++ b/sysdeps/x86_64/tst-avxmod.c
@@ -0,0 +1,48 @@
+/* Test case for x86-64 preserved AVX registers in dynamic linker. */
+
+#ifdef __AVX__
+#include <stdlib.h>
+#include <string.h>
+#include <immintrin.h>
+
+__m256i
+avx_test (__m256i x0, __m256i x1, __m256i x2, __m256i x3,
+ __m256i x4, __m256i x5, __m256i x6, __m256i x7)
+{
+ __m256i ymm;
+
+ ymm = _mm256_set1_epi32 (0);
+ if (memcmp (&ymm, &x0, sizeof (ymm)))
+ abort ();
+
+ ymm = _mm256_set1_epi32 (1);
+ if (memcmp (&ymm, &x1, sizeof (ymm)))
+ abort ();
+
+ ymm = _mm256_set1_epi32 (2);
+ if (memcmp (&ymm, &x2, sizeof (ymm)))
+ abort ();
+
+ ymm = _mm256_set1_epi32 (3);
+ if (memcmp (&ymm, &x3, sizeof (ymm)))
+ abort ();
+
+ ymm = _mm256_set1_epi32 (4);
+ if (memcmp (&ymm, &x4, sizeof (ymm)))
+ abort ();
+
+ ymm = _mm256_set1_epi32 (5);
+ if (memcmp (&ymm, &x5, sizeof (ymm)))
+ abort ();
+
+ ymm = _mm256_set1_epi32 (6);
+ if (memcmp (&ymm, &x6, sizeof (ymm)))
+ abort ();
+
+ ymm = _mm256_set1_epi32 (7);
+ if (memcmp (&ymm, &x7, sizeof (ymm)))
+ abort ();
+
+ return _mm256_set1_epi32 (0x12349876);
+}
+#endif
diff --git a/sysdeps/x86_64/tst-sse.c b/sysdeps/x86_64/tst-sse.c
new file mode 100644
index 0000000000..dd1537cf27
--- /dev/null
+++ b/sysdeps/x86_64/tst-sse.c
@@ -0,0 +1,46 @@
+/* Test case for preserved SSE registers in dynamic linker.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <immintrin.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern __m128i sse_test (__m128i, __m128i, __m128i, __m128i,
+ __m128i, __m128i, __m128i, __m128i);
+
+static int
+do_test (void)
+{
+ __m128i xmm0 = _mm_set1_epi32 (0);
+ __m128i xmm1 = _mm_set1_epi32 (1);
+ __m128i xmm2 = _mm_set1_epi32 (2);
+ __m128i xmm3 = _mm_set1_epi32 (3);
+ __m128i xmm4 = _mm_set1_epi32 (4);
+ __m128i xmm5 = _mm_set1_epi32 (5);
+ __m128i xmm6 = _mm_set1_epi32 (6);
+ __m128i xmm7 = _mm_set1_epi32 (7);
+ __m128i ret = sse_test (xmm0, xmm1, xmm2, xmm3,
+ xmm4, xmm5, xmm6, xmm7);
+ xmm0 = _mm_set1_epi32 (0x12349876);
+ if (memcmp (&xmm0, &ret, sizeof (ret)))
+ abort ();
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../../test-skeleton.c"
diff --git a/sysdeps/x86_64/tst-ssemod.c b/sysdeps/x86_64/tst-ssemod.c
new file mode 100644
index 0000000000..907a64c69e
--- /dev/null
+++ b/sysdeps/x86_64/tst-ssemod.c
@@ -0,0 +1,46 @@
+/* Test case for x86-64 preserved SSE registers in dynamic linker. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <immintrin.h>
+
+__m128i
+sse_test (__m128i x0, __m128i x1, __m128i x2, __m128i x3,
+ __m128i x4, __m128i x5, __m128i x6, __m128i x7)
+{
+ __m128i xmm;
+
+ xmm = _mm_set1_epi32 (0);
+ if (memcmp (&xmm, &x0, sizeof (xmm)))
+ abort ();
+
+ xmm = _mm_set1_epi32 (1);
+ if (memcmp (&xmm, &x1, sizeof (xmm)))
+ abort ();
+
+ xmm = _mm_set1_epi32 (2);
+ if (memcmp (&xmm, &x2, sizeof (xmm)))
+ abort ();
+
+ xmm = _mm_set1_epi32 (3);
+ if (memcmp (&xmm, &x3, sizeof (xmm)))
+ abort ();
+
+ xmm = _mm_set1_epi32 (4);
+ if (memcmp (&xmm, &x4, sizeof (xmm)))
+ abort ();
+
+ xmm = _mm_set1_epi32 (5);
+ if (memcmp (&xmm, &x5, sizeof (xmm)))
+ abort ();
+
+ xmm = _mm_set1_epi32 (6);
+ if (memcmp (&xmm, &x6, sizeof (xmm)))
+ abort ();
+
+ xmm = _mm_set1_epi32 (7);
+ if (memcmp (&xmm, &x7, sizeof (xmm)))
+ abort ();
+
+ return _mm_set1_epi32 (0x12349876);
+}