LCOV - code coverage report
Current view: top level - gcc/analyzer - checker-event.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 89.5 % 459 411
Test Date: 2026-02-28 14:20:25 Functions: 94.1 % 68 64
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Subclasses of diagnostics::paths::event for analyzer diagnostics.
       2              :    Copyright (C) 2019-2026 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 "analyzer/common.h"
      22              : 
      23              : #include "gimple-pretty-print.h"
      24              : #include "sbitmap.h"
      25              : #include "ordered-hash-map.h"
      26              : #include "fold-const.h"
      27              : #include "gimple-iterator.h"
      28              : #include "inlining-iterator.h"
      29              : #include "tree-logical-location.h"
      30              : #include "diagnostics/sarif-sink.h"
      31              : #include "diagnostics/state-graphs.h"
      32              : #include "custom-sarif-properties/state-graphs.h"
      33              : 
      34              : #include "analyzer/analyzer-logging.h"
      35              : #include "analyzer/sm.h"
      36              : #include "analyzer/call-string.h"
      37              : #include "analyzer/program-point.h"
      38              : #include "analyzer/store.h"
      39              : #include "analyzer/region-model.h"
      40              : #include "analyzer/program-state.h"
      41              : #include "analyzer/checker-path.h"
      42              : #include "analyzer/supergraph.h"
      43              : #include "analyzer/pending-diagnostic.h"
      44              : #include "analyzer/diagnostic-manager.h"
      45              : #include "analyzer/constraint-manager.h"
      46              : #include "analyzer/checker-event.h"
      47              : #include "analyzer/exploded-graph.h"
      48              : 
      49              : #if ENABLE_ANALYZER
      50              : 
      51              : namespace ana {
      52              : 
      53              : /* Get a string for EK.  */
      54              : 
      55              : const char *
      56          192 : event_kind_to_string (enum event_kind ek)
      57              : {
      58          192 :   switch (ek)
      59              :     {
      60            0 :     default:
      61            0 :       gcc_unreachable ();
      62              :     case event_kind::debug:
      63              :       return "debug";
      64            4 :     case event_kind::custom:
      65            4 :       return "custom";
      66            8 :     case event_kind::stmt:
      67            8 :       return "stmt";
      68           18 :     case event_kind::region_creation:
      69           18 :       return "region_creation";
      70           23 :     case event_kind::function_entry:
      71           23 :       return "function_entry";
      72           26 :     case event_kind::state_change:
      73           26 :       return "state_change";
      74           19 :     case event_kind::start_cfg_edge:
      75           19 :       return "start_cfg_edge";
      76           19 :     case event_kind::end_cfg_edge:
      77           19 :       return "end_cfg_edge";
      78            6 :     case event_kind::catch_:
      79            6 :       return "catch";
      80           13 :     case event_kind::call_:
      81           13 :       return "call";
      82            3 :     case event_kind::return_:
      83            3 :       return "return";
      84            0 :     case event_kind::start_consolidated_cfg_edges:
      85            0 :       return "start_consolidated_cfg_edges";
      86            0 :     case event_kind::end_consolidated_cfg_edges:
      87            0 :       return "end_consolidated_cfg_edges";
      88            1 :     case event_kind::inlined_call:
      89            1 :       return "inlined_call";
      90            1 :     case event_kind::setjmp_:
      91            1 :       return "setjmp";
      92            1 :     case event_kind::rewind_from_longjmp:
      93            1 :       return "rewind_from_longjmp";
      94            1 :     case event_kind::rewind_to_setjmp:
      95            1 :       return "rewind_to_setjmp";
      96            6 :     case event_kind::throw_:
      97            6 :       return "throw";
      98            3 :     case event_kind::unwind:
      99            3 :       return "unwind";
     100           40 :     case event_kind::warning:
     101           40 :       return "warning";
     102              :     }
     103              : }
     104              : 
     105              : /* class checker_event : public diagnostics::paths::event.  */
     106              : 
     107              : /* checker_event's ctor.  */
     108              : 
     109        36566 : checker_event::checker_event (enum event_kind kind,
     110        36566 :                               const event_loc_info &loc_info)
     111        36566 : : m_path (nullptr),
     112        36566 :   m_kind (kind), m_loc (loc_info.m_loc),
     113        36566 :   m_original_fndecl (loc_info.m_fndecl),
     114        36566 :   m_effective_fndecl (loc_info.m_fndecl),
     115        36566 :   m_original_depth (loc_info.m_depth),
     116        36566 :   m_effective_depth (loc_info.m_depth),
     117        36566 :   m_pending_diagnostic (nullptr), m_emission_id (),
     118              :   m_logical_loc
     119        36566 :     (tree_logical_location_manager::key_from_tree (loc_info.m_fndecl))
     120              : {
     121              :   /* Update effective fndecl and depth if inlining has been recorded.  */
     122        36566 :   if (flag_analyzer_undo_inlining)
     123              :     {
     124        36554 :       inlining_info info (m_loc);
     125        36554 :       if (info.get_inner_fndecl ())
     126              :         {
     127        29451 :           m_effective_fndecl = info.get_inner_fndecl ();
     128        29451 :           m_effective_depth += info.get_extra_frames ();
     129        29451 :           m_logical_loc
     130        29451 :             = tree_logical_location_manager::key_from_tree (m_effective_fndecl);
     131              :         }
     132              :     }
     133        36566 : }
     134              : 
     135              : /* No-op implementation of diagnostics::paths::event::get_meaning vfunc for
     136              :    checker_event: checker events have no meaning by default.  */
     137              : 
     138              : diagnostics::paths::event::meaning
     139           56 : checker_event::get_meaning () const
     140              : {
     141           56 :   return diagnostics::paths::event::meaning ();
     142              : }
     143              : 
     144              : /* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
     145              :    for checker_event.  */
     146              : 
     147              : void
     148          155 : checker_event::
     149              : maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
     150              :                             diagnostics::sarif_object &thread_flow_loc_obj) const
     151              : {
     152          155 :   auto &props = thread_flow_loc_obj.get_or_create_properties ();
     153              : #define PROPERTY_PREFIX "gcc/analyzer/checker_event/"
     154          310 :   props.set (PROPERTY_PREFIX "emission_id",
     155          155 :              diagnostic_event_id_to_json  (m_emission_id));
     156          155 :   props.set_string (PROPERTY_PREFIX "kind", event_kind_to_string (m_kind));
     157              : 
     158          155 :   if (m_original_fndecl != m_effective_fndecl)
     159            0 :     props.set_logical_location
     160            0 :       (PROPERTY_PREFIX "original_fndecl",
     161              :        builder,
     162            0 :        tree_logical_location_manager::key_from_tree (m_original_fndecl));
     163              : 
     164          155 :   if (m_original_depth != m_effective_depth)
     165            0 :     props.set_integer (PROPERTY_PREFIX "original_depth", m_original_depth);
     166              : #undef PROPERTY_PREFIX
     167          155 : }
     168              : 
     169              : /* Dump this event to PP (for debugging/logging purposes).  */
     170              : 
     171              : void
     172           37 : checker_event::dump (pretty_printer *pp) const
     173              : {
     174           37 :   pp_character (pp, '"');
     175           37 :   print_desc (*pp);
     176           37 :   pp_printf (pp, "\" (depth %i", m_effective_depth);
     177              : 
     178           37 :   if (m_effective_depth != m_original_depth)
     179           10 :     pp_printf (pp, " corrected from %i",
     180              :                m_original_depth);
     181           37 :   if (m_effective_fndecl)
     182              :     {
     183           37 :       pp_printf (pp, ", fndecl %qE", m_effective_fndecl);
     184           37 :       if (m_effective_fndecl != m_original_fndecl)
     185           10 :         pp_printf (pp, " corrected from %qE", m_original_fndecl);
     186              :     }
     187           37 :   pp_printf (pp, ", m_loc=%llx)",
     188           37 :              (unsigned long long) get_location ());
     189           37 : }
     190              : 
     191              : /* Dump this event to stderr (for debugging/logging purposes).  */
     192              : 
     193              : DEBUG_FUNCTION void
     194            0 : checker_event::debug () const
     195              : {
     196            0 :   tree_dump_pretty_printer pp (stderr);
     197            0 :   dump (&pp);
     198            0 :   pp_newline (&pp);
     199            0 : }
     200              : 
     201              : /* Hook for being notified when this event has its final id EMISSION_ID
     202              :    and is about to emitted for PD.
     203              : 
     204              :    Base implementation of checker_event::prepare_for_emission vfunc;
     205              :    subclasses that override this should chain up to it.
     206              : 
     207              :    Record PD and EMISSION_ID, and call the print_desc vfunc, so that any
     208              :    side-effects of the call to print_desc take place before
     209              :    pending_diagnostic::emit is called.
     210              : 
     211              :    For example, state_change_event::print_desc can call
     212              :    pending_diagnostic::describe_state_change; free_of_non_heap can use this
     213              :    to tweak the message (TODO: would be neater to simply capture the
     214              :    pertinent data within the sm-state).  */
     215              : 
     216              : void
     217        16707 : checker_event::prepare_for_emission (checker_path *path,
     218              :                                      pending_diagnostic *pd,
     219              :                                      diagnostics::paths::event_id_t emission_id)
     220              : {
     221        16707 :   m_path = path;
     222        16707 :   m_pending_diagnostic = pd;
     223        16707 :   m_emission_id = emission_id;
     224              : 
     225        16707 :   auto pp = global_dc->clone_printer ();
     226        16707 :   print_desc (*pp.get ());
     227        16707 : }
     228              : 
     229              : std::unique_ptr<diagnostics::digraphs::digraph>
     230           28 : checker_event::maybe_make_diagnostic_state_graph (bool debug) const
     231              : {
     232           28 :   const program_state *state = get_program_state ();
     233           28 :   if (!state)
     234            0 :     return nullptr;
     235              : 
     236           28 :   gcc_assert (m_path);
     237           28 :   const extrinsic_state &ext_state = m_path->get_ext_state ();
     238              : 
     239           28 :   auto result = state->make_diagnostic_state_graph (ext_state);
     240              : 
     241           28 :   if (debug)
     242              :     {
     243           27 :       pretty_printer pp;
     244           27 :       text_art::theme *theme = global_dc->get_diagram_theme ();
     245           27 :       text_art::dump_to_pp (*state, theme, &pp);
     246           27 :       const json::string_property program_state_property
     247              :         (custom_sarif_properties::state_graphs::graph::prefix,
     248           27 :          "analyzer/program_state/");
     249           27 :       result->set_property (program_state_property,
     250              :                             pp_formatted_text (&pp));
     251           27 :     }
     252              : 
     253           28 :   return result;
     254           28 : }
     255              : 
     256              : /* class debug_event : public checker_event.  */
     257              : 
     258              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     259              :    debug_event.
     260              :    Use the saved string as the event's description.  */
     261              : 
     262              : void
     263            0 : debug_event::print_desc (pretty_printer &pp) const
     264              : {
     265            0 :   pp_string (&pp, m_desc);
     266            0 : }
     267              : 
     268              : /* class precanned_custom_event : public custom_event.  */
     269              : 
     270              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     271              :    precanned_custom_event.
     272              :    Use the saved string as the event's description.  */
     273              : 
     274              : void
     275           40 : precanned_custom_event::print_desc (pretty_printer &pp) const
     276              : {
     277           40 :   pp_string (&pp, m_desc);
     278           40 : }
     279              : 
     280              : /* class statement_event : public checker_event.  */
     281              : 
     282              : /* statement_event's ctor.  */
     283              : 
     284        13613 : statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
     285        13613 :                                   const program_state &dst_state)
     286              : : checker_event (event_kind::stmt,
     287        13613 :                  event_loc_info (gimple_location (stmt), fndecl, depth)),
     288        13613 :   m_stmt (stmt),
     289        13613 :   m_dst_state (dst_state)
     290              : {
     291        13613 : }
     292              : 
     293              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     294              :    statement_event.
     295              :    Use the statement's dump form as the event's description.  */
     296              : 
     297              : void
     298           12 : statement_event::print_desc (pretty_printer &pp) const
     299              : {
     300           12 :   pp_string (&pp, "stmt: ");
     301           12 :   pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
     302           12 : }
     303              : 
     304              : /* class region_creation_event : public checker_event.  */
     305              : 
     306         1571 : region_creation_event::region_creation_event (const event_loc_info &loc_info)
     307         1571 : : checker_event (event_kind::region_creation, loc_info)
     308              : {
     309         1571 : }
     310              : 
     311              : /* The various region_creation_event subclasses' print_desc
     312              :    implementations.  */
     313              : 
     314              : void
     315         1208 : region_creation_event_memory_space::print_desc (pretty_printer &pp) const
     316              : {
     317         1208 :   switch (m_mem_space)
     318              :     {
     319           28 :     default:
     320           28 :       pp_string (&pp, "region created here");
     321           28 :       return;
     322         1082 :     case MEMSPACE_STACK:
     323         1082 :       pp_string (&pp, "region created on stack here");
     324         1082 :       return;
     325           98 :     case MEMSPACE_HEAP:
     326           98 :       pp_string (&pp, "region created on heap here");
     327           98 :       return;
     328              :     }
     329              : }
     330              : 
     331              : void
     332         1618 : region_creation_event_capacity::print_desc (pretty_printer &pp) const
     333              : {
     334         1618 :   gcc_assert (m_capacity);
     335         1618 :   if (TREE_CODE (m_capacity) == INTEGER_CST)
     336              :     {
     337         1422 :       unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
     338         1422 :       return pp_printf_n (&pp,
     339              :                           hwi,
     340              :                           "capacity: %wu byte",
     341              :                           "capacity: %wu bytes",
     342         1422 :                           hwi);
     343              :     }
     344              :   else
     345          196 :     return pp_printf (&pp, "capacity: %qE bytes", m_capacity);
     346              : }
     347              : 
     348              : void
     349          214 : region_creation_event_allocation_size::print_desc (pretty_printer &pp) const
     350              : {
     351          214 :   if (m_capacity)
     352              :     {
     353          206 :       if (TREE_CODE (m_capacity) == INTEGER_CST)
     354          118 :         pp_printf_n (&pp,
     355              :                      tree_to_uhwi (m_capacity),
     356              :                      "allocated %E byte here",
     357              :                      "allocated %E bytes here",
     358              :                      m_capacity);
     359              :       else
     360           88 :         pp_printf (&pp,
     361              :                    "allocated %qE bytes here",
     362              :                    m_capacity);
     363              :     }
     364              :   else
     365            8 :     pp_printf (&pp, "allocated here");
     366          214 : }
     367              : 
     368              : void
     369            0 : region_creation_event_debug::print_desc (pretty_printer &pp) const
     370              : {
     371            0 :   pp_string (&pp, "region creation: ");
     372            0 :   m_reg->dump_to_pp (&pp, true);
     373            0 :   if (m_capacity)
     374            0 :     pp_printf (&pp, " capacity: %qE", m_capacity);
     375            0 : }
     376              : 
     377              : /* class function_entry_event : public checker_event.  */
     378              : 
     379         5104 : function_entry_event::function_entry_event (const program_point &dst_point,
     380         5104 :                                             const program_state &state)
     381              : : checker_event (event_kind::function_entry,
     382         5104 :                  event_loc_info (dst_point.get_location (),
     383              :                                  dst_point.get_fndecl (),
     384        15312 :                                  dst_point.get_stack_depth ())),
     385        10208 :   m_state (state)
     386              : {
     387         5104 : }
     388              : 
     389              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     390              :    function_entry_event.
     391              : 
     392              :    Use a string such as "entry to 'foo'" as the event's description.  */
     393              : 
     394              : void
     395         2719 : function_entry_event::print_desc (pretty_printer &pp) const
     396              : {
     397         2719 :   pp_printf (&pp, "entry to %qE", m_effective_fndecl);
     398         2719 : }
     399              : 
     400              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
     401              :    function entry.  */
     402              : 
     403              : diagnostics::paths::event::meaning
     404          220 : function_entry_event::get_meaning () const
     405              : {
     406          220 :   return meaning (verb::enter, noun::function);
     407              : }
     408              : 
     409              : /* class state_change_event : public checker_event.  */
     410              : 
     411              : /* state_change_event's ctor.  */
     412              : 
     413         3772 : state_change_event::state_change_event (const event_loc_info &loc_info,
     414              :                                         const gimple *stmt,
     415              :                                         const state_machine &sm,
     416              :                                         const svalue *sval,
     417              :                                         state_machine::state_t from,
     418              :                                         state_machine::state_t to,
     419              :                                         const svalue *origin,
     420              :                                         const program_state &dst_state,
     421         3772 :                                         const exploded_node *enode)
     422              : : checker_event (event_kind::state_change, loc_info),
     423         3772 :   m_stmt (stmt),
     424         3772 :   m_sm (sm),
     425         3772 :   m_sval (sval), m_from (from), m_to (to),
     426         3772 :   m_origin (origin),
     427         3772 :   m_dst_state (dst_state),
     428         3772 :   m_enode (enode)
     429              : {
     430         3772 : }
     431              : 
     432              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     433              :    state_change_event.
     434              : 
     435              :    Attempt to generate a nicer human-readable description.
     436              :    For greatest precision-of-wording, give the pending diagnostic
     437              :    a chance to describe this state change (in terms of the
     438              :    diagnostic).
     439              :    Note that we only have a pending_diagnostic set on the event once
     440              :    the diagnostic is about to being emitted, so the description for
     441              :    an event can change.  */
     442              : 
     443              : void
     444         4204 : state_change_event::print_desc (pretty_printer &pp) const
     445              : {
     446         4204 :   if (m_pending_diagnostic)
     447              :     {
     448         4204 :       region_model *model = m_dst_state.m_region_model;
     449         4204 :       tree var = model->get_representative_tree (m_sval);
     450         4204 :       tree origin = model->get_representative_tree (m_origin);
     451         4204 :       evdesc::state_change evd (var, origin,
     452         4204 :                                 m_from, m_to, m_emission_id, *this);
     453         4204 :       if (m_pending_diagnostic->describe_state_change (pp, evd))
     454              :         {
     455         4198 :           if (flag_analyzer_verbose_state_changes)
     456              :             {
     457              :               /* Append debugging information about this event.  */
     458              : 
     459          144 :               if (var)
     460          136 :                 pp_printf (&pp, " (state of %qE: ", var);
     461              :               else
     462            8 :                 pp_string (&pp, " (state: ");
     463              : 
     464          144 :               pp_printf (&pp, "%qs -> %qs, ",
     465          144 :                          m_from->get_name (),
     466          144 :                          m_to->get_name ());
     467              : 
     468          144 :               if (m_origin)
     469            0 :                 pp_printf (&pp, "origin: %qE", origin);
     470              :               else
     471          144 :                 pp_string (&pp, "NULL origin");
     472              : 
     473              :               /* Get any "meaning" of event.  */
     474          144 :               diagnostics::paths::event::meaning meaning = get_meaning ();
     475          144 :               pp_string (&pp, ", meaning: ");
     476          144 :               meaning.dump_to_pp (&pp);
     477          144 :               pp_string (&pp, ")");
     478              :             }
     479         4198 :           return;
     480              :         }
     481              :     }
     482              : 
     483              :   /* Fallback description.  */
     484            6 :   if (m_sval)
     485              :     {
     486            6 :       label_text sval_desc = m_sval->get_desc ();
     487            6 :       pp_printf (&pp,
     488              :                  "state of %qs: %qs -> %qs",
     489              :                  sval_desc.get (),
     490            6 :                  m_from->get_name (),
     491            6 :                  m_to->get_name ());
     492            6 :       if (m_origin)
     493              :         {
     494            0 :           label_text origin_desc = m_origin->get_desc ();
     495            0 :           pp_printf (&pp, " (origin: %qs)",
     496              :                      origin_desc.get ());
     497            0 :         }
     498              :       else
     499            6 :         pp_string (&pp, " (NULL origin)");
     500            6 :     }
     501              :   else
     502              :     {
     503            0 :       gcc_assert (m_origin == nullptr);
     504            0 :       pp_printf (&pp,
     505              :                  "global state: %qs -> %qs",
     506            0 :                  m_from->get_name (),
     507            0 :                  m_to->get_name ());
     508              :     }
     509              : }
     510              : 
     511              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
     512              :    state change events: delegate to the pending_diagnostic to
     513              :    get any meaning.  */
     514              : 
     515              : diagnostics::paths::event::meaning
     516          336 : state_change_event::get_meaning () const
     517              : {
     518          336 :   if (m_pending_diagnostic)
     519              :     {
     520          336 :       region_model *model = m_dst_state.m_region_model;
     521          336 :       tree var = model->get_representative_tree (m_sval);
     522          336 :       tree origin = model->get_representative_tree (m_origin);
     523          336 :       evdesc::state_change evd (var, origin,
     524          336 :                                 m_from, m_to, m_emission_id, *this);
     525          336 :       return m_pending_diagnostic->get_meaning_for_state_change (evd);
     526              :     }
     527              :   else
     528            0 :     return meaning ();
     529              : }
     530              : 
     531              : /* class superedge_event : public checker_event.  */
     532              : 
     533              : /* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
     534              :    for superedge_event.  */
     535              : 
     536              : void
     537           49 : superedge_event::
     538              : maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
     539              :                             diagnostics::sarif_object &thread_flow_loc_obj)
     540              :   const
     541              : {
     542           49 :   checker_event::maybe_add_sarif_properties (builder, thread_flow_loc_obj);
     543           49 :   auto &props = thread_flow_loc_obj.get_or_create_properties ();
     544              : #define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
     545           49 :   if (m_sedge)
     546           49 :     props.set (PROPERTY_PREFIX "superedge", m_sedge->to_json ());
     547              : #undef PROPERTY_PREFIX
     548           49 : }
     549              : 
     550              : /* Determine if this event should be filtered at the given verbosity
     551              :    level.  */
     552              : 
     553              : bool
     554         2607 : superedge_event::should_filter_p (int verbosity) const
     555              : {
     556         2607 :   if (m_sedge->get_any_cfg_edge ())
     557              :     {
     558         2607 :       if (verbosity < 2)
     559              :         return true;
     560              : 
     561         2574 :       if (verbosity < 4)
     562              :         {
     563              :           /* Filter events with empty descriptions.  This ought to filter
     564              :              FALLTHRU, but retain true/false/switch edges.  */
     565         2574 :           auto pp = global_dc->clone_printer ();
     566         2574 :           print_desc (*pp.get ());
     567         2574 :           if (pp_formatted_text (pp.get ()) [0] == '\0')
     568            3 :             return true;
     569         2574 :         }
     570              :     }
     571              :   return false;
     572              : }
     573              : 
     574              : const program_state *
     575           12 : superedge_event::get_program_state () const
     576              : {
     577           12 :   return &m_eedge.m_dest->get_state ();
     578              : }
     579              : 
     580              : const call_and_return_op *
     581         1193 : superedge_event::get_call_and_return_op () const
     582              : {
     583         1193 :   if (m_sedge)
     584         1193 :     if (auto base_op = m_sedge->get_op ())
     585         1193 :       return base_op->dyn_cast_call_and_return_op ();
     586              :   return nullptr;
     587              : }
     588              : 
     589              : /* superedge_event's ctor.  */
     590              : 
     591         6800 : superedge_event::superedge_event (enum event_kind kind,
     592              :                                   const exploded_edge &eedge,
     593         6800 :                                   const event_loc_info &loc_info)
     594              : : checker_event (kind, loc_info),
     595         6800 :   m_eedge (eedge), m_sedge (eedge.m_sedge)
     596              : {
     597         6800 :   gcc_assert (m_sedge);
     598         6800 : }
     599              : 
     600              : /* class cfg_edge_event : public superedge_event.  */
     601              : 
     602              : /* cfg_edge_event's ctor.  */
     603              : 
     604         5607 : cfg_edge_event::cfg_edge_event (enum event_kind kind,
     605              :                                 const exploded_edge &eedge,
     606              :                                 const event_loc_info &loc_info,
     607         5607 :                                 const control_flow_op *op)
     608              : : superedge_event (kind, eedge, loc_info),
     609         5607 :   m_op (op)
     610              : {
     611         5607 : }
     612              : 
     613              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
     614              :    CFG edge events.  */
     615              : 
     616              : diagnostics::paths::event::meaning
     617          292 : cfg_edge_event::get_meaning () const
     618              : {
     619          292 :   if (::edge e = get_cfg_edge ())
     620              :     {
     621          292 :       if (e->flags & EDGE_TRUE_VALUE)
     622          124 :         return meaning (verb::branch, property::true_);
     623          168 :       else if (e->flags & EDGE_FALSE_VALUE)
     624          128 :         return meaning (verb::branch, property::false_);
     625              :     }
     626           40 :   return meaning ();
     627              : }
     628              : 
     629              : ::edge
     630          799 : cfg_edge_event::get_cfg_edge () const
     631              : {
     632          799 :   return m_sedge->get_any_cfg_edge ();
     633              : }
     634              : 
     635              : /* If this event is for a conditional, write the sense of the
     636              :    conditional to *OUT and return true.
     637              :    Otherwise return false.  */
     638              : 
     639              : bool
     640          507 : cfg_edge_event::maybe_get_edge_sense (bool *out) const
     641              : {
     642          507 :   if (::edge e = get_cfg_edge ())
     643              :     {
     644          507 :       if (e->flags & EDGE_TRUE_VALUE)
     645              :         {
     646          256 :           *out = true;
     647          256 :           return true;
     648              :         }
     649          251 :       else if (e->flags & EDGE_FALSE_VALUE)
     650              :         {
     651          251 :           *out = false;
     652          251 :           return true;
     653              :         }
     654              :     }
     655              :   return false;
     656              : }
     657              : 
     658              : /* class start_cfg_edge_event : public cfg_edge_event.  */
     659              : 
     660              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     661              :    start_cfg_edge_event.
     662              : 
     663              :    If -fanalyzer-verbose-edges, then generate low-level descriptions, such
     664              :    as
     665              :      "taking 'true' edge SN:7 -> SN:8".
     666              : 
     667              :    Otherwise, generate strings using the label of the underlying CFG if
     668              :    any, such as:
     669              :      "following 'true' branch..." or
     670              :      "following 'case 3' branch..."
     671              :      "following 'default' branch..."
     672              : 
     673              :    For conditionals, attempt to supply a description of the condition that
     674              :    holds, such as:
     675              :      "following 'false' branch (when 'ptr' is non-NULL)..."
     676              : 
     677              :    Failing that, print nothing (which will lead to this event
     678              :    being filtered).  */
     679              : 
     680              : void
     681         7070 : start_cfg_edge_event::print_desc (pretty_printer &pp) const
     682              : {
     683         7070 :   bool user_facing = !flag_analyzer_verbose_edges;
     684         7070 :   label_text edge_desc (m_sedge->get_description (user_facing));
     685         7070 :   if (user_facing)
     686              :     {
     687         7070 :       if (edge_desc.get ()
     688         7070 :           && strlen (edge_desc.get ()) > 0
     689        14137 :           && m_op)
     690              :         {
     691         7067 :           label_text cond_desc
     692         7067 :             = m_op->maybe_describe_condition (pp_show_color (&pp));
     693         7067 :           label_text result;
     694         7067 :           if (cond_desc.get ())
     695         3954 :             pp_printf (&pp,
     696              :                        "following %qs branch (%s)...",
     697              :                        edge_desc.get (), cond_desc.get ());
     698              :           else
     699         3113 :             pp_printf (&pp,
     700              :                        "following %qs branch...",
     701              :                        edge_desc.get ());
     702        10901 :         }
     703              :     }
     704              :   else
     705              :     {
     706            0 :       if (strlen (edge_desc.get ()) > 0)
     707            0 :         return pp_printf (&pp,
     708              :                           "taking %qs edge SN:%i -> SN:%i",
     709              :                           edge_desc.get (),
     710            0 :                           m_sedge->m_src->m_id,
     711            0 :                           m_sedge->m_dest->m_id);
     712              :       else
     713            0 :         return pp_printf (&pp,
     714              :                           "taking edge SN:%i -> SN:%i",
     715            0 :                           m_sedge->m_src->m_id,
     716            0 :                           m_sedge->m_dest->m_id);
     717              :     }
     718         7070 : }
     719              : 
     720              : /* class catch_cfg_edge_event : public cfg_edge_event.  */
     721              : 
     722              : diagnostics::paths::event::meaning
     723            6 : catch_cfg_edge_event::get_meaning () const
     724              : {
     725            6 :   return meaning (verb::catch_);
     726              : }
     727              : 
     728              : /* class call_event : public superedge_event.  */
     729              : 
     730              : /* call_event's ctor.  */
     731              : 
     732         1193 : call_event::call_event (const exploded_edge &eedge,
     733         1193 :                         const event_loc_info &loc_info)
     734         1193 : : superedge_event (event_kind::call_, eedge, loc_info)
     735              : {
     736         1193 :    m_src_snode = eedge.m_src->get_supernode ();
     737         1193 :    m_dest_snode = eedge.m_dest->get_supernode ();
     738         1193 : }
     739              : 
     740              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     741              :    call_event.
     742              : 
     743              :    If this call event passes critical state for an sm-based warning,
     744              :    allow the diagnostic to generate a precise description, such as:
     745              : 
     746              :      "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
     747              : 
     748              :    Otherwise, generate a description of the form
     749              :    "calling 'foo' from 'bar'".  */
     750              : 
     751              : void
     752         1707 : call_event::print_desc (pretty_printer &pp) const
     753              : {
     754         1707 :   if (m_critical_state.m_state && m_pending_diagnostic)
     755              :     {
     756          388 :       gcc_assert (m_critical_state.m_var);
     757          388 :       tree var = fixup_tree_for_diagnostic (m_critical_state.m_var);
     758          388 :       evdesc::call_with_state evd (m_src_snode->m_fun->decl,
     759          388 :                                    m_dest_snode->m_fun->decl,
     760              :                                    var,
     761          388 :                                    m_critical_state.m_state);
     762          388 :       if (m_pending_diagnostic->describe_call_with_state (pp, evd))
     763          180 :         return;
     764              :     }
     765              : 
     766         1527 :   pp_printf (&pp,
     767              :              "calling %qE from %qE",
     768              :              get_callee_fndecl (),
     769              :              get_caller_fndecl ());
     770              : }
     771              : 
     772              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
     773              :    function call events.  */
     774              : 
     775              : diagnostics::paths::event::meaning
     776          136 : call_event::get_meaning () const
     777              : {
     778          136 :   return meaning (verb::call, noun::function);
     779              : }
     780              : 
     781              : /* Override of checker_event::is_call_p for calls.  */
     782              : 
     783              : bool
     784         1919 : call_event::is_call_p () const
     785              : {
     786         1919 :   return true;
     787              : }
     788              : 
     789              : tree
     790         1595 : call_event::get_caller_fndecl () const
     791              : {
     792         1595 :   return m_src_snode->m_fun->decl;
     793              : }
     794              : 
     795              : tree
     796         1595 : call_event::get_callee_fndecl () const
     797              : {
     798         1595 :   return m_dest_snode->m_fun->decl;
     799              : }
     800              : 
     801              : const program_state *
     802            3 : call_event::get_program_state () const
     803              : {
     804              :   /* Use the state at the source (at the caller),
     805              :      rather than the one at the dest, which has a frame for the callee.  */
     806            3 :   return &m_eedge.m_src->get_state ();
     807              : }
     808              : 
     809              : /* class return_event : public checker_event.  */
     810              : 
     811              : /* return_event's ctor.  */
     812              : 
     813          601 : return_event::return_event (const exploded_edge &eedge,
     814          601 :                             const event_loc_info &loc_info)
     815              : : checker_event (event_kind::return_, loc_info),
     816          601 :   m_eedge (eedge)
     817              : {
     818          601 :   m_src_snode = eedge.m_src->get_supernode ();
     819          601 :   m_dest_snode = eedge.m_dest->get_supernode ();
     820          601 :   m_call_and_return_op
     821          601 :     = eedge.m_src->get_point ().get_call_string ().get_top_of_stack ().m_call_op;
     822          601 : }
     823              : 
     824              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     825              :    return_event.
     826              : 
     827              :    If this return event returns critical state for an sm-based warning,
     828              :    allow the diagnostic to generate a precise description, such as:
     829              : 
     830              :       "possible of NULL to 'foo' from 'bar'"
     831              : 
     832              :    Otherwise, generate a description of the form
     833              :    "returning to 'foo' from 'bar'.  */
     834              : 
     835              : void
     836          576 : return_event::print_desc (pretty_printer &pp) const
     837              : {
     838              :   /*  For greatest precision-of-wording, if this is returning the
     839              :       state involved in the pending diagnostic, give the pending
     840              :       diagnostic a chance to describe this return (in terms of
     841              :       itself).  */
     842          576 :   if (m_critical_state.m_state && m_pending_diagnostic)
     843              :     {
     844          133 :       evdesc::return_of_state evd (m_dest_snode->m_fun->decl,
     845          133 :                                    m_src_snode->m_fun->decl,
     846          133 :                                    m_critical_state.m_state);
     847          133 :       if (m_pending_diagnostic->describe_return_of_state (pp, evd))
     848           50 :         return;
     849              :     }
     850          526 :   pp_printf (&pp,
     851              :              "returning to %qE from %qE",
     852          526 :              m_dest_snode->m_fun->decl,
     853          526 :              m_src_snode->m_fun->decl);
     854              : }
     855              : 
     856              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
     857              :    function return events.  */
     858              : 
     859              : diagnostics::paths::event::meaning
     860           54 : return_event::get_meaning () const
     861              : {
     862           54 :   return meaning (verb::return_, noun::function);
     863              : }
     864              : 
     865              : /* Override of checker_event::is_return_p for returns.  */
     866              : 
     867              : bool
     868          601 : return_event::is_return_p () const
     869              : {
     870          601 :   return true;
     871              : }
     872              : 
     873              : const program_state *
     874            3 : return_event::get_program_state () const
     875              : {
     876            3 :   return &m_eedge.m_dest->get_state ();
     877              : }
     878              : 
     879              : /* class start_consolidated_cfg_edges_event : public checker_event.  */
     880              : 
     881              : void
     882          200 : start_consolidated_cfg_edges_event::print_desc (pretty_printer &pp) const
     883              : {
     884          200 :   pp_printf (&pp,
     885              :              "following %qs branch...",
     886          200 :              m_edge_sense ? "true" : "false");
     887          200 : }
     888              : 
     889              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
     890              :    start_consolidated_cfg_edges_event.  */
     891              : 
     892              : diagnostics::paths::event::meaning
     893            0 : start_consolidated_cfg_edges_event::get_meaning () const
     894              : {
     895            0 :   return meaning (verb::branch,
     896            0 :                   (m_edge_sense ? property::true_ : property::false_));
     897              : }
     898              : 
     899              : /* class inlined_call_event : public checker_event.  */
     900              : 
     901              : void
     902          326 : inlined_call_event::print_desc (pretty_printer &pp) const
     903              : {
     904          326 :   pp_printf (&pp,
     905              :              "inlined call to %qE from %qE",
     906          326 :              m_apparent_callee_fndecl,
     907          326 :              m_apparent_caller_fndecl);
     908          326 : }
     909              : 
     910              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
     911              :    reconstructed inlined function calls.  */
     912              : 
     913              : diagnostics::paths::event::meaning
     914           72 : inlined_call_event::get_meaning () const
     915              : {
     916           72 :   return meaning (verb::call, noun::function);
     917              : }
     918              : 
     919              : /* class setjmp_event : public checker_event.  */
     920              : 
     921              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     922              :    setjmp_event.  */
     923              : 
     924              : void
     925           41 : setjmp_event::print_desc (pretty_printer &pp) const
     926              : {
     927           41 :   pp_printf (&pp,
     928              :              "%qs called here",
     929              :              get_user_facing_name (m_setjmp_call));
     930           41 : }
     931              : 
     932              : diagnostics::paths::event::meaning
     933           17 : setjmp_event::get_meaning () const
     934              : {
     935           17 :   return meaning (verb::setjmp_);
     936              : }
     937              : 
     938              : /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
     939              : 
     940              :    Record this setjmp's event ID into the path, so that rewind events can
     941              :    use it.  */
     942              : 
     943              : void
     944           20 : setjmp_event::prepare_for_emission (checker_path *path,
     945              :                                     pending_diagnostic *pd,
     946              :                                     diagnostics::paths::event_id_t emission_id)
     947              : {
     948           20 :   checker_event::prepare_for_emission (path, pd, emission_id);
     949           20 :   path->record_setjmp_event (m_enode, emission_id);
     950           20 : }
     951              : 
     952              : /* class rewind_event : public checker_event.  */
     953              : 
     954              : /* Get the fndecl containing the site of the longjmp call.  */
     955              : 
     956              : tree
     957           93 : rewind_event::get_longjmp_caller () const
     958              : {
     959           93 :   return m_eedge->m_src->get_function ()->decl;
     960              : }
     961              : 
     962              : /* Get the fndecl containing the site of the setjmp call.  */
     963              : 
     964              : tree
     965           85 : rewind_event::get_setjmp_caller () const
     966              : {
     967           85 :   return m_eedge->m_dest->get_function ()->decl;
     968              : }
     969              : 
     970              : diagnostics::paths::event::meaning
     971           26 : rewind_event::get_meaning () const
     972              : {
     973           26 :   return meaning (verb::longjmp_);
     974              : }
     975              : 
     976              : /* rewind_event's ctor.  */
     977              : 
     978           30 : rewind_event::rewind_event (const exploded_edge *eedge,
     979              :                             enum event_kind kind,
     980              :                             const event_loc_info &loc_info,
     981           30 :                             const rewind_info_t *rewind_info)
     982              : : checker_event (kind, loc_info),
     983           30 :   m_rewind_info (rewind_info),
     984           30 :   m_eedge (eedge)
     985              : {
     986           30 :   gcc_assert (m_eedge->m_custom_info.get () == m_rewind_info);
     987           30 : }
     988              : 
     989              : /* class rewind_from_longjmp_event : public rewind_event.  */
     990              : 
     991              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     992              :    rewind_from_longjmp_event.  */
     993              : 
     994              : void
     995           31 : rewind_from_longjmp_event::print_desc (pretty_printer &pp) const
     996              : {
     997           31 :   const char *src_name
     998           31 :     = get_user_facing_name (m_rewind_info->get_longjmp_call ());
     999              : 
    1000           31 :   if (get_longjmp_caller () == get_setjmp_caller ())
    1001              :     /* Special-case: purely intraprocedural rewind.  */
    1002            8 :     pp_printf (&pp,
    1003              :                "rewinding within %qE from %qs...",
    1004              :                get_longjmp_caller (),
    1005              :                src_name);
    1006              :   else
    1007           23 :     pp_printf (&pp,
    1008              :                "rewinding from %qs in %qE...",
    1009              :                src_name,
    1010              :                get_longjmp_caller ());
    1011           31 : }
    1012              : 
    1013              : /* class rewind_to_setjmp_event : public rewind_event.  */
    1014              : 
    1015              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
    1016              :    rewind_to_setjmp_event.  */
    1017              : 
    1018              : void
    1019           31 : rewind_to_setjmp_event::print_desc (pretty_printer &pp) const
    1020              : {
    1021           31 :   const char *dst_name
    1022           31 :     = get_user_facing_name (m_rewind_info->get_setjmp_call ());
    1023              : 
    1024              :   /* If we can, identify the ID of the setjmp_event.  */
    1025           31 :   if (m_original_setjmp_event_id.known_p ())
    1026              :     {
    1027           16 :       if (get_longjmp_caller () == get_setjmp_caller ())
    1028              :         /* Special-case: purely intraprocedural rewind.  */
    1029            4 :         pp_printf (&pp,
    1030              :                    "...to %qs (saved at %@)",
    1031              :                    dst_name,
    1032              :                    &m_original_setjmp_event_id);
    1033              :       else
    1034           12 :         pp_printf (&pp,
    1035              :                    "...to %qs in %qE (saved at %@)",
    1036              :                    dst_name,
    1037              :                    get_setjmp_caller (),
    1038              :                    &m_original_setjmp_event_id);
    1039              :     }
    1040              :   else
    1041              :     {
    1042           15 :       if (get_longjmp_caller () == get_setjmp_caller ())
    1043              :         /* Special-case: purely intraprocedural rewind.  */
    1044            4 :         pp_printf (&pp,
    1045              :                    "...to %qs",
    1046              :                    dst_name);
    1047              :       else
    1048           11 :         pp_printf (&pp,
    1049              :                    "...to %qs in %qE",
    1050              :                    dst_name,
    1051              :                    get_setjmp_caller ());
    1052              :     }
    1053           31 : }
    1054              : 
    1055              : /* Implementation of checker_event::prepare_for_emission vfunc for
    1056              :    rewind_to_setjmp_event.
    1057              : 
    1058              :    Attempt to look up the setjmp event ID that recorded the jmp_buf
    1059              :    for this rewind.  */
    1060              : 
    1061              : void
    1062           15 : rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
    1063              :                                               pending_diagnostic *pd,
    1064              :                                               diagnostics::paths::event_id_t emission_id)
    1065              : {
    1066           15 :   checker_event::prepare_for_emission (path, pd, emission_id);
    1067           15 :   path->get_setjmp_event (m_rewind_info->get_enode_origin (),
    1068              :                           &m_original_setjmp_event_id);
    1069           15 : }
    1070              : 
    1071              : /* class throw_event : public checker_event.  */
    1072              : 
    1073              : diagnostics::paths::event::meaning
    1074            6 : throw_event::get_meaning () const
    1075              : {
    1076            6 :   return meaning (verb::throw_);
    1077              : }
    1078              : 
    1079              : /* class explicit_throw_event : public throw_event.  */
    1080              : void
    1081          150 : explicit_throw_event::print_desc (pretty_printer &pp) const
    1082              : {
    1083          150 :   if (m_is_rethrow)
    1084              :     {
    1085           30 :       if (m_type)
    1086           18 :         pp_printf (&pp, "rethrowing exception of type %qT here...", m_type);
    1087              :       else
    1088           12 :         pp_printf (&pp, "rethrowing exception here...");
    1089              :     }
    1090              :   else
    1091              :     {
    1092          120 :       if (m_type)
    1093          120 :         pp_printf (&pp, "throwing exception of type %qT here...", m_type);
    1094              :       else
    1095            0 :         pp_printf (&pp, "throwing exception here...");
    1096              :     }
    1097          150 : }
    1098              : 
    1099              : /* class throw_from_call_to_external_fn_event : public throw_event.  */
    1100              : 
    1101              : void
    1102           46 : throw_from_call_to_external_fn_event::print_desc (pretty_printer &pp) const
    1103              : {
    1104           46 :   if (m_fndecl)
    1105           46 :     pp_printf (&pp, "if %qD throws an exception...", m_fndecl);
    1106              :   else
    1107            0 :     pp_printf (&pp, "if the called function throws an exception...");
    1108           46 : }
    1109              : 
    1110              : // class unwind_event : public checker_event
    1111              : 
    1112              : void
    1113           26 : unwind_event::print_desc (pretty_printer &pp) const
    1114              : {
    1115           26 :   if (m_num_frames > 1)
    1116           18 :     pp_printf (&pp, "unwinding %i stack frames", m_num_frames);
    1117              :   else
    1118            8 :     pp_printf (&pp, "unwinding stack frame");
    1119           26 : }
    1120              : 
    1121              : diagnostics::paths::event::meaning
    1122            3 : unwind_event::get_meaning () const
    1123              : {
    1124            3 :   return meaning (verb::unwind_);
    1125              : }
    1126              : 
    1127              : /* class warning_event : public checker_event.  */
    1128              : 
    1129              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
    1130              :    warning_event.
    1131              : 
    1132              :    If the pending diagnostic implements describe_final_event, use it,
    1133              :    generating a precise description e.g.
    1134              :      "second 'free' here; first 'free' was at (7)"
    1135              : 
    1136              :    Otherwise generate a generic description.  */
    1137              : 
    1138              : void
    1139         7953 : warning_event::print_desc (pretty_printer &pp) const
    1140              : {
    1141         7953 :   if (m_pending_diagnostic)
    1142              :     {
    1143         7941 :       tree var = fixup_tree_for_diagnostic (m_var);
    1144         7941 :       evdesc::final_event evd (var, m_state, *this);
    1145         7941 :       if (m_pending_diagnostic->describe_final_event (pp, evd))
    1146              :         {
    1147         7322 :           if (m_sm && flag_analyzer_verbose_state_changes)
    1148              :             {
    1149           72 :               if (var)
    1150           64 :                 pp_printf (&pp, " (%qE is in state %qs)",
    1151           64 :                            var, m_state->get_name ());
    1152              :               else
    1153            8 :                 pp_printf (&pp, " (in global state %qs)",
    1154            8 :                            m_state->get_name ());
    1155              :             }
    1156         7322 :           return;
    1157              :         }
    1158              :     }
    1159              : 
    1160          631 :   if (m_sm)
    1161              :     {
    1162           64 :       if (m_var)
    1163           64 :         pp_printf (&pp, "here (%qE is in state %qs)",
    1164           64 :                    m_var, m_state->get_name ());
    1165              :       else
    1166            0 :         pp_printf (&pp, "here (in global state %qs)",
    1167            0 :                    m_state->get_name ());
    1168           64 :       return;
    1169              :     }
    1170              :   else
    1171          567 :     pp_string (&pp, "here");
    1172              : }
    1173              : 
    1174              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
    1175              :    warning_event.  */
    1176              : 
    1177              : diagnostics::paths::event::meaning
    1178          232 : warning_event::get_meaning () const
    1179              : {
    1180          232 :   return meaning (verb::danger, noun::unknown);
    1181              : }
    1182              : 
    1183              : const program_state *
    1184            3 : warning_event::get_program_state () const
    1185              : {
    1186            3 :   if (m_program_state)
    1187              :     return m_program_state.get ();
    1188              :   else
    1189            1 :     return &m_enode->get_state ();
    1190              : }
    1191              : 
    1192              : } // namespace ana
    1193              : 
    1194              : #endif /* #if ENABLE_ANALYZER */
        

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.