d8307d
commit bc79db3fd487daea36e7c130f943cfb9826a41b4
d8307d
Author: Stefan Liebler <stli@linux.ibm.com>
d8307d
Date:   Wed Feb 6 09:06:34 2019 +0100
d8307d
d8307d
    Fix alignment of TLS variables for tls variant TLS_TCB_AT_TP [BZ #23403]
d8307d
    
d8307d
    The alignment of TLS variables is wrong if accessed from within a thread
d8307d
    for architectures with tls variant TLS_TCB_AT_TP.
d8307d
    For the main thread the static tls data is properly aligned.
d8307d
    For other threads the alignment depends on the alignment of the thread
d8307d
    pointer as the static tls data is located relative to this pointer.
d8307d
    
d8307d
    This patch adds this alignment for TLS_TCB_AT_TP variants in the same way
d8307d
    as it is already done for TLS_DTV_AT_TP. The thread pointer is also already
d8307d
    properly aligned if the user provides its own stack for the new thread.
d8307d
    
d8307d
    This patch extends the testcase nptl/tst-tls1.c in order to check the
d8307d
    alignment of the tls variables and it adds a pthread_create invocation
d8307d
    with a user provided stack.
d8307d
    The test itself is migrated from test-skeleton.c to test-driver.c
d8307d
    and the missing support functions xpthread_attr_setstack and xposix_memalign
d8307d
    are added.
d8307d
    
d8307d
    ChangeLog:
d8307d
    
d8307d
            [BZ #23403]
d8307d
            * nptl/allocatestack.c (allocate_stack): Align pointer pd for
d8307d
            TLS_TCB_AT_TP tls variant.
d8307d
            * nptl/tst-tls1.c: Migrate to support/test-driver.c.
d8307d
            Add alignment checks.
d8307d
            * support/Makefile (libsupport-routines): Add xposix_memalign and
d8307d
            xpthread_setstack.
d8307d
            * support/support.h: Add xposix_memalign.
d8307d
            * support/xthread.h: Add xpthread_attr_setstack.
d8307d
            * support/xposix_memalign.c: New File.
d8307d
            * support/xpthread_attr_setstack.c: Likewise.
d8307d
d8307d
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
d8307d
index 670cb8ffe6..590350647b 100644
d8307d
--- a/nptl/allocatestack.c
d8307d
+++ b/nptl/allocatestack.c
d8307d
@@ -572,7 +572,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
d8307d
 
d8307d
 	  /* Place the thread descriptor at the end of the stack.  */
d8307d
 #if TLS_TCB_AT_TP
d8307d
-	  pd = (struct pthread *) ((char *) mem + size) - 1;
d8307d
+	  pd = (struct pthread *) ((((uintptr_t) mem + size)
d8307d
+				    - TLS_TCB_SIZE)
d8307d
+				   & ~__static_tls_align_m1);
d8307d
 #elif TLS_DTV_AT_TP
d8307d
 	  pd = (struct pthread *) ((((uintptr_t) mem + size
d8307d
 				    - __static_tls_size)
d8307d
diff --git a/nptl/tst-tls1.c b/nptl/tst-tls1.c
d8307d
index 00489e23e9..1a915224a7 100644
d8307d
--- a/nptl/tst-tls1.c
d8307d
+++ b/nptl/tst-tls1.c
d8307d
@@ -19,12 +19,16 @@
d8307d
 #include <pthread.h>
d8307d
 #include <stdio.h>
d8307d
 #include <stdlib.h>
d8307d
-
d8307d
+#include <stdint.h>
d8307d
+#include <inttypes.h>
d8307d
+#include <support/support.h>
d8307d
+#include <support/check.h>
d8307d
+#include <support/xthread.h>
d8307d
 
d8307d
 struct test_s
d8307d
 {
d8307d
-  int a;
d8307d
-  int b;
d8307d
+  __attribute__ ((aligned(0x20))) int a;
d8307d
+  __attribute__ ((aligned(0x200))) int b;
d8307d
 };
d8307d
 
d8307d
 #define INIT_A 1
d8307d
@@ -36,15 +40,34 @@ __thread struct test_s s __attribute__ ((tls_model ("initial-exec"))) =
d8307d
   .b = INIT_B
d8307d
 };
d8307d
 
d8307d
+/* Use noinline in combination with not static to ensure that the
d8307d
+   alignment check is really done.  Otherwise it was optimized out!  */
d8307d
+__attribute__ ((noinline)) void
d8307d
+check_alignment (const char *thr_name, const char *ptr_name,
d8307d
+		 int *ptr, int alignment)
d8307d
+{
d8307d
+  uintptr_t offset_aligment = ((uintptr_t) ptr) & (alignment - 1);
d8307d
+  if (offset_aligment)
d8307d
+    {
d8307d
+      FAIL_EXIT1 ("%s (%p) is not 0x%x-byte aligned in %s thread\n",
d8307d
+		  ptr_name, ptr, alignment, thr_name);
d8307d
+    }
d8307d
+}
d8307d
+
d8307d
+static void
d8307d
+check_s (const char *thr_name)
d8307d
+{
d8307d
+  if (s.a != INIT_A || s.b != INIT_B)
d8307d
+    FAIL_EXIT1 ("initial value of s in %s thread wrong\n", thr_name);
d8307d
+
d8307d
+  check_alignment (thr_name, "s.a", &s.a, 0x20);
d8307d
+  check_alignment (thr_name, "s.b", &s.b, 0x200);
d8307d
+}
d8307d
 
d8307d
 static void *
d8307d
 tf (void *arg)
d8307d
 {
d8307d
-  if (s.a != INIT_A || s.b != INIT_B)
d8307d
-    {
d8307d
-      puts ("initial value of s in child thread wrong");
d8307d
-      exit (1);
d8307d
-    }
d8307d
+  check_s ("child");
d8307d
 
d8307d
   ++s.a;
d8307d
 
d8307d
@@ -55,25 +78,14 @@ tf (void *arg)
d8307d
 int
d8307d
 do_test (void)
d8307d
 {
d8307d
-  if (s.a != INIT_A || s.b != INIT_B)
d8307d
-    {
d8307d
-      puts ("initial value of s in main thread wrong");
d8307d
-      exit (1);
d8307d
-    }
d8307d
+  check_s ("main");
d8307d
 
d8307d
   pthread_attr_t a;
d8307d
 
d8307d
-  if (pthread_attr_init (&a) != 0)
d8307d
-    {
d8307d
-      puts ("attr_init failed");
d8307d
-      exit (1);
d8307d
-    }
d8307d
+  xpthread_attr_init (&a);
d8307d
 
d8307d
-  if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
d8307d
-    {
d8307d
-      puts ("attr_setstacksize failed");
d8307d
-      return 1;
d8307d
-    }
d8307d
+#define STACK_SIZE (1 * 1024 * 1024)
d8307d
+  xpthread_attr_setstacksize (&a, STACK_SIZE);
d8307d
 
d8307d
 #define N 10
d8307d
   int i;
d8307d
@@ -83,29 +95,25 @@ do_test (void)
d8307d
       pthread_t th[M];
d8307d
       int j;
d8307d
       for (j = 0; j < M; ++j, ++s.a)
d8307d
-	if (pthread_create (&th[j], &a, tf, NULL) != 0)
d8307d
-	  {
d8307d
-	    puts ("pthread_create failed");
d8307d
-	    exit (1);
d8307d
-	  }
d8307d
+	th[j] = xpthread_create (&a, tf, NULL);
d8307d
 
d8307d
       for (j = 0; j < M; ++j)
d8307d
-	if (pthread_join (th[j], NULL) != 0)
d8307d
-	  {
d8307d
-	    puts ("pthread_join failed");
d8307d
-	    exit (1);
d8307d
-	  }
d8307d
+	xpthread_join (th[j]);
d8307d
     }
d8307d
 
d8307d
-  if (pthread_attr_destroy (&a) != 0)
d8307d
-    {
d8307d
-      puts ("attr_destroy failed");
d8307d
-      exit (1);
d8307d
-    }
d8307d
+  /* Also check the alignment of the tls variables if a misaligned stack is
d8307d
+     specified.  */
d8307d
+  pthread_t th;
d8307d
+  void *thr_stack = NULL;
d8307d
+  thr_stack = xposix_memalign (0x200, STACK_SIZE + 1);
d8307d
+  xpthread_attr_setstack (&a, thr_stack + 1, STACK_SIZE);
d8307d
+  th = xpthread_create (&a, tf, NULL);
d8307d
+  xpthread_join (th);
d8307d
+  free (thr_stack);
d8307d
+
d8307d
+  xpthread_attr_destroy (&a);
d8307d
 
d8307d
   return 0;
d8307d
 }
d8307d
 
d8307d
-
d8307d
-#define TEST_FUNCTION do_test ()
d8307d
-#include "../test-skeleton.c"
d8307d
+#include <support/test-driver.c>
d8307d
diff --git a/support/Makefile b/support/Makefile
d8307d
index c15b93647c..9ff0ec3fff 100644
d8307d
--- a/support/Makefile
d8307d
+++ b/support/Makefile
d8307d
@@ -99,10 +99,12 @@ libsupport-routines = \
d8307d
   xopen \
d8307d
   xpipe \
d8307d
   xpoll \
d8307d
+  xposix_memalign \
d8307d
   xpthread_attr_destroy \
d8307d
   xpthread_attr_init \
d8307d
   xpthread_attr_setdetachstate \
d8307d
   xpthread_attr_setguardsize \
d8307d
+  xpthread_attr_setstack \
d8307d
   xpthread_attr_setstacksize \
d8307d
   xpthread_barrier_destroy \
d8307d
   xpthread_barrier_init \
d8307d
diff --git a/support/support.h b/support/support.h
d8307d
index 119495e5a9..97fef2cd23 100644
d8307d
--- a/support/support.h
d8307d
+++ b/support/support.h
d8307d
@@ -86,6 +86,7 @@ int support_descriptor_supports_holes (int fd);
d8307d
 void *xmalloc (size_t) __attribute__ ((malloc));
d8307d
 void *xcalloc (size_t n, size_t s) __attribute__ ((malloc));
d8307d
 void *xrealloc (void *p, size_t n);
d8307d
+void *xposix_memalign (size_t alignment, size_t n);
d8307d
 char *xasprintf (const char *format, ...)
d8307d
   __attribute__ ((format (printf, 1, 2), malloc));
d8307d
 char *xstrdup (const char *);
d8307d
diff --git a/support/xposix_memalign.c b/support/xposix_memalign.c
d8307d
new file mode 100644
d8307d
index 0000000000..5501a0846a
d8307d
--- /dev/null
d8307d
+++ b/support/xposix_memalign.c
d8307d
@@ -0,0 +1,35 @@
d8307d
+/* Error-checking wrapper for posix_memalign.
d8307d
+   Copyright (C) 2019 Free Software Foundation, Inc.
d8307d
+   This file is part of the GNU C Library.
d8307d
+
d8307d
+   The GNU C Library is free software; you can redistribute it and/or
d8307d
+   modify it under the terms of the GNU Lesser General Public
d8307d
+   License as published by the Free Software Foundation; either
d8307d
+   version 2.1 of the License, or (at your option) any later version.
d8307d
+
d8307d
+   The GNU C Library is distributed in the hope that it will be useful,
d8307d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
d8307d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
d8307d
+   Lesser General Public License for more details.
d8307d
+
d8307d
+   You should have received a copy of the GNU Lesser General Public
d8307d
+   License along with the GNU C Library; if not, see
d8307d
+   <http://www.gnu.org/licenses/>.  */
d8307d
+
d8307d
+#include <support/support.h>
d8307d
+#include <stdlib.h>
d8307d
+#include <errno.h>
d8307d
+
d8307d
+void *
d8307d
+xposix_memalign (size_t alignment, size_t n)
d8307d
+{
d8307d
+  void *p = NULL;
d8307d
+
d8307d
+  int ret = posix_memalign (&p, alignment, n);
d8307d
+  if (ret)
d8307d
+    {
d8307d
+      errno = ret;
d8307d
+      oom_error ("posix_memalign", n);
d8307d
+    }
d8307d
+  return p;
d8307d
+}
d8307d
diff --git a/support/xpthread_attr_setstack.c b/support/xpthread_attr_setstack.c
d8307d
new file mode 100644
d8307d
index 0000000000..c3772e240b
d8307d
--- /dev/null
d8307d
+++ b/support/xpthread_attr_setstack.c
d8307d
@@ -0,0 +1,26 @@
d8307d
+/* pthread_attr_setstack with error checking.
d8307d
+   Copyright (C) 2019 Free Software Foundation, Inc.
d8307d
+   This file is part of the GNU C Library.
d8307d
+
d8307d
+   The GNU C Library is free software; you can redistribute it and/or
d8307d
+   modify it under the terms of the GNU Lesser General Public
d8307d
+   License as published by the Free Software Foundation; either
d8307d
+   version 2.1 of the License, or (at your option) any later version.
d8307d
+
d8307d
+   The GNU C Library is distributed in the hope that it will be useful,
d8307d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
d8307d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
d8307d
+   Lesser General Public License for more details.
d8307d
+
d8307d
+   You should have received a copy of the GNU Lesser General Public
d8307d
+   License along with the GNU C Library; if not, see
d8307d
+   <http://www.gnu.org/licenses/>.  */
d8307d
+
d8307d
+#include <support/xthread.h>
d8307d
+
d8307d
+void
d8307d
+xpthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, size_t stacksize)
d8307d
+{
d8307d
+  xpthread_check_return ("pthread_attr_setstack",
d8307d
+			 pthread_attr_setstack (attr, stackaddr, stacksize));
d8307d
+}
d8307d
diff --git a/support/xthread.h b/support/xthread.h
d8307d
index 9fe1f68b3b..5204f78ed2 100644
d8307d
--- a/support/xthread.h
d8307d
+++ b/support/xthread.h
d8307d
@@ -68,6 +68,8 @@ void xpthread_attr_destroy (pthread_attr_t *attr);
d8307d
 void xpthread_attr_init (pthread_attr_t *attr);
d8307d
 void xpthread_attr_setdetachstate (pthread_attr_t *attr,
d8307d
 				   int detachstate);
d8307d
+void xpthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
d8307d
+			     size_t stacksize);
d8307d
 void xpthread_attr_setstacksize (pthread_attr_t *attr,
d8307d
 				 size_t stacksize);
d8307d
 void xpthread_attr_setguardsize (pthread_attr_t *attr,