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