From 0cdd8aa34c070597cfe6c16dceeb764a294abed7 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 24 Jun 2019 11:41:58 -0400
Subject: [PATCH 37/51] FIXME: hide the state_machine subclasses in their
 respective source files

---
 gcc/analyzer/impl-2.cc          |  29 +++---
 gcc/analyzer/impl-3.cc          |  27 +++---
 gcc/analyzer/sm-file.cc         |  39 ++++++++
 gcc/analyzer/sm-malloc.cc       |  43 +++++++++
 gcc/analyzer/sm-pattern-test.cc |  35 ++++++++
 gcc/analyzer/sm-sensitive.cc    |  42 +++++++++
 gcc/analyzer/sm-taint.cc        |  42 ++++++++-
 gcc/analyzer/sm.cc              |  10 +--
 gcc/analyzer/sm.h               | 194 ++++------------------------------------
 9 files changed, 256 insertions(+), 205 deletions(-)

diff --git a/gcc/analyzer/impl-2.cc b/gcc/analyzer/impl-2.cc
index a6aa3e5..23a587b 100644
--- a/gcc/analyzer/impl-2.cc
+++ b/gcc/analyzer/impl-2.cc
@@ -3833,26 +3833,33 @@ run_checkers_impl_2 ()
 
     {
       auto_client_timevar tv ("malloc_state_machine");
-      malloc_state_machine sm (the_logger.get_logger ());
-      run_one_checker (sg, sm, the_logger.get_logger ());
+      state_machine *sm = make_malloc_state_machine (the_logger.get_logger ());
+      run_one_checker (sg, *sm, the_logger.get_logger ());
+      delete sm;
     }
 
     {
       auto_client_timevar tv ("fileptr_state_machine");
-      fileptr_state_machine sm (the_logger.get_logger ());
-      run_one_checker (sg, sm, the_logger.get_logger ());
+      state_machine *sm
+	= make_fileptr_state_machine (the_logger.get_logger ());
+      run_one_checker (sg, *sm, the_logger.get_logger ());
+      delete sm;
     }
 
     {
       auto_client_timevar tv ("taint_state_machine");
-      taint_state_machine sm (the_logger.get_logger ());
-      run_one_checker (sg, sm, the_logger.get_logger ());
+      state_machine *sm
+	= make_taint_state_machine (the_logger.get_logger ());
+      run_one_checker (sg, *sm, the_logger.get_logger ());
+      delete sm;
     }
 
     {
       auto_client_timevar tv ("sensitive_state_machine");
-      sensitive_state_machine sm (the_logger.get_logger ());
-      run_one_checker (sg, sm, the_logger.get_logger ());
+      state_machine *sm
+	= make_sensitive_state_machine (the_logger.get_logger ());
+      run_one_checker (sg, *sm, the_logger.get_logger ());
+      delete sm;
     }
 
     /* We only attempt to run the pattern tests if it might have been manually
@@ -3860,8 +3867,10 @@ run_checkers_impl_2 ()
     if (flag_analyzer_checker)
       {
 	auto_client_timevar tv ("pattern_test_state_machine");
-	pattern_test_state_machine sm (the_logger.get_logger ());
-	run_one_checker (sg, sm, the_logger.get_logger ());
+	state_machine *sm
+	  = make_pattern_test_state_machine (the_logger.get_logger ());
+	run_one_checker (sg, *sm, the_logger.get_logger ());
+	delete sm;
       }
 
     /* end of lifetime of the_logger (so that dump file is closed after the
diff --git a/gcc/analyzer/impl-3.cc b/gcc/analyzer/impl-3.cc
index ef79051..3d55344 100644
--- a/gcc/analyzer/impl-3.cc
+++ b/gcc/analyzer/impl-3.cc
@@ -1610,26 +1610,31 @@ run_checkers_impl_3 ()
 #if 1
     {
       auto_client_timevar tv ("malloc_state_machine");
-      malloc_state_machine sm (the_logger.get_logger ());
-      impl_3::run_one_checker (sg, sm, the_logger.get_logger ());
+      state_machine *sm = make_malloc_state_machine (the_logger.get_logger ());
+      impl_3::run_one_checker (sg, *sm, the_logger.get_logger ());
+      delete sm;
     }
 
     {
       auto_client_timevar tv ("fileptr_state_machine");
-      fileptr_state_machine sm (the_logger.get_logger ());
-      impl_3::run_one_checker (sg, sm, the_logger.get_logger ());
+      state_machine *sm = make_fileptr_state_machine (the_logger.get_logger ());
+      impl_3::run_one_checker (sg, *sm, the_logger.get_logger ());
+      delete sm;
     }
 
     {
       auto_client_timevar tv ("taint_state_machine");
-      taint_state_machine sm (the_logger.get_logger ());
-      impl_3::run_one_checker (sg, sm, the_logger.get_logger ());
+      state_machine *sm = make_taint_state_machine (the_logger.get_logger ());
+      impl_3::run_one_checker (sg, *sm, the_logger.get_logger ());
+      delete sm;
     }
 
     {
       auto_client_timevar tv ("sensitive_state_machine");
-      sensitive_state_machine sm (the_logger.get_logger ());
-      impl_3::run_one_checker (sg, sm, the_logger.get_logger ());
+      state_machine *sm
+	= make_sensitive_state_machine (the_logger.get_logger ());
+      impl_3::run_one_checker (sg, *sm, the_logger.get_logger ());
+      delete sm;
     }
 
     /* We only attempt to run the pattern tests if it might have been manually
@@ -1637,8 +1642,10 @@ run_checkers_impl_3 ()
     if (flag_analyzer_checker)
       {
 	auto_client_timevar tv ("pattern_test_state_machine");
-	pattern_test_state_machine sm (the_logger.get_logger ());
-	impl_3::run_one_checker (sg, sm, the_logger.get_logger ());
+	state_machine *sm
+	  = make_pattern_test_state_machine (the_logger.get_logger ());
+	impl_3::run_one_checker (sg, *sm, the_logger.get_logger ());
+	delete sm;
       }
 #endif
 
diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc
index 3133277..3579f88 100644
--- a/gcc/analyzer/sm-file.cc
+++ b/gcc/analyzer/sm-file.cc
@@ -1,3 +1,4 @@
+/* A state machine for detecting misuses of <stdio.h>'s FILE * API.  */
 /* FIXME.  */
 #include "config.h"
 #include "gcc-plugin.h"
