LCOV - code coverage report
Current view: top level - gcc/analyzer - kf-analyzer.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 88.7 % 150 133
Test Date: 2024-04-13 14:00:49 Functions: 84.0 % 25 21
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Handling for the various __analyzer_* known functions.
       2                 :             :    Copyright (C) 2020-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                 :             : #include "config.h"
      22                 :             : #define INCLUDE_MEMORY
      23                 :             : #include "system.h"
      24                 :             : #include "coretypes.h"
      25                 :             : #include "tree.h"
      26                 :             : #include "function.h"
      27                 :             : #include "basic-block.h"
      28                 :             : #include "gimple.h"
      29                 :             : #include "diagnostic-core.h"
      30                 :             : #include "analyzer/analyzer.h"
      31                 :             : #include "analyzer/analyzer-logging.h"
      32                 :             : #include "diagnostic.h"
      33                 :             : #include "tree-diagnostic.h" /* for default_tree_printer.  */
      34                 :             : #include "analyzer/region-model.h"
      35                 :             : #include "analyzer/pending-diagnostic.h"
      36                 :             : #include "analyzer/call-details.h"
      37                 :             : #include "make-unique.h"
      38                 :             : 
      39                 :             : #if ENABLE_ANALYZER
      40                 :             : 
      41                 :             : namespace ana {
      42                 :             : 
      43                 :             : /* Handle calls to "__analyzer_break" by triggering a breakpoint within
      44                 :             :    the analyzer.  */
      45                 :             : 
      46                 :        3783 : class kf_analyzer_break : public known_function
      47                 :             : {
      48                 :             : public:
      49                 :           0 :   bool matches_call_types_p (const call_details &cd) const final override
      50                 :             :   {
      51                 :           0 :     return cd.num_args () == 0;
      52                 :             :   }
      53                 :           0 :   void impl_call_pre (const call_details &) const final override
      54                 :             :   {
      55                 :             :     /* TODO: is there a good cross-platform way to do this?  */
      56                 :           0 :     raise (SIGINT);
      57                 :           0 :   }
      58                 :             : };
      59                 :             : 
      60                 :             : /* Handler for calls to "__analyzer_describe".
      61                 :             : 
      62                 :             :    Emit a warning describing the 2nd argument (which can be of any
      63                 :             :    type), at the given verbosity level.  This is for use when
      64                 :             :    debugging, and may be of use in DejaGnu tests.  */
      65                 :             : 
      66                 :        3783 : class kf_analyzer_describe : public known_function
      67                 :             : {
      68                 :             : public:
      69                 :         940 :   bool matches_call_types_p (const call_details &cd) const final override
      70                 :             :   {
      71                 :         940 :     return cd.num_args () == 2;
      72                 :             :   }
      73                 :         182 :   void impl_call_pre (const call_details &cd) const final override
      74                 :             :   {
      75                 :         182 :     if (!cd.get_ctxt ())
      76                 :          38 :       return;
      77                 :         144 :     tree t_verbosity = cd.get_arg_tree (0);
      78                 :         144 :     const svalue *sval = cd.get_arg_svalue (1);
      79                 :         144 :     bool simple = zerop (t_verbosity);
      80                 :         144 :     label_text desc = sval->get_desc (simple);
      81                 :         144 :     warning_at (cd.get_location (), 0, "svalue: %qs", desc.get ());
      82                 :         144 :   }
      83                 :             : };
      84                 :             : 
      85                 :             : /* Handler for calls to "__analyzer_dump_capacity".
      86                 :             : 
      87                 :             :    Emit a warning describing the capacity of the base region of
      88                 :             :    the region pointed to by the 1st argument.
      89                 :             :    This is for use when debugging, and may be of use in DejaGnu tests.  */
      90                 :             : 
      91                 :        3783 : class kf_analyzer_dump_capacity : public known_function
      92                 :             : {
      93                 :             : public:
      94                 :        2040 :   bool matches_call_types_p (const call_details &cd) const final override
      95                 :             :   {
      96                 :        2040 :     return (cd.num_args () == 1
      97                 :        2040 :             && cd.arg_is_pointer_p (0));
      98                 :             :   }
      99                 :             : 
     100                 :         445 :   void impl_call_pre (const call_details &cd) const final override
     101                 :             :   {
     102                 :         445 :     region_model_context *ctxt = cd.get_ctxt ();
     103                 :         445 :     if (!ctxt)
     104                 :         165 :       return;
     105                 :         280 :     region_model *model = cd.get_model ();
     106                 :         280 :     tree t_ptr = cd.get_arg_tree (0);
     107                 :         280 :     const svalue *sval_ptr = model->get_rvalue (t_ptr, ctxt);
     108                 :         280 :     const region *reg = model->deref_rvalue (sval_ptr, t_ptr, ctxt);
     109                 :         280 :     const region *base_reg = reg->get_base_region ();
     110                 :         280 :     const svalue *capacity = model->get_capacity (base_reg);
     111                 :         280 :     label_text desc = capacity->get_desc (true);
     112                 :         280 :     warning_at (cd.get_call_stmt ()->location, 0,
     113                 :             :                 "capacity: %qs", desc.get ());
     114                 :         280 :   }
     115                 :             : };
     116                 :             : 
     117                 :             : /* Compare D1 and D2 using their names, and then IDs to order them.  */
     118                 :             : 
     119                 :             : static int
     120                 :          20 : cmp_decls (tree d1, tree d2)
     121                 :             : {
     122                 :          20 :   gcc_assert (DECL_P (d1));
     123                 :          20 :   gcc_assert (DECL_P (d2));
     124                 :          20 :   if (DECL_NAME (d1) && DECL_NAME (d2))
     125                 :          20 :     if (int cmp = strcmp (IDENTIFIER_POINTER (DECL_NAME (d1)),
     126                 :          20 :                           IDENTIFIER_POINTER (DECL_NAME (d2))))
     127                 :             :       return cmp;
     128                 :           0 :   return (int)DECL_UID (d1) - (int)DECL_UID (d2);
     129                 :             : }
     130                 :             : 
     131                 :             : /* Comparator for use by vec<tree>::qsort,
     132                 :             :    using their names, and then IDs to order them.  */
     133                 :             : 
     134                 :             : static int
     135                 :          20 : cmp_decls_ptr_ptr (const void *p1, const void *p2)
     136                 :             : {
     137                 :          20 :   tree const *d1 = (tree const *)p1;
     138                 :          20 :   tree const *d2 = (tree const *)p2;
     139                 :             : 
     140                 :          20 :   return cmp_decls (*d1, *d2);
     141                 :             : }
     142                 :             : 
     143                 :             : /* Handler for calls to "__analyzer_dump_escaped".
     144                 :             : 
     145                 :             :    Emit a warning giving the number of decls that have escaped, followed
     146                 :             :    by a comma-separated list of their names, in alphabetical order.
     147                 :             : 
     148                 :             :    This is for use when debugging, and may be of use in DejaGnu tests.  */
     149                 :             : 
     150                 :        3783 : class kf_analyzer_dump_escaped : public known_function
     151                 :             : {
     152                 :             : public:
     153                 :         150 :   bool matches_call_types_p (const call_details &cd) const final override
     154                 :             :   {
     155                 :         150 :     return cd.num_args () == 0;
     156                 :             :   }
     157                 :          25 :   void impl_call_pre (const call_details &cd) const final override
     158                 :             :   {
     159                 :          25 :     region_model_context *ctxt = cd.get_ctxt ();
     160                 :          25 :     if (!ctxt)
     161                 :           0 :       return;
     162                 :          25 :     region_model *model = cd.get_model ();
     163                 :             : 
     164                 :          25 :     auto_vec<tree> escaped_decls;
     165                 :          65 :     for (auto iter : *model->get_store ())
     166                 :             :       {
     167                 :          20 :         const binding_cluster *c = iter.second;
     168                 :          20 :         if (!c->escaped_p ())
     169                 :           0 :           continue;
     170                 :          20 :         if (tree decl = c->get_base_region ()->maybe_get_decl ())
     171                 :          20 :           escaped_decls.safe_push (decl);
     172                 :             :       }
     173                 :             : 
     174                 :             :     /* Sort them into deterministic order; alphabetical is
     175                 :             :        probably most user-friendly.  */
     176                 :          25 :     escaped_decls.qsort (cmp_decls_ptr_ptr);
     177                 :             : 
     178                 :          25 :     pretty_printer pp;
     179                 :          25 :     pp_format_decoder (&pp) = default_tree_printer;
     180                 :          25 :     pp_show_color (&pp) = pp_show_color (global_dc->printer);
     181                 :          25 :     bool first = true;
     182                 :          75 :     for (auto iter : escaped_decls)
     183                 :             :       {
     184                 :          20 :         if (first)
     185                 :             :           first = false;
     186                 :             :         else
     187                 :           5 :           pp_string (&pp, ", ");
     188                 :          20 :         pp_printf (&pp, "%qD", iter);
     189                 :             :       }
     190                 :             :     /* Print the number to make it easier to write DejaGnu tests for
     191                 :             :        the "nothing has escaped" case.  */
     192                 :          40 :     warning_at (cd.get_location (), 0, "escaped: %i: %s",
     193                 :             :                 escaped_decls.length (),
     194                 :             :                 pp_formatted_text (&pp));
     195                 :          25 :   }
     196                 :             : };
     197                 :             : 
     198                 :             : /* Placeholder handler for calls to "__analyzer_dump_exploded_nodes".
     199                 :             :    This is a no-op; the real implementation happens when the
     200                 :             :    exploded_graph is postprocessed.  */
     201                 :             : 
     202                 :        3783 : class kf_analyzer_dump_exploded_nodes : public known_function
     203                 :             : {
     204                 :             : public:
     205                 :        8904 :   bool matches_call_types_p (const call_details &cd) const final override
     206                 :             :   {
     207                 :        8904 :     return cd.num_args () == 1;
     208                 :             :   }
     209                 :             : };
     210                 :             : 
     211                 :             : /* Handler for calls to "__analyzer_dump_named_constant".
     212                 :             : 
     213                 :             :    Look up the given name, and emit a warning describing the
     214                 :             :    state of the corresponding stashed value.
     215                 :             : 
     216                 :             :    This is for use when debugging, and for DejaGnu tests.  */
     217                 :             : 
     218                 :        3783 : class kf_analyzer_dump_named_constant : public known_function
     219                 :             : {
     220                 :             : public:
     221                 :         672 :   bool matches_call_types_p (const call_details &cd) const final override
     222                 :             :   {
     223                 :         672 :     return cd.num_args () == 1;
     224                 :             :   }
     225                 :         112 :   void impl_call_pre (const call_details &cd) const final override
     226                 :             :   {
     227                 :         112 :     region_model_context *ctxt = cd.get_ctxt ();
     228                 :         112 :     if (!ctxt)
     229                 :             :       return;
     230                 :             : 
     231                 :         112 :     const char *name = cd.get_arg_string_literal (0);
     232                 :         112 :     if (!name)
     233                 :             :       {
     234                 :           0 :         error_at (cd.get_location (), "cannot determine name");
     235                 :           0 :         return;
     236                 :             :       }
     237                 :         112 :     tree value = get_stashed_constant_by_name (name);
     238                 :         112 :     if (value)
     239                 :          19 :       warning_at (cd.get_location (), 0, "named constant %qs has value %qE",
     240                 :             :                   name, value);
     241                 :             :     else
     242                 :          93 :       warning_at (cd.get_location (), 0, "named constant %qs has unknown value",
     243                 :             :                   name);
     244                 :             :   }
     245                 :             : };
     246                 :             : 
     247                 :             : /* A pending_diagnostic subclass for implementing "__analyzer_dump_path".  */
     248                 :             : 
     249                 :         243 : class dump_path_diagnostic
     250                 :             :   : public pending_diagnostic_subclass<dump_path_diagnostic>
     251                 :             : {
     252                 :             : public:
     253                 :         426 :   int get_controlling_option () const final override
     254                 :             :   {
     255                 :         426 :     return 0;
     256                 :             :   }
     257                 :             : 
     258                 :         183 :   bool emit (diagnostic_emission_context &ctxt) final override
     259                 :             :   {
     260                 :         183 :     ctxt.inform ("path");
     261                 :         183 :     return true;
     262                 :             :   }
     263                 :             : 
     264                 :         858 :   const char *get_kind () const final override
     265                 :             :   {
     266                 :         858 :     return "dump_path_diagnostic";
     267                 :             :   }
     268                 :             : 
     269                 :             :   bool operator== (const dump_path_diagnostic &) const
     270                 :             :   {
     271                 :             :     return true;
     272                 :             :   }
     273                 :             : };
     274                 :             : 
     275                 :             : /* Handle calls to "__analyzer_dump_path" by queuing a diagnostic at this
     276                 :             :    exploded_node.  */
     277                 :             : 
     278                 :        3783 : class kf_analyzer_dump_path : public known_function
     279                 :             : {
     280                 :             : public:
     281                 :        1586 :   bool matches_call_types_p (const call_details &cd) const final override
     282                 :             :   {
     283                 :        1586 :     return cd.num_args () == 0;
     284                 :             :   }
     285                 :         307 :   void impl_call_pre (const call_details &cd) const final override
     286                 :             :   {
     287                 :         307 :     region_model_context *ctxt = cd.get_ctxt ();
     288                 :         307 :     if (!ctxt)
     289                 :             :       return;
     290                 :         243 :     ctxt->warn (make_unique<dump_path_diagnostic> ());
     291                 :             :   }
     292                 :             : };
     293                 :             : 
     294                 :             : /* Handle calls to "__analyzer_dump_region_model" by dumping
     295                 :             :    the region model's state to stderr.  */
     296                 :             : 
     297                 :        3783 : class kf_analyzer_dump_region_model : public known_function
     298                 :             : {
     299                 :             : public:
     300                 :           0 :   bool matches_call_types_p (const call_details &cd) const final override
     301                 :             :   {
     302                 :           0 :     return cd.num_args () == 0;
     303                 :             :   }
     304                 :           0 :   void impl_call_pre (const call_details &cd) const final override
     305                 :             :   {
     306                 :           0 :     region_model_context *ctxt = cd.get_ctxt ();
     307                 :           0 :     if (!ctxt)
     308                 :             :       return;
     309                 :           0 :     region_model *model = cd.get_model ();
     310                 :           0 :     model->dump (false);
     311                 :             :   }
     312                 :             : };
     313                 :             : 
     314                 :             : /* Handle a call to "__analyzer_eval" by evaluating the input
     315                 :             :    and dumping as a dummy warning, so that test cases can use
     316                 :             :    dg-warning to validate the result (and so unexpected warnings will
     317                 :             :    lead to DejaGnu failures).
     318                 :             :    Broken out as a subroutine to make it easier to put a breakpoint on it
     319                 :             :    - though typically this doesn't help, as we have an SSA name as the arg,
     320                 :             :    and what's more interesting is usually the def stmt for that name.  */
     321                 :             : 
     322                 :        3783 : class kf_analyzer_eval : public known_function
     323                 :             : {
     324                 :             : public:
     325                 :       31348 :   bool matches_call_types_p (const call_details &cd) const final override
     326                 :             :   {
     327                 :       31348 :     return cd.num_args () == 1;
     328                 :             :   }
     329                 :        5716 :   void impl_call_pre (const call_details &cd) const final override
     330                 :             :   {
     331                 :        5716 :     region_model_context *ctxt = cd.get_ctxt ();
     332                 :        5716 :     if (!ctxt)
     333                 :         737 :       return;
     334                 :        4979 :     region_model *model = cd.get_model ();
     335                 :             : 
     336                 :        4979 :     tree t_arg = cd.get_arg_tree (0);
     337                 :        4979 :     tristate t = model->eval_condition (t_arg, NE_EXPR, integer_zero_node,
     338                 :             :                                         ctxt);
     339                 :        4979 :     warning_at (cd.get_location (), 0, "%s", t.as_string ());
     340                 :             :   }
     341                 :             : };
     342                 :             : 
     343                 :             : /* Handler for "__analyzer_get_unknown_ptr".  */
     344                 :             : 
     345                 :        3783 : class kf_analyzer_get_unknown_ptr : public known_function
     346                 :             : {
     347                 :             : public:
     348                 :           6 :   bool matches_call_types_p (const call_details &cd) const final override
     349                 :             :   {
     350                 :           6 :     return cd.num_args () == 0;
     351                 :             :   }
     352                 :           1 :   void impl_call_pre (const call_details &cd) const final override
     353                 :             :   {
     354                 :           1 :     region_model_manager *mgr = cd.get_manager ();
     355                 :           1 :     const svalue *ptr_sval
     356                 :           1 :       = mgr->get_or_create_unknown_svalue (cd.get_lhs_type ());
     357                 :           1 :     cd.maybe_set_lhs (ptr_sval);
     358                 :           1 :   }
     359                 :             : };
     360                 :             : 
     361                 :             : /* Populate KFM with instances of known functions used for debugging the
     362                 :             :    analyzer and for writing DejaGnu tests, all with a "__analyzer_" prefix.  */
     363                 :             : 
     364                 :             : void
     365                 :        3783 : register_known_analyzer_functions (known_function_manager &kfm)
     366                 :             : {
     367                 :        3783 :   kfm.add ("__analyzer_break", make_unique<kf_analyzer_break> ());
     368                 :        3783 :   kfm.add ("__analyzer_describe", make_unique<kf_analyzer_describe> ());
     369                 :        3783 :   kfm.add ("__analyzer_dump_capacity",
     370                 :        7566 :            make_unique<kf_analyzer_dump_capacity> ());
     371                 :        3783 :   kfm.add ("__analyzer_dump_escaped", make_unique<kf_analyzer_dump_escaped> ());
     372                 :        3783 :   kfm.add ("__analyzer_dump_exploded_nodes",
     373                 :        7566 :            make_unique<kf_analyzer_dump_exploded_nodes> ());
     374                 :        3783 :   kfm.add ("__analyzer_dump_named_constant",
     375                 :        7566 :            make_unique<kf_analyzer_dump_named_constant> ());
     376                 :        3783 :   kfm.add ("__analyzer_dump_path", make_unique<kf_analyzer_dump_path> ());
     377                 :        3783 :   kfm.add ("__analyzer_dump_region_model",
     378                 :        7566 :            make_unique<kf_analyzer_dump_region_model> ());
     379                 :        3783 :   kfm.add ("__analyzer_eval", make_unique<kf_analyzer_eval> ());
     380                 :        3783 :   kfm.add ("__analyzer_get_unknown_ptr",
     381                 :        7566 :            make_unique<kf_analyzer_get_unknown_ptr> ());
     382                 :        3783 :   kfm.add ("__analyzer_get_strlen", make_kf_strlen ());
     383                 :        3783 : }
     384                 :             : 
     385                 :             : } // namespace ana
     386                 :             : 
     387                 :             : #endif /* #if ENABLE_ANALYZER */
        

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.