1 /* Test that pthread_exit does not clobber callee-saved registers.
2    Copyright (C) 2018-2021 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
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.
9 
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.
14 
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    <https://www.gnu.org/licenses/>.  */
18 
19 #include <stdio.h>
20 #include <support/check.h>
21 #include <support/xthread.h>
22 
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.
26 
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.
32 
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.
38 
39    These tests are performed both for unsigned int and double values,
40    to cover different calling conventions.  */
41 
42 template <class T>
43 struct values
44 {
45   T v0;
46   T v1;
47   T v2;
48   T v3;
49   T v4;
50 };
51 
52 static const values<unsigned int> magic_values =
53   {
54     0x57f7fc72,
55     0xe582daba,
56     0x5f6ac994,
57     0x35efddb7,
58     0x1fbf5a74,
59   };
60 
61 static const values<double> magic_values_double =
62   {
63     0.6764041905675465,
64     0.9533336788140494,
65     0.6091161359041452,
66     0.7668653957125336,
67     0.010374520235509666,
68   };
69 
70 /* Special index value which tells check_magic that no check should be
71    performed.  */
72 enum { no_check = -1 };
73 
74 /* Check that VALUE is the magic value for INDEX, behind a compiler
75    barrier.  */
76 __attribute__ ((noinline, noclone, weak))
77 void
check_magic(int index,unsigned int value)78 check_magic (int index, unsigned int value)
79 {
80   switch (index)
81     {
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);
101     }
102 }
103 
104 /* Check that VALUE is the magic value for INDEX, behind a compiler
105    barrier.  Double variant.  */
106 __attribute__ ((noinline, noclone, weak))
107 void
check_magic(int index,double value)108 check_magic (int index, double value)
109 {
110   switch (index)
111     {
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);
131     }
132 }
133 
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
138 {
139   T value;
140 
checkerchecker141   checker (T v)
142     : value (v)
143   {
144   }
145 
~checkerchecker146   ~checker ()
147   {
148     check_magic (I, value);
149   }
150 };
151 
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.  */
155 
156 __attribute__ ((noinline, noclone, weak))
157 void
call_pthread_exit_0(const values<unsigned int> * pvalues)158 call_pthread_exit_0 (const values<unsigned int> *pvalues)
159 {
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);
165 
166   pthread_exit (NULL);
167 }
168 
169 __attribute__ ((noinline, noclone, weak))
170 void
call_pthread_exit_1(const values<double> * pvalues)171 call_pthread_exit_1 (const values<double> *pvalues)
172 {
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);
178 
179   values<unsigned int> other_values = { 0, };
180   call_pthread_exit_0 (&other_values);
181 }
182 
183 __attribute__ ((noinline, noclone, weak))
184 void
call_pthread_exit()185 call_pthread_exit ()
186 {
187   values<double> other_values = { 0, };
188   call_pthread_exit_1 (&other_values);
189 }
190 
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 *
threadfunc(void * closure)197 threadfunc (void *closure)
198 {
199   const values<T> *pvalues = static_cast<const values<T> *> (closure);
200 
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);
206 
207   if (Nested)
208     call_pthread_exit ();
209   else
210     pthread_exit (NULL);
211 
212   /* This should not be reached.  */
213   return const_cast<char *> ("");
214 }
215 
216 static int
do_test()217 do_test ()
218 {
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);
224 
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);
229 
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);
234 
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);
239 
240   return 0;
241 }
242 
243 #include <support/test-driver.c>
244