This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] Test for lazy tls descriptor initialization
- From: Szabolcs Nagy <szabolcs dot nagy at arm dot com>
- To: GNU C Library <libc-alpha at sourceware dot org>
- Date: Tue, 17 Nov 2015 16:51:20 +0000
- Subject: [PATCH] Test for lazy tls descriptor initialization
- Authentication-results: sourceware.org; auth=none
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 <szabolcs.nagy@arm.com>
* 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 <<EOF
+__thread int bar;
+int foo (void) { return bar; }
+EOF
+ if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
+ -fPIC -shared -o conftest.so conftest.c
+ "$libc_cv_cc_tlsdesc" -nostdlib -nostartfiles'
+ { { 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
+ 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 <<EOF
+__thread int bar;
+int foo (void) { return bar; }
+EOF
+ if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
+ -fPIC -shared -o conftest.so conftest.c
+ "$libc_cv_cc_tlsdesc" -nostdlib -nostartfiles]); then
+ if $READELF -rW conftest.so | grep _TLSDESC > /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 <<EOF
diff --git a/elf/Makefile b/elf/Makefile
index 76985cc..b919531 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -160,6 +160,9 @@ selinux-enabled := $(shell cat /selinux/enforce 2> /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 <pthread.h>
+#include <assert.h>
+
+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"