(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
plugin/
analyzer_known_fns_plugin.c
       1  /* Proof-of-concept of a -fanalyzer plugin to handle known functions.  */
       2  /* { dg-options "-g" } */
       3  
       4  #define INCLUDE_MEMORY
       5  #include "gcc-plugin.h"
       6  #include "config.h"
       7  #include "system.h"
       8  #include "coretypes.h"
       9  #include "tree.h"
      10  #include "function.h"
      11  #include "basic-block.h"
      12  #include "gimple.h"
      13  #include "gimple-iterator.h"
      14  #include "diagnostic-core.h"
      15  #include "graphviz.h"
      16  #include "options.h"
      17  #include "cgraph.h"
      18  #include "tree-dfa.h"
      19  #include "stringpool.h"
      20  #include "convert.h"
      21  #include "target.h"
      22  #include "fold-const.h"
      23  #include "tree-pretty-print.h"
      24  #include "diagnostic-color.h"
      25  #include "diagnostic-metadata.h"
      26  #include "tristate.h"
      27  #include "bitmap.h"
      28  #include "selftest.h"
      29  #include "function.h"
      30  #include "json.h"
      31  #include "analyzer/analyzer.h"
      32  #include "analyzer/analyzer-logging.h"
      33  #include "ordered-hash-map.h"
      34  #include "options.h"
      35  #include "cgraph.h"
      36  #include "cfg.h"
      37  #include "digraph.h"
      38  #include "analyzer/supergraph.h"
      39  #include "sbitmap.h"
      40  #include "analyzer/call-string.h"
      41  #include "analyzer/program-point.h"
      42  #include "analyzer/store.h"
      43  #include "analyzer/region-model.h"
      44  #include "analyzer/call-details.h"
      45  #include "analyzer/call-info.h"
      46  #include "make-unique.h"
      47  
      48  int plugin_is_GPL_compatible;
      49  
      50  #if ENABLE_ANALYZER
      51  
      52  namespace ana {
      53  
      54  /* Basic example of known fn behavior.  */
      55  
      56  class known_function_returns_42 : public known_function
      57  {
      58  public:
      59    bool matches_call_types_p (const call_details &) const final override
      60    {
      61      return true;
      62    }
      63  
      64    void impl_call_pre (const call_details &cd) const final override
      65    {
      66      if (cd.get_lhs_type ())
      67        {
      68  	const svalue *result
      69  	  = cd.get_manager ()->get_or_create_int_cst (cd.get_lhs_type (), 42);
      70  	cd.maybe_set_lhs (result);
      71        }
      72    }
      73  };
      74  
      75  /* Example of bifurcation, with a copy that can fail.  */
      76  
      77  class known_function_attempt_to_copy : public known_function
      78  {
      79  public:
      80    class copy_success : public success_call_info
      81    {
      82    public:
      83      copy_success (const call_details &cd,
      84  		  const region *sized_dest_reg,
      85  		  const svalue *copied_sval)
      86      : success_call_info (cd),
      87        m_sized_dest_reg (sized_dest_reg),
      88        m_copied_sval (copied_sval)
      89      {}
      90  
      91      bool update_model (region_model *model,
      92  		       const exploded_edge *,
      93  		       region_model_context *ctxt) const final override
      94      {
      95        call_details cd (get_call_details (model, ctxt));
      96        model->update_for_zero_return (cd, true);
      97        model->set_value (m_sized_dest_reg, m_copied_sval, ctxt);
      98        return true;
      99      }
     100  
     101      const region *m_sized_dest_reg;
     102      const svalue *m_copied_sval;
     103      const region *m_sized_src_reg;
     104    };
     105  
     106    class copy_failure : public failed_call_info
     107    {
     108    public:
     109      copy_failure (const call_details &cd)
     110      : failed_call_info (cd)
     111      {}
     112  
     113      bool update_model (region_model *model,
     114  		       const exploded_edge *,
     115  		       region_model_context *ctxt) const final override
     116      {
     117        call_details cd (get_call_details (model, ctxt));
     118        model->update_for_nonzero_return (cd);
     119        /* Leave the destination region untouched.  */
     120        return true;
     121      }
     122    };
     123  
     124    bool matches_call_types_p (const call_details &cd) const
     125    {
     126      return cd.num_args () == 3;
     127    }
     128  
     129    void impl_call_pre (const call_details &cd) const final override
     130    {
     131      region_model_manager *mgr = cd.get_manager ();
     132      region_model *model = cd.get_model ();
     133  
     134      const svalue *dest_sval = cd.get_arg_svalue (0);
     135      const svalue *src_sval = cd.get_arg_svalue (1);
     136      const svalue *num_bytes_sval = cd.get_arg_svalue (2);
     137  
     138      const region *dest_reg = model->deref_rvalue (dest_sval,
     139  						  cd.get_arg_tree (0),
     140  						  cd.get_ctxt ());
     141      const region *src_reg = model->deref_rvalue (src_sval,
     142  						 cd.get_arg_tree (1),
     143  						 cd.get_ctxt ());
     144      if (const svalue * bounded_sval
     145  	  = model->maybe_get_copy_bounds (src_reg, num_bytes_sval))
     146        num_bytes_sval = bounded_sval;
     147  
     148      if (tree cst = num_bytes_sval->maybe_get_constant ())
     149        if (zerop (cst))
     150  	/* No-op.  */
     151  	return;
     152  
     153      const region *sized_src_reg = mgr->get_sized_region (src_reg,
     154  							 NULL_TREE,
     155  							 num_bytes_sval);
     156  
     157      const svalue *copied_sval
     158        = model->get_store_value (sized_src_reg, cd.get_ctxt ());
     159  
     160      const region *sized_dest_reg = mgr->get_sized_region (dest_reg,
     161  							  NULL_TREE,
     162  							  num_bytes_sval);
     163  
     164      if (cd.get_ctxt ())
     165        {
     166  	/* Bifurcate state, creating a "failure" out-edge.  */
     167  	cd.get_ctxt ()->bifurcate (make_unique<copy_failure> (cd));
     168  
     169  	/* The "unbifurcated" state is the "success" case.  */
     170  	copy_success success (cd,
     171  			      sized_dest_reg,
     172  			      copied_sval);
     173  	success.update_model (model, NULL, cd.get_ctxt ());
     174        }
     175    }
     176  };
     177  
     178  /* Callback handler for the PLUGIN_ANALYZER_INIT event.  */
     179  
     180  static void
     181  known_fn_analyzer_init_cb (void *gcc_data, void */*user_data*/)
     182  {
     183    ana::plugin_analyzer_init_iface *iface
     184      = (ana::plugin_analyzer_init_iface *)gcc_data;
     185    LOG_SCOPE (iface->get_logger ());
     186    if (0)
     187      inform (input_location, "got here: known_fn_analyzer_init_cb");
     188    iface->register_known_function ("returns_42",
     189  				  make_unique<known_function_returns_42> ());
     190    iface->register_known_function
     191      ("attempt_to_copy",
     192       make_unique<known_function_attempt_to_copy> ());
     193  }
     194  
     195  } // namespace ana
     196  
     197  #endif /* #if ENABLE_ANALYZER */
     198  
     199  int
     200  plugin_init (struct plugin_name_args *plugin_info,
     201  	     struct plugin_gcc_version *version)
     202  {
     203  #if ENABLE_ANALYZER
     204    const char *plugin_name = plugin_info->base_name;
     205    if (0)
     206      inform (input_location, "got here; %qs", plugin_name);
     207    register_callback (plugin_info->base_name,
     208  		     PLUGIN_ANALYZER_INIT,
     209  		     ana::known_fn_analyzer_init_cb,
     210  		     NULL); /* void *user_data */
     211  #else
     212    sorry_no_analyzer ();
     213  #endif
     214    return 0;
     215  }