analyzer: move known funs for fds to sm-fd.cc

This mostly mechanical change enables a simplification in the
followup patch.  No functional change intended.

gcc/analyzer/ChangeLog:
	* analyzer.h (register_known_fd_functions): New decl.
	* region-model-impl-calls.cc (class kf_accept): Move to sm-fd.cc.
	(class kf_bind): Likewise.
	(class kf_connect): Likewise.
	(class kf_listen): Likewise.
	(class kf_pipe): Likewise.
	(class kf_socket): Likewise.
	(register_known_functions): Remove registration of the above
	functions, instead calling register_known_fd_functions.
	* sm-fd.cc: Include "analyzer/call-info.h".
	(class kf_socket): Move here from region-model-impl-calls.cc.
	(class kf_bind): Likewise.
	(class kf_listen): Likewise.
	(class kf_accept): Likewise.
	(class kf_connect): Likewise.
	(class kf_pipe): Likewise.
	(register_known_fd_functions): New.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index d424b43..4fbe092 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -258,6 +258,7 @@
 };
 
 extern void register_known_functions (known_function_manager &mgr);
+extern void register_known_fd_functions (known_function_manager &kfm);
 extern void register_varargs_builtins (known_function_manager &kfm);
 
 /* Passed by pointer to PLUGIN_ANALYZER_INIT callbacks.  */
diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc
index 23a21d7..d3f2bf8 100644
--- a/gcc/analyzer/region-model-impl-calls.cc
+++ b/gcc/analyzer/region-model-impl-calls.cc
@@ -595,83 +595,6 @@
   }
 };
 
-/* Handle calls to "accept".
-   See e.g. https://man7.org/linux/man-pages/man3/accept.3p.html  */
-
-class kf_accept : public known_function
-{
-  class outcome_of_accept : public succeed_or_fail_call_info
-  {
-  public:
-    outcome_of_accept (const call_details &cd, bool success)
-    : succeed_or_fail_call_info (cd, success)
-    {}
-
-    bool update_model (region_model *model,
-		       const exploded_edge *,
-		       region_model_context *ctxt) const final override
-    {
-      const call_details cd (get_call_details (model, ctxt));
-      return cd.get_model ()->on_accept (cd, m_success);
-    }
-  };
-
-  bool matches_call_types_p (const call_details &cd) const final override
-  {
-    return (cd.num_args () == 3
-	    && cd.arg_is_pointer_p (1)
-	    && cd.arg_is_pointer_p (2));
-  }
-
-  void impl_call_post (const call_details &cd) const final override
-  {
-    if (cd.get_ctxt ())
-      {
-	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, false));
-	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, true));
-	cd.get_ctxt ()->terminate_path ();
-      }
-  }
-};
-
-/* Handle calls to "bind".
-   See e.g. https://man7.org/linux/man-pages/man3/bind.3p.html  */
-
-class kf_bind : public known_function
-{
-public:
-  class outcome_of_bind : public succeed_or_fail_call_info
-  {
-  public:
-    outcome_of_bind (const call_details &cd, bool success)
-    : succeed_or_fail_call_info (cd, success)
-    {}
-
-    bool update_model (region_model *model,
-		       const exploded_edge *,
-		       region_model_context *ctxt) const final override
-    {
-      const call_details cd (get_call_details (model, ctxt));
-      return cd.get_model ()->on_bind (cd, m_success);
-    }
-  };
-
-  bool matches_call_types_p (const call_details &cd) const final override
-  {
-    return (cd.num_args () == 3 && cd.arg_is_pointer_p (1));
-  }
-
-  void impl_call_post (const call_details &cd) const final override
-  {
-    if (cd.get_ctxt ())
-      {
-	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, false));
-	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, true));
-	cd.get_ctxt ()->terminate_path ();
-      }
-  }
-};
-
 /* Handler for "__builtin_expect" etc.  */
 
 class kf_expect : public internal_known_function
@@ -723,45 +646,6 @@
     }
 }
 
