Line data Source code
1 : /* Unit tests for GCC's garbage collector (and gengtype etc).
2 : Copyright (C) 2015-2026 Free Software Foundation, Inc.
3 :
4 : This file is part of GCC.
5 :
6 : GCC is free software; you can redistribute it and/or modify it under
7 : the terms of the GNU General Public License as published by the Free
8 : Software Foundation; either version 3, or (at your option) any later
9 : version.
10 :
11 : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 : for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with GCC; see the file COPYING3. If not see
18 : <http://www.gnu.org/licenses/>. */
19 :
20 : #include "config.h"
21 : #include "system.h"
22 : #include "coretypes.h"
23 : #include "tree-core.h"
24 : #include "tree.h"
25 : #include "selftest.h"
26 :
27 : #if CHECKING_P
28 :
29 : /* The various GTY markers must be outside of a namespace to be seen by
30 : gengtype, so we don't put this file within the selftest namespace. */
31 :
32 :
33 :
34 : /* Verify that a simple struct works, and that it can
35 : own references to non-roots, and have them be marked. */
36 :
37 : struct GTY(()) test_struct
38 : {
39 : struct test_struct *other;
40 : };
41 :
42 : static GTY(()) test_struct *root_test_struct;
43 :
44 : static void
45 4 : test_basic_struct ()
46 : {
47 4 : root_test_struct = ggc_cleared_alloc <test_struct> ();
48 4 : root_test_struct->other = ggc_cleared_alloc <test_struct> ();
49 :
50 4 : ggc_collect (GGC_COLLECT_FORCE);
51 :
52 4 : ASSERT_TRUE (ggc_marked_p (root_test_struct));
53 4 : ASSERT_TRUE (ggc_marked_p (root_test_struct->other));
54 4 : }
55 :
56 :
57 :
58 : /* Selftest for GTY((length)). */
59 :
60 : /* A test struct using GTY((length)). */
61 :
62 : struct GTY(()) test_of_length
63 : {
64 : int num_elem;
65 : struct test_of_length * GTY ((length ("%h.num_elem"))) elem[1];
66 : };
67 :
68 : static GTY(()) test_of_length *root_test_of_length;
69 :
70 : static void
71 4 : test_length ()
72 : {
73 4 : const int count = 5;
74 4 : size_t sz = sizeof (test_of_length) + (count- 1) * sizeof (test_of_length *);
75 4 : root_test_of_length = (test_of_length *)ggc_internal_cleared_alloc (sz);
76 4 : root_test_of_length->num_elem = count;
77 24 : for (int i = 0; i < count; i++)
78 20 : root_test_of_length->elem[i] = ggc_cleared_alloc <test_of_length> ();
79 :
80 4 : ggc_collect (GGC_COLLECT_FORCE);
81 :
82 4 : ASSERT_TRUE (ggc_marked_p (root_test_of_length));
83 24 : for (int i = 0; i < count; i++)
84 20 : ASSERT_TRUE (ggc_marked_p (root_test_of_length->elem[i]));
85 4 : }
86 :
87 :
88 :
89 : /* Selftest for unions, GTY((tag)), and GTY((desc)). */
90 :
91 : /* A struct with a reference that's an a different offset to test_struct,
92 : to ensure that we're using the correct types. */
93 :
94 : struct GTY(()) test_other
95 : {
96 : char dummy[256];
97 : test_struct *m_ptr;
98 : };
99 :
100 : enum which_field
101 : {
102 : WHICH_FIELD_USE_TEST_STRUCT,
103 : WHICH_FIELD_USE_TEST_OTHER
104 : };
105 :
106 : /* An example function for use by a GTY((desc)) marker. */
107 :
108 : static enum which_field
109 88 : calc_desc (int kind)
110 : {
111 88 : switch (kind)
112 : {
113 : case 0: return WHICH_FIELD_USE_TEST_STRUCT;
114 44 : case 1: return WHICH_FIELD_USE_TEST_OTHER;
115 0 : default:
116 0 : gcc_unreachable ();
117 : }
118 : }
119 :
120 : /* A struct containing an example of a union, showing the "tag" and
121 : "desc" markers. */
122 :
123 : struct GTY(()) test_of_union
124 : {
125 : int m_kind;
126 : union u {
127 : test_struct * GTY ((tag ("WHICH_FIELD_USE_TEST_STRUCT") )) u_test_struct;
128 : test_other * GTY ((tag ("WHICH_FIELD_USE_TEST_OTHER") )) u_test_other;
129 : } GTY ((desc ("calc_desc (%0.m_kind)"))) m_u;
130 : };
131 :
132 : /* Example roots. */
133 :
134 : static GTY(()) test_of_union *root_test_of_union_1;
135 : static GTY(()) test_of_union *root_test_of_union_2;
136 :
137 : /* Verify that the above work correctly. */
138 :
139 : static void
140 4 : test_union ()
141 : {
142 4 : root_test_of_union_1 = ggc_cleared_alloc <test_of_union> ();
143 4 : root_test_of_union_1->m_kind = 0;
144 4 : test_struct *ts = ggc_cleared_alloc <test_struct> ();
145 4 : root_test_of_union_1->m_u.u_test_struct = ts;
146 :
147 4 : root_test_of_union_2 = ggc_cleared_alloc <test_of_union> ();
148 4 : root_test_of_union_2->m_kind = 1;
149 4 : test_other *other = ggc_cleared_alloc <test_other> ();
150 4 : root_test_of_union_2->m_u.u_test_other = other;
151 4 : test_struct *referenced_by_other = ggc_cleared_alloc <test_struct> ();
152 4 : other->m_ptr = referenced_by_other;
153 :
154 4 : ggc_collect (GGC_COLLECT_FORCE);
155 :
156 4 : ASSERT_TRUE (ggc_marked_p (root_test_of_union_1));
157 4 : ASSERT_TRUE (ggc_marked_p (ts));
158 :
159 4 : ASSERT_TRUE (ggc_marked_p (root_test_of_union_2));
160 4 : ASSERT_TRUE (ggc_marked_p (other));
161 4 : ASSERT_TRUE (ggc_marked_p (referenced_by_other));
162 4 : }
163 :
164 :
165 :
166 : /* Verify that destructors get run when instances are collected. */
167 :
168 : class GTY(()) test_struct_with_dtor
169 : {
170 : public:
171 : /* This struct has a destructor; it *ought* to be called
172 : by the ggc machinery when instances are collected. */
173 40 : ~test_struct_with_dtor () { dtor_call_count++; }
174 :
175 : static int dtor_call_count;
176 : };
177 :
178 : int test_struct_with_dtor::dtor_call_count;
179 :
180 : static void
181 4 : test_finalization ()
182 : {
183 : #if GCC_VERSION >= 4003
184 4 : ASSERT_FALSE (need_finalization_p <test_struct> ());
185 4 : ASSERT_TRUE (need_finalization_p <test_struct_with_dtor> ());
186 : #endif
187 :
188 : /* Create some garbage. */
189 4 : const int count = 10;
190 44 : for (int i = 0; i < count; i++)
191 40 : ggc_cleared_alloc <test_struct_with_dtor> ();
192 :
193 4 : test_struct_with_dtor::dtor_call_count = 0;
194 :
195 4 : ggc_collect (GGC_COLLECT_FORCE);
196 :
197 : /* Verify that the destructor was run for each instance. */
198 4 : ASSERT_EQ (count, test_struct_with_dtor::dtor_call_count);
199 4 : }
200 :
201 :
202 :
203 : /* Verify that a global can be marked as "deletable". */
204 :
205 : static GTY((deletable)) test_struct *test_of_deletable;
206 :
207 : static void
208 4 : test_deletable_global ()
209 : {
210 4 : test_of_deletable = ggc_cleared_alloc <test_struct> ();
211 4 : ASSERT_TRUE (test_of_deletable != NULL);
212 :
213 4 : ggc_collect (GGC_COLLECT_FORCE);
214 :
215 4 : ASSERT_EQ (NULL, test_of_deletable);
216 4 : }
217 :
218 :
219 :
220 : /* Verify that gengtype etc can cope with inheritance. */
221 :
222 : class GTY((desc("%h.m_kind"), tag("0"))) example_base
223 : {
224 : public:
225 4 : example_base ()
226 4 : : m_kind (0),
227 8 : m_a (ggc_cleared_alloc <test_struct> ())
228 : {}
229 :
230 : void *
231 20 : operator new (size_t sz)
232 : {
233 40 : return ggc_internal_cleared_alloc (sz);
234 : }
235 :
236 : protected:
237 16 : example_base (int kind)
238 16 : : m_kind (kind),
239 32 : m_a (ggc_cleared_alloc <test_struct> ())
240 : {}
241 :
242 : public:
243 : int m_kind;
244 : test_struct *m_a;
245 : };
246 :
247 : class GTY((tag("1"))) some_subclass : public example_base
248 : {
249 : public:
250 8 : some_subclass ()
251 8 : : example_base (1),
252 8 : m_b (ggc_cleared_alloc <test_struct> ())
253 8 : {}
254 :
255 : test_struct *m_b;
256 : };
257 :
258 : class GTY((tag("2"))) some_other_subclass : public example_base
259 : {
260 : public:
261 8 : some_other_subclass ()
262 8 : : example_base (2),
263 8 : m_c (ggc_cleared_alloc <test_struct> ())
264 8 : {}
265 :
266 : test_struct *m_c;
267 : };
268 :
269 : /* Various test roots, both expressed as a ptr to the actual class, and
270 : as a ptr to the base class. */
271 : static GTY(()) example_base *test_example_base;
272 : static GTY(()) some_subclass *test_some_subclass;
273 : static GTY(()) some_other_subclass *test_some_other_subclass;
274 : static GTY(()) example_base *test_some_subclass_as_base_ptr;
275 : static GTY(()) example_base *test_some_other_subclass_as_base_ptr;
276 :
277 : static void
278 4 : test_inheritance ()
279 : {
280 4 : test_example_base = new example_base ();
281 4 : test_some_subclass = new some_subclass ();
282 4 : test_some_other_subclass = new some_other_subclass ();
283 4 : test_some_subclass_as_base_ptr = new some_subclass ();
284 4 : test_some_other_subclass_as_base_ptr = new some_other_subclass ();
285 :
286 4 : ggc_collect (GGC_COLLECT_FORCE);
287 :
288 : /* Verify that the roots and everything referenced by them got marked
289 : (both for fields in the base class and those in subclasses). */
290 4 : ASSERT_TRUE (ggc_marked_p (test_example_base));
291 4 : ASSERT_TRUE (ggc_marked_p (test_example_base->m_a));
292 :
293 4 : ASSERT_TRUE (ggc_marked_p (test_some_subclass));
294 4 : ASSERT_TRUE (ggc_marked_p (test_some_subclass->m_a));
295 4 : ASSERT_TRUE (ggc_marked_p (test_some_subclass->m_b));
296 :
297 4 : ASSERT_TRUE (ggc_marked_p (test_some_other_subclass));
298 4 : ASSERT_TRUE (ggc_marked_p (test_some_other_subclass->m_a));
299 4 : ASSERT_TRUE (ggc_marked_p (test_some_other_subclass->m_c));
300 :
301 4 : ASSERT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr));
302 4 : ASSERT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr->m_a));
303 4 : ASSERT_TRUE (ggc_marked_p (((some_subclass *)
304 : test_some_subclass_as_base_ptr)->m_b));
305 :
306 4 : ASSERT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr));
307 4 : ASSERT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr->m_a));
308 4 : ASSERT_TRUE (ggc_marked_p (((some_other_subclass *)
309 : test_some_other_subclass_as_base_ptr)->m_c));
310 4 : }
311 :
312 :
313 :
314 : /* Test of chain_next/chain_prev
315 :
316 : Construct a very long linked list, so that without
317 : the chain_next/chain_prev optimization we'd have
318 : a stack overflow when gt_ggc_mx_test_node recurses. */
319 :
320 : struct GTY(( chain_next ("%h.m_next"),
321 : chain_prev ("%h.m_prev") )) test_node
322 : {
323 : test_node *m_prev;
324 : test_node *m_next;
325 : int m_idx;
326 : };
327 :
328 : static GTY(()) test_node *root_test_node;
329 :
330 : static void
331 4 : test_chain_next ()
332 : {
333 : /* Ideally we would construct a long list so that the number of
334 : stack frames would be deep enough to crash if gengtype has created
335 : something that recurses.
336 :
337 : However, as the list is lengthened to increase the chance of
338 : overflowing the stack, the test will require more time and memory
339 : to run. On a Fedora 20 x86_64 box with 128GB of RAM, count=2000000
340 : without the chain_next optimization reliably overflowed the stack,
341 : but the test took 0.5s to run.
342 :
343 : For now this test runs with a low value for "count", which defeats
344 : the main purpose of the test - though it at least gives us coverage
345 : for walking a GTY((chain_next)) list.
346 :
347 : We could potentially increase this value once we have a better sense
348 : of the time and space requirements of the test on different hosts,
349 : or perhaps find a way to reduce the stack size when running this
350 : testcase. */
351 4 : const int count = 10;
352 :
353 : /* Build the linked list. */
354 4 : root_test_node = ggc_cleared_alloc <test_node> ();
355 4 : test_node *tail_node = root_test_node;
356 44 : for (int i = 0; i < count; i++)
357 : {
358 40 : test_node *new_node = ggc_cleared_alloc <test_node> ();
359 40 : tail_node->m_next = new_node;
360 40 : new_node->m_prev = tail_node;
361 40 : new_node->m_idx = i;
362 40 : tail_node = new_node;
363 : }
364 :
365 4 : ggc_collect (GGC_COLLECT_FORCE);
366 :
367 : /* If we got here, we survived. */
368 :
369 : /* Verify that all nodes in the list were marked. */
370 4 : ASSERT_TRUE (ggc_marked_p (root_test_node));
371 4 : test_node *iter_node = root_test_node->m_next;
372 44 : for (int i = 0; i < count; i++)
373 : {
374 40 : ASSERT_TRUE (ggc_marked_p (iter_node));
375 40 : ASSERT_EQ (i, iter_node->m_idx);
376 40 : iter_node = iter_node->m_next;
377 : }
378 4 : }
379 :
380 :
381 :
382 : /* Test for GTY((user)). */
383 :
384 : struct GTY((user)) user_struct
385 : {
386 : char dummy[16];
387 : test_struct *m_ptr;
388 : };
389 :
390 : static GTY(()) user_struct *root_user_struct_ptr;
391 :
392 : /* A global for verifying that the user-provided gt_ggc_mx gets
393 : called. */
394 : static int num_calls_to_user_gt_ggc_mx;
395 :
396 : /* User-provided implementation of gt_ggc_mx. */
397 :
398 : static void
399 24 : gt_ggc_mx (user_struct *p)
400 : {
401 24 : num_calls_to_user_gt_ggc_mx++;
402 24 : gt_ggc_mx_test_struct (p->m_ptr);
403 24 : }
404 :
405 : /* User-provided implementation of gt_pch_nx. */
406 :
407 : static void
408 0 : gt_pch_nx (user_struct *p)
409 : {
410 0 : gt_pch_nx_test_struct (p->m_ptr);
411 0 : }
412 :
413 : /* User-provided implementation of gt_pch_nx. */
414 :
415 : static void
416 0 : gt_pch_nx (user_struct *p, gt_pointer_operator op, void *cookie)
417 : {
418 0 : op (&(p->m_ptr), NULL, cookie);
419 0 : }
420 :
421 : /* Verify that GTY((user)) works. */
422 :
423 : static void
424 4 : test_user_struct ()
425 : {
426 4 : root_user_struct_ptr = ggc_cleared_alloc <user_struct> ();
427 4 : test_struct *referenced = ggc_cleared_alloc <test_struct> ();
428 4 : root_user_struct_ptr->m_ptr = referenced;
429 :
430 4 : num_calls_to_user_gt_ggc_mx = 0;
431 :
432 4 : ggc_collect (GGC_COLLECT_FORCE);
433 :
434 4 : ASSERT_TRUE (ggc_marked_p (root_user_struct_ptr));
435 4 : ASSERT_TRUE (ggc_marked_p (referenced));
436 4 : ASSERT_TRUE (num_calls_to_user_gt_ggc_mx > 0);
437 4 : }
438 :
439 :
440 :
441 : /* Smoketest to ensure that the tree type is marked. */
442 :
443 : static GTY(()) tree dummy_unittesting_tree;
444 :
445 : static void
446 4 : test_tree_marking ()
447 : {
448 4 : dummy_unittesting_tree = build_int_cst (integer_type_node, 1066);
449 :
450 4 : ggc_collect (GGC_COLLECT_FORCE);
451 :
452 4 : ASSERT_TRUE (ggc_marked_p (dummy_unittesting_tree));
453 4 : }
454 :
455 :
456 :
457 : /* Ideas for other tests:
458 : - pch-handling */
459 :
460 : namespace selftest {
461 :
462 : /* Run all of the selftests within this file. */
463 :
464 : void
465 4 : ggc_tests_cc_tests ()
466 : {
467 4 : test_basic_struct ();
468 4 : test_length ();
469 4 : test_union ();
470 4 : test_finalization ();
471 4 : test_deletable_global ();
472 4 : test_inheritance ();
473 4 : test_chain_next ();
474 4 : test_user_struct ();
475 4 : test_tree_marking ();
476 4 : }
477 :
478 : } // namespace selftest
479 :
480 : #include "gt-ggc-tests.h"
481 :
482 : #else /* #if CHECKING_P */
483 :
484 : /* The #if CHECKING_P code above has various GTY-marked roots.
485 : gengtype has no knowledge of the preprocessor, and so detects
486 : these roots and writes them out to gt-ggc-tests.h.
487 : In a !CHECKING_P build we can ignore gt-ggc-tests.h, but the
488 : root tables are referenced in the various generated gtype-*.c
489 : files like this:
490 :
491 : ...snip...
492 : extern const struct ggc_root_tab gt_ggc_r_gt_ggc_tests_h[];
493 : ...snip...
494 :
495 : EXPORTED_CONST struct ggc_root_tab * const gt_ggc_rtab[] = {
496 : ...snip...
497 : gt_ggc_r_gt_ggc_tests_h,
498 : ...snip...
499 : };
500 :
501 : Hence to avoid a link failure, we provide dummy implementations
502 : of these root tables in an unchecked build.
503 :
504 : Note that these conditional roots imply that PCH files are
505 : incompatible between checked and unchecked builds. */
506 :
507 : EXPORTED_CONST struct ggc_root_tab gt_ggc_r_gt_ggc_tests_h[] = {
508 : LAST_GGC_ROOT_TAB
509 : };
510 :
511 : EXPORTED_CONST struct ggc_root_tab gt_ggc_rd_gt_ggc_tests_h[] = {
512 : LAST_GGC_ROOT_TAB
513 : };
514 :
515 : #endif /* #else clause of #if CHECKING_P */
|