analyzer: only use CWE-690 for unchecked return value [PR97893]
[gcc.git] / gcc / analyzer / supergraph.cc
index a5bf52d8aca17c687f114564741866a56d53cd65..37f143c6fca007aa4ba604837531f55619a908ec 100644 (file)
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "cfganal.h"
 #include "function.h"
+#include "json.h"
 #include "analyzer/analyzer.h"
 #include "ordered-hash-map.h"
 #include "options.h"
@@ -56,6 +57,18 @@ along with GCC; see the file COPYING3.  If not see
 
 namespace ana {
 
+/* Get the function of the ultimate alias target being called at EDGE,
+   if any.  */
+
+static function *
+get_ultimate_function_for_cgraph_edge (cgraph_edge *edge)
+{
+  cgraph_node *ultimate_node = edge->callee->ultimate_alias_target ();
+  if (!ultimate_node)
+    return NULL;
+  return ultimate_node->get_fun ();
+}
+
 /* Get the cgraph_edge, but only if there's an underlying function body.  */
 
 cgraph_edge *
@@ -69,7 +82,7 @@ supergraph_call_edge (function *fun, gimple *stmt)
     return NULL;
   if (!edge->callee)
     return NULL; /* e.g. for a function pointer.  */
-  if (!edge->callee->get_fun ())
+  if (!get_ultimate_function_for_cgraph_edge (edge))
     return NULL;
   return edge;
 }
