1 /* Test that pthread_exit does not clobber callee-saved registers.
2 Copyright (C) 2018-2019 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/>. */
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. */
52 static const values
<unsigned int> magic_values
=
61 static const values
<double> magic_values_double
=
70 /* Special index value which tells check_magic that no check should be
72 enum { no_check
= -1 };
74 /* Check that VALUE is the magic value for INDEX, behind a compiler
76 __attribute__ ((noinline
, noclone
, weak
))
78 check_magic (int index
, unsigned int value
)
83 TEST_COMPARE (value
, magic_values
.v0
);
86 TEST_COMPARE (value
, magic_values
.v1
);
89 TEST_COMPARE (value
, magic_values
.v2
);
92 TEST_COMPARE (value
, magic_values
.v3
);
95 TEST_COMPARE (value
, magic_values
.v4
);
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
))
108 check_magic (int index
, double value
)
113 TEST_VERIFY (value
== magic_values_double
.v0
);
116 TEST_VERIFY (value
== magic_values_double
.v1
);
119 TEST_VERIFY (value
== magic_values_double
.v2
);
122 TEST_VERIFY (value
== magic_values_double
.v3
);
125 TEST_VERIFY (value
== magic_values_double
.v4
);
130 FAIL_EXIT1 ("invalid magic value index %d", index
);
134 /* Store a magic value and check, via the destructor, that it has the
136 template <class T
, int I
>
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
))
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
);
169 __attribute__ ((noinline
, noclone
, weak
))
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
))
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
))
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
);
208 call_pthread_exit ();
212 /* This should not be reached. */
213 return const_cast<char *> ("");
219 puts ("info: unsigned int, direct pthread_exit call");
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
);
243 #include <support/test-driver.c>