LCOV - code coverage report
Current view: top level - gcc/analyzer - pending-diagnostic.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 94.0 % 67 63
Test Date: 2024-12-21 13:15:12 Functions: 97.2 % 36 35
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Classes for analyzer diagnostics.
       2                 :             :    Copyright (C) 2019-2024 Free Software Foundation, Inc.
       3                 :             :    Contributed by David Malcolm <dmalcolm@redhat.com>.
       4                 :             : 
       5                 :             : This file is part of GCC.
       6                 :             : 
       7                 :             : GCC is free software; you can redistribute it and/or modify it
       8                 :             : under the terms of the GNU General Public License as published by
       9                 :             : the Free Software Foundation; either version 3, or (at your option)
      10                 :             : any later version.
      11                 :             : 
      12                 :             : GCC is distributed in the hope that it will be useful, but
      13                 :             : WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15                 :             : General Public License for more details.
      16                 :             : 
      17                 :             : You should have received a copy of the GNU General Public License
      18                 :             : along with GCC; see the file COPYING3.  If not see
      19                 :             : <http://www.gnu.org/licenses/>.  */
      20                 :             : 
      21                 :             : #ifndef GCC_ANALYZER_PENDING_DIAGNOSTIC_H
      22                 :             : #define GCC_ANALYZER_PENDING_DIAGNOSTIC_H
      23                 :             : 
      24                 :             : #include "diagnostic-metadata.h"
      25                 :             : #include "diagnostic-path.h"
      26                 :             : #include "analyzer/sm.h"
      27                 :             : 
      28                 :             : namespace ana {
      29                 :             : 
      30                 :             : /* A bundle of information about things that are of interest to a
      31                 :             :    pending_diagnostic.
      32                 :             : 
      33                 :             :    For now, merely the set of regions that are pertinent to the
      34                 :             :    diagnostic, so that we can notify the user about when they
      35                 :             :    were created.  */
      36                 :             : 
      37                 :        7698 : struct interesting_t
      38                 :             : {
      39                 :             :   void add_region_creation (const region *reg);
      40                 :             : 
      41                 :             :   void dump_to_pp (pretty_printer *pp, bool simple) const;
      42                 :             : 
      43                 :             :   auto_vec<const region *> m_region_creation;
      44                 :             : };
      45                 :             : 
      46                 :             : /* Various bundles of information used for generating more precise
      47                 :             :    messages for events within a diagnostic_path, for passing to the
      48                 :             :    various "describe_*" vfuncs of pending_diagnostic.  See those
      49                 :             :    for more information.  */
      50                 :             : 
      51                 :             : namespace evdesc {
      52                 :             : 
      53                 :             : /* For use by pending_diagnostic::describe_state_change.  */
      54                 :             : 
      55                 :             : struct state_change
      56                 :             : {
      57                 :        4797 :   state_change (tree expr,
      58                 :             :                 tree origin,
      59                 :             :                 state_machine::state_t old_state,
      60                 :             :                 state_machine::state_t new_state,
      61                 :             :                 diagnostic_event_id_t event_id,
      62                 :             :                 const state_change_event &event)
      63                 :        4797 :   : m_expr (expr), m_origin (origin),
      64                 :        4797 :     m_old_state (old_state), m_new_state (new_state),
      65                 :        4797 :     m_event_id (event_id), m_event (event)
      66                 :             :   {}
      67                 :             : 
      68                 :          22 :   bool is_global_p () const { return m_expr == NULL_TREE; }
      69                 :             : 
      70                 :             :   tree m_expr;
      71                 :             :   tree m_origin;
      72                 :             :   state_machine::state_t m_old_state;
      73                 :             :   state_machine::state_t m_new_state;
      74                 :             :   diagnostic_event_id_t m_event_id;
      75                 :             :   const state_change_event &m_event;
      76                 :             : };
      77                 :             : 
      78                 :             : /* For use by pending_diagnostic::describe_call_with_state.  */
      79                 :             : 
      80                 :             : struct call_with_state
      81                 :             : {
      82                 :         353 :   call_with_state (tree caller_fndecl, tree callee_fndecl,
      83                 :             :                    tree expr, state_machine::state_t state)
      84                 :         353 :   : m_caller_fndecl (caller_fndecl),
      85                 :         353 :     m_callee_fndecl (callee_fndecl),
      86                 :         353 :     m_expr (expr),
      87                 :         353 :     m_state (state)
      88                 :             :   {
      89                 :             :   }
      90                 :             : 
      91                 :             :   tree m_caller_fndecl;
      92                 :             :   tree m_callee_fndecl;
      93                 :             :   tree m_expr;
      94                 :             :   state_machine::state_t m_state;
      95                 :             : };
      96                 :             : 
      97                 :             : /* For use by pending_diagnostic::describe_return_of_state.  */
      98                 :             : 
      99                 :             : struct return_of_state
     100                 :             : {
     101                 :          92 :   return_of_state (tree caller_fndecl, tree callee_fndecl,
     102                 :             :                    state_machine::state_t state)
     103                 :          92 :   : m_caller_fndecl (caller_fndecl),
     104                 :          92 :     m_callee_fndecl (callee_fndecl),
     105                 :          92 :     m_state (state)
     106                 :             :   {
     107                 :             :   }
     108                 :             : 
     109                 :             :   tree m_caller_fndecl;
     110                 :             :   tree m_callee_fndecl;
     111                 :             :   state_machine::state_t m_state;
     112                 :             : };
     113                 :             : 
     114                 :             : /* For use by pending_diagnostic::describe_final_event.  */
     115                 :             : 
     116                 :             : struct final_event
     117                 :             : {
     118                 :        7626 :   final_event (tree expr, state_machine::state_t state,
     119                 :             :                const warning_event &event)
     120                 :        7626 :   : m_expr (expr), m_state (state), m_event (event)
     121                 :             :   {}
     122                 :             : 
     123                 :             :   tree m_expr;
     124                 :             :   state_machine::state_t m_state;
     125                 :             :   const warning_event &m_event;
     126                 :             : };
     127                 :             : 
     128                 :             : } /* end of namespace evdesc */
     129                 :             : 
     130                 :             : /*  A bundle of information for use by implementations of the
     131                 :             :     pending_diagnostic::emit vfunc.
     132                 :             : 
     133                 :             :     The rich_location will have already been populated with a
     134                 :             :     diagnostic_path.  */
     135                 :             : 
     136                 :             : class diagnostic_emission_context
     137                 :             : {
     138                 :             : public:
     139                 :        3849 :   diagnostic_emission_context (const saved_diagnostic &sd,
     140                 :             :                                rich_location &rich_loc,
     141                 :             :                                diagnostic_metadata &metadata,
     142                 :             :                                logger *logger)
     143                 :        3849 :   : m_sd (sd),
     144                 :        3849 :     m_rich_loc (rich_loc),
     145                 :        3849 :     m_metadata (metadata),
     146                 :        3849 :     m_logger (logger)
     147                 :             :   {
     148                 :             :   }
     149                 :             : 
     150                 :             :   const pending_diagnostic &get_pending_diagnostic () const;
     151                 :             : 
     152                 :             :   bool warn (const char *, ...) ATTRIBUTE_GCC_DIAG (2,3);
     153                 :             :   void inform (const char *, ...) ATTRIBUTE_GCC_DIAG (2,3);
     154                 :             : 
     155                 :         942 :   location_t get_location () const { return m_rich_loc.get_loc (); }
     156                 :         551 :   logger *get_logger () const { return m_logger; }
     157                 :             : 
     158                 :        3275 :   void add_cwe (int cwe) { m_metadata.add_cwe (cwe); }
     159                 :           7 :   void add_rule (const diagnostic_metadata::rule &r)
     160                 :             :   {
     161                 :           7 :     m_metadata.add_rule (r);
     162                 :             :   }
     163                 :             : 
     164                 :             : private:
     165                 :             :   const saved_diagnostic &m_sd;
     166                 :             :   rich_location &m_rich_loc;
     167                 :             :   diagnostic_metadata &m_metadata;
     168                 :             :   logger *m_logger;
     169                 :             : };
     170                 :             : 
     171                 :             : /* An abstract base class for capturing information about a diagnostic in
     172                 :             :    a form that is ready to emit at a later point (or be rejected).
     173                 :             :    Each kind of diagnostic will have a concrete subclass of
     174                 :             :    pending_diagnostic.
     175                 :             : 
     176                 :             :    Normally, gcc diagnostics are emitted using va_list, which can't be
     177                 :             :    portably stored for later use, so we have to use an "emit" virtual
     178                 :             :    function.
     179                 :             : 
     180                 :             :    This class also supports comparison, so that multiple pending_diagnostic
     181                 :             :    instances can be de-duplicated.
     182                 :             : 
     183                 :             :    As well as emitting a diagnostic, the class has various "precision of
     184                 :             :    wording" virtual functions, for generating descriptions for events
     185                 :             :    within a diagnostic_path.  These are optional, but implementing these
     186                 :             :    allows for more precise wordings than the more generic
     187                 :             :    implementation.  */
     188                 :             : 
     189                 :        2725 : class pending_diagnostic
     190                 :             : {
     191                 :             :  public:
     192                 :           0 :   virtual ~pending_diagnostic () {}
     193                 :             : 
     194                 :             :   /* Vfunc to get the command-line option used when emitting the diagnostic,
     195                 :             :      or zero if there is none.
     196                 :             :      Used by diagnostic_manager for early rejection of diagnostics (to avoid
     197                 :             :      having to generate feasible execution paths for them).  */
     198                 :             :   virtual int get_controlling_option () const = 0;
     199                 :             : 
     200                 :             :   /* Vfunc to give the diagnostic the chance to terminate the execution
     201                 :             :      path being explored.  By default, don't terminate the path.  */
     202                 :        7315 :   virtual bool terminate_path_p () const { return false; }
     203                 :             : 
     204                 :             :   /* Vfunc for emitting the diagnostic.
     205                 :             :      Return true if a diagnostic is actually emitted.  */
     206                 :             :   virtual bool emit (diagnostic_emission_context &) = 0;
     207                 :             : 
     208                 :             :   /* Hand-coded RTTI: get an ID for the subclass.  */
     209                 :             :   virtual const char *get_kind () const = 0;
     210                 :             : 
     211                 :             :   /* A vfunc for identifying "use of uninitialized value".  */
     212                 :         206 :   virtual bool use_of_uninit_p () const { return false; }
     213                 :             : 
     214                 :             :   /* Compare for equality with OTHER, which might be of a different
     215                 :             :      subclass.  */
     216                 :             : 
     217                 :        6516 :   bool equal_p (const pending_diagnostic &other) const
     218                 :             :   {
     219                 :             :     /* Check for pointer equality on the IDs from get_kind.  */
     220                 :        6516 :     if (get_kind () != other.get_kind ())
     221                 :             :       return false;
     222                 :             :     /* Call vfunc now we know they have the same ID: */
     223                 :        6459 :     return subclass_equal_p (other);
     224                 :             :   }
     225                 :             : 
     226                 :             :   /* A vfunc for testing for equality, where we've already
     227                 :             :      checked they have the same ID.  See pending_diagnostic_subclass
     228                 :             :      below for a convenience subclass for implementing this.  */
     229                 :             :   virtual bool subclass_equal_p (const pending_diagnostic &other) const = 0;
     230                 :             : 
     231                 :             :   /* Return true if T1 and T2 are "the same" for the purposes of
     232                 :             :      diagnostic deduplication.  */
     233                 :             :   static bool same_tree_p (tree t1, tree t2);
     234                 :             : 
     235                 :             :   /* Vfunc for fixing up locations, e.g. to avoid unwinding
     236                 :             :      inside specific macros.  PRIMARY is true for the primary location
     237                 :             :      for the diagnostic, and FALSE for events in their paths.  */
     238                 :             :   virtual location_t fixup_location (location_t loc, bool primary) const;
     239                 :             : 
     240                 :             :   /* Precision-of-wording vfunc for describing a critical state change
     241                 :             :      within the diagnostic_path.
     242                 :             : 
     243                 :             :      For example, a double-free diagnostic might use the descriptions:
     244                 :             :      - "first 'free' happens here"
     245                 :             :      - "second 'free' happens here"
     246                 :             :      for the pertinent events, whereas a use-after-free might use the
     247                 :             :      descriptions:
     248                 :             :      - "freed here"
     249                 :             :      - "use after free here"
     250                 :             :      Note how in both cases the first event is a "free": the best
     251                 :             :      description to use depends on the diagnostic.
     252                 :             : 
     253                 :             :      Print the description to PP and return true,
     254                 :             :      or do nothing and return false.  */
     255                 :             : 
     256                 :           0 :   virtual bool describe_state_change (pretty_printer &,
     257                 :             :                                       const evdesc::state_change &)
     258                 :             :   {
     259                 :             :     /* Default no-op implementation.  */
     260                 :           0 :     return false;
     261                 :             :   }
     262                 :             : 
     263                 :             :   /* Vfunc for implementing diagnostic_event::get_meaning for
     264                 :             :      state_change_event.  */
     265                 :             :   virtual diagnostic_event::meaning
     266                 :           2 :   get_meaning_for_state_change (const evdesc::state_change &) const
     267                 :             :   {
     268                 :             :     /* Default no-op implementation.  */
     269                 :           2 :     return diagnostic_event::meaning ();
     270                 :             :   }
     271                 :             : 
     272                 :             :   /* Precision-of-wording vfunc for describing an interprocedural call
     273                 :             :      carrying critial state for the diagnostic, from caller to callee.
     274                 :             : 
     275                 :             :      For example a double-free diagnostic might use:
     276                 :             :      - "passing freed pointer 'ptr' in call to 'deallocator' from 'test'"
     277                 :             :      to make it clearer how the freed value moves from caller to
     278                 :             :      callee.  */
     279                 :             : 
     280                 :          51 :   virtual bool describe_call_with_state (pretty_printer &,
     281                 :             :                                          const evdesc::call_with_state &)
     282                 :             :   {
     283                 :             :     /* Default no-op implementation.  */
     284                 :          51 :     return false;
     285                 :             :   }
     286                 :             : 
     287                 :             :   /* Precision-of-wording vfunc for describing an interprocedural return
     288                 :             :      within the diagnostic_path that carries critial state for the
     289                 :             :      diagnostic, from callee back to caller.
     290                 :             : 
     291                 :             :      For example, a deref-of-unchecked-malloc diagnostic might use:
     292                 :             :      - "returning possibly-NULL pointer to 'make_obj' from 'allocator'"
     293                 :             :      to make it clearer how the unchecked value moves from callee
     294                 :             :      back to caller.  */
     295                 :             : 
     296                 :          42 :   virtual bool describe_return_of_state (pretty_printer &,
     297                 :             :                                          const evdesc::return_of_state &)
     298                 :             :   {
     299                 :             :     /* Default no-op implementation.  */
     300                 :          42 :     return false;
     301                 :             :   }
     302                 :             : 
     303                 :             :   /* Precision-of-wording vfunc for describing the final event within a
     304                 :             :      diagnostic_path.
     305                 :             : 
     306                 :             :      For example a double-free diagnostic might use:
     307                 :             :       - "second 'free' here; first 'free' was at (3)"
     308                 :             :      and a use-after-free might use
     309                 :             :       - "use after 'free' here; memory was freed at (2)".  */
     310                 :             : 
     311                 :         382 :   virtual bool describe_final_event (pretty_printer &,
     312                 :             :                                      const evdesc::final_event &)
     313                 :             :   {
     314                 :             :     /* Default no-op implementation.  */
     315                 :         382 :     return false;
     316                 :             :   }
     317                 :             : 
     318                 :             :   /* End of precision-of-wording vfuncs.  */
     319                 :             : 
     320                 :             :   /* Vfunc for adding a function_entry_event to a checker_path, so that e.g.
     321                 :             :      the infinite recursion diagnostic can add a custom event subclass
     322                 :             :      that annotates recursively entering a function.  */
     323                 :             : 
     324                 :             :   virtual void
     325                 :             :   add_function_entry_event (const exploded_edge &eedge,
     326                 :             :                             checker_path *emission_path);
     327                 :             : 
     328                 :             :   /* Vfunc for extending/overriding creation of the events for an
     329                 :             :      exploded_edge that corresponds to a superedge, allowing for custom
     330                 :             :      events to be created that are pertinent to a particular
     331                 :             :      pending_diagnostic subclass.
     332                 :             : 
     333                 :             :      For example, the -Wanalyzer-stale-setjmp-buffer diagnostic adds a
     334                 :             :      custom event showing when the pertinent stack frame is popped
     335                 :             :      (and thus the point at which the jmp_buf becomes invalid).  */
     336                 :             : 
     337                 :       13147 :   virtual bool maybe_add_custom_events_for_superedge (const exploded_edge &,
     338                 :             :                                                       checker_path *)
     339                 :             :   {
     340                 :       13147 :     return false;
     341                 :             :   }
     342                 :             : 
     343                 :             :   /* Vfunc for adding a call_event to a checker_path, so that e.g.
     344                 :             :      the varargs diagnostics can add a custom event subclass that annotates
     345                 :             :      the variadic arguments.  */
     346                 :             :   virtual void add_call_event (const exploded_edge &,
     347                 :             :                                checker_path *);
     348                 :             : 
     349                 :             :   /* Vfunc for adding any events for the creation of regions identified
     350                 :             :      by the mark_interesting_stuff vfunc.
     351                 :             :      See the comment for class region_creation_event.  */
     352                 :             :   virtual void add_region_creation_events (const region *reg,
     353                 :             :                                            tree capacity,
     354                 :             :                                            const event_loc_info &loc_info,
     355                 :             :                                            checker_path &emission_path);
     356                 :             : 
     357                 :             :   /* Vfunc for adding the final warning_event to a checker_path, so that e.g.
     358                 :             :      the infinite recursion diagnostic can have its diagnostic appear at
     359                 :             :      the callsite, but the final event in the path be at the entrypoint
     360                 :             :      of the called function.  */
     361                 :             :   virtual void add_final_event (const state_machine *sm,
     362                 :             :                                 const exploded_node *enode,
     363                 :             :                                 const event_loc_info &loc_info,
     364                 :             :                                 tree var, state_machine::state_t state,
     365                 :             :                                 checker_path *emission_path);
     366                 :             : 
     367                 :             :   /* Vfunc for determining that this pending_diagnostic supercedes OTHER,
     368                 :             :      and that OTHER should therefore not be emitted.
     369                 :             :      They have already been tested for being at the same stmt.  */
     370                 :             : 
     371                 :             :   virtual bool
     372                 :        4811 :   supercedes_p (const pending_diagnostic &other ATTRIBUTE_UNUSED) const
     373                 :             :   {
     374                 :        4811 :     return false;
     375                 :             :   }
     376                 :             : 
     377                 :             :   /* Vfunc for registering additional information of interest to this
     378                 :             :      diagnostic.  */
     379                 :             : 
     380                 :        2528 :   virtual void mark_interesting_stuff (interesting_t *)
     381                 :             :   {
     382                 :             :     /* Default no-op implementation.  */
     383                 :        2528 :   }
     384                 :             : 
     385                 :             :   /* Vfunc to give diagnostic subclasses the opportunity to reject diagnostics
     386                 :             :      by imposing their own additional feasibility checks on the path to a
     387                 :             :      given feasible_node.  */
     388                 :        4776 :   virtual bool check_valid_fpath_p (const feasible_node &,
     389                 :             :                                     const gimple *) const
     390                 :             :   {
     391                 :             :     /* Default implementation: accept this path.  */
     392                 :        4776 :     return true;
     393                 :             :   }
     394                 :             : 
     395                 :             :   /* Vfunc for use in SARIF output to give pending_diagnostic subclasses
     396                 :             :      the opportunity to add diagnostic-specific properties to the SARIF
     397                 :             :      "result" object for the diagnostic.
     398                 :             :      This is intended for use when debugging a diagnostic.  */
     399                 :          13 :   virtual void maybe_add_sarif_properties (sarif_object &/*result_obj*/) const
     400                 :             :   {
     401                 :             :     /* Default no-op implementation.  */
     402                 :          13 :   }
     403                 :             : };
     404                 :             : 
     405                 :             : /* A template to make it easier to make subclasses of pending_diagnostic.
     406                 :             : 
     407                 :             :    This uses the curiously-recurring template pattern, to implement
     408                 :             :    pending_diagnostic::subclass_equal_p by casting and calling
     409                 :             :    the operator==
     410                 :             : 
     411                 :             :    This assumes that BASE_OTHER has already been checked to have
     412                 :             :    been of the same subclass (which pending_diagnostic::equal_p does).  */
     413                 :             : 
     414                 :             : template <class Subclass>
     415                 :        1131 : class pending_diagnostic_subclass : public pending_diagnostic
     416                 :             : {
     417                 :             :  public:
     418                 :        2385 :   bool subclass_equal_p (const pending_diagnostic &base_other) const
     419                 :             :     final override
     420                 :             :   {
     421                 :        2385 :     const Subclass &other = (const Subclass &)base_other;
     422                 :        2385 :     return *(const Subclass*)this == other;
     423                 :             :   }
     424                 :             : };
     425                 :             : 
     426                 :             : /* An abstract base class for capturing additional notes that are to be
     427                 :             :    emitted with a diagnostic.  */
     428                 :             : 
     429                 :         206 : class pending_note
     430                 :             : {
     431                 :             : public:
     432                 :           0 :   virtual ~pending_note () {}
     433                 :             : 
     434                 :             :   /* Hand-coded RTTI: get an ID for the subclass.  */
     435                 :             :   virtual const char *get_kind () const = 0;
     436                 :             : 
     437                 :             :   /* Vfunc for emitting the note.  */
     438                 :             :   virtual void emit () const = 0;
     439                 :             : 
     440                 :         799 :   bool equal_p (const pending_note &other) const
     441                 :             :   {
     442                 :             :     /* Check for pointer equality on the IDs from get_kind.  */
     443                 :         799 :     if (get_kind () != other.get_kind ())
     444                 :             :       return false;
     445                 :             :     /* Call vfunc now we know they have the same ID: */
     446                 :         799 :     return subclass_equal_p (other);
     447                 :             :   }
     448                 :             : 
     449                 :             :   /* A vfunc for testing for equality, where we've already
     450                 :             :      checked they have the same ID.  See pending_note_subclass
     451                 :             :      below for a convenience subclass for implementing this.  */
     452                 :             :   virtual bool subclass_equal_p (const pending_note &other) const = 0;
     453                 :             : };
     454                 :             : 
     455                 :             : /* Analogous to pending_diagnostic_subclass, but for pending_note.  */
     456                 :             : 
     457                 :             : template <class Subclass>
     458                 :          22 : class pending_note_subclass : public pending_note
     459                 :             : {
     460                 :             :  public:
     461                 :         799 :   bool subclass_equal_p (const pending_note &base_other) const
     462                 :             :     final override
     463                 :             :   {
     464                 :         799 :     const Subclass &other = (const Subclass &)base_other;
     465                 :         799 :     return *(const Subclass*)this == other;
     466                 :             :   }
     467                 :             : };
     468                 :             : 
     469                 :             : } // namespace ana
     470                 :             : 
     471                 :             : #endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */
        

Generated by: LCOV version 2.1-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.