LCOV - code coverage report
Current view: top level - gcc/analyzer - impl-sm-context.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 93.5 % 138 129
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 19 19
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Concrete implementation of sm_context.
       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              : #ifndef GCC_ANALYZER_IMPL_SM_CONTEXT
      22              : #define GCC_ANALYZER_IMPL_SM_CONTEXT
      23              : 
      24              : namespace ana {
      25              : 
      26              : /* Concrete implementation of sm_context, wiring it up to the rest of this
      27              :    file.  */
      28              : 
      29      2438563 : class impl_sm_context : public sm_context
      30              : {
      31              : public:
      32      2439311 :   impl_sm_context (exploded_graph &eg,
      33              :                    int sm_idx,
      34              :                    const state_machine &sm,
      35              :                    exploded_node *enode_for_diag,
      36              :                    const program_state *old_state,
      37              :                    program_state *new_state,
      38              :                    const sm_state_map *old_smap,
      39              :                    sm_state_map *new_smap,
      40              :                    path_context *path_ctxt,
      41              :                    bool unknown_side_effects = false)
      42      2439311 :   : sm_context (sm_idx, sm),
      43      2439311 :     m_logger (eg.get_logger ()),
      44      2439311 :     m_eg (eg), m_enode_for_diag (enode_for_diag),
      45      2439311 :     m_old_state (old_state), m_new_state (new_state),
      46      2439311 :     m_old_smap (old_smap), m_new_smap (new_smap),
      47      2439311 :     m_path_ctxt (path_ctxt),
      48      2439311 :     m_unknown_side_effects (unknown_side_effects)
      49              :   {
      50              :   }
      51              : 
      52       262955 :   logger *get_logger () const { return m_logger.get_logger (); }
      53              : 
      54       346774 :   tree get_fndecl_for_call (const gcall &call) final override
      55              :   {
      56       346774 :     impl_region_model_context old_ctxt
      57              :       (m_eg, m_enode_for_diag, nullptr, nullptr, nullptr/*m_enode->get_state ()*/,
      58       346774 :        nullptr, &call);
      59       346774 :     region_model *model = m_new_state->m_region_model;
      60       346774 :     return model->get_fndecl_for_call (call, &old_ctxt);
      61       346774 :   }
      62              : 
      63        80340 :   state_machine::state_t get_state (tree var) final override
      64              :   {
      65        80340 :     logger * const logger = get_logger ();
      66        80340 :     LOG_FUNC (logger);
      67              :     /* Use nullptr ctxt on this get_rvalue call to avoid triggering
      68              :        uninitialized value warnings.  */
      69        80340 :     const svalue *var_old_sval
      70        80340 :       = m_old_state->m_region_model->get_rvalue (var, nullptr);
      71              : 
      72        80340 :     state_machine::state_t current
      73        80340 :       = m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ());
      74       160680 :     return current;
      75        80340 :   }
      76       140742 :   state_machine::state_t get_state (const svalue *sval) final override
      77              :   {
      78       140742 :     logger * const logger = get_logger ();
      79       140742 :     LOG_FUNC (logger);
      80       140742 :     state_machine::state_t current
      81       140742 :       = m_old_smap->get_state (sval, m_eg.get_ext_state ());
      82       281484 :     return current;
      83       140742 :   }
      84              : 
      85              : 
      86        31940 :   void set_next_state (tree var,
      87              :                        state_machine::state_t to,
      88              :                        tree origin) final override
      89              :   {
      90        31940 :     logger * const logger = get_logger ();
      91        31940 :     LOG_FUNC (logger);
      92        31940 :     const svalue *var_new_sval
      93        31940 :       = m_new_state->m_region_model->get_rvalue (var, nullptr);
      94        31940 :     const svalue *origin_new_sval
      95        31940 :       = m_new_state->m_region_model->get_rvalue (origin, nullptr);
      96              : 
      97              :     /* We use the new sval here to avoid issues with uninitialized values.  */
      98        31940 :     state_machine::state_t current
      99        31940 :       = m_old_smap->get_state (var_new_sval, m_eg.get_ext_state ());
     100        31940 :     if (logger)
     101           25 :       logger->log ("%s: state transition of %qE: %s -> %s",
     102           25 :                    m_sm.get_name (),
     103              :                    var,
     104              :                    current->get_name (),
     105              :                    to->get_name ());
     106        31940 :     m_new_smap->set_state (m_new_state->m_region_model, var_new_sval,
     107        31940 :                            to, origin_new_sval, m_eg.get_ext_state ());
     108        31940 :   }
     109              : 
     110         4308 :   void set_next_state (const svalue *sval,
     111              :                        state_machine::state_t to,
     112              :                        tree origin) final override
     113              :   {
     114         4308 :     logger * const logger = get_logger ();
     115         4308 :     LOG_FUNC (logger);
     116         4308 :     impl_region_model_context old_ctxt
     117              :       (m_eg, m_enode_for_diag, nullptr, nullptr, nullptr/*m_enode->get_state ()*/,
     118         4308 :        nullptr, nullptr);
     119              : 
     120         4308 :     const svalue *origin_new_sval
     121         4308 :       = m_new_state->m_region_model->get_rvalue (origin, nullptr);
     122              : 
     123         4308 :     state_machine::state_t current
     124         4308 :       = m_old_smap->get_state (sval, m_eg.get_ext_state ());
     125         4308 :     if (logger)
     126              :       {
     127            0 :         logger->start_log_line ();
     128            0 :         logger->log_partial ("%s: state transition of ",
     129            0 :                              m_sm.get_name ());
     130            0 :         sval->dump_to_pp (logger->get_printer (), true);
     131            0 :         logger->log_partial (": %s -> %s",
     132              :                              current->get_name (),
     133              :                              to->get_name ());
     134            0 :         logger->end_log_line ();
     135              :       }
     136         4308 :     m_new_smap->set_state (m_new_state->m_region_model, sval,
     137         4308 :                            to, origin_new_sval, m_eg.get_ext_state ());
     138         4308 :   }
     139              : 
     140         5513 :   void warn (tree var,
     141              :              std::unique_ptr<pending_diagnostic> d) final override
     142              :   {
     143         5513 :     LOG_FUNC (get_logger ());
     144         5513 :     gcc_assert (d);
     145         5513 :     const svalue *var_old_sval
     146         5513 :       = m_old_state->m_region_model->get_rvalue (var, nullptr);
     147         5513 :     state_machine::state_t current
     148              :       = (var
     149         5513 :          ? m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ())
     150           67 :          : m_old_smap->get_global_state ());
     151         5513 :     bool terminate_path = d->terminate_path_p ();
     152         5513 :     pending_location ploc (m_enode_for_diag);
     153         5513 :     m_eg.get_diagnostic_manager ().add_diagnostic
     154         5513 :       (&m_sm, std::move (ploc),
     155              :        var, var_old_sval, current, std::move (d));
     156         5513 :     if (m_path_ctxt
     157         5222 :         && terminate_path
     158          180 :         && flag_analyzer_suppress_followups)
     159          138 :       m_path_ctxt->terminate_path ();
     160         5513 :   }
     161              : 
     162          112 :   void warn (const svalue *sval,
     163              :              std::unique_ptr<pending_diagnostic> d) final override
     164              :   {
     165          112 :     LOG_FUNC (get_logger ());
     166          112 :     gcc_assert (d);
     167          112 :     state_machine::state_t current
     168              :       = (sval
     169          112 :          ? m_old_smap->get_state (sval, m_eg.get_ext_state ())
     170            0 :          : m_old_smap->get_global_state ());
     171          112 :     bool terminate_path = d->terminate_path_p ();
     172          112 :     pending_location ploc (m_enode_for_diag);
     173          112 :     m_eg.get_diagnostic_manager ().add_diagnostic
     174          112 :       (&m_sm, std::move (ploc),
     175              :        NULL_TREE, sval, current, std::move (d));
     176          112 :     if (m_path_ctxt
     177           12 :         && terminate_path
     178            0 :         && flag_analyzer_suppress_followups)
     179            0 :       m_path_ctxt->terminate_path ();
     180          112 :   }
     181              : 
     182              :   /* Hook for picking more readable trees for SSA names of temporaries,
     183              :      so that rather than e.g.
     184              :        "double-free of '<unknown>'"
     185              :      we can print:
     186              :        "double-free of 'inbuf.data'".  */
     187              : 
     188         5891 :   tree get_diagnostic_tree (tree expr) final override
     189              :   {
     190              :     /* Only for SSA_NAMEs of temporaries; otherwise, return EXPR, as it's
     191              :        likely to be the least surprising tree to report.  */
     192         5891 :     if (TREE_CODE (expr) != SSA_NAME)
     193              :       return expr;
     194         5793 :     if (SSA_NAME_VAR (expr) != NULL)
     195              :       return expr;
     196              : 
     197          290 :     gcc_assert (m_new_state);
     198          290 :     const svalue *sval = m_new_state->m_region_model->get_rvalue (expr, nullptr);
     199              :     /* Find trees for all regions storing the value.  */
     200          290 :     if (tree t = m_new_state->m_region_model->get_representative_tree (sval))
     201              :       return t;
     202              :     else
     203              :       return expr;
     204              :   }
     205              : 
     206          132 :   tree get_diagnostic_tree (const svalue *sval) final override
     207              :   {
     208          132 :     return m_new_state->m_region_model->get_representative_tree (sval);
     209              :   }
     210              : 
     211       251407 :   state_machine::state_t get_global_state () const final override
     212              :   {
     213       251407 :     return m_old_state->m_checker_states[m_sm_idx]->get_global_state ();
     214              :   }
     215              : 
     216        45356 :   void set_global_state (state_machine::state_t state) final override
     217              :   {
     218        45356 :     m_new_state->m_checker_states[m_sm_idx]->set_global_state (state);
     219        45356 :   }
     220              : 
     221         9681 :   void clear_all_per_svalue_state () final override
     222              :   {
     223         9681 :     m_new_state->m_checker_states[m_sm_idx]->clear_all_per_svalue_state ();
     224         9681 :   }
     225              : 
     226           10 :   void on_custom_transition (custom_transition *transition) final override
     227              :   {
     228           10 :     transition->impl_transition (&m_eg,
     229              :                                  const_cast<exploded_node *> (m_enode_for_diag),
     230              :                                  m_sm_idx);
     231           10 :   }
     232              : 
     233       232447 :   tree is_zero_assignment (const gimple *stmt) final override
     234              :   {
     235       232447 :     const gassign *assign_stmt = dyn_cast <const gassign *> (stmt);
     236       152822 :     if (!assign_stmt)
     237              :      return NULL_TREE;
     238       152822 :     impl_region_model_context old_ctxt
     239       152822 :       (m_eg, m_enode_for_diag, m_old_state, m_new_state, nullptr, nullptr, stmt);
     240       305644 :     if (const svalue *sval
     241       152822 :         = m_new_state->m_region_model->get_gassign_result (assign_stmt,
     242              :                                                             &old_ctxt))
     243       147810 :       if (tree cst = sval->maybe_get_constant ())
     244        36353 :         if (::zerop(cst))
     245        14567 :           return gimple_assign_lhs (assign_stmt);
     246              :     return NULL_TREE;
     247       152822 :   }
     248              : 
     249           24 :   path_context *get_path_context () const final override
     250              :   {
     251           24 :     return m_path_ctxt;
     252              :   }
     253              : 
     254        45369 :   bool unknown_side_effects_p () const final override
     255              :   {
     256        45369 :     return m_unknown_side_effects;
     257              :   }
     258              : 
     259       271724 :   const program_state *get_old_program_state () const final override
     260              :   {
     261       271724 :     return m_old_state;
     262              :   }
     263              : 
     264         1634 :   const program_state *get_new_program_state () const final override
     265              :   {
     266         1634 :     return m_new_state;
     267              :   }
     268              : 
     269          147 :   location_t get_emission_location () const final override
     270              :   {
     271          147 :     return pending_location (m_enode_for_diag).get_location ();
     272              :   }
     273              : 
     274              :   log_user m_logger;
     275              :   exploded_graph &m_eg;
     276              :   exploded_node *m_enode_for_diag;
     277              :   const program_state *m_old_state;
     278              :   program_state *m_new_state;
     279              :   const sm_state_map *m_old_smap;
     280              :   sm_state_map *m_new_smap;
     281              :   path_context *m_path_ctxt;
     282              : 
     283              :   /* Are we handling an external function with unknown side effects?  */
     284              :   bool m_unknown_side_effects;
     285              : };
     286              : 
     287              : } // namespace ana
     288              : 
     289              : #endif /* GCC_ANALYZER_IMPL_SM_CONTEXT */
        

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.