Fix alignment of TLS variables for tls variant TLS_TCB_AT_TP [BZ #23403]

The alignment of TLS variables is wrong if accessed from within a thread
for architectures with tls variant TLS_TCB_AT_TP.
For the main thread the static tls data is properly aligned.
For other threads the alignment depends on the alignment of the thread
pointer as the static tls data is located relative to this pointer.

This patch adds this alignment for TLS_TCB_AT_TP variants in the same way
as it is already done for TLS_DTV_AT_TP. The thread pointer is also already
properly aligned if the user provides its own stack for the new thread.

This patch extends the testcase nptl/tst-tls1.c in order to check the
alignment of the tls variables and it adds a pthread_create invocation
with a user provided stack.
The test itself is migrated from test-skeleton.c to test-driver.c
and the missing support functions xpthread_attr_setstack and xposix_memalign
are added.

ChangeLog:

	[BZ #23403]
	* nptl/allocatestack.c (allocate_stack): Align pointer pd for
	TLS_TCB_AT_TP tls variant.
	* nptl/tst-tls1.c: Migrate to support/test-driver.c.
	Add alignment checks.
	* support/Makefile (libsupport-routines): Add xposix_memalign and
	xpthread_setstack.
	* support/support.h: Add xposix_memalign.
	* support/xthread.h: Add xpthread_attr_setstack.
	* support/xposix_memalign.c: New File.
	* support/xpthread_attr_setstack.c: Likewise.

(cherry picked from commit bc79db3fd4)
This commit is contained in:
Stefan Liebler 2019-02-06 09:06:34 +01:00 committed by DJ Delorie
parent fe7c01cb14
commit cedb3e47c6
8 changed files with 132 additions and 42 deletions

View File

@ -1,3 +1,17 @@
2019-02-06 Stefan Liebler <stli@linux.ibm.com>
[BZ #23403]
* nptl/allocatestack.c (allocate_stack): Align pointer pd for
TLS_TCB_AT_TP tls variant.
* nptl/tst-tls1.c: Migrate to support/test-driver.c.
Add alignment checks.
* support/Makefile (libsupport-routines): Add xposix_memalign and
xpthread_setstack.
* support/support.h: Add xposix_memalign.
* support/xthread.h: Add xpthread_attr_setstack.
* support/xposix_memalign.c: New File.
* support/xpthread_attr_setstack.c: Likewise.
2019-06-18 Florian Weimer <fweimer@redhat.com> 2019-06-18 Florian Weimer <fweimer@redhat.com>
[BZ #24323] [BZ #24323]

View File

@ -572,7 +572,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
/* Place the thread descriptor at the end of the stack. */ /* Place the thread descriptor at the end of the stack. */
#if TLS_TCB_AT_TP #if TLS_TCB_AT_TP
pd = (struct pthread *) ((char *) mem + size) - 1; pd = (struct pthread *) ((((uintptr_t) mem + size)
- TLS_TCB_SIZE)
& ~__static_tls_align_m1);
#elif TLS_DTV_AT_TP #elif TLS_DTV_AT_TP
pd = (struct pthread *) ((((uintptr_t) mem + size pd = (struct pthread *) ((((uintptr_t) mem + size
- __static_tls_size) - __static_tls_size)

View File

@ -19,12 +19,16 @@
#include <pthread.h> #include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <support/support.h>
#include <support/check.h>
#include <support/xthread.h>
struct test_s struct test_s
{ {
int a; __attribute__ ((aligned(0x20))) int a;
int b; __attribute__ ((aligned(0x200))) int b;
}; };
#define INIT_A 1 #define INIT_A 1
@ -36,15 +40,34 @@ __thread struct test_s s __attribute__ ((tls_model ("initial-exec"))) =
.b = INIT_B .b = INIT_B
}; };
/* Use noinline in combination with not static to ensure that the
alignment check is really done. Otherwise it was optimized out! */
__attribute__ ((noinline)) void
check_alignment (const char *thr_name, const char *ptr_name,
int *ptr, int alignment)
{
uintptr_t offset_aligment = ((uintptr_t) ptr) & (alignment - 1);
if (offset_aligment)
{
FAIL_EXIT1 ("%s (%p) is not 0x%x-byte aligned in %s thread\n",
ptr_name, ptr, alignment, thr_name);
}
}
static void
check_s (const char *thr_name)
{
if (s.a != INIT_A || s.b != INIT_B)
FAIL_EXIT1 ("initial value of s in %s thread wrong\n", thr_name);
check_alignment (thr_name, "s.a", &s.a, 0x20);
check_alignment (thr_name, "s.b", &s.b, 0x200);
}
static void * static void *
tf (void *arg) tf (void *arg)
{ {
if (s.a != INIT_A || s.b != INIT_B) check_s ("child");
{
puts ("initial value of s in child thread wrong");
exit (1);
}
++s.a; ++s.a;
@ -55,25 +78,14 @@ tf (void *arg)
int int
do_test (void) do_test (void)
{ {
if (s.a != INIT_A || s.b != INIT_B) check_s ("main");
{
puts ("initial value of s in main thread wrong");
exit (1);
}
pthread_attr_t a; pthread_attr_t a;
if (pthread_attr_init (&a) != 0) xpthread_attr_init (&a);
{
puts ("attr_init failed");
exit (1);
}
if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) #define STACK_SIZE (1 * 1024 * 1024)
{ xpthread_attr_setstacksize (&a, STACK_SIZE);
puts ("attr_setstacksize failed");
return 1;
}
#define N 10 #define N 10
int i; int i;
@ -83,29 +95,25 @@ do_test (void)
pthread_t th[M]; pthread_t th[M];
int j; int j;
for (j = 0; j < M; ++j, ++s.a) for (j = 0; j < M; ++j, ++s.a)
if (pthread_create (&th[j], &a, tf, NULL) != 0) th[j] = xpthread_create (&a, tf, NULL);
{
puts ("pthread_create failed");
exit (1);
}
for (j = 0; j < M; ++j) for (j = 0; j < M; ++j)
if (pthread_join (th[j], NULL) != 0) xpthread_join (th[j]);
{
puts ("pthread_join failed");
exit (1);
}
} }
if (pthread_attr_destroy (&a) != 0) /* Also check the alignment of the tls variables if a misaligned stack is
{ specified. */
puts ("attr_destroy failed"); pthread_t th;
exit (1); void *thr_stack = NULL;
} thr_stack = xposix_memalign (0x200, STACK_SIZE + 1);
xpthread_attr_setstack (&a, thr_stack + 1, STACK_SIZE);
th = xpthread_create (&a, tf, NULL);
xpthread_join (th);
free (thr_stack);
xpthread_attr_destroy (&a);
return 0; return 0;
} }
#include <support/test-driver.c>
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -93,10 +93,12 @@ libsupport-routines = \
xopen \ xopen \
xpipe \ xpipe \
xpoll \ xpoll \
xposix_memalign \
xpthread_attr_destroy \ xpthread_attr_destroy \
xpthread_attr_init \ xpthread_attr_init \
xpthread_attr_setdetachstate \ xpthread_attr_setdetachstate \
xpthread_attr_setguardsize \ xpthread_attr_setguardsize \
xpthread_attr_setstack \
xpthread_attr_setstacksize \ xpthread_attr_setstacksize \
xpthread_barrier_destroy \ xpthread_barrier_destroy \
xpthread_barrier_init \ xpthread_barrier_init \

View File

@ -76,6 +76,7 @@ char *support_quote_string (const char *);
void *xmalloc (size_t) __attribute__ ((malloc)); void *xmalloc (size_t) __attribute__ ((malloc));
void *xcalloc (size_t n, size_t s) __attribute__ ((malloc)); void *xcalloc (size_t n, size_t s) __attribute__ ((malloc));
void *xrealloc (void *p, size_t n); void *xrealloc (void *p, size_t n);
void *xposix_memalign (size_t alignment, size_t n);
char *xasprintf (const char *format, ...) char *xasprintf (const char *format, ...)
__attribute__ ((format (printf, 1, 2), malloc)); __attribute__ ((format (printf, 1, 2), malloc));
char *xstrdup (const char *); char *xstrdup (const char *);

35
support/xposix_memalign.c Normal file
View File

@ -0,0 +1,35 @@
/* Error-checking wrapper for posix_memalign.
Copyright (C) 2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <support/support.h>
#include <stdlib.h>
#include <errno.h>
void *
xposix_memalign (size_t alignment, size_t n)
{
void *p = NULL;
int ret = posix_memalign (&p, alignment, n);
if (ret)
{
errno = ret;
oom_error ("posix_memalign", n);
}
return p;
}

View File

@ -0,0 +1,26 @@
/* pthread_attr_setstack with error checking.
Copyright (C) 2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <support/xthread.h>
void
xpthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, size_t stacksize)
{
xpthread_check_return ("pthread_attr_setstack",
pthread_attr_setstack (attr, stackaddr, stacksize));
}

View File

@ -68,6 +68,8 @@ void xpthread_attr_destroy (pthread_attr_t *attr);
void xpthread_attr_init (pthread_attr_t *attr); void xpthread_attr_init (pthread_attr_t *attr);
void xpthread_attr_setdetachstate (pthread_attr_t *attr, void xpthread_attr_setdetachstate (pthread_attr_t *attr,
int detachstate); int detachstate);
void xpthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
size_t stacksize);
void xpthread_attr_setstacksize (pthread_attr_t *attr, void xpthread_attr_setstacksize (pthread_attr_t *attr,
size_t stacksize); size_t stacksize);
void xpthread_attr_setguardsize (pthread_attr_t *attr, void xpthread_attr_setguardsize (pthread_attr_t *attr,