51f0aa
The required TEST_COMPARE and C++ changes are included in the
51f0aa
support/ rebase in glibc-rh1418978-1.patch
51f0aa
51f0aa
commit 579396ee082565ab5f42ff166a264891223b7b82
51f0aa
Author: Florian Weimer <fweimer@redhat.com>
51f0aa
Date:   Mon Jan 8 14:57:25 2018 +0100
51f0aa
51f0aa
    nptl: Add test for callee-saved register restore in pthread_exit
51f0aa
    
51f0aa
    GCC PR 83641 results in a miscompilation of libpthread, which
51f0aa
    causes pthread_exit not to restore callee-saved registers before
51f0aa
    running destructors for objects on the stack.  This test detects
51f0aa
    this situation:
51f0aa
    
51f0aa
    info: unsigned int, direct pthread_exit call
51f0aa
    tst-thread-exit-clobber.cc:80: numeric comparison failure
51f0aa
       left: 4148288912 (0xf741dd90); from: value
51f0aa
      right: 1600833940 (0x5f6ac994); from: magic_values.v2
51f0aa
    info: double, direct pthread_exit call
51f0aa
    info: unsigned int, indirect pthread_exit call
51f0aa
    info: double, indirect pthread_exit call
51f0aa
    error: 1 test failures
51f0aa
51f0aa
Index: glibc-2.17-c758a686/nptl/Makefile
51f0aa
===================================================================
51f0aa
--- glibc-2.17-c758a686.orig/nptl/Makefile
51f0aa
+++ glibc-2.17-c758a686/nptl/Makefile
51f0aa
@@ -199,6 +199,7 @@ CFLAGS-send.c = -fexceptions -fasynchron
51f0aa
 CFLAGS-pt-system.c = -fexceptions
51f0aa
 
51f0aa
 CFLAGS-tst-minstack-throw.cc = -std=gnu++11
51f0aa
+CFLAGS-tst-thread-exit-clobber.o = -std=gnu++11
51f0aa
 
51f0aa
 tests = tst-typesizes \
51f0aa
 	tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
51f0aa
@@ -269,7 +270,8 @@ tests = tst-typesizes \
51f0aa
 	tst-getpid1 tst-getpid2 tst-getpid3 \
51f0aa
 	tst-initializers1 $(patsubst %,tst-initializers1-%,c89 gnu89 c99 gnu99) \
51f0aa
 	tst-mutex-errorcheck \
51f0aa
-	tst-minstack-cancel tst-minstack-exit tst-minstack-throw
51f0aa
+	tst-minstack-cancel tst-minstack-exit tst-minstack-throw \
51f0aa
+	tst-thread-exit-clobber
51f0aa
 xtests = tst-setuid1 tst-setuid1-static tst-mutexpp1 tst-mutexpp6 tst-mutexpp10
51f0aa
 test-srcs = tst-oddstacklimit
51f0aa
 
51f0aa
@@ -529,6 +531,7 @@ $(objpfx)tst-_res1: $(objpfx)tst-_res1mo
51f0aa
 LDLIBS-tst-cancel24 = $(no-as-needed) -lstdc++
51f0aa
 LDLIBS-tst-cancel24-static = $(LDLIBS-tst-cancel24)
51f0aa
 LDLIBS-tst-minstack-throw = -lstdc++
51f0aa
+LDLIBS-tst-thread-exit-clobber = -lstdc++
51f0aa
 
51f0aa
 extra-B-pthread.so = -B$(common-objpfx)nptl/
51f0aa
 $(objpfx)libpthread.so: $(addprefix $(objpfx),$(crti-objs) $(crtn-objs))