@@ -39,6 +40,38 @@
 static const bool DEBUG = false;
 //static const bool DEBUG = true;
 
+/* A state machine for detecting misuses of <stdio.h>'s FILE * API.  */
+
+class fileptr_state_machine : public state_machine
+{
+public:
+  fileptr_state_machine (logger *logger);
+
+  bool inherited_state_p () const FINAL OVERRIDE { return false; }
+
+  bool on_stmt (sm_context *sm_ctxt,
+		const supernode *node,
+		const gimple *stmt) const FINAL OVERRIDE;
+
+  void on_edge (sm_context *sm_ctxt,
+		const gimple *last_stmt,
+		const superedge *edge) const FINAL OVERRIDE;
+
+  void on_leak (sm_context *sm_ctxt,
+		const supernode *node,
+		const gimple *stmt,
+		tree var,
+		state_machine::state_t state) const FINAL OVERRIDE;
+  bool can_purge_p (state_t s) const FINAL OVERRIDE;
+
+  state_t m_start;
+  state_t m_unchecked;
+  state_t m_null;
+  state_t m_nonnull;
+  state_t m_closed;
+  state_t m_stop;
+};
+
 ////////////////////////////////////////////////////////////////////////////
 
 class file_diagnostic : public pending_diagnostic
@@ -289,3 +322,9 @@ fileptr_state_machine::can_purge_p (state_t s) const
 {
   return s != m_unchecked && s != m_nonnull;
 }
+
+state_machine *
+make_fileptr_state_machine (logger *logger)
+{
+  return new fileptr_state_machine (logger);
+}
diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc
index cd40dec..09f6b53 100644
--- a/gcc/analyzer/sm-malloc.cc
+++ b/gcc/analyzer/sm-malloc.cc
@@ -1,3 +1,4 @@
+/* A state machine for detecting misuses of the malloc/free API.  */
 /* FIXME.  */
 #include "config.h"
 #include "gcc-plugin.h"
