hurd: Fix build
[glibc.git] / nptl / tst-thread-exit-clobber.cc
blobb9be25a65b86866f9257d210cca6b598a6fb360e
1 /* Test that pthread_exit does not clobber callee-saved registers.
2 Copyright (C) 2018 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <stdio.h>
20 #include <support/check.h>
21 #include <support/xthread.h>
23 /* This test attempts to check that callee-saved registers are
24 restored to their original values when destructors are run after
25 pthread_exit is called. GCC PR 83641 causes this test to fail.
27 The constants have been chosen randomly and are magic values which
28 are used to detect whether registers have been clobbered. The idea
29 is that these values are hidden behind a compiler barrier and only
30 present in .rodata initially, so that it is less likely that they
31 are in a register by accident.
33 The checker class can be stored in registers, and the magic values
34 are directly loaded into these registers. The checker destructor
35 is eventually invoked by pthread_exit and calls one of the
36 check_magic functions to verify that the class contents (that is,
37 register value) is correct.
39 These tests are performed both for unsigned int and double values,
40 to cover different calling conventions. */
42 template <class T>
43 struct values
45 T v0;
46 T v1;
47 T v2;
48 T v3;
49 T v4;
52 static const values<unsigned int> magic_values =
54 0x57f7fc72,
55 0xe582daba,
56 0x5f6ac994,
57 0x35efddb7,
58 0x1fbf5a74,
61 static const values<double> magic_values_double =
63 0.6764041905675465,
64 0.9533336788140494,
65 0.6091161359041452,
66 0.7668653957125336,
67 0.010374520235509666,
70 /* Special index value which tells check_magic that no check should be
71 performed. */
72 enum { no_check = -1 };
74 /* Check that VALUE is the magic value for INDEX, behind a compiler
75 barrier. */
76 __attribute__ ((noinline, noclone, weak))
77 void
78 check_magic (int index, unsigned int value)
80 switch (index)
82 case 0:
83 TEST_COMPARE (value, magic_values.v0);
84 break;
85 case 1:
86 TEST_COMPARE (value, magic_values.v1);
87 break;
88 case 2:
89 TEST_COMPARE (value, magic_values.v2);
90 break;
91 case 3:
92 TEST_COMPARE (value, magic_values.v3);
93 break;
94 case 4:
95 TEST_COMPARE (value, magic_values.v4);
96 break;
97 case no_check:
98 break;
99 default:
100 FAIL_EXIT1 ("invalid magic value index %d", index);
104 /* Check that VALUE is the magic value for INDEX, behind a compiler
105 barrier. Double variant. */
106 __attribute__ ((noinline, noclone, weak))
107 void
108 check_magic (int index, double value)
110 switch (index)
112 case 0:
113 TEST_VERIFY (value == magic_values_double.v0);
114 break;
115 case 1:
116 TEST_VERIFY (value == magic_values_double.v1);
117 break;
118 case 2:
119 TEST_VERIFY (value == magic_values_double.v2);
120 break;
121 case 3:
122 TEST_VERIFY (value == magic_values_double.v3);
123 break;
124 case 4:
125 TEST_VERIFY (value == magic_values_double.v4);
126 break;
127 case no_check:
128 break;
129 default:
130 FAIL_EXIT1 ("invalid magic value index %d", index);
134 /* Store a magic value and check, via the destructor, that it has the
135 expected value. */
136 template <class T, int I>
137 struct checker
139 T value;
141 checker (T v)
142 : value (v)
146 ~checker ()
148 check_magic (I, value);
152 /* The functions call_pthread_exit_0, call_pthread_exit_1,
153 call_pthread_exit are used to call pthread_exit indirectly, with
154 the intent of clobbering the register values. */
156 __attribute__ ((noinline, noclone, weak))
157 void
158 call_pthread_exit_0 (const values<unsigned int> *pvalues)
160 checker<unsigned int, no_check> c0 (pvalues->v0);
161 checker<unsigned int, no_check> c1 (pvalues->v1);
162 checker<unsigned int, no_check> c2 (pvalues->v2);
163 checker<unsigned int, no_check> c3 (pvalues->v3);
164 checker<unsigned int, no_check> c4 (pvalues->v4);
166 pthread_exit (NULL);
169 __attribute__ ((noinline, noclone, weak))
170 void
171 call_pthread_exit_1 (const values<double> *pvalues)
173 checker<double, no_check> c0 (pvalues->v0);
174 checker<double, no_check> c1 (pvalues->v1);
175 checker<double, no_check> c2 (pvalues->v2);
176 checker<double, no_check> c3 (pvalues->v3);
177 checker<double, no_check> c4 (pvalues->v4);
179 values<unsigned int> other_values = { 0, };
180 call_pthread_exit_0 (&other_values);
183 __attribute__ ((noinline, noclone, weak))
184 void
185 call_pthread_exit ()
187 values<double> other_values = { 0, };
188 call_pthread_exit_1 (&other_values);
191 /* Create on-stack objects and check that their values are restored by
192 pthread_exit. If Nested is true, call pthread_exit indirectly via
193 call_pthread_exit. */
194 template <class T, bool Nested>
195 __attribute__ ((noinline, noclone, weak))
196 void *
197 threadfunc (void *closure)
199 const values<T> *pvalues = static_cast<const values<T> *> (closure);
201 checker<T, 0> c0 (pvalues->v0);
202 checker<T, 1> c1 (pvalues->v1);
203 checker<T, 2> c2 (pvalues->v2);
204 checker<T, 3> c3 (pvalues->v3);
205 checker<T, 4> c4 (pvalues->v4);
207 if (Nested)
208 call_pthread_exit ();
209 else
210 pthread_exit (NULL);
212 /* This should not be reached. */
213 return const_cast<char *> ("");
216 static int
217 do_test ()
219 puts ("info: unsigned int, direct pthread_exit call");
220 pthread_t thr
221 = xpthread_create (NULL, &threadfunc<unsigned int, false>,
222 const_cast<values<unsigned int> *> (&magic_values));
223 TEST_VERIFY (xpthread_join (thr) == NULL);
225 puts ("info: double, direct pthread_exit call");
226 thr = xpthread_create (NULL, &threadfunc<double, false>,
227 const_cast<values<double> *> (&magic_values_double));
228 TEST_VERIFY (xpthread_join (thr) == NULL);
230 puts ("info: unsigned int, indirect pthread_exit call");
231 thr = xpthread_create (NULL, &threadfunc<unsigned int, true>,
232 const_cast<values<unsigned int> *> (&magic_values));
233 TEST_VERIFY (xpthread_join (thr) == NULL);
235 puts ("info: double, indirect pthread_exit call");
236 thr = xpthread_create (NULL, &threadfunc<double, true>,
237 const_cast<values<double> *> (&magic_values_double));
238 TEST_VERIFY (xpthread_join (thr) == NULL);
240 return 0;
243 #include <support/test-driver.c>