public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [pushed] analyzer: basic support for computed gotos (PR analyzer/110529)
@ 2023-09-07 22:49 David Malcolm
  0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2023-09-07 22:49 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

PR analyzer/110529 notes that -fanalyzer was giving up on execution
paths that follow a computed goto, due to ignoring CFG edges with the
flag EDGE_ABNORMAL set.

This patch implements enough handling for them to allow analysis of
such execution paths to continue.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r14-3796-g1b761fede44afa.

gcc/analyzer/ChangeLog:
	PR analyzer/110529
	* program-point.cc (program_point::on_edge): Don't reject
	EDGE_ABNORMAL for computed gotos.
	* region-model.cc (region_model::maybe_update_for_edge): Handle
	computed goto statements.
	(region_model::apply_constraints_for_ggoto): New.
	* region-model.h (region_model::apply_constraints_for_ggoto): New decl.
	* supergraph.cc (supernode::get_label): New.
	* supergraph.h (supernode::get_label): New decl.

gcc/testsuite/ChangeLog:
	PR analyzer/110529
	* c-c++-common/analyzer/computed-goto-1.c: New test.
	* gcc.dg/analyzer/computed-goto-pr110529.c: New test.
---
 gcc/analyzer/program-point.cc                 | 17 +++++-
 gcc/analyzer/region-model.cc                  | 39 +++++++++++-
 gcc/analyzer/region-model.h                   |  3 +
 gcc/analyzer/supergraph.cc                    | 13 ++++
 gcc/analyzer/supergraph.h                     |  2 +
 .../c-c++-common/analyzer/computed-goto-1.c   | 60 +++++++++++++++++++
 .../gcc.dg/analyzer/computed-goto-pr110529.c  | 27 +++++++++
 7 files changed, 158 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/analyzer/computed-goto-1.c
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/computed-goto-pr110529.c

diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc
index f2d6490f0c04..d7db2f522394 100644
--- a/gcc/analyzer/program-point.cc
+++ b/gcc/analyzer/program-point.cc
@@ -426,9 +426,22 @@ program_point::on_edge (exploded_graph &eg,
       {
 	const cfg_superedge *cfg_sedge = as_a <const cfg_superedge *> (succ);
 
-	/* Reject abnormal edges; we special-case setjmp/longjmp.  */
 	if (cfg_sedge->get_flags () & EDGE_ABNORMAL)
-	  return false;
+	  {
+	    const supernode *src_snode = cfg_sedge->m_src;
+	    if (gimple *last_stmt = src_snode->get_last_stmt ())
+	      if (last_stmt->code == GIMPLE_GOTO)
+		{
+		  /* For the program_point aspect here, consider all
+		     out-edges from goto stmts to be valid; we'll
+		     consider state separately.  */
+		  return true;
+		}
+
+	    /* Reject other kinds of abnormal edges;
+	       we special-case setjmp/longjmp.  */
+	    return false;
+	  }
       }
       break;
 
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 999480e55ef7..a351e5cd214b 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -4997,7 +4997,7 @@ region_model::maybe_update_for_edge (const superedge &edge,
   if (last_stmt == NULL)
     return true;
 
-  /* Apply any constraints for conditionals/switch statements.  */
+  /* Apply any constraints for conditionals/switch/computed-goto statements.  */
 
   if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
     {
@@ -5013,6 +5013,12 @@ region_model::maybe_update_for_edge (const superedge &edge,
 					    ctxt, out);
     }
 
+  if (const ggoto *goto_stmt = dyn_cast <const ggoto *> (last_stmt))
+    {
+      const cfg_superedge *cfg_sedge = as_a <const cfg_superedge *> (&edge);
+      return apply_constraints_for_ggoto (*cfg_sedge, goto_stmt, ctxt);
+    }
+
   /* Apply any constraints due to an exception being thrown.  */
   if (const cfg_superedge *cfg_sedge = dyn_cast <const cfg_superedge *> (&edge))
     if (cfg_sedge->get_flags () & EDGE_EH)
@@ -5267,6 +5273,37 @@ region_model::apply_constraints_for_gswitch (const switch_cfg_superedge &edge,
   return sat;
 }
 
+/* Given an edge reached by GOTO_STMT, determine appropriate constraints
+   for the edge to be taken.
+
+   If they are feasible, add the constraints and return true.
+
+   Return false if the constraints contradict existing knowledge
+   (and so the edge should not be taken).  */
+
+bool
+region_model::apply_constraints_for_ggoto (const cfg_superedge &edge,
+					   const ggoto *goto_stmt,
+					   region_model_context *ctxt)
+{
+  tree dest = gimple_goto_dest (goto_stmt);
+  const svalue *dest_sval = get_rvalue (dest, ctxt);
+
+  /* If we know we were jumping to a specific label.  */
+  if (tree dst_label = edge.m_dest->get_label ())
+    {
+      const label_region *dst_label_reg
+	= m_mgr->get_region_for_label (dst_label);
+      const svalue *dst_label_ptr
+	= m_mgr->get_ptr_svalue (ptr_type_node, dst_label_reg);
+
+      if (!add_constraint (dest_sval, EQ_EXPR, dst_label_ptr, ctxt))
+	return false;
+    }
+
+  return true;
+}
+
 /* Apply any constraints due to an exception being thrown at LAST_STMT.
 
    If they are feasible, add the constraints and return true.
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 1ac3a32b7a41..62d463419d67 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -589,6 +589,9 @@ private:
 				      const gswitch *switch_stmt,
 				      region_model_context *ctxt,
 				      rejected_constraint **out);
+  bool apply_constraints_for_ggoto (const cfg_superedge &edge,
+				    const ggoto *goto_stmt,
+				    region_model_context *ctxt);
   bool apply_constraints_for_exception (const gimple *last_stmt,
 					region_model_context *ctxt,
 					rejected_constraint **out);
diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc
index a23ff15ece45..31707e743a58 100644
--- a/gcc/analyzer/supergraph.cc
+++ b/gcc/analyzer/supergraph.cc
@@ -829,6 +829,19 @@ supernode::get_stmt_index (const gimple *stmt) const
   gcc_unreachable ();
 }
 
+/* Get any label_decl for this supernode, or NULL_TREE if there isn't one.  */
+
+tree
+supernode::get_label () const
+{
+  if (m_stmts.length () == 0)
+    return NULL_TREE;
+  const glabel *label_stmt = dyn_cast<const glabel *> (m_stmts[0]);
+  if (!label_stmt)
+    return NULL_TREE;
+  return gimple_label_label (label_stmt);
+}
+
 /* Get a string for PK.  */
 
 static const char *
diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h
index f8b36d789dc9..27ebd13feb2c 100644
--- a/gcc/analyzer/supergraph.h
+++ b/gcc/analyzer/supergraph.h
@@ -297,6 +297,8 @@ class supernode : public dnode<supergraph_traits>
 
   unsigned int get_stmt_index (const gimple *stmt) const;
 
+  tree get_label () const;
+
   function * const m_fun; // alternatively could be stored as runs of indices within the supergraph
   const basic_block m_bb;
   gcall * const m_returning_call; // for handling the result of a returned call
diff --git a/gcc/testsuite/c-c++-common/analyzer/computed-goto-1.c b/gcc/testsuite/c-c++-common/analyzer/computed-goto-1.c
new file mode 100644
index 000000000000..d6877d3959fe
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/analyzer/computed-goto-1.c
@@ -0,0 +1,60 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+void test_1 (int pc)
+{
+  void *arr[2] = {&&x, &&y};
+  
+  goto *arr[pc];
+
+x:
+  __analyzer_dump_path (); /* { dg-message "path" } */
+  __analyzer_eval (pc == 0); /* { dg-warning "TRUE" "true" { xfail *-*-* } .-1 } */
+  /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */
+  return;
+
+ y:
+  __analyzer_dump_path (); /* { dg-message "path" } */
+  __analyzer_eval (pc == 1); /* { dg-warning "TRUE" "" { xfail *-*-* } } */
+  /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */
+  return;
+}
+
+void test_duplicates (int pc)
+{
+  void *arr[3] = {&&x, &&y, &&x};
+  int var = 0;
+    
+  goto *arr[pc];
+
+ x:
+  __analyzer_dump_path (); /* { dg-message "path" } */
+  __analyzer_eval (pc == 0); /* { dg-warning "UNKNOWN" } */
+  return;
+
+ y:
+  __analyzer_dump_path (); /* { dg-message "path" } */
+  __analyzer_eval (pc == 1); /* { dg-warning "TRUE" "" { xfail *-*-* } } */
+  /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */
+  return;
+}
+
+void test_multiple (int pc)
+{
+  void *arr[2] = {&&x, &&y};
+  
+  goto *arr[pc];
+
+x:
+  __analyzer_dump_path (); /* { dg-message "path" } */
+  __analyzer_eval (pc == 0); /* { dg-warning "TRUE" "true" { xfail *-*-* } .-1 } */
+  /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */
+
+  goto *arr[pc];
+
+ y:
+  __analyzer_dump_path (); /* { dg-message "path" } */
+  __analyzer_eval (pc == 1); /* { dg-warning "TRUE" "" { xfail *-*-* } } */
+  /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */
+
+  goto *arr[pc];
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/computed-goto-pr110529.c b/gcc/testsuite/gcc.dg/analyzer/computed-goto-pr110529.c
new file mode 100644
index 000000000000..988f94a0e819
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/computed-goto-pr110529.c
@@ -0,0 +1,27 @@
+/* C only: reuse of same array for int and label pointers.  */
+
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+void foo(int pc) {
+    int *arr[2] = {&&x, &&y};
+    int var = 0;
+    __analyzer_dump_path (); /* { dg-message "path" } */
+    
+    goto *arr[pc];
+
+x:
+    __analyzer_dump_path (); /* { dg-message "path" } */
+    __analyzer_eval (pc == 0); /* { dg-warning "TRUE" } */
+    /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */
+    arr[0] = (void *)0;
+    *arr[0] = 10086; /* { dg-warning "dereference of NULL" } */
+    return;
+y:
+    __analyzer_dump_path (); /* { dg-message "path" } */
+    __analyzer_eval (pc == 1); /* { dg-warning "TRUE" "" { xfail *-*-* } } */
+    /* { dg-bogus "FALSE" "" { target *-*-* } .-1 } */
+    /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-2 } */
+    return;
+}
+
+int main() { foo(0); }
-- 
2.26.3


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-09-07 22:49 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-07 22:49 [pushed] analyzer: basic support for computed gotos (PR analyzer/110529) David Malcolm

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).