-/* Handle calls to "connect".
-   See e.g. https://man7.org/linux/man-pages/man3/connect.3p.html  */
-
-class kf_connect : public known_function
-{
-public:
-  class outcome_of_connect : public succeed_or_fail_call_info
-  {
-  public:
-    outcome_of_connect (const call_details &cd, bool success)
-    : succeed_or_fail_call_info (cd, success)
-    {}
-
-    bool update_model (region_model *model,
-		       const exploded_edge *,
-		       region_model_context *ctxt) const final override
-    {
-      const call_details cd (get_call_details (model, ctxt));
-      return cd.get_model ()->on_connect (cd, m_success);
-    }
-  };
-
-  bool matches_call_types_p (const call_details &cd) const final override
-  {
-    return (cd.num_args () == 3
-	    && cd.arg_is_pointer_p (1));
-  }
-
-  void impl_call_post (const call_details &cd) const final override
-  {
-    if (cd.get_ctxt ())
-      {
-	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, false));
-	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, true));
-	cd.get_ctxt ()->terminate_path ();
-      }
-  }
-};
-
 /* Handler for glibc's "__errno_location".  */
 
 class kf_errno_location : public known_function
@@ -933,43 +817,6 @@
      for the analyzer).  */
 };
 
-/* Handle calls to "listen".
-   See e.g. https://man7.org/linux/man-pages/man3/listen.3p.html  */
-
-class kf_listen : public known_function
-{
-  class outcome_of_listen : public succeed_or_fail_call_info
-  {
-  public:
-    outcome_of_listen (const call_details &cd, bool success)
-    : succeed_or_fail_call_info (cd, success)
-    {}
-
-    bool update_model (region_model *model,
-		       const exploded_edge *,
-		       region_model_context *ctxt) const final override
-    {
-      const call_details cd (get_call_details (model, ctxt));
-      return cd.get_model ()->on_listen (cd, m_success);
-    }
-  };
-
-  bool matches_call_types_p (const call_details &cd) const final override
-  {
-    return cd.num_args () == 2;
-  }
-
-  void impl_call_post (const call_details &cd) const final override
-  {
-    if (cd.get_ctxt ())
-      {
-	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, false));
-	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, true));
-	cd.get_ctxt ()->terminate_path ();
-      }
-  }
-};
-
 /* Handle the on_call_pre part of "malloc".  */
 
 class kf_malloc : public known_function
@@ -1077,92 +924,6 @@
   model->fill_region (sized_dest_reg, fill_value_u8);
 }
 
-/* Handler for calls to "pipe" and "pipe2".
-   See e.g. https://www.man7.org/linux/man-pages/man2/pipe.2.html  */
-
-class kf_pipe : public known_function
-{
-  class failure : public failed_call_info
-  {
-  public:
-    failure (const call_details &cd) : failed_call_info (cd) {}
-
-    bool update_model (region_model *model,
-		       const exploded_edge *,
-		       region_model_context *ctxt) const final override
-    {
-      /* Return -1; everything else is unchanged.  */
-      const call_details cd (get_call_details (model, ctxt));
-      model->update_for_int_cst_return (cd, -1, true);
-      return true;
-    }
-  };
-
-  class success : public success_call_info
-  {
-  public:
-    success (const call_details &cd) : success_call_info (cd) {}
-
-    bool update_model (region_model *model,
-		       const exploded_edge *,
-		       region_model_context *ctxt) const final override
-    {
-      const call_details cd (get_call_details (model, ctxt));
-
-      /* Return 0.  */
-      model->update_for_zero_return (cd, true);
-
-      /* Update fd array.  */
-      region_model_manager *mgr = cd.get_manager ();
-      tree arr_tree = cd.get_arg_tree (0);
-      const svalue *arr_sval = cd.get_arg_svalue (0);
-      for (int idx = 0; idx < 2; idx++)
-	{
-	  const region *arr_reg
-	    = model->deref_rvalue (arr_sval, arr_tree, cd.get_ctxt ());
-	  const svalue *idx_sval
-	    = mgr->get_or_create_int_cst (integer_type_node, idx);
-	  const region *element_reg
-	    = mgr->get_element_region (arr_reg, integer_type_node, idx_sval);
-	  conjured_purge p (model, cd.get_ctxt ());
-	  const svalue *fd_sval
-	    = mgr->get_or_create_conjured_svalue (integer_type_node,
-						  cd.get_call_stmt (),
-						  element_reg,
-						  p);
-	  model->set_value (element_reg, fd_sval, cd.get_ctxt ());
-	  model->mark_as_valid_fd (fd_sval, cd.get_ctxt ());
-	}
-      return true;
-    }
-  };
-
-public:
-  kf_pipe (unsigned num_args)
-  : m_num_args (num_args)
-  {
-    gcc_assert (num_args > 0);
-  }
-
-  bool matches_call_types_p (const call_details &cd) const final override
-  {
-    return (cd.num_args () == m_num_args && cd.arg_is_pointer_p (0));
-  }
-
-  void impl_call_post (const call_details &cd) const final override
-  {
-    if (cd.get_ctxt ())
-      {
-	cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
-	cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
-	cd.get_ctxt ()->terminate_path ();
-      }
-  }
-
-private:
-  unsigned m_num_args;
-};
-
 /* A subclass of pending_diagnostic for complaining about 'putenv'
    called on an auto var.  */
 