@@ -77,7 +90,8 @@ supergraph_call_edge (function *fun, gimple *stmt)
 /* supergraph's ctor.  Walk the callgraph, building supernodes for each
    CFG basic block, splitting the basic blocks at callsites.  Join
    together the supernodes with interprocedural and intraprocedural
-   superedges as appropriate.  */
+   superedges as appropriate.
+   Assign UIDs to the gimple stmts.  */
 
 supergraph::supergraph (logger *logger)
 {
@@ -85,8 +99,10 @@ supergraph::supergraph (logger *logger)
 
   LOG_FUNC (logger);
 
-  /* First pass: make supernodes.  */
+  /* First pass: make supernodes (and assign UIDs to the gimple stmts).  */
   {
+    unsigned next_uid = 0;
+
     /* Sort the cgraph_nodes?  */
     cgraph_node *node;
     FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
@@ -111,6 +127,7 @@ supergraph::supergraph (logger *logger)
            {
              gimple *stmt = gsi_stmt (gpi);
              m_stmt_to_node_t.put (stmt, node_for_stmts);
+             stmt->uid = next_uid++;
            }
 
          /* Append statements from BB to the current supernode, splitting
@@ -122,6 +139,7 @@ supergraph::supergraph (logger *logger)
              gimple *stmt = gsi_stmt (gsi);
              node_for_stmts->m_stmts.safe_push (stmt);
              m_stmt_to_node_t.put (stmt, node_for_stmts);
+             stmt->uid = next_uid++;
              if (cgraph_edge *edge = supergraph_call_edge (fun, stmt))
                {
                  m_cgraph_edge_to_caller_prev_node.put(edge, node_for_stmts);
@@ -178,8 +196,10 @@ supergraph::supergraph (logger *logger)
        {
          cgraph_edge *edge = (*iter).first;
          supernode *caller_prev_supernode = (*iter).second;
-         basic_block callee_cfg_block
-           = ENTRY_BLOCK_PTR_FOR_FN (edge->callee->get_fun ());
+         function* callee_fn = get_ultimate_function_for_cgraph_edge (edge);
+         if (!callee_fn || !callee_fn->cfg)
+           continue;
+         basic_block callee_cfg_block = ENTRY_BLOCK_PTR_FOR_FN (callee_fn);
          supernode *callee_supernode
            = *m_bb_to_initial_node.get (callee_cfg_block);
          call_superedge *sedge
@@ -199,8 +219,10 @@ supergraph::supergraph (logger *logger)
        {
          cgraph_edge *edge = (*iter).first;
          supernode *caller_next_supernode = (*iter).second;
-         basic_block callee_cfg_block
-           = EXIT_BLOCK_PTR_FOR_FN (edge->callee->get_fun ());
+         function* callee_fn = get_ultimate_function_for_cgraph_edge (edge);
+         if (!callee_fn || !callee_fn->cfg)
+           continue;
+         basic_block callee_cfg_block = EXIT_BLOCK_PTR_FOR_FN (callee_fn);
          supernode *callee_supernode
            = *m_bb_to_initial_node.get (callee_cfg_block);
          return_superedge *sedge
@@ -358,6 +380,38 @@ supergraph::dump_dot (const char *path, const dump_args_t &dump_args) const
   fclose (fp);
 }
 
+/* Return a new json::object of the form
+   {"nodes" : [objs for snodes],
+    "edges" : [objs for sedges]}.  */
+
+json::object *
+supergraph::to_json () const
+{
+  json::object *sgraph_obj = new json::object ();
+
+  /* Nodes.  */
+  {
+    json::array *nodes_arr = new json::array ();
+    unsigned i;
+    supernode *n;
+    FOR_EACH_VEC_ELT (m_nodes, i, n)
+      nodes_arr->append (n->to_json ());
+    sgraph_obj->set ("nodes", nodes_arr);
+  }
+
+  /* Edges.  */
+  {
+    json::array *edges_arr = new json::array ();
+    unsigned i;
+    superedge *n;
+    FOR_EACH_VEC_ELT (m_edges, i, n)
+      edges_arr->append (n->to_json ());
+    sgraph_obj->set ("edges", edges_arr);
+  }
+
+  return sgraph_obj;
+}
+
 /* Create a supernode for BB within FUN and add it to this supergraph.
 
    If RETURNING_CALL is non-NULL, the supernode represents the resumption
@@ -437,12 +491,12 @@ supernode::dump_dot (graphviz_out *gv, const dump_args_t &args) const
   gv->println("style=\"solid\";");
   gv->println("color=\"black\";");
   gv->println("fillcolor=\"lightgrey\";");
-  gv->println("label=\"sn: %i\";", m_index);
+  gv->println("label=\"sn: %i (bb: %i)\";", m_index, m_bb->index);
 
   pretty_printer *pp = gv->get_pp ();
 
   if (args.m_node_annotator)
-    args.m_node_annotator->add_node_annotations (gv, *this);
+    args.m_node_annotator->add_node_annotations (gv, *this, false);
 
   gv->write_indent ();
   dump_dot_id (pp);
@@ -454,19 +508,33 @@ supernode::dump_dot (graphviz_out *gv, const dump_args_t &args) const
 
   bool had_row = false;
 
+  /* Give any annotator the chance to add its own per-node TR elements. */
+  if (args.m_node_annotator)
+    if (args.m_node_annotator->add_node_annotations (gv, *this, true))
+      had_row = true;
+
   if (m_returning_call)
     {
-      gv->begin_tr ();
+      gv->begin_trtd ();
       pp_string (pp, "returning call: ");
-      gv->end_tr ();
+      gv->end_tdtr ();
 
       gv->begin_tr ();
+      gv->begin_td ();
       pp_gimple_stmt_1 (pp, m_returning_call, 0, (dump_flags_t)0);
       pp_write_text_as_html_like_dot_to_stream (pp);
+      gv->end_td ();
+      /* Give any annotator the chance to add per-stmt TD elements to
+        this row.  */
+      if (args.m_node_annotator)
+       args.m_node_annotator->add_stmt_annotations (gv, m_returning_call,
+                                                    true);
       gv->end_tr ();
 
+      /* Give any annotator the chance to add per-stmt TR elements.  */
       if (args.m_node_annotator)
-       args.m_node_annotator->add_stmt_annotations (gv, m_returning_call);
+       args.m_node_annotator->add_stmt_annotations (gv, m_returning_call,
+                                                    false);
       pp_newline (pp);
 
       had_row = true;
@@ -492,12 +560,19 @@ supernode::dump_dot (graphviz_out *gv, const dump_args_t &args) const
     {
       const gimple *stmt = gsi_stmt (gpi);
       gv->begin_tr ();
+      gv->begin_td ();
       pp_gimple_stmt_1 (pp, stmt, 0, (dump_flags_t)0);
       pp_write_text_as_html_like_dot_to_stream (pp);
+      gv->end_td ();
+      /* Give any annotator the chance to add per-phi TD elements to
+        this row.  */
+      if (args.m_node_annotator)
+       args.m_node_annotator->add_stmt_annotations (gv, stmt, true);
       gv->end_tr ();
 
+      /* Give any annotator the chance to add per-phi TR elements.  */
       if (args.m_node_annotator)
-       args.m_node_annotator->add_stmt_annotations (gv, stmt);
+       args.m_node_annotator->add_stmt_annotations (gv, stmt, false);
 
       pp_newline (pp);
       had_row = true;
@@ -509,17 +584,30 @@ supernode::dump_dot (graphviz_out *gv, const dump_args_t &args) const
   FOR_EACH_VEC_ELT (m_stmts, i, stmt)
     {
       gv->begin_tr ();
+      gv->begin_td ();
       pp_gimple_stmt_1 (pp, stmt, 0, (dump_flags_t)0);
       pp_write_text_as_html_like_dot_to_stream (pp);
+      gv->end_td ();
+      /* Give any annotator the chance to add per-stmt TD elements to
+        this row.  */
+      if (args.m_node_annotator)
+       args.m_node_annotator->add_stmt_annotations (gv, stmt, true);
       gv->end_tr ();
 
+      /* Give any annotator the chance to add per-stmt TR elements.  */
       if (args.m_node_annotator)
-       args.m_node_annotator->add_stmt_annotations (gv, stmt);
+       args.m_node_annotator->add_stmt_annotations (gv, stmt, false);
 
       pp_newline (pp);
       had_row = true;
     }
 
+  /* Give any annotator the chance to add additional per-node TR elements
+     to the end of the TABLE. */
+  if (args.m_node_annotator)
+    if (args.m_node_annotator->add_after_node_annotations (gv, *this))
+      had_row = true;
+
   /* Graphviz requires a TABLE element to have at least one TR
      (and each TR to have at least one TD).  */
   if (!had_row)
@@ -544,6 +632,63 @@ supernode::dump_dot_id (pretty_printer *pp) const
   pp_printf (pp, "node_%i", m_index);
 }
 
+/* Return a new json::object of the form
+   {"idx": int,
+    "bb_idx": int,
+    "m_returning_call": optional str,
+    "phis": [str],
+    "stmts" : [str]}.  */
+
+json::object *
+supernode::to_json () const
+{
+  json::object *snode_obj = new json::object ();
+
+  snode_obj->set ("idx", new json::integer_number (m_index));
+  snode_obj->set ("bb_idx", new json::integer_number (m_bb->index));
+
+  if (m_returning_call)
+    {
+      pretty_printer pp;
+      pp_format_decoder (&pp) = default_tree_printer;
+      pp_gimple_stmt_1 (&pp, m_returning_call, 0, (dump_flags_t)0);
+      snode_obj->set ("returning_call",
+                     new json::string (pp_formatted_text (&pp)));
+    }
+
+  /* Phi nodes.  */
+  {
+    json::array *phi_arr = new json::array ();
+    for (gphi_iterator gpi = const_cast<supernode *> (this)->start_phis ();
+        !gsi_end_p (gpi); gsi_next (&gpi))
+      {
+       const gimple *stmt = gsi_stmt (gpi);
+       pretty_printer pp;
+       pp_format_decoder (&pp) = default_tree_printer;
+       pp_gimple_stmt_1 (&pp, stmt, 0, (dump_flags_t)0);
+       phi_arr->append (new json::string (pp_formatted_text (&pp)));
+      }
+    snode_obj->set ("phis", phi_arr);
+  }
+
+  /* Statements.  */
+  {
+    json::array *stmt_arr = new json::array ();
+    int i;
+    gimple *stmt;
+    FOR_EACH_VEC_ELT (m_stmts, i, stmt)
+      {
+       pretty_printer pp;
+       pp_format_decoder (&pp) = default_tree_printer;
+       pp_gimple_stmt_1 (&pp, stmt, 0, (dump_flags_t)0);
+       stmt_arr->append (new json::string (pp_formatted_text (&pp)));
+      }
+    snode_obj->set ("stmts", stmt_arr);
+  }
+
+  return snode_obj;
+}
+
 /* Get a location_t for the start of this supernode.  */
 
 location_t
@@ -608,6 +753,35 @@ supernode::get_stmt_index (const gimple *stmt) const
   gcc_unreachable ();
 }
 
+/* Dump this superedge to PP.  */
+
+void
+superedge::dump (pretty_printer *pp) const
+{
+  pp_printf (pp, "edge: SN: %i -> SN: %i", m_src->m_index, m_dest->m_index);
+  char *desc = get_description (false);
+  if (strlen (desc) > 0)
+    {
+      pp_space (pp);
+      pp_string (pp, desc);
+    }
+  free (desc);
+}
+
+/* Dump this superedge to stderr.  */
+
+DEBUG_FUNCTION void
+superedge::dump () const
+{
+  pretty_printer pp;
+  pp_format_decoder (&pp) = default_tree_printer;
+  pp_show_color (&pp) = pp_show_color (global_dc->printer);
+  pp.buffer->stream = stderr;
+  dump (&pp);
+  pp_newline (&pp);
+  pp_flush (&pp);
+}
+
 /* Implementation of dedge::dump_dot for superedges.
    Write a .dot edge to GV representing this superedge.  */
 
@@ -680,6 +854,28 @@ superedge::dump_dot (graphviz_out *gv, const dump_args_t &) const
   pp_printf (pp, "\"];\n");
 }
 
+/* Return a new json::object of the form
+   {"src_idx": int, the index of the source supernode,
+    "dst_idx": int, the index of the destination supernode,
+    "desc"   : str.  */
+
+json::object *
+superedge::to_json () const
+{
+  json::object *sedge_obj = new json::object ();
+  sedge_obj->set ("src_idx", new json::integer_number (m_src->m_index));
+  sedge_obj->set ("dst_idx", new json::integer_number (m_dest->m_index));
+
+  {
+    pretty_printer pp;
+    pp_format_decoder (&pp) = default_tree_printer;
+    dump_label_to_pp (&pp, false);
+    sedge_obj->set ("desc", new json::string (pp_formatted_text (&pp)));
+  }
+
+  return sedge_obj;
+}
+
 /* If this is an intraprocedural superedge, return the associated
    CFG edge.  Otherwise, return NULL.  */
 
@@ -840,7 +1036,7 @@ callgraph_superedge::dump_label_to_pp (pretty_printer *pp,
 function *
 callgraph_superedge::get_callee_function () const
 {
-  return m_cedge->callee->get_fun ();
+  return get_ultimate_function_for_cgraph_edge (m_cedge);
 }
 
 /* Get the calling function at this interprocedural call/return edge.  */