LCOV - code coverage report
Current view: top level - gcc - ggc-tests.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 94.7 % 151 143
Test Date: 2026-02-28 14:20:25 Functions: 87.5 % 16 14
Legend: Lines:     hit not hit

            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 */
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.