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