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