1 | /* Test that pthread_exit does not clobber callee-saved registers. |
2 | Copyright (C) 2018-2022 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 | .v0: 0x57f7fc72, |
55 | .v1: 0xe582daba, |
56 | .v2: 0x5f6ac994, |
57 | .v3: 0x35efddb7, |
58 | .v4: 0x1fbf5a74, |
59 | }; |
60 | |
61 | static const values<double> magic_values_double = |
62 | { |
63 | .v0: 0.6764041905675465, |
64 | .v1: 0.9533336788140494, |
65 | .v2: 0.6091161359041452, |
66 | .v3: 0.7668653957125336, |
67 | .v4: 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 |
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 |
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 | |
141 | checker (T v) |
142 | : value (v) |
143 | { |
144 | } |
145 | |
146 | ~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 |
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 |
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 = { .v0: 0, }; |
180 | call_pthread_exit_0 (pvalues: &other_values); |
181 | } |
182 | |
183 | __attribute__ ((noinline, noclone, weak)) |
184 | void |
185 | call_pthread_exit () |
186 | { |
187 | values<double> other_values = { .v0: 0, }; |
188 | call_pthread_exit_1 (pvalues: &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 * |
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 |
217 | do_test () |
218 | { |
219 | puts (s: "info: unsigned int, direct pthread_exit call" ); |
220 | pthread_t thr |
221 | = xpthread_create (NULL, thread_func: &threadfunc<unsigned int, false>, |
222 | closure: const_cast<values<unsigned int> *> (&magic_values)); |
223 | TEST_VERIFY (xpthread_join (thr) == NULL); |
224 | |
225 | puts (s: "info: double, direct pthread_exit call" ); |
226 | thr = xpthread_create (NULL, thread_func: &threadfunc<double, false>, |
227 | closure: const_cast<values<double> *> (&magic_values_double)); |
228 | TEST_VERIFY (xpthread_join (thr) == NULL); |
229 | |
230 | puts (s: "info: unsigned int, indirect pthread_exit call" ); |
231 | thr = xpthread_create (NULL, thread_func: &threadfunc<unsigned int, true>, |
232 | closure: const_cast<values<unsigned int> *> (&magic_values)); |
233 | TEST_VERIFY (xpthread_join (thr) == NULL); |
234 | |
235 | puts (s: "info: double, indirect pthread_exit call" ); |
236 | thr = xpthread_create (NULL, thread_func: &threadfunc<double, true>, |
237 | closure: 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 | |