@@ -1587,44 +1348,6 @@
     }
 }
 
-/* Handle calls to "socket".
-   See e.g. https://man7.org/linux/man-pages/man3/socket.3p.html  */
-
-class kf_socket : public known_function
-{
-public:
-  class outcome_of_socket : public succeed_or_fail_call_info
-  {
-  public:
-    outcome_of_socket (const call_details &cd, bool success)
-    : succeed_or_fail_call_info (cd, success)
-    {}
-
-    bool update_model (region_model *model,
-		       const exploded_edge *,
-		       region_model_context *ctxt) const final override
-    {
-      const call_details cd (get_call_details (model, ctxt));
-      return cd.get_model ()->on_socket (cd, m_success);
-    }
-  };
-
-  bool matches_call_types_p (const call_details &cd) const final override
-  {
-    return cd.num_args () == 3;
-  }
-
-  void impl_call_post (const call_details &cd) const final override
-  {
-    if (cd.get_ctxt ())
-      {
-	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, false));
-	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, true));
-	cd.get_ctxt ()->terminate_path ();
-      }
-  }
-};
-
 /* Handler for "strchr" and "__builtin_strchr".  */
 
 class kf_strchr : public known_function
@@ -1933,17 +1656,12 @@
 
   /* Known POSIX functions, and some non-standard extensions.  */
   {
-    kfm.add ("accept", make_unique<kf_accept> ());
-    kfm.add ("bind", make_unique<kf_bind> ());
-    kfm.add ("connect", make_unique<kf_connect> ());
     kfm.add ("fgets", make_unique<kf_fgets> ());
     kfm.add ("fgets_unlocked", make_unique<kf_fgets> ()); // non-standard
     kfm.add ("fread", make_unique<kf_fread> ());
-    kfm.add ("listen", make_unique<kf_listen> ());
-    kfm.add ("pipe", make_unique<kf_pipe> (1));
-    kfm.add ("pipe2", make_unique<kf_pipe> (2));
     kfm.add ("putenv", make_unique<kf_putenv> ());
-    kfm.add ("socket", make_unique<kf_socket> ());
+
+    register_known_fd_functions (kfm);
   }
 
   /* glibc functions.  */
diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc
index f7779be..af59aef 100644
--- a/gcc/analyzer/sm-fd.cc
+++ b/gcc/analyzer/sm-fd.cc
@@ -47,6 +47,7 @@
 #include "analyzer/program-state.h"
 #include "analyzer/supergraph.h"
 #include "analyzer/analyzer-language.h"
+#include "analyzer/call-info.h"
 
 #if ENABLE_ANALYZER
 
@@ -2251,6 +2252,44 @@
   fd_sm->mark_as_valid_fd (this, smap, sval, *ext_state);
 }
 
+/* Handle calls to "socket".
+   See e.g. https://man7.org/linux/man-pages/man3/socket.3p.html  */
+
+class kf_socket : public known_function
+{
+public:
+  class outcome_of_socket : public succeed_or_fail_call_info
+  {
+  public:
+    outcome_of_socket (const call_details &cd, bool success)
+    : succeed_or_fail_call_info (cd, success)
+    {}
+
+    bool update_model (region_model *model,
+		       const exploded_edge *,
+		       region_model_context *ctxt) const final override
+    {
+      const call_details cd (get_call_details (model, ctxt));
+      return cd.get_model ()->on_socket (cd, m_success);
+    }
+  };
+
+  bool matches_call_types_p (const call_details &cd) const final override
+  {
+    return cd.num_args () == 3;
+  }
+
+  void impl_call_post (const call_details &cd) const final override
+  {
+    if (cd.get_ctxt ())
+      {
+	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, false));
+	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, true));
+	cd.get_ctxt ()->terminate_path ();
+      }
+  }
+};
+
 /* Specialcase hook for handling "socket", for use by
    kf_socket::outcome_of_socket::update_model.  */
 
@@ -2269,6 +2308,44 @@
   return fd_sm->on_socket (cd, successful, sm_ctxt.get (), *ext_state);
 }
 
