(root)/
gcc-13.2.0/
gcc/
analyzer/
checker-event.h
       1  /* Subclasses of diagnostic_event for analyzer diagnostics.
       2     Copyright (C) 2019-2023 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_CHECKER_EVENT_H
      22  #define GCC_ANALYZER_CHECKER_EVENT_H
      23  
      24  #include "tree-logical-location.h"
      25  #include "analyzer/program-state.h"
      26  
      27  namespace ana {
      28  
      29  /* A bundle of location information for a checker_event.  */
      30  
      31  struct event_loc_info
      32  {
      33    event_loc_info (location_t loc, tree fndecl, int depth)
      34    : m_loc (loc), m_fndecl (fndecl), m_depth (depth)
      35    {}
      36  
      37    location_t m_loc;
      38    tree m_fndecl;
      39    int m_depth;
      40  };
      41  
      42  /* An enum for discriminating between the concrete subclasses of
      43     checker_event.  */
      44  
      45  enum event_kind
      46  {
      47    EK_DEBUG,
      48    EK_CUSTOM,
      49    EK_STMT,
      50    EK_REGION_CREATION,
      51    EK_FUNCTION_ENTRY,
      52    EK_STATE_CHANGE,
      53    EK_START_CFG_EDGE,
      54    EK_END_CFG_EDGE,
      55    EK_CALL_EDGE,
      56    EK_RETURN_EDGE,
      57    EK_START_CONSOLIDATED_CFG_EDGES,
      58    EK_END_CONSOLIDATED_CFG_EDGES,
      59    EK_INLINED_CALL,
      60    EK_SETJMP,
      61    EK_REWIND_FROM_LONGJMP,
      62    EK_REWIND_TO_SETJMP,
      63    EK_WARNING
      64  };
      65  
      66  extern const char *event_kind_to_string (enum event_kind ek);
      67  
      68  /* Event subclasses.
      69  
      70     The class hierarchy looks like this (using indentation to show
      71     inheritance, and with event_kinds shown for the concrete subclasses):
      72  
      73     diagnostic_event
      74       checker_event
      75         debug_event (EK_DEBUG)
      76         custom_event (EK_CUSTOM)
      77  	 precanned_custom_event
      78         statement_event (EK_STMT)
      79         region_creation_event (EK_REGION_CREATION)
      80         function_entry_event (EK_FUNCTION_ENTRY)
      81         state_change_event (EK_STATE_CHANGE)
      82         superedge_event
      83           cfg_edge_event
      84  	   start_cfg_edge_event (EK_START_CFG_EDGE)
      85  	   end_cfg_edge_event (EK_END_CFG_EDGE)
      86           call_event (EK_CALL_EDGE)
      87           return_edge (EK_RETURN_EDGE)
      88         start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES)
      89         end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES)
      90         inlined_call_event (EK_INLINED_CALL)
      91         setjmp_event (EK_SETJMP)
      92         rewind_event
      93           rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
      94  	 rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
      95         warning_event (EK_WARNING).  */
      96  
      97  /* Abstract subclass of diagnostic_event; the base class for use in
      98     checker_path (the analyzer's diagnostic_path subclass).  */
      99  
     100  class checker_event : public diagnostic_event
     101  {
     102  public:
     103    /* Implementation of diagnostic_event.  */
     104  
     105    location_t get_location () const final override { return m_loc; }
     106    tree get_fndecl () const final override { return m_effective_fndecl; }
     107    int get_stack_depth () const final override { return m_effective_depth; }
     108    const logical_location *get_logical_location () const final override
     109    {
     110      if (m_effective_fndecl)
     111        return &m_logical_loc;
     112      else
     113        return NULL;
     114    }
     115    meaning get_meaning () const override;
     116  
     117    /* Additional functionality.  */
     118  
     119    int get_original_stack_depth () const { return m_original_depth; }
     120  
     121    virtual void prepare_for_emission (checker_path *,
     122  				     pending_diagnostic *pd,
     123  				     diagnostic_event_id_t emission_id);
     124    virtual bool is_call_p () const { return false; }
     125    virtual bool is_function_entry_p () const  { return false; }
     126    virtual bool is_return_p () const  { return false; }
     127  
     128    /* For use with %@.  */
     129    const diagnostic_event_id_t *get_id_ptr () const
     130    {
     131      return &m_emission_id;
     132    }
     133  
     134    void dump (pretty_printer *pp) const;
     135    void debug () const;
     136  
     137    void set_location (location_t loc) { m_loc = loc; }
     138  
     139  protected:
     140    checker_event (enum event_kind kind,
     141  		 const event_loc_info &loc_info);
     142  
     143   public:
     144    const enum event_kind m_kind;
     145   protected:
     146    location_t m_loc;
     147    tree m_original_fndecl;
     148    tree m_effective_fndecl;
     149    int m_original_depth;
     150    int m_effective_depth;
     151    pending_diagnostic *m_pending_diagnostic;
     152    diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
     153    tree_logical_location m_logical_loc;
     154  };
     155  
     156  /* A concrete event subclass for a purely textual event, for use in
     157     debugging path creation and filtering.  */
     158  
     159  class debug_event : public checker_event
     160  {
     161  public:
     162  
     163    debug_event (const event_loc_info &loc_info,
     164  	       const char *desc)
     165    : checker_event (EK_DEBUG, loc_info),
     166      m_desc (xstrdup (desc))
     167    {
     168    }
     169    ~debug_event ()
     170    {
     171      free (m_desc);
     172    }
     173  
     174    label_text get_desc (bool) const final override;
     175  
     176  private:
     177    char *m_desc;
     178  };
     179  
     180  /* An abstract event subclass for custom events.  These are not filtered,
     181     as they are likely to be pertinent to the diagnostic.  */
     182  
     183  class custom_event : public checker_event
     184  {
     185  protected:
     186    custom_event (const event_loc_info &loc_info)
     187    : checker_event (EK_CUSTOM, loc_info)
     188    {
     189    }
     190  };
     191  
     192  /* A concrete custom_event subclass with a precanned message.  */
     193  
     194  class precanned_custom_event : public custom_event
     195  {
     196  public:
     197    precanned_custom_event (const event_loc_info &loc_info,
     198  			  const char *desc)
     199    : custom_event (loc_info),
     200      m_desc (xstrdup (desc))
     201    {
     202    }
     203    ~precanned_custom_event ()
     204    {
     205      free (m_desc);
     206    }
     207  
     208    label_text get_desc (bool) const final override;
     209  
     210  private:
     211    char *m_desc;
     212  };
     213  
     214  /* A concrete event subclass describing the execution of a gimple statement,
     215     for use at high verbosity levels when debugging paths.  */
     216  
     217  class statement_event : public checker_event
     218  {
     219  public:
     220    statement_event (const gimple *stmt, tree fndecl, int depth,
     221  		   const program_state &dst_state);
     222  
     223    label_text get_desc (bool) const final override;
     224  
     225    const gimple * const m_stmt;
     226    const program_state m_dst_state;
     227  };
     228  
     229  /* An abstract event subclass describing the creation of a region that
     230     is significant for a diagnostic.
     231  
     232     There are too many combinations to express region creation in one message,
     233     so we emit multiple region_creation_event instances when each pertinent
     234     region is created.
     235  
     236     The events are created by pending_diagnostic's add_region_creation_events
     237     vfunc, which by default creates a region_creation_event_memory_space, and
     238     if a capacity is known, a region_creation_event_capacity, giving e.g.:
     239       (1) region created on stack here
     240       (2) capacity: 100 bytes
     241     but this vfunc can be overridden to create other events if other wordings
     242     are more appropriate foa a given pending_diagnostic.  */
     243  
     244  class region_creation_event : public checker_event
     245  {
     246  protected:
     247    region_creation_event (const event_loc_info &loc_info);
     248  };
     249  
     250  /* Concrete subclass of region_creation_event.
     251     Generates a message based on the memory space of the region
     252     e.g. "region created on stack here".  */
     253  
     254  class region_creation_event_memory_space : public region_creation_event
     255  {
     256  public:
     257    region_creation_event_memory_space (enum memory_space mem_space,
     258  				      const event_loc_info &loc_info)
     259    : region_creation_event (loc_info),
     260      m_mem_space (mem_space)
     261    {
     262    }
     263  
     264    label_text get_desc (bool can_colorize) const final override;
     265  
     266  private:
     267    enum memory_space m_mem_space;
     268  };
     269  
     270  /* Concrete subclass of region_creation_event.
     271     Generates a message based on the capacity of the region
     272     e.g. "capacity: 100 bytes".  */
     273  
     274  class region_creation_event_capacity : public region_creation_event
     275  {
     276  public:
     277    region_creation_event_capacity (tree capacity,
     278  				  const event_loc_info &loc_info)
     279    : region_creation_event (loc_info),
     280      m_capacity (capacity)
     281    {
     282      gcc_assert (m_capacity);
     283    }
     284  
     285    label_text get_desc (bool can_colorize) const final override;
     286  
     287  private:
     288    tree m_capacity;
     289  };
     290  
     291  /* Concrete subclass of region_creation_event.
     292     Generates a message based on the capacity of the region
     293     e.g. "allocated 100 bytes here".  */
     294  
     295  class region_creation_event_allocation_size : public region_creation_event
     296  {
     297  public:
     298    region_creation_event_allocation_size (tree capacity,
     299  					 const event_loc_info &loc_info)
     300    : region_creation_event (loc_info),
     301      m_capacity (capacity)
     302    {}
     303  
     304    label_text get_desc (bool can_colorize) const final override;
     305  
     306  private:
     307    tree m_capacity;
     308  };
     309  
     310  /* Concrete subclass of region_creation_event.
     311     Generates a debug message intended for analyzer developers.  */
     312  
     313  class region_creation_event_debug : public region_creation_event
     314  {
     315  public:
     316    region_creation_event_debug (const region *reg, tree capacity,
     317  			       const event_loc_info &loc_info)
     318    : region_creation_event (loc_info),
     319      m_reg (reg), m_capacity (capacity)
     320    {
     321    }
     322  
     323    label_text get_desc (bool can_colorize) const final override;
     324  
     325  private:
     326    const region *m_reg;
     327    tree m_capacity;
     328  };
     329  
     330  /* An event subclass describing the entry to a function.  */
     331  
     332  class function_entry_event : public checker_event
     333  {
     334  public:
     335    function_entry_event (const event_loc_info &loc_info)
     336    : checker_event (EK_FUNCTION_ENTRY, loc_info)
     337    {
     338    }
     339  
     340    function_entry_event (const program_point &dst_point);
     341  
     342    label_text get_desc (bool can_colorize) const override;
     343    meaning get_meaning () const override;
     344  
     345    bool is_function_entry_p () const final override { return true; }
     346  };
     347  
     348  /* Subclass of checker_event describing a state change.  */
     349  
     350  class state_change_event : public checker_event
     351  {
     352  public:
     353    state_change_event (const supernode *node, const gimple *stmt,
     354  		      int stack_depth,
     355  		      const state_machine &sm,
     356  		      const svalue *sval,
     357  		      state_machine::state_t from,
     358  		      state_machine::state_t to,
     359  		      const svalue *origin,
     360  		      const program_state &dst_state,
     361  		      const exploded_node *enode);
     362  
     363    label_text get_desc (bool can_colorize) const final override;
     364    meaning get_meaning () const override;
     365  
     366    function *get_dest_function () const
     367    {
     368      return m_dst_state.get_current_function ();
     369    }
     370  
     371    const exploded_node *get_exploded_node () const { return m_enode; }
     372  
     373    const supernode *m_node;
     374    const gimple *m_stmt;
     375    const state_machine &m_sm;
     376    const svalue *m_sval;
     377    state_machine::state_t m_from;
     378    state_machine::state_t m_to;
     379    const svalue *m_origin;
     380    program_state m_dst_state;
     381    const exploded_node *m_enode;
     382  };
     383  
     384  /* Subclass of checker_event; parent class for subclasses that relate to
     385     a superedge.  */
     386  
     387  class superedge_event : public checker_event
     388  {
     389  public:
     390    /* Mark this edge event as being either an interprocedural call or
     391       return in which VAR is in STATE, and that this is critical to the
     392       diagnostic (so that get_desc can attempt to get a better description
     393       from any pending_diagnostic).  */
     394    void record_critical_state (tree var, state_machine::state_t state)
     395    {
     396      m_var = var;
     397      m_critical_state = state;
     398    }
     399  
     400    const callgraph_superedge& get_callgraph_superedge () const;
     401  
     402    bool should_filter_p (int verbosity) const;
     403  
     404   protected:
     405    superedge_event (enum event_kind kind, const exploded_edge &eedge,
     406  		   const event_loc_info &loc_info);
     407  
     408   public:
     409    const exploded_edge &m_eedge;
     410    const superedge *m_sedge;
     411    tree m_var;
     412    state_machine::state_t m_critical_state;
     413  };
     414  
     415  /* An abstract event subclass for when a CFG edge is followed; it has two
     416     subclasses, representing the start of the edge and the end of the
     417     edge, which come in pairs.  */
     418  
     419  class cfg_edge_event : public superedge_event
     420  {
     421  public:
     422    meaning get_meaning () const override;
     423  
     424    const cfg_superedge& get_cfg_superedge () const;
     425  
     426   protected:
     427    cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
     428  		  const event_loc_info &loc_info);
     429  };
     430  
     431  /* A concrete event subclass for the start of a CFG edge
     432     e.g. "following 'false' branch...'.  */
     433  
     434  class start_cfg_edge_event : public cfg_edge_event
     435  {
     436  public:
     437    start_cfg_edge_event (const exploded_edge &eedge,
     438  			const event_loc_info &loc_info)
     439    : cfg_edge_event (EK_START_CFG_EDGE, eedge, loc_info)
     440    {
     441    }
     442  
     443    label_text get_desc (bool can_colorize) const final override;
     444  
     445   private:
     446    label_text maybe_describe_condition (bool can_colorize) const;
     447  
     448    static label_text maybe_describe_condition (bool can_colorize,
     449  					      tree lhs,
     450  					      enum tree_code op,
     451  					      tree rhs);
     452    static bool should_print_expr_p (tree);
     453  };
     454  
     455  /* A concrete event subclass for the end of a CFG edge
     456     e.g. "...to here'.  */
     457  
     458  class end_cfg_edge_event : public cfg_edge_event
     459  {
     460  public:
     461    end_cfg_edge_event (const exploded_edge &eedge,
     462  		      const event_loc_info &loc_info)
     463    : cfg_edge_event (EK_END_CFG_EDGE, eedge, loc_info)
     464    {
     465    }
     466  
     467    label_text get_desc (bool /*can_colorize*/) const final override
     468    {
     469      return label_text::borrow ("...to here");
     470    }
     471  };
     472  
     473  /* A concrete event subclass for an interprocedural call.  */
     474  
     475  class call_event : public superedge_event
     476  {
     477  public:
     478    call_event (const exploded_edge &eedge,
     479  	      const event_loc_info &loc_info);
     480  
     481    label_text get_desc (bool can_colorize) const override;
     482    meaning get_meaning () const override;
     483  
     484    bool is_call_p () const final override;
     485  
     486  protected:
     487    tree get_caller_fndecl () const;
     488    tree get_callee_fndecl () const;
     489  
     490    const supernode *m_src_snode;
     491    const supernode *m_dest_snode;
     492  };
     493  
     494  /* A concrete event subclass for an interprocedural return.  */
     495  
     496  class return_event : public superedge_event
     497  {
     498  public:
     499    return_event (const exploded_edge &eedge,
     500  		const event_loc_info &loc_info);
     501  
     502    label_text get_desc (bool can_colorize) const final override;
     503    meaning get_meaning () const override;
     504  
     505    bool is_return_p () const final override;
     506  
     507    const supernode *m_src_snode;
     508    const supernode *m_dest_snode;
     509  };
     510  
     511  /* A concrete event subclass for the start of a consolidated run of CFG
     512     edges all either TRUE or FALSE e.g. "following 'false' branch...'.  */
     513  
     514  class start_consolidated_cfg_edges_event : public checker_event
     515  {
     516  public:
     517    start_consolidated_cfg_edges_event (const event_loc_info &loc_info,
     518  				      bool edge_sense)
     519    : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc_info),
     520      m_edge_sense (edge_sense)
     521    {
     522    }
     523  
     524    label_text get_desc (bool can_colorize) const final override;
     525    meaning get_meaning () const override;
     526  
     527   private:
     528    bool m_edge_sense;
     529  };
     530  
     531  /* A concrete event subclass for the end of a consolidated run of
     532     CFG edges e.g. "...to here'.  */
     533  
     534  class end_consolidated_cfg_edges_event : public checker_event
     535  {
     536  public:
     537    end_consolidated_cfg_edges_event (const event_loc_info &loc_info)
     538    : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc_info)
     539    {
     540    }
     541  
     542    label_text get_desc (bool /*can_colorize*/) const final override
     543    {
     544      return label_text::borrow ("...to here");
     545    }
     546  };
     547  
     548  /* A concrete event subclass for describing an inlined call event
     549     e.g. "inlined call to 'callee' from 'caller'".  */
     550  
     551  class inlined_call_event : public checker_event
     552  {
     553  public:
     554    inlined_call_event (location_t loc,
     555  		      tree apparent_callee_fndecl,
     556  		      tree apparent_caller_fndecl,
     557  		      int actual_depth,
     558  		      int stack_depth_adjustment)
     559    : checker_event (EK_INLINED_CALL,
     560  		   event_loc_info (loc,
     561  				   apparent_caller_fndecl,
     562  				   actual_depth + stack_depth_adjustment)),
     563      m_apparent_callee_fndecl (apparent_callee_fndecl),
     564      m_apparent_caller_fndecl (apparent_caller_fndecl)
     565    {
     566      gcc_assert (LOCATION_BLOCK (loc) == NULL);
     567    }
     568  
     569    label_text get_desc (bool /*can_colorize*/) const final override;
     570    meaning get_meaning () const override;
     571  
     572  private:
     573    tree m_apparent_callee_fndecl;
     574    tree m_apparent_caller_fndecl;
     575  };
     576  
     577  /* A concrete event subclass for a setjmp or sigsetjmp call.  */
     578  
     579  class setjmp_event : public checker_event
     580  {
     581  public:
     582    setjmp_event (const event_loc_info &loc_info,
     583  		const exploded_node *enode,
     584  		const gcall *setjmp_call)
     585    : checker_event (EK_SETJMP, loc_info),
     586      m_enode (enode), m_setjmp_call (setjmp_call)
     587    {
     588    }
     589  
     590    label_text get_desc (bool can_colorize) const final override;
     591  
     592    void prepare_for_emission (checker_path *path,
     593  			     pending_diagnostic *pd,
     594  			     diagnostic_event_id_t emission_id) final override;
     595  
     596  private:
     597    const exploded_node *m_enode;
     598    const gcall *m_setjmp_call;
     599  };
     600  
     601  /* An abstract event subclass for rewinding from a longjmp to a setjmp
     602     (or siglongjmp to sigsetjmp).
     603  
     604     Base class for two from/to subclasses, showing the two halves of the
     605     rewind.  */
     606  
     607  class rewind_event : public checker_event
     608  {
     609  public:
     610    tree get_longjmp_caller () const;
     611    tree get_setjmp_caller () const;
     612    const exploded_edge *get_eedge () const { return m_eedge; }
     613  
     614   protected:
     615    rewind_event (const exploded_edge *eedge,
     616  		enum event_kind kind,
     617  		const event_loc_info &loc_info,
     618  		const rewind_info_t *rewind_info);
     619    const rewind_info_t *m_rewind_info;
     620  
     621   private:
     622    const exploded_edge *m_eedge;
     623  };
     624  
     625  /* A concrete event subclass for rewinding from a longjmp to a setjmp,
     626     showing the longjmp (or siglongjmp).  */
     627  
     628  class rewind_from_longjmp_event : public rewind_event
     629  {
     630  public:
     631    rewind_from_longjmp_event (const exploded_edge *eedge,
     632  			     const event_loc_info &loc_info,
     633  			     const rewind_info_t *rewind_info)
     634    : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc_info,
     635  		  rewind_info)
     636    {
     637    }
     638  
     639    label_text get_desc (bool can_colorize) const final override;
     640  };
     641  
     642  /* A concrete event subclass for rewinding from a longjmp to a setjmp,
     643     showing the setjmp (or sigsetjmp).  */
     644  
     645  class rewind_to_setjmp_event : public rewind_event
     646  {
     647  public:
     648    rewind_to_setjmp_event (const exploded_edge *eedge,
     649  			  const event_loc_info &loc_info,
     650  			  const rewind_info_t *rewind_info)
     651    : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc_info,
     652  		  rewind_info)
     653    {
     654    }
     655  
     656    label_text get_desc (bool can_colorize) const final override;
     657  
     658    void prepare_for_emission (checker_path *path,
     659  			     pending_diagnostic *pd,
     660  			     diagnostic_event_id_t emission_id) final override;
     661  
     662  private:
     663    diagnostic_event_id_t m_original_setjmp_event_id;
     664  };
     665  
     666  /* Concrete subclass of checker_event for use at the end of a path:
     667     a repeat of the warning message at the end of the path (perhaps with
     668     references to pertinent events that occurred on the way), at the point
     669     where the problem occurs.  */
     670  
     671  class warning_event : public checker_event
     672  {
     673  public:
     674    warning_event (const event_loc_info &loc_info,
     675  		 const exploded_node *enode,
     676  		 const state_machine *sm,
     677  		 tree var, state_machine::state_t state)
     678    : checker_event (EK_WARNING, loc_info),
     679      m_enode (enode),
     680      m_sm (sm), m_var (var), m_state (state)
     681    {
     682    }
     683  
     684    label_text get_desc (bool can_colorize) const final override;
     685    meaning get_meaning () const override;
     686  
     687    const exploded_node *get_exploded_node () const { return m_enode; }
     688  
     689  private:
     690    const exploded_node *m_enode;
     691    const state_machine *m_sm;
     692    tree m_var;
     693    state_machine::state_t m_state;
     694  };
     695  
     696  } // namespace ana
     697  
     698  #endif /* GCC_ANALYZER_CHECKER_EVENT_H */