@@ -41,6 +42,42 @@ static const bool DEBUG = false;
 
 ////////////////////////////////////////////////////////////////////////////
 
+/* A state machine for detecting misuses of the malloc/free API.  */
+
+class malloc_state_machine : public state_machine
+{
+public:
+  malloc_state_machine (logger *logger);
+
+  bool inherited_state_p () const FINAL OVERRIDE { return false; }
+
+  bool on_stmt (sm_context *sm_ctxt,
+		const supernode *node,
+		const gimple *stmt) const FINAL OVERRIDE;
+
+  void on_edge (sm_context *sm_ctxt,
+		const gimple *last_stmt,
+		const superedge *edge) const FINAL OVERRIDE;
+
+  void on_leak (sm_context *sm_ctxt,
+		const supernode *node,
+		const gimple *stmt,
+		tree var,
+		state_machine::state_t state) const FINAL OVERRIDE;
+  bool can_purge_p (state_t s) const FINAL OVERRIDE;
+
+  state_t m_start;
+  state_t m_unchecked;
+  state_t m_null;
+  state_t m_nonnull;
+  state_t m_free;
+  state_t m_non_heap; // FIXME: or should this be a different state machine?
+  // or do we need child values etc?
+  state_t m_stop;
+};
+
+////////////////////////////////////////////////////////////////////////////
+
 class malloc_diagnostic : public pending_diagnostic
 {
 public:
@@ -728,3 +765,9 @@ malloc_state_machine::can_purge_p (state_t s) const
 {
   return s != m_unchecked && s != m_nonnull;
 }
+
+state_machine *
+make_malloc_state_machine (logger *logger)
+{
+  return new malloc_state_machine (logger);
+}
diff --git a/gcc/analyzer/sm-pattern-test.cc b/gcc/analyzer/sm-pattern-test.cc
index 9a1f6b4..6fbb8c5 100644
--- a/gcc/analyzer/sm-pattern-test.cc
+++ b/gcc/analyzer/sm-pattern-test.cc
@@ -39,6 +39,35 @@
 static const bool DEBUG = false;
 //static const bool DEBUG = true;
 
+/* A state machine for use in DejaGnu tests, to check that
+   pattern-matching works as expected.  */
+
+class pattern_test_state_machine : public state_machine
+{
+public:
+  pattern_test_state_machine (logger *logger);
+
+  bool inherited_state_p () const FINAL OVERRIDE { return false; }
+
+  bool on_stmt (sm_context *sm_ctxt,
+		const supernode *node,
+		const gimple *stmt) const FINAL OVERRIDE;
+
+  void on_edge (sm_context *sm_ctxt,
+		const gimple *last_stmt,
+		const superedge *edge) const FINAL OVERRIDE;
+
+  void on_leak (sm_context *sm_ctxt,
+		const supernode *node,
+		const gimple *stmt,
+		tree var,
+		state_machine::state_t state) const FINAL OVERRIDE;
+  bool can_purge_p (state_t s) const FINAL OVERRIDE;
+
+private:
+  state_t m_start;
+};
+
 ////////////////////////////////////////////////////////////////////////////
 
 class pattern_match : public pending_diagnostic_subclass<pattern_match>
@@ -150,3 +179,9 @@ pattern_test_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
 {
   return true;
 }
+
+state_machine *
+make_pattern_test_state_machine (logger *logger)
+{
+  return new pattern_test_state_machine (logger);
+}
diff --git a/gcc/analyzer/sm-sensitive.cc b/gcc/analyzer/sm-sensitive.cc
index 056d6fa..3a2a582 100644
--- a/gcc/analyzer/sm-sensitive.cc
+++ b/gcc/analyzer/sm-sensitive.cc
@@ -39,6 +39,42 @@
 static const bool DEBUG = false;
 //static const bool DEBUG = true;
 
+/* An experimental state machine, for tracking exposure of sensitive
+   data (e.g. through logging).  */
+
+class sensitive_state_machine : public state_machine
+{
+public:
+  sensitive_state_machine (logger *logger);
+
+  bool inherited_state_p () const FINAL OVERRIDE { return true; }
+
+  bool on_stmt (sm_context *sm_ctxt,
+		const supernode *node,
+		const gimple *stmt) const FINAL OVERRIDE;
+
+  void on_edge (sm_context *sm_ctxt,
+		const gimple *last_stmt,
+		const superedge *edge) const FINAL OVERRIDE;
+
+  void on_leak (sm_context *sm_ctxt,
+		const supernode *node,
+		const gimple *stmt,
+		tree var,
+		state_machine::state_t state) const FINAL OVERRIDE;
+  bool can_purge_p (state_t s) const FINAL OVERRIDE;
+
+private:
+  void warn_for_any_exposure (sm_context *sm_ctxt,
+			      const supernode *node,
+			      const gimple *stmt,
+			      tree arg) const;
+
+  state_t m_start;
+  state_t m_sensitive;
+  state_t m_stop;
+};
+
 ////////////////////////////////////////////////////////////////////////////
 
 class exposure_through_output_file
@@ -153,3 +189,9 @@ sensitive_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
 {
   return true;
 }
+
+state_machine *
+make_sensitive_state_machine (logger *logger)
+{
+  return new sensitive_state_machine (logger);
+}
diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc
index 26a2b55..4881702 100644
--- a/gcc/analyzer/sm-taint.cc
+++ b/gcc/analyzer/sm-taint.cc
@@ -39,9 +39,43 @@
 static const bool DEBUG = false;
 //static const bool DEBUG = true;
 
+/* An experimental state machine, for tracking "taint": unsanitized uses
+   of data potentially under an attacker's control.  */
+
+class taint_state_machine : public state_machine
+{
+public:
+  taint_state_machine (logger *logger);
+
+  bool inherited_state_p () const FINAL OVERRIDE { return true; }
+
+  bool on_stmt (sm_context *sm_ctxt,
+		const supernode *node,
+		const gimple *stmt) const FINAL OVERRIDE;
+
+  void on_edge (sm_context *sm_ctxt,
+		const gimple *last_stmt,
+		const superedge *edge) const FINAL OVERRIDE;
+
+  void on_leak (sm_context *sm_ctxt,
+		const supernode *node,
+		const gimple *stmt,
+		tree var,
+		state_machine::state_t state) const FINAL OVERRIDE;
+  bool can_purge_p (state_t s) const FINAL OVERRIDE;
+
+private:
+  state_t m_start;
+  state_t m_tainted;
+  state_t m_has_lb;
+  state_t m_has_ub;
+  state_t m_stop;
+};
+
 ////////////////////////////////////////////////////////////////////////////
 
-class tainted_array_index : public pending_diagnostic_subclass<tainted_array_index>
+class tainted_array_index
+  : public pending_diagnostic_subclass<tainted_array_index>
 {
 public:
   tainted_array_index (tree arg) : m_arg (arg) {}
@@ -234,3 +268,9 @@ taint_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
 {
   return true;
 }
+
+state_machine *
+make_taint_state_machine (logger *logger)
+{
+  return new taint_state_machine (logger);
+}
diff --git a/gcc/analyzer/sm.cc b/gcc/analyzer/sm.cc
index 8ea064a..8c4bb06 100644
--- a/gcc/analyzer/sm.cc
+++ b/gcc/analyzer/sm.cc
@@ -119,15 +119,15 @@ state_machine::validate (state_t s) const
 void
 make_checkers (auto_delete_vec <state_machine> &out, logger *logger)
 {
-  out.safe_push (new malloc_state_machine (logger));
-  out.safe_push (new fileptr_state_machine (logger));
-  out.safe_push (new taint_state_machine (logger));
-  out.safe_push (new sensitive_state_machine (logger));
+  out.safe_push (make_malloc_state_machine (logger));
+  out.safe_push (make_fileptr_state_machine (logger));
+  out.safe_push (make_taint_state_machine (logger));
+  out.safe_push (make_sensitive_state_machine (logger));
 
   /* We only attempt to run the pattern tests if it might have been manually
      enabled (for DejaGnu purposes).  */
   if (flag_analyzer_checker)
-    out.safe_push (new pattern_test_state_machine (logger));
+    out.safe_push (make_pattern_test_state_machine (logger));
 
   if (flag_analyzer_checker)
     {
diff --git a/gcc/analyzer/sm.h b/gcc/analyzer/sm.h
index 90d52fd..775813a 100644
--- a/gcc/analyzer/sm.h
+++ b/gcc/analyzer/sm.h
@@ -25,6 +25,8 @@ along with GCC; see the file COPYING3.  If not see
 
 ////////////////////////////////////////////////////////////////////////////
 
+/* Utility functions for use by state machines.  */
+
 extern tree is_zero_assignment (const gimple *stmt);
 extern bool is_comparison_against_zero (const gcond *cond_stmt,
 					tree *out_lhs, enum tree_code *out_op);
@@ -36,8 +38,8 @@ class state_machine;
 class sm_context;
 class pending_diagnostic;
 
-/* A state machine describing an API.
-   A mapping from state IDs to names, and (for now) a vfunc implementation
+/* An abstract base class for a state machine describing an API.
+   A mapping from state IDs to names, and various virtual functions
    for pattern-matching on statements.  */
 
 class state_machine : public log_user
@@ -101,8 +103,8 @@ start_start_p (state_machine::state_t state)
 
 ////////////////////////////////////////////////////////////////////////////
 
-/* Interface for the state machine to call the checker engine, at a
-   particular stmt.  */
+/* Abstract base class giving an interface for the state machine to call
+   the checker engine, at a particular stmt.  */
 
 class sm_context
 {
@@ -141,182 +143,16 @@ protected:
 
 ////////////////////////////////////////////////////////////////////////////
 
-extern void make_checkers (auto_delete_vec <state_machine> &out, logger *logger);
-
-////////////////////////////////////////////////////////////////////////////
-
-/* A particular state machine, for prototyping purposes:
-   the malloc/free API.  */
-
-class malloc_state_machine : public state_machine
-{
-public:
-  malloc_state_machine (logger *logger);
-
-  bool inherited_state_p () const FINAL OVERRIDE { return false; }
-
-  bool on_stmt (sm_context *sm_ctxt,
-		const supernode *node,
-		const gimple *stmt) const FINAL OVERRIDE;
-
-  void on_edge (sm_context *sm_ctxt,
-		const gimple *last_stmt,
-		const superedge *edge) const FINAL OVERRIDE;
-
-  void on_leak (sm_context *sm_ctxt,
-		const supernode *node,
-		const gimple *stmt,
-		tree var,
-		state_machine::state_t state) const FINAL OVERRIDE;
-  bool can_purge_p (state_t s) const FINAL OVERRIDE;
-
-  state_t m_start;
-  state_t m_unchecked;
-  state_t m_null;
-  state_t m_nonnull;
-  state_t m_free;
-  state_t m_non_heap; // FIXME: or should this be a different state machine?
-  // or do we need child values etc?
-  state_t m_stop;
-};
-
-////////////////////////////////////////////////////////////////////////////
-
-/* A particular state machine, for prototyping purposes:
-   the fopen API.  */
-
-class fileptr_state_machine : public state_machine
-{
-public:
-  fileptr_state_machine (logger *logger);
-
-  bool inherited_state_p () const FINAL OVERRIDE { return false; }
-
-  bool on_stmt (sm_context *sm_ctxt,
-		const supernode *node,
-		const gimple *stmt) const FINAL OVERRIDE;
-
-  void on_edge (sm_context *sm_ctxt,
-		const gimple *last_stmt,
-		const superedge *edge) const FINAL OVERRIDE;
-
-  void on_leak (sm_context *sm_ctxt,
-		const supernode *node,
-		const gimple *stmt,
-		tree var,
-		state_machine::state_t state) const FINAL OVERRIDE;
-  bool can_purge_p (state_t s) const FINAL OVERRIDE;
-
-  state_t m_start;
-  state_t m_unchecked;
-  state_t m_null;
-  state_t m_nonnull;
-  state_t m_closed;
-  state_t m_stop;
-};
-
-////////////////////////////////////////////////////////////////////////////
-
-/* A particular state machine, for prototyping purposes:
-   tainted data.  */
-
-class taint_state_machine : public state_machine
-{
-public:
-  taint_state_machine (logger *logger);
-
-  bool inherited_state_p () const FINAL OVERRIDE { return true; }
-
-  bool on_stmt (sm_context *sm_ctxt,
-		const supernode *node,
-		const gimple *stmt) const FINAL OVERRIDE;
-
-  void on_edge (sm_context *sm_ctxt,
-		const gimple *last_stmt,
-		const superedge *edge) const FINAL OVERRIDE;
-
-  void on_leak (sm_context *sm_ctxt,
-		const supernode *node,
-		const gimple *stmt,
-		tree var,
-		state_machine::state_t state) const FINAL OVERRIDE;
-  bool can_purge_p (state_t s) const FINAL OVERRIDE;
-
-private:
-  state_t m_start;
-  state_t m_tainted;
-  state_t m_has_lb;
-  state_t m_has_ub;
-  state_t m_stop;
-};
-
-////////////////////////////////////////////////////////////////////////////
-
-/* A particular state machine, for prototyping purposes:
-   sensitive data.  */
-
-class sensitive_state_machine : public state_machine
-{
-public:
-  sensitive_state_machine (logger *logger);
-
-  bool inherited_state_p () const FINAL OVERRIDE { return true; }
-
-  bool on_stmt (sm_context *sm_ctxt,
-		const supernode *node,
-		const gimple *stmt) const FINAL OVERRIDE;
-
-  void on_edge (sm_context *sm_ctxt,
-		const gimple *last_stmt,
-		const superedge *edge) const FINAL OVERRIDE;
-
-  void on_leak (sm_context *sm_ctxt,
-		const supernode *node,
-		const gimple *stmt,
-		tree var,
-		state_machine::state_t state) const FINAL OVERRIDE;
-  bool can_purge_p (state_t s) const FINAL OVERRIDE;
-
-private:
-  void warn_for_any_exposure (sm_context *sm_ctxt,
-			      const supernode *node,
-			      const gimple *stmt,
-			      tree arg) const;
-
-  state_t m_start;
-  state_t m_sensitive;
-  state_t m_stop;
-};
-
-////////////////////////////////////////////////////////////////////////////
-
-/* A particular state machine, for prototyping purposes:
-   a pattern-matching test, for DejaGnu tests.  */
+/* The various state_machine subclasses are hidden in their respective
+   implementation files.  */
 
-class pattern_test_state_machine : public state_machine
-{
-public:
-  pattern_test_state_machine (logger *logger);
+extern void make_checkers (auto_delete_vec <state_machine> &out,
+			   logger *logger);
 
-  bool inherited_state_p () const FINAL OVERRIDE { return false; }
-
-  bool on_stmt (sm_context *sm_ctxt,
-		const supernode *node,
-		const gimple *stmt) const FINAL OVERRIDE;
-
-  void on_edge (sm_context *sm_ctxt,
-		const gimple *last_stmt,
-		const superedge *edge) const FINAL OVERRIDE;
-
-  void on_leak (sm_context *sm_ctxt,
-		const supernode *node,
-		const gimple *stmt,
-		tree var,
-		state_machine::state_t state) const FINAL OVERRIDE;
-  bool can_purge_p (state_t s) const FINAL OVERRIDE;
-
-private:
-  state_t m_start;
-};
+extern state_machine *make_malloc_state_machine (logger *logger);
+extern state_machine *make_fileptr_state_machine (logger *logger);
+extern state_machine *make_taint_state_machine (logger *logger);
+extern state_machine *make_sensitive_state_machine (logger *logger);
+extern state_machine *make_pattern_test_state_machine (logger *logger);
 
 #endif /* GCC_ANALYZER_SM_H */
-- 
1.8.5.3

