LCOV - code coverage report
Current view: top level - gcc/analyzer - checker-path.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 55.2 % 116 64
Test Date: 2024-03-23 14:05:01 Functions: 75.0 % 8 6
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Subclass of diagnostic_path for analyzer diagnostics.
       2                 :             :    Copyright (C) 2019-2024 Free Software Foundation, Inc.
       3                 :             :    Contributed by David Malcolm <dmalcolm@redhat.com>.
       4                 :             : 
       5                 :             : This file is part of GCC.
       6                 :             : 
       7                 :             : GCC is free software; you can redistribute it and/or modify it
       8                 :             : under the terms of the GNU General Public License as published by
       9                 :             : the Free Software Foundation; either version 3, or (at your option)
      10                 :             : any later version.
      11                 :             : 
      12                 :             : GCC is distributed in the hope that it will be useful, but
      13                 :             : WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15                 :             : General Public License for more details.
      16                 :             : 
      17                 :             : You should have received a copy of the GNU General Public License
      18                 :             : along with GCC; see the file COPYING3.  If not see
      19                 :             : <http://www.gnu.org/licenses/>.  */
      20                 :             : 
      21                 :             : #include "config.h"
      22                 :             : #define INCLUDE_MEMORY
      23                 :             : #include "system.h"
      24                 :             : #include "coretypes.h"
      25                 :             : #include "tree.h"
      26                 :             : #include "function.h"
      27                 :             : #include "basic-block.h"
      28                 :             : #include "gimple.h"
      29                 :             : #include "diagnostic-core.h"
      30                 :             : #include "gimple-pretty-print.h"
      31                 :             : #include "fold-const.h"
      32                 :             : #include "diagnostic-path.h"
      33                 :             : #include "options.h"
      34                 :             : #include "cgraph.h"
      35                 :             : #include "cfg.h"
      36                 :             : #include "digraph.h"
      37                 :             : #include "diagnostic-event-id.h"
      38                 :             : #include "analyzer/analyzer.h"
      39                 :             : #include "analyzer/analyzer-logging.h"
      40                 :             : #include "analyzer/sm.h"
      41                 :             : #include "sbitmap.h"
      42                 :             : #include "bitmap.h"
      43                 :             : #include "ordered-hash-map.h"
      44                 :             : #include "analyzer/call-string.h"
      45                 :             : #include "analyzer/program-point.h"
      46                 :             : #include "analyzer/store.h"
      47                 :             : #include "analyzer/region-model.h"
      48                 :             : #include "analyzer/program-state.h"
      49                 :             : #include "analyzer/checker-path.h"
      50                 :             : #include "gimple-iterator.h"
      51                 :             : #include "inlining-iterator.h"
      52                 :             : #include "analyzer/supergraph.h"
      53                 :             : #include "analyzer/pending-diagnostic.h"
      54                 :             : #include "analyzer/diagnostic-manager.h"
      55                 :             : #include "analyzer/constraint-manager.h"
      56                 :             : #include "analyzer/diagnostic-manager.h"
      57                 :             : #include "analyzer/checker-path.h"
      58                 :             : #include "analyzer/exploded-graph.h"
      59                 :             : #include "make-unique.h"
      60                 :             : 
      61                 :             : #if ENABLE_ANALYZER
      62                 :             : 
      63                 :             : namespace ana {
      64                 :             : 
      65                 :             : /* Print a single-line representation of this path to PP.  */
      66                 :             : 
      67                 :             : void
      68                 :           0 : checker_path::dump (pretty_printer *pp) const
      69                 :             : {
      70                 :           0 :   pp_character (pp, '[');
      71                 :             : 
      72                 :           0 :   checker_event *e;
      73                 :           0 :   int i;
      74                 :           0 :   FOR_EACH_VEC_ELT (m_events, i, e)
      75                 :             :     {
      76                 :           0 :       if (i > 0)
      77                 :           0 :         pp_string (pp, ", ");
      78                 :           0 :       label_text event_desc (e->get_desc (false));
      79                 :           0 :       pp_printf (pp, "\"%s\"", event_desc.get ());
      80                 :           0 :     }
      81                 :           0 :   pp_character (pp, ']');
      82                 :           0 : }
      83                 :             : 
      84                 :             : /* Print a multiline form of this path to LOGGER, prefixing it with DESC.  */
      85                 :             : 
      86                 :             : void
      87                 :       18026 : checker_path::maybe_log (logger *logger, const char *desc) const
      88                 :             : {
      89                 :       18026 :   if (!logger)
      90                 :             :     return;
      91                 :           0 :   logger->start_log_line ();
      92                 :           0 :   logger->log_partial ("%s: ", desc);
      93                 :           0 :   dump (logger->get_printer ());
      94                 :           0 :   logger->end_log_line ();
      95                 :           0 :   for (unsigned i = 0; i < m_events.length (); i++)
      96                 :             :     {
      97                 :           0 :       logger->start_log_line ();
      98                 :           0 :       logger->log_partial ("%s[%i]: %s ", desc, i,
      99                 :           0 :                            event_kind_to_string (m_events[i]->m_kind));
     100                 :           0 :       m_events[i]->dump (logger->get_printer ());
     101                 :           0 :       logger->end_log_line ();
     102                 :             :     }
     103                 :             : }
     104                 :             : 
     105                 :             : void
     106                 :       65569 : checker_path::add_event (std::unique_ptr<checker_event> event)
     107                 :             : {
     108                 :       65569 :   if (m_logger)
     109                 :             :     {
     110                 :           0 :       m_logger->start_log_line ();
     111                 :           0 :       m_logger->log_partial ("added event[%i]: %s ",
     112                 :             :                              m_events.length (),
     113                 :           0 :                              event_kind_to_string (event.get ()->m_kind));
     114                 :           0 :       event.get ()->dump (m_logger->get_printer ());
     115                 :           0 :       m_logger->end_log_line ();
     116                 :             :     }
     117                 :       65569 :   m_events.safe_push (event.release ());
     118                 :       65569 : }
     119                 :             : 
     120                 :             : /* Print a multiline form of this path to STDERR.  */
     121                 :             : 
     122                 :             : DEBUG_FUNCTION void
     123                 :           0 : checker_path::debug () const
     124                 :             : {
     125                 :           0 :   checker_event *e;
     126                 :           0 :   int i;
     127                 :           0 :   FOR_EACH_VEC_ELT (m_events, i, e)
     128                 :             :     {
     129                 :           0 :       label_text event_desc (e->get_desc (false));
     130                 :           0 :       fprintf (stderr,
     131                 :             :                "[%i]: %s \"%s\"\n",
     132                 :             :                i,
     133                 :           0 :                event_kind_to_string (m_events[i]->m_kind),
     134                 :             :                event_desc.get ());
     135                 :           0 :     }
     136                 :           0 : }
     137                 :             : 
     138                 :             : /* Add region_creation_event instances to this path for REG,
     139                 :             :    describing whether REG is on the stack or heap and what
     140                 :             :    its capacity is (if known).
     141                 :             :    If DEBUG is true, also create an RCE_DEBUG event.  */
     142                 :             : 
     143                 :             : void
     144                 :        1404 : checker_path::add_region_creation_events (pending_diagnostic *pd,
     145                 :             :                                           const region *reg,
     146                 :             :                                           const region_model *model,
     147                 :             :                                           const event_loc_info &loc_info,
     148                 :             :                                           bool debug)
     149                 :             : {
     150                 :        1404 :   tree capacity = NULL_TREE;
     151                 :        1404 :   if (model)
     152                 :        1175 :     if (const svalue *capacity_sval = model->get_capacity (reg))
     153                 :        1175 :       capacity = model->get_representative_tree (capacity_sval);
     154                 :             : 
     155                 :        1404 :   pd->add_region_creation_events (reg, capacity, loc_info, *this);
     156                 :             : 
     157                 :        1404 :   if (debug)
     158                 :           0 :     add_event (make_unique<region_creation_event_debug> (reg, capacity,
     159                 :             :                                                          loc_info));
     160                 :        1404 : }
     161                 :             : 
     162                 :             : void
     163                 :        4509 : checker_path::fixup_locations (pending_diagnostic *pd)
     164                 :             : {
     165                 :       32707 :   for (checker_event *e : m_events)
     166                 :       19180 :     e->set_location (pd->fixup_location (e->get_location (), false));
     167                 :        4509 : }
     168                 :             : 
     169                 :             : /* Return true if there is a (start_cfg_edge_event, end_cfg_edge_event) pair
     170                 :             :    at (IDX, IDX + 1).  */
     171                 :             : 
     172                 :             : bool
     173                 :       13511 : checker_path::cfg_edge_pair_at_p (unsigned idx) const
     174                 :             : {
     175                 :       27022 :   if (m_events.length () < idx + 1)
     176                 :             :     return false;
     177                 :       13363 :   return (m_events[idx]->m_kind == EK_START_CFG_EDGE
     178                 :       13363 :           && m_events[idx + 1]->m_kind == EK_END_CFG_EDGE);
     179                 :             : }
     180                 :             : 
     181                 :             : /* Consider a call from "outer" to "middle" which calls "inner",
     182                 :             :    where "inner" and "middle" have been inlined into "outer".
     183                 :             : 
     184                 :             :    We expect the stmt locations for the inlined stmts to have a
     185                 :             :    chain like:
     186                 :             : 
     187                 :             :      [{fndecl: inner},
     188                 :             :       {fndecl: middle, callsite: within middle to inner},
     189                 :             :       {fndecl: outer, callsite: without outer to middle}]
     190                 :             : 
     191                 :             :    The location for the stmt will already be fixed up to reflect
     192                 :             :    the two extra frames, so that we have e.g. this as input
     193                 :             :    (for gcc.dg/analyzer/inlining-4.c):
     194                 :             : 
     195                 :             :     before[0]:
     196                 :             :       EK_FUNCTION_ENTRY "entry to ‘outer’"
     197                 :             :       (depth 1, fndecl ‘outer’, m_loc=511c4)
     198                 :             :     before[1]:
     199                 :             :       EK_START_CFG_EDGE "following ‘true’ branch (when ‘flag != 0’)..."
     200                 :             :       (depth 3 corrected from 1,
     201                 :             :        fndecl ‘inner’ corrected from ‘outer’, m_loc=8000000f)
     202                 :             :     before[2]:
     203                 :             :       EK_END_CFG_EDGE "...to here"
     204                 :             :       (depth 1, fndecl ‘outer’, m_loc=0)
     205                 :             :     before[3]:
     206                 :             :       EK_WARNING "here (‘<unknown>’ is in state ‘null’)"
     207                 :             :       (depth 1, fndecl ‘outer’, m_loc=80000004)
     208                 :             : 
     209                 :             :    We want to add inlined_call_events showing the calls, so that
     210                 :             :    the above becomes:
     211                 :             : 
     212                 :             :     after[0]:
     213                 :             :       EK_FUNCTION_ENTRY "entry to ‘outer’"
     214                 :             :       (depth 1, fndecl ‘outer’, m_loc=511c4)
     215                 :             :     after[1]:
     216                 :             :       EK_INLINED_CALL "inlined call to ‘middle’ from ‘outer’"
     217                 :             :       (depth 1, fndecl ‘outer’, m_loc=53300)
     218                 :             :     after[2]:
     219                 :             :       EK_INLINED_CALL "inlined call to ‘inner’ from ‘middle’"
     220                 :             :       (depth 2, fndecl ‘middle’, m_loc=4d2e0)
     221                 :             :     after[3]:
     222                 :             :       EK_START_CFG_EDGE "following ‘true’ branch (when ‘flag != 0’)..."
     223                 :             :       (depth 3 corrected from 1,
     224                 :             :        fndecl ‘inner’ corrected from ‘outer’, m_loc=8000000f)
     225                 :             :     after[4]: EK_END_CFG_EDGE "...to here"
     226                 :             :       (depth 1, fndecl ‘outer’, m_loc=0)
     227                 :             :     after[5]: EK_WARNING "here (‘<unknown>’ is in state ‘null’)"
     228                 :             :       (depth 1, fndecl ‘outer’, m_loc=80000004)
     229                 :             : 
     230                 :             :     where we've added events between before[0] and before[1] to show
     231                 :             :     the inlined calls leading to the effective stack depths, making
     232                 :             :     the generated path much easier for a user to read.
     233                 :             : 
     234                 :             :     Note how in the above we have a branch (before[1] to before[2])
     235                 :             :     where the locations were originally in different functions.
     236                 :             :     Hence we have to add these events quite late when generating
     237                 :             :     checker_path.  */
     238                 :             : 
     239                 :             : void
     240                 :        4509 : checker_path::inject_any_inlined_call_events (logger *logger)
     241                 :             : {
     242                 :        4509 :   LOG_SCOPE (logger);
     243                 :             : 
     244                 :        4509 :   if (!flag_analyzer_undo_inlining)
     245                 :           5 :     return;
     246                 :             : 
     247                 :             :   /* Build a copy of m_events with the new events inserted.  */
     248                 :        4504 :   auto_vec<checker_event *> updated_events;
     249                 :             : 
     250                 :        4504 :   maybe_log (logger, "before");
     251                 :             : 
     252                 :        4504 :   hash_set<tree> blocks_in_prev_event;
     253                 :             : 
     254                 :       46932 :   for (unsigned ev_idx = 0; ev_idx < m_events.length (); ev_idx++)
     255                 :             :     {
     256                 :       18962 :       checker_event *curr_event = m_events[ev_idx];
     257                 :       18962 :       location_t curr_loc = curr_event->get_location ();
     258                 :       18962 :       hash_set<tree> blocks_in_curr_event;
     259                 :             : 
     260                 :       18962 :       if (logger)
     261                 :             :         {
     262                 :           0 :           logger->start_log_line ();
     263                 :           0 :           logger->log_partial ("event[%i]: %s ", ev_idx,
     264                 :           0 :                                event_kind_to_string (curr_event->m_kind));
     265                 :           0 :           curr_event->dump (logger->get_printer ());
     266                 :           0 :           logger->end_log_line ();
     267                 :           0 :           for (inlining_iterator iter (curr_event->get_location ());
     268                 :           0 :                !iter.done_p (); iter.next ())
     269                 :             :             {
     270                 :           0 :               logger->start_log_line ();
     271                 :           0 :               logger->log_partial ("  %qE", iter.get_block ());
     272                 :           0 :               if (!flag_dump_noaddr)
     273                 :           0 :                 logger->log_partial (" (%p)", iter.get_block ());
     274                 :           0 :               logger->log_partial (", fndecl: %qE, callsite: 0x%x",
     275                 :             :                                    iter.get_fndecl (), iter.get_callsite ());
     276                 :           0 :               if (iter.get_callsite ())
     277                 :           0 :                 dump_location (logger->get_printer (), iter.get_callsite ());
     278                 :           0 :               logger->end_log_line ();
     279                 :             :             }
     280                 :             :         }
     281                 :             : 
     282                 :             :       /* We want to add events to show inlined calls.
     283                 :             : 
     284                 :             :          We want to show changes relative to the previous event, omitting
     285                 :             :          the commonality between the inlining chain.
     286                 :             : 
     287                 :             :          The chain is ordered from innermost frame to outermost frame;
     288                 :             :          we want to walk it backwards to show the calls, so capture it
     289                 :             :          in a vec.  */
     290                 :       18962 :       struct chain_element { tree m_block; tree m_fndecl; };
     291                 :       18962 :       auto_vec<chain_element> elements;
     292                 :       50148 :       for (inlining_iterator iter (curr_loc); !iter.done_p (); iter.next ())
     293                 :             :         {
     294                 :       15593 :           chain_element ce;
     295                 :       15593 :           ce.m_block = iter.get_block ();
     296                 :       15593 :           ce.m_fndecl = iter.get_fndecl ();
     297                 :             : 
     298                 :       15593 :           if (!blocks_in_prev_event.contains (ce.m_block))
     299                 :        6458 :             elements.safe_push (ce);
     300                 :       15593 :           blocks_in_curr_event.add (ce.m_block);
     301                 :             :         }
     302                 :             : 
     303                 :             :       /* Walk from outermost to innermost.  */
     304                 :       18962 :       if (elements.length () > 0)
     305                 :             :         {
     306                 :        6250 :           int orig_stack_depth = curr_event->get_original_stack_depth ();
     307                 :        6458 :           for (unsigned element_idx = elements.length () - 1; element_idx > 0;
     308                 :             :                element_idx--)
     309                 :             :             {
     310                 :         208 :               const chain_element &ce = elements[element_idx];
     311                 :         208 :               int stack_depth_adjustment
     312                 :         208 :                 = (blocks_in_curr_event.elements () - element_idx) - 1;
     313                 :         208 :               if (location_t callsite = BLOCK_SOURCE_LOCATION (ce.m_block))
     314                 :         208 :                 updated_events.safe_push
     315                 :         208 :                   (new inlined_call_event (callsite,
     316                 :         416 :                                            elements[element_idx - 1].m_fndecl,
     317                 :         208 :                                            ce.m_fndecl,
     318                 :             :                                            orig_stack_depth,
     319                 :         416 :                                            stack_depth_adjustment));
     320                 :             :             }
     321                 :             :         }
     322                 :             : 
     323                 :             :       /* Ideally we'd use assignment here:
     324                 :             :            blocks_in_prev_event = blocks_in_curr_event; */
     325                 :       18962 :       blocks_in_prev_event.empty ();
     326                 :       34555 :       for (auto iter : blocks_in_curr_event)
     327                 :       15593 :         blocks_in_prev_event.add (iter);
     328                 :             : 
     329                 :             :       /* Add the existing event.  */
     330                 :       18962 :       updated_events.safe_push (curr_event);
     331                 :       18962 :     }
     332                 :             : 
     333                 :             :   /* Replace m_events with updated_events.  */
     334                 :        4504 :   m_events.truncate (0);
     335                 :        4504 :   m_events.safe_splice (updated_events);
     336                 :             : 
     337                 :        4504 :   maybe_log (logger, " after");
     338                 :        4509 : }
     339                 :             : 
     340                 :             : } // namespace ana
     341                 :             : 
     342                 :             : #endif /* #if ENABLE_ANALYZER */
        

Generated by: LCOV version 2.0-1

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.