+/* Handle calls to "bind".
+   See e.g. https://man7.org/linux/man-pages/man3/bind.3p.html  */
+
+class kf_bind : public known_function
+{
+public:
+  class outcome_of_bind : public succeed_or_fail_call_info
+  {
+  public:
+    outcome_of_bind (const call_details &cd, bool success)
+    : succeed_or_fail_call_info (cd, success)
+    {}
+
+    bool update_model (region_model *model,
+		       const exploded_edge *,
+		       region_model_context *ctxt) const final override
+    {
+      const call_details cd (get_call_details (model, ctxt));
+      return cd.get_model ()->on_bind (cd, m_success);
+    }
+  };
+
+  bool matches_call_types_p (const call_details &cd) const final override
+  {
+    return (cd.num_args () == 3 && cd.arg_is_pointer_p (1));
+  }
+
+  void impl_call_post (const call_details &cd) const final override
+  {
+    if (cd.get_ctxt ())
+      {
+	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, false));
+	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, true));
+	cd.get_ctxt ()->terminate_path ();
+      }
+  }
+};
+
 /* Specialcase hook for handling "bind", for use by
    kf_bind::outcome_of_bind::update_model.  */
 
@@ -2287,6 +2364,43 @@
   return fd_sm->on_bind (cd, successful, sm_ctxt.get (), *ext_state);
 }
 
+/* Handle calls to "listen".
+   See e.g. https://man7.org/linux/man-pages/man3/listen.3p.html  */
+
+class kf_listen : public known_function
+{
+  class outcome_of_listen : public succeed_or_fail_call_info
+  {
+  public:
+    outcome_of_listen (const call_details &cd, bool success)
+    : succeed_or_fail_call_info (cd, success)
+    {}
+
+    bool update_model (region_model *model,
+		       const exploded_edge *,
+		       region_model_context *ctxt) const final override
+    {
+      const call_details cd (get_call_details (model, ctxt));
+      return cd.get_model ()->on_listen (cd, m_success);
+    }
+  };
+
+  bool matches_call_types_p (const call_details &cd) const final override
+  {
+    return cd.num_args () == 2;
+  }
+
+  void impl_call_post (const call_details &cd) const final override
+  {
+    if (cd.get_ctxt ())
+      {
+	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, false));
+	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, true));
+	cd.get_ctxt ()->terminate_path ();
+      }
+  }
+};
+
 /* Specialcase hook for handling "listen", for use by
    kf_listen::outcome_of_listen::update_model.  */
 
@@ -2305,6 +2419,45 @@
   return fd_sm->on_listen (cd, successful, sm_ctxt.get (), *ext_state);
 }
 
+/* Handle calls to "accept".
+   See e.g. https://man7.org/linux/man-pages/man3/accept.3p.html  */
+
+class kf_accept : public known_function
+{
+  class outcome_of_accept : public succeed_or_fail_call_info
+  {
+  public:
+    outcome_of_accept (const call_details &cd, bool success)
+    : succeed_or_fail_call_info (cd, success)
+    {}
+
+    bool update_model (region_model *model,
+		       const exploded_edge *,
+		       region_model_context *ctxt) const final override
+    {
+      const call_details cd (get_call_details (model, ctxt));
+      return cd.get_model ()->on_accept (cd, m_success);
+    }
+  };
+
+  bool matches_call_types_p (const call_details &cd) const final override
+  {
+    return (cd.num_args () == 3
+	    && cd.arg_is_pointer_p (1)
+	    && cd.arg_is_pointer_p (2));
+  }
+
+  void impl_call_post (const call_details &cd) const final override
+  {
+    if (cd.get_ctxt ())
+      {
+	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, false));
+	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, true));
+	cd.get_ctxt ()->terminate_path ();
+      }
+  }
+};
+
 /* Specialcase hook for handling "accept", for use by
    kf_accept::outcome_of_accept::update_model.  */
 
@@ -2323,6 +2476,45 @@
   return fd_sm->on_accept (cd, successful, sm_ctxt.get (), *ext_state);
 }
 