51f0aa
Index: glibc-2.17-c758a686/nptl/tst-thread-exit-clobber.cc
51f0aa
===================================================================
51f0aa
--- /dev/null
51f0aa
+++ glibc-2.17-c758a686/nptl/tst-thread-exit-clobber.cc
51f0aa
@@ -0,0 +1,243 @@
51f0aa
+/* Test that pthread_exit does not clobber callee-saved registers.
51f0aa
+   Copyright (C) 2018 Free Software Foundation, Inc.
51f0aa
+   This file is part of the GNU C Library.
51f0aa
+
51f0aa
+   The GNU C Library is free software; you can redistribute it and/or
51f0aa
+   modify it under the terms of the GNU Lesser General Public
51f0aa
+   License as published by the Free Software Foundation; either
51f0aa
+   version 2.1 of the License, or (at your option) any later version.
51f0aa
+
51f0aa
+   The GNU C Library is distributed in the hope that it will be useful,
51f0aa
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
51f0aa
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
51f0aa
+   Lesser General Public License for more details.
51f0aa
+
51f0aa
+   You should have received a copy of the GNU Lesser General Public
51f0aa
+   License along with the GNU C Library; if not, see
51f0aa
+   <http://www.gnu.org/licenses/>.  */
51f0aa
+
51f0aa
+#include <stdio.h>
51f0aa
+#include <support/check.h>
51f0aa
+#include <support/xthread.h>
51f0aa
+
51f0aa
+/* This test attempts to check that callee-saved registers are
51f0aa
+   restored to their original values when destructors are run after
51f0aa
+   pthread_exit is called.  GCC PR 83641 causes this test to fail.
51f0aa
+
51f0aa
+   The constants have been chosen randomly and are magic values which
51f0aa
+   are used to detect whether registers have been clobbered.  The idea
51f0aa
+   is that these values are hidden behind a compiler barrier and only
51f0aa
+   present in .rodata initially, so that it is less likely that they
51f0aa
+   are in a register by accident.
51f0aa
+
51f0aa
+   The checker class can be stored in registers, and the magic values
51f0aa
+   are directly loaded into these registers.  The checker destructor
51f0aa
+   is eventually invoked by pthread_exit and calls one of the
51f0aa
+   check_magic functions to verify that the class contents (that is,
51f0aa
+   register value) is correct.
51f0aa
+
51f0aa
+   These tests are performed both for unsigned int and double values,
51f0aa
+   to cover different calling conventions.  */
51f0aa
+
51f0aa
+template <class T>
51f0aa
+struct values
51f0aa
+{
51f0aa
+  T v0;
51f0aa
+  T v1;
51f0aa
+  T v2;
51f0aa
+  T v3;
51f0aa
+  T v4;
51f0aa
+};
51f0aa
+
51f0aa
+static const values<unsigned int> magic_values =
51f0aa
+  {
51f0aa
+    0x57f7fc72,
51f0aa
+    0xe582daba,
51f0aa
+    0x5f6ac994,
51f0aa
+    0x35efddb7,
51f0aa
+    0x1fbf5a74,
51f0aa
+  };
51f0aa
+
51f0aa
+static const values<double> magic_values_double =
51f0aa
+  {
51f0aa
+    0.6764041905675465,
51f0aa
+    0.9533336788140494,
51f0aa
+    0.6091161359041452,
51f0aa
+    0.7668653957125336,
51f0aa
+    0.010374520235509666,
51f0aa
+  };
51f0aa
+
51f0aa
+/* Special index value which tells check_magic that no check should be
51f0aa
+   performed.  */
51f0aa
+enum { no_check = -1 };
51f0aa
+
51f0aa
+/* Check that VALUE is the magic value for INDEX, behind a compiler
51f0aa
+   barrier.  */
51f0aa
+__attribute__ ((noinline, noclone, weak))
51f0aa
+void
51f0aa
+check_magic (int index, unsigned int value)
51f0aa
+{
51f0aa
+  switch (index)
51f0aa
+    {
51f0aa
+    case 0:
51f0aa
+      TEST_COMPARE (value, magic_values.v0);
51f0aa
+      break;
51f0aa
+    case 1:
51f0aa
+      TEST_COMPARE (value, magic_values.v1);
51f0aa
+      break;
51f0aa
+    case 2:
51f0aa
+      TEST_COMPARE (value, magic_values.v2);
51f0aa
+      break;
51f0aa
+    case 3:
51f0aa
+      TEST_COMPARE (value, magic_values.v3);
51f0aa
+      break;
51f0aa
+    case 4:
51f0aa
+      TEST_COMPARE (value, magic_values.v4);
51f0aa
+      break;
51f0aa
+    case no_check:
51f0aa
+      break;
51f0aa
+    default:
51f0aa
+      FAIL_EXIT1 ("invalid magic value index %d", index);
51f0aa
+    }
51f0aa
+}
51f0aa
+
51f0aa
+/* Check that VALUE is the magic value for INDEX, behind a compiler
51f0aa
+   barrier.  Double variant.  */
51f0aa
+__attribute__ ((noinline, noclone, weak))
51f0aa
+void
51f0aa
+check_magic (int index, double value)
51f0aa
+{
51f0aa
+  switch (index)
51f0aa
+    {
51f0aa
+    case 0:
51f0aa
+      TEST_VERIFY (value == magic_values_double.v0);
51f0aa
+      break;
51f0aa
+    case 1:
51f0aa
+      TEST_VERIFY (value == magic_values_double.v1);
51f0aa
+      break;
51f0aa
+    case 2:
51f0aa
+      TEST_VERIFY (value == magic_values_double.v2);
51f0aa
+      break;
51f0aa
+    case 3:
51f0aa
+      TEST_VERIFY (value == magic_values_double.v3);
51f0aa
+      break;
51f0aa
+    case 4:
51f0aa
+      TEST_VERIFY (value == magic_values_double.v4);
51f0aa
+      break;
51f0aa
+    case no_check:
51f0aa
+      break;
51f0aa
+    default:
51f0aa
+      FAIL_EXIT1 ("invalid magic value index %d", index);
51f0aa
+    }
51f0aa
+}
51f0aa
+
51f0aa
+/* Store a magic value and check, via the destructor, that it has the
51f0aa
+   expected value.  */
51f0aa
+template <class T, int I>
51f0aa
+struct checker
51f0aa
+{
51f0aa
+  T value;
51f0aa
+
51f0aa
+  checker (T v)
51f0aa
+    : value (v)
51f0aa
+  {
51f0aa
+  }
51f0aa
+
51f0aa
+  ~checker ()
51f0aa
+  {
51f0aa
+    check_magic (I, value);
51f0aa
+  }
51f0aa
+};
51f0aa
+
51f0aa
+/* The functions call_pthread_exit_0, call_pthread_exit_1,
51f0aa
+   call_pthread_exit are used to call pthread_exit indirectly, with
51f0aa
+   the intent of clobbering the register values.  */
51f0aa
+
51f0aa
+__attribute__ ((noinline, noclone, weak))
51f0aa
+void
51f0aa
+call_pthread_exit_0 (const values<unsigned int> *pvalues)
51f0aa
+{
51f0aa
+  checker<unsigned int, no_check> c0 (pvalues->v0);
51f0aa
+  checker<unsigned int, no_check> c1 (pvalues->v1);
51f0aa
+  checker<unsigned int, no_check> c2 (pvalues->v2);
51f0aa
+  checker<unsigned int, no_check> c3 (pvalues->v3);
51f0aa
+  checker<unsigned int, no_check> c4 (pvalues->v4);
51f0aa
+
51f0aa
+  pthread_exit (NULL);
51f0aa
+}
51f0aa
+
51f0aa
+__attribute__ ((noinline, noclone, weak))
51f0aa
+void
51f0aa
+call_pthread_exit_1 (const values<double> *pvalues)
51f0aa
+{
51f0aa
+  checker<double, no_check> c0 (pvalues->v0);
51f0aa
+  checker<double, no_check> c1 (pvalues->v1);
51f0aa
+  checker<double, no_check> c2 (pvalues->v2);
51f0aa
+  checker<double, no_check> c3 (pvalues->v3);
51f0aa
+  checker<double, no_check> c4 (pvalues->v4);
51f0aa
+
51f0aa
+  values<unsigned int> other_values = { 0, };
51f0aa
+  call_pthread_exit_0 (&other_values);
51f0aa
+}
51f0aa
+
51f0aa
+__attribute__ ((noinline, noclone, weak))
51f0aa
+void
51f0aa
+call_pthread_exit ()
51f0aa
+{
51f0aa
+  values<double> other_values = { 0, };
51f0aa
+  call_pthread_exit_1 (&other_values);
51f0aa
+}
51f0aa
+
51f0aa
+/* Create on-stack objects and check that their values are restored by
51f0aa
+   pthread_exit.  If Nested is true, call pthread_exit indirectly via
51f0aa
+   call_pthread_exit.  */
51f0aa
+template <class T, bool Nested>
51f0aa
+__attribute__ ((noinline, noclone, weak))
51f0aa
+void *
51f0aa
+threadfunc (void *closure)
51f0aa
+{
51f0aa
+  const values<T> *pvalues = static_cast<const values<T> *> (closure);
51f0aa
+
51f0aa
+  checker<T, 0> c0 (pvalues->v0);
51f0aa
+  checker<T, 1> c1 (pvalues->v1);
51f0aa
+  checker<T, 2> c2 (pvalues->v2);
51f0aa
+  checker<T, 3> c3 (pvalues->v3);
51f0aa
+  checker<T, 4> c4 (pvalues->v4);
51f0aa
+
51f0aa
+  if (Nested)
51f0aa
+    call_pthread_exit ();
51f0aa
+  else
51f0aa
+    pthread_exit (NULL);
51f0aa
+
51f0aa
+  /* This should not be reached.  */
51f0aa
+  return const_cast<char *> ("");
51f0aa
+}
51f0aa
+
51f0aa
+static int
51f0aa
+do_test ()
51f0aa
+{
51f0aa
+  puts ("info: unsigned int, direct pthread_exit call");
51f0aa
+  pthread_t thr
51f0aa
+    = xpthread_create (NULL, &threadfunc<unsigned int, false>,
51f0aa
+                       const_cast<values<unsigned int> *> (&magic_values));
51f0aa
+  TEST_VERIFY (xpthread_join (thr) == NULL);
51f0aa
+
51f0aa
+  puts ("info: double, direct pthread_exit call");
51f0aa
+  thr = xpthread_create (NULL, &threadfunc<double, false>,
51f0aa
+                         const_cast<values<double> *> (&magic_values_double));
51f0aa
+  TEST_VERIFY (xpthread_join (thr) == NULL);
51f0aa
+
51f0aa
+  puts ("info: unsigned int, indirect pthread_exit call");
51f0aa
+  thr = xpthread_create (NULL, &threadfunc<unsigned int, true>,
51f0aa
+                       const_cast<values<unsigned int> *> (&magic_values));
51f0aa
+  TEST_VERIFY (xpthread_join (thr) == NULL);
51f0aa
+
51f0aa
+  puts ("info: double, indirect pthread_exit call");
51f0aa
+  thr = xpthread_create (NULL, &threadfunc<double, true>,
51f0aa
+                         const_cast<values<double> *> (&magic_values_double));
51f0aa
+  TEST_VERIFY (xpthread_join (thr) == NULL);
51f0aa
+
51f0aa
+  return 0;
51f0aa
+}
51f0aa
+
51f0aa
+#include <support/test-driver.c>