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