+/* Handle calls to "connect".
+   See e.g. https://man7.org/linux/man-pages/man3/connect.3p.html  */
+
+class kf_connect : public known_function
+{
+public:
+  class outcome_of_connect : public succeed_or_fail_call_info
+  {
+  public:
+    outcome_of_connect (const call_details &cd, bool success)
+    : succeed_or_fail_call_info (cd, success)
+    {}
+
+    bool update_model (region_model *model,
+		       const exploded_edge *,
+		       region_model_context *ctxt) const final override
+    {
+      const call_details cd (get_call_details (model, ctxt));
+      return cd.get_model ()->on_connect (cd, m_success);
+    }
+  };
+
+  bool matches_call_types_p (const call_details &cd) const final override
+  {
+    return (cd.num_args () == 3
+	    && cd.arg_is_pointer_p (1));
+  }
+
+  void impl_call_post (const call_details &cd) const final override
+  {
+    if (cd.get_ctxt ())
+      {
+	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, false));
+	cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, true));
+	cd.get_ctxt ()->terminate_path ();
+      }
+  }
+};
+
 /* Specialcase hook for handling "connect", for use by
    kf_connect::outcome_of_connect::update_model.  */
 
@@ -2341,6 +2533,107 @@
   return fd_sm->on_connect (cd, successful, sm_ctxt.get (), *ext_state);
 }
 
+/* Handler for calls to "pipe" and "pipe2".
+   See e.g. https://www.man7.org/linux/man-pages/man2/pipe.2.html  */
+
+class kf_pipe : public known_function
+{
+  class failure : public failed_call_info
+  {
+  public:
+    failure (const call_details &cd) : failed_call_info (cd) {}
+
+    bool update_model (region_model *model,
+		       const exploded_edge *,
+		       region_model_context *ctxt) const final override
+    {
+      /* Return -1; everything else is unchanged.  */
+      const call_details cd (get_call_details (model, ctxt));
+      model->update_for_int_cst_return (cd, -1, true);
+      return true;
+    }
+  };
+
+  class success : public success_call_info
+  {
+  public:
+    success (const call_details &cd) : success_call_info (cd) {}
+
+    bool update_model (region_model *model,
+		       const exploded_edge *,
+		       region_model_context *ctxt) const final override
+    {
+      const call_details cd (get_call_details (model, ctxt));
+
+      /* Return 0.  */
+      model->update_for_zero_return (cd, true);
+
+      /* Update fd array.  */
+      region_model_manager *mgr = cd.get_manager ();
+      tree arr_tree = cd.get_arg_tree (0);
+      const svalue *arr_sval = cd.get_arg_svalue (0);
+      for (int idx = 0; idx < 2; idx++)
+	{
+	  const region *arr_reg
+	    = model->deref_rvalue (arr_sval, arr_tree, cd.get_ctxt ());
+	  const svalue *idx_sval
+	    = mgr->get_or_create_int_cst (integer_type_node, idx);
+	  const region *element_reg
+	    = mgr->get_element_region (arr_reg, integer_type_node, idx_sval);
+	  conjured_purge p (model, cd.get_ctxt ());
+	  const svalue *fd_sval
+	    = mgr->get_or_create_conjured_svalue (integer_type_node,
+						  cd.get_call_stmt (),
+						  element_reg,
+						  p);
+	  model->set_value (element_reg, fd_sval, cd.get_ctxt ());
+	  model->mark_as_valid_fd (fd_sval, cd.get_ctxt ());
+	}
+      return true;
+    }
+  };
+
+public:
+  kf_pipe (unsigned num_args)
+  : m_num_args (num_args)
+  {
+    gcc_assert (num_args > 0);
+  }
+
+  bool matches_call_types_p (const call_details &cd) const final override
+  {
+    return (cd.num_args () == m_num_args && cd.arg_is_pointer_p (0));
+  }
+
+  void impl_call_post (const call_details &cd) const final override
+  {
+    if (cd.get_ctxt ())
+      {
+	cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
+	cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
+	cd.get_ctxt ()->terminate_path ();
+      }
+  }
+
+private:
+  unsigned m_num_args;
+};
+
+/* Populate KFM with instances of known functions relating to
+   file descriptors.  */
+
+void
+register_known_fd_functions (known_function_manager &kfm)
+{
+  kfm.add ("accept", make_unique<kf_accept> ());
+  kfm.add ("bind", make_unique<kf_bind> ());
+  kfm.add ("connect", make_unique<kf_connect> ());
+  kfm.add ("listen", make_unique<kf_listen> ());
+  kfm.add ("pipe", make_unique<kf_pipe> (1));
+  kfm.add ("pipe2", make_unique<kf_pipe> (2));
+  kfm.add ("socket", make_unique<kf_socket> ());
+}
+
 } // namespace ana
 
 #endif // ENABLE_ANALYZER