From patchwork Tue Nov 17 16:51:20 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Szabolcs Nagy X-Patchwork-Id: 9706 Received: (qmail 122156 invoked by alias); 17 Nov 2015 16:51:27 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 122144 invoked by uid 89); 17 Nov 2015 16:51:27 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.8 required=5.0 tests=AWL, BAYES_00, SPF_PASS autolearn=ham version=3.3.2 X-HELO: eu-smtp-delivery-143.mimecast.com Message-ID: <564B5B08.50205@arm.com> Date: Tue, 17 Nov 2015 16:51:20 +0000 From: Szabolcs Nagy User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.8.0 MIME-Version: 1.0 To: GNU C Library Subject: [PATCH] Test for lazy tls descriptor initialization X-MC-Unique: vHvtVuiURtakszJGJOxufg-1 These tests can trigger BZ 19129, 18572, 18034 with varying reliability. They test concurrent first access of tls objects with internal and external linkage in a dso. The four variants are {static,extern} x 2 alignments. (The tlsdesc race is more likely to trigger when the tls descriptors are not double-word aligned in the .rel.plt section.) I enabled the tests for tlsdesc because that's the only case when first tls access does lazy initialization. There might be a cleaner solution for the -mtls-dialect=... check. Currently I'm looking at disabling lazy symbol binding of tlsdesc, but it's not as trivial as i'd like it to be, in case such patch is accepted then these tests are not useful. ChangeLog: 2015-11-17 Szabolcs Nagy * config.make.in (have-tlsdesc, config-clfags-tlsdesc): New. * configure.ac (libc_cv_tlsdesc, libc_cv_cc_tlsdesc): New. * configure: Regenerated. * elf/Makefile (tests): Add tst-lazytls{1,2,3,4}. (modules-names): Add tst-lazytls{1,2,3,4}mod. ($(objpfx)tst-lazytls{1,2,3,4}): Add dependencies. * elf/tst-lazytls.h: New. * elf/tst-lazytls1.c: New. * elf/tst-lazytls2.c: New. * elf/tst-lazytls3.c: New. * elf/tst-lazytls4.c: New. * elf/tst-lazytls1mod.c: New. * elf/tst-lazytls2mod.c: New. * elf/tst-lazytls3mod.c: New. * elf/tst-lazytls4mod.c: New. diff --git a/config.make.in b/config.make.in index 75bb9cc..09c71fb 100644 --- a/config.make.in +++ b/config.make.in @@ -53,6 +53,8 @@ have-protected-data = @libc_cv_protected_data@ with-fp = @with_fp@ enable-timezone-tools = @enable_timezone_tools@ unwind-find-fde = @libc_cv_gcc_unwind_find_fde@ +have-tlsdesc = @libc_cv_tlsdesc@ +config-cflags-tlsdesc = @libc_cv_cc_tlsdesc@ have-fpie = @libc_cv_fpie@ stack-protector = @stack_protector@ have-selinux = @have_selinux@ diff --git a/configure b/configure index 01f5075..4865e48 100755 --- a/configure +++ b/configure @@ -617,6 +617,8 @@ have_libcap have_libaudit LIBGD libc_cv_cc_loop_to_function +libc_cv_tlsdesc +libc_cv_cc_tlsdesc libc_cv_cc_submachine libc_cv_cc_nofma stack_protector @@ -5929,6 +5931,57 @@ $as_echo "$libc_cv_cc_submachine" >&6; } fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler option to enable TLS descriptors" >&5 +$as_echo_n "checking for compiler option to enable TLS descriptors... " >&6; } +if ${libc_cv_cc_tlsdesc+:} false; then : + $as_echo_n "(cached) " >&6 +else + libc_cv_cc_tlsdesc=-no-tlsdesc-support +for opt in -mtls-dialect=desc -mtls-dialect=gnu2; do + if { ac_try='${CC-cc} $opt -xc /dev/null -S -o /dev/null' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + libc_cv_cc_tlsdesc=$opt; break +fi +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_cc_tlsdesc" >&5 +$as_echo "$libc_cv_cc_tlsdesc" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TLS descriptor support" >&5 +$as_echo_n "checking for TLS descriptor support... " >&6; } +if ${libc_cv_tlsdesc+:} false; then : + $as_echo_n "(cached) " >&6 +else + libc_cv_tlsdesc=no +if test "$libc_cv_cc_tlsdesc" != -no-tlsdesc-support; then +cat > conftest.c <&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + if $READELF -rW conftest.so | grep _TLSDESC > /dev/null; then + libc_cv_tlsdesc=yes + fi + fi +fi +rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_tlsdesc" >&5 +$as_echo "$libc_cv_tlsdesc" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC accepts -fno-tree-loop-distribute-patterns with \ __attribute__ ((__optimize__))" >&5 $as_echo_n "checking if $CC accepts -fno-tree-loop-distribute-patterns with \ diff --git a/configure.ac b/configure.ac index 3fdf992..13f6630 100644 --- a/configure.ac +++ b/configure.ac @@ -1474,6 +1474,32 @@ if test -n "$submachine"; then fi AC_SUBST(libc_cv_cc_submachine) +AC_CACHE_CHECK(for compiler option to enable TLS descriptors, + libc_cv_cc_tlsdesc, [dnl +libc_cv_cc_tlsdesc=-no-tlsdesc-support +for opt in -mtls-dialect=desc -mtls-dialect=gnu2; do + LIBC_TRY_CC_OPTION([$opt], [libc_cv_cc_tlsdesc=$opt; break]) +done]) +AC_SUBST(libc_cv_cc_tlsdesc) + +AC_CACHE_CHECK(for TLS descriptor support, libc_cv_tlsdesc, [dnl +libc_cv_tlsdesc=no +if test "$libc_cv_cc_tlsdesc" != -no-tlsdesc-support; then +cat > conftest.c < /dev/null; then + libc_cv_tlsdesc=yes + fi + fi +fi +rm -f conftest*]) +AC_SUBST(libc_cv_tlsdesc) + AC_CACHE_CHECK(if $CC accepts -fno-tree-loop-distribute-patterns with \ __attribute__ ((__optimize__)), libc_cv_cc_loop_to_function, [dnl cat > conftest.c < /dev/null) ifneq ($(selinux-enabled),1) tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog endif +ifeq ($(have-tlsdesc),yes) +tests += tst-lazytls1 tst-lazytls2 tst-lazytls3 tst-lazytls4 +endif endif ifeq ($(run-built-tests),yes) tests-special += $(objpfx)tst-leaks1-mem.out \ @@ -279,6 +282,10 @@ modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6 endif endif +ifeq ($(have-tlsdesc),yes) +modules-names += tst-lazytls1mod tst-lazytls2mod tst-lazytls3mod tst-lazytls4mod +endif + ifeq (yes,$(build-shared)) ifeq ($(run-built-tests),yes) tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out @@ -1234,3 +1241,15 @@ $(objpfx)tst-audit12: $(libdl) tst-audit12-ENV = LD_AUDIT=$(objpfx)tst-auditmod12.so $(objpfx)tst-audit12mod1.so: $(objpfx)tst-audit12mod2.so LDFLAGS-tst-audit12mod2.so = -Wl,--version-script=tst-audit12mod2.map + +$(objpfx)tst-lazytls1: $(shared-thread-library) $(objpfx)tst-lazytls1mod.so +$(objpfx)tst-lazytls2: $(shared-thread-library) $(objpfx)tst-lazytls2mod.so +$(objpfx)tst-lazytls3: $(shared-thread-library) $(objpfx)tst-lazytls3mod.so +$(objpfx)tst-lazytls4: $(shared-thread-library) $(objpfx)tst-lazytls4mod.so + +ifeq ($(have-tlsdesc),yes) +CFLAGS-tst-lazytls1mod.c += $(config-cflags-tlsdesc) +CFLAGS-tst-lazytls2mod.c += $(config-cflags-tlsdesc) +CFLAGS-tst-lazytls3mod.c += $(config-cflags-tlsdesc) +CFLAGS-tst-lazytls4mod.c += $(config-cflags-tlsdesc) +endif diff --git a/elf/tst-lazytls.h b/elf/tst-lazytls.h new file mode 100644 index 0000000..4067240 --- /dev/null +++ b/elf/tst-lazytls.h @@ -0,0 +1,11 @@ +#define A(n) \ +B(n##0) B(n##1) B(n##2) B(n##3) B(n##4) B(n##5) B(n##6) B(n##7) B(n##8) B(n##9) +#define B(n) \ +T(n##0) T(n##1) T(n##2) T(n##3) T(n##4) T(n##5) T(n##6) T(n##7) T(n##8) T(n##9) + +/* Invoke T 500 times with different arguments. */ +A(0) +A(1) +A(2) +A(3) +A(4) diff --git a/elf/tst-lazytls1.c b/elf/tst-lazytls1.c new file mode 100644 index 0000000..5130277 --- /dev/null +++ b/elf/tst-lazytls1.c @@ -0,0 +1,38 @@ +#include +#include + +static pthread_barrier_t b; + +void * +start (void *a) +{ + pthread_barrier_wait (&b); + +#define T(n) \ + extern void f##n (void); \ + f##n (); + +#include "tst-lazytls.h" + + return 0; +} + +#define NTHREAD 66 + +static int +do_test (void) +{ + pthread_t td[NTHREAD]; + int i; + + assert (pthread_barrier_init (&b, 0, NTHREAD) == 0); + for (i = 0; i < NTHREAD; i++) + assert (pthread_create (td+i, 0, start, 0) == 0); + for (i = 0; i < NTHREAD; i++) + assert (pthread_join (td[i], 0) == 0); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/elf/tst-lazytls1mod.c b/elf/tst-lazytls1mod.c new file mode 100644 index 0000000..b33dcb5 --- /dev/null +++ b/elf/tst-lazytls1mod.c @@ -0,0 +1,17 @@ +int want = 8; + +#ifndef LINKAGE +#define LINKAGE static +#endif + +#define T(n) \ +__attribute__ ((section (".a."#n))) \ +LINKAGE __thread int a##n = 7; \ +\ +void \ +f##n (void) \ +{ \ + if (++a##n != want) __builtin_trap (); \ +} + +#include "tst-lazytls.h" diff --git a/elf/tst-lazytls2.c b/elf/tst-lazytls2.c new file mode 100644 index 0000000..42afb27 --- /dev/null +++ b/elf/tst-lazytls2.c @@ -0,0 +1 @@ +#include "tst-lazytls1.c" diff --git a/elf/tst-lazytls2mod.c b/elf/tst-lazytls2mod.c new file mode 100644 index 0000000..8df3289 --- /dev/null +++ b/elf/tst-lazytls2mod.c @@ -0,0 +1,10 @@ +/* Add an extern call hoping that it adds a relocation entry to .rel.plt + that changes the alignment of the tlsdesc entries. */ +void +unused (void) +{ + extern int puts (const char*); + puts (""); +} + +#include "tst-lazytls1mod.c" diff --git a/elf/tst-lazytls3.c b/elf/tst-lazytls3.c new file mode 100644 index 0000000..42afb27 --- /dev/null +++ b/elf/tst-lazytls3.c @@ -0,0 +1 @@ +#include "tst-lazytls1.c" diff --git a/elf/tst-lazytls3mod.c b/elf/tst-lazytls3mod.c new file mode 100644 index 0000000..7551e42 --- /dev/null +++ b/elf/tst-lazytls3mod.c @@ -0,0 +1,2 @@ +#define LINKAGE +#include "tst-lazytls1mod.c" diff --git a/elf/tst-lazytls4.c b/elf/tst-lazytls4.c new file mode 100644 index 0000000..42afb27 --- /dev/null +++ b/elf/tst-lazytls4.c @@ -0,0 +1 @@ +#include "tst-lazytls1.c" diff --git a/elf/tst-lazytls4mod.c b/elf/tst-lazytls4mod.c new file mode 100644 index 0000000..4d10b29 --- /dev/null +++ b/elf/tst-lazytls4mod.c @@ -0,0 +1,2 @@ +#define LINKAGE +#include "tst-lazytls2mod.c"