]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
analyzer: use unique_ptr for state_machine instances
authorDavid Malcolm <dmalcolm@redhat.com>
Mon, 28 Apr 2025 22:21:22 +0000 (18:21 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Mon, 28 Apr 2025 22:21:22 +0000 (18:21 -0400)
gcc/analyzer/ChangeLog:
* engine.cc (class plugin_analyzer_init_impl): Convert
"m_checkers" to use std::vector of std::unique_ptr.  Convert
"m_known_fn_mgr" to a reference.
(impl_run_checkers): Convert "checkers" to use std::vector of
std::unique_ptr and move it into the extrinsic_state.
* program-state.cc (extrinsic_state::dump_to_pp): Update for
changes to m_checkers.
(extrinsic_state::to_json): Likewise.
(extrinsic_state::get_sm_idx_by_name): Likewise.
(selftest::test_sm_state_map): Update to use std::unique_ptr
for state machines.
(selftest::test_program_state_1): Likewise.
(selftest::test_program_state_2): Likewise.
(selftest::test_program_state_merging): Likewise.
(selftest::test_program_state_merging_2): Likewise.
* program-state.h (class extrinsic_state): Convert "m_checkers" to
use std::vector of std::unique_ptr and to be owned by this object,
rather than a reference.  Add ctor for use in selftests.
* sm-fd.cc (make_fd_state_machine): Update to use std::unique_ptr.
* sm-file.cc (make_fileptr_state_machine): Likewise.
* sm-malloc.cc (make_malloc_state_machine): Likewise.
* sm-pattern-test.cc (make_pattern_test_state_machine): Likewise.
* sm-sensitive.cc (make_sensitive_state_machine): Likewise.
* sm-signal.cc (make_signal_state_machine): Likewise.
* sm-taint.cc (make_taint_state_machine): Likewise.
* sm.cc: Define INCLUDE_LIST.
(make_checkers): Return the vector directly, rather than pass it
in by reference.  Update to use std::unique_ptr throughout.  Use
an intermediate list, and use that to filter with
flag_analyzer_checker, fixing memory leak for this case.
* sm.h: (make_checkers): Return the vector directly, rather than
pass it in by reference, and use std::vector of std::unique_ptr.
(make_malloc_state_machine): Convert return type to use std::unique_ptr.
(make_fileptr_state_machine): Likewise.
(make_taint_state_machine): Likewise.
(make_sensitive_state_machine): Likewise.
(make_signal_state_machine): Likewise.
(make_pattern_test_state_machine): Likewise.
(make_va_list_state_machine): Likewise.
(make_fd_state_machine): Likewise.
* varargs.cc (make_va_list_state_machine): Update to use
std::unique_ptr.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
13 files changed:
gcc/analyzer/engine.cc
gcc/analyzer/program-state.cc
gcc/analyzer/program-state.h
gcc/analyzer/sm-fd.cc
gcc/analyzer/sm-file.cc
gcc/analyzer/sm-malloc.cc
gcc/analyzer/sm-pattern-test.cc
gcc/analyzer/sm-sensitive.cc
gcc/analyzer/sm-signal.cc
gcc/analyzer/sm-taint.cc
gcc/analyzer/sm.cc
gcc/analyzer/sm.h
gcc/analyzer/varargs.cc

index f33cc0bda4d1183369ead061d67bb779b5a2478f..c04bda1e6458a2e554c7eb94f257abca8b937653 100644 (file)
@@ -6103,8 +6103,8 @@ dump_analyzer_json (const supergraph &sg,
 class plugin_analyzer_init_impl : public plugin_analyzer_init_iface
 {
 public:
-  plugin_analyzer_init_impl (auto_delete_vec <state_machine> *checkers,
-                            known_function_manager *known_fn_mgr,
+  plugin_analyzer_init_impl (std::vector<std::unique_ptr<state_machine>> &checkers,
+                            known_function_manager &known_fn_mgr,
                             logger *logger)
   : m_checkers (checkers),
     m_known_fn_mgr (known_fn_mgr),
@@ -6114,14 +6114,14 @@ public:
   void register_state_machine (std::unique_ptr<state_machine> sm) final override
   {
     LOG_SCOPE (m_logger);
-    m_checkers->safe_push (sm.release ());
+    m_checkers.push_back (std::move (sm));
   }
 
   void register_known_function (const char *name,
                                std::unique_ptr<known_function> kf) final override
   {
     LOG_SCOPE (m_logger);
-    m_known_fn_mgr->add (name, std::move (kf));
+    m_known_fn_mgr.add (name, std::move (kf));
   }
 
   logger *get_logger () const final override
@@ -6130,8 +6130,8 @@ public:
   }
 
 private:
-  auto_delete_vec <state_machine> *m_checkers;
-  known_function_manager *m_known_fn_mgr;
+  std::vector<std::unique_ptr<state_machine>> &m_checkers;
+  known_function_manager &m_known_fn_mgr;
   logger *m_logger;
 };
 
@@ -6185,27 +6185,25 @@ impl_run_checkers (logger *logger)
       free (filename);
     }
 
-  auto_delete_vec <state_machine> checkers;
-  make_checkers (checkers, logger);
+  auto checkers = make_checkers (logger);
 
   register_known_functions (*eng.get_known_function_manager (),
                            *eng.get_model_manager ());
 
-  plugin_analyzer_init_impl data (&checkers,
-                                 eng.get_known_function_manager (),
+  plugin_analyzer_init_impl data (checkers,
+                                 *eng.get_known_function_manager (),
                                  logger);
   invoke_plugin_callbacks (PLUGIN_ANALYZER_INIT, &data);
 
   if (logger)
     {
-      int i;
-      state_machine *sm;
-      FOR_EACH_VEC_ELT (checkers, i, sm)
-       logger->log ("checkers[%i]: %s", i, sm->get_name ());
+      int i = 0;
+      for (auto &sm : checkers)
+       logger->log ("checkers[%i]: %s", ++i, sm->get_name ());
     }
 
   /* Extrinsic state shared by nodes in the graph.  */
-  const extrinsic_state ext_state (checkers, &eng, logger);
+  const extrinsic_state ext_state (std::move (checkers), &eng, logger);
 
   const analysis_plan plan (sg, logger);
 
index 32b50070e01b13c004ea26abf8df2263c48814ec..4d3fec0b960543a385d19899c6504c6effa51ac4 100644 (file)
@@ -61,11 +61,10 @@ void
 extrinsic_state::dump_to_pp (pretty_printer *pp) const
 {
   pp_printf (pp, "extrinsic_state: %i checker(s)\n", get_num_checkers ());
-  unsigned i;
-  state_machine *checker;
-  FOR_EACH_VEC_ELT (m_checkers, i, checker)
+  unsigned i = 0;
+  for (auto &checker : m_checkers)
     {
-      pp_printf (pp, "m_checkers[%i]: %qs\n", i, checker->get_name ());
+      pp_printf (pp, "m_checkers[%i]: %qs\n", ++i, checker->get_name ());
       checker->dump_to_pp (pp);
     }
 }
@@ -97,9 +96,7 @@ extrinsic_state::to_json () const
 
   {
     auto checkers_arr = ::make_unique<json::array> ();
-    unsigned i;
-    state_machine *sm;
-    FOR_EACH_VEC_ELT (m_checkers, i, sm)
+    for (auto &sm : m_checkers)
       checkers_arr->append (sm->to_json ());
     ext_state_obj->set ("checkers", std::move (checkers_arr));
   }
@@ -125,10 +122,8 @@ extrinsic_state::get_model_manager () const
 bool
 extrinsic_state::get_sm_idx_by_name (const char *name, unsigned *out) const
 {
-  unsigned i;
-  state_machine *sm;
-  FOR_EACH_VEC_ELT (m_checkers, i, sm)
-    if (0 == strcmp (name, sm->get_name ()))
+  for (size_t i = 0; i < m_checkers.size (); ++i)
+    if (0 == strcmp (name, m_checkers[i]->get_name ()))
       {
        /* Found NAME.  */
        *out = i;
@@ -1783,12 +1778,13 @@ test_sm_state_map ()
   tree y = build_global_decl ("y", integer_type_node);
   tree z = build_global_decl ("z", integer_type_node);
 
-  state_machine *sm = make_malloc_state_machine (NULL);
-  auto_delete_vec <state_machine> checkers;
-  checkers.safe_push (sm);
-  engine eng;
-  extrinsic_state ext_state (checkers, &eng);
+  std::unique_ptr<state_machine> sm = make_malloc_state_machine (NULL);
   state_machine::state_t start = sm->get_start_state ();
+  std::vector<std::unique_ptr<state_machine>> checkers;
+  const state_machine &borrowed_sm = *sm.get ();
+  checkers.push_back (std::move (sm));
+  engine eng;
+  extrinsic_state ext_state (std::move (checkers), &eng);
 
   /* Test setting states on svalue_id instances directly.  */
   {
@@ -1800,7 +1796,7 @@ test_sm_state_map ()
     const svalue *y_sval = model.get_rvalue (y, NULL);
     const svalue *z_sval = model.get_rvalue (z, NULL);
 
-    sm_state_map map (*sm);
+    sm_state_map map (borrowed_sm);
     ASSERT_TRUE (map.is_empty_p ());
     ASSERT_EQ (map.get_state (x_sval, ext_state), start);
 
@@ -1829,7 +1825,7 @@ test_sm_state_map ()
     const svalue *y_sval = model.get_rvalue (y, NULL);
     const svalue *z_sval = model.get_rvalue (z, NULL);
 
-    sm_state_map map (*sm);
+    sm_state_map map (borrowed_sm);
     ASSERT_TRUE (map.is_empty_p ());
     ASSERT_EQ (map.get_state (x_sval, ext_state), start);
     ASSERT_EQ (map.get_state (y_sval, ext_state), start);
@@ -1852,9 +1848,9 @@ test_sm_state_map ()
     const svalue *y_sval = model.get_rvalue (y, NULL);
     const svalue *z_sval = model.get_rvalue (z, NULL);
 
-    sm_state_map map0 (*sm);
-    sm_state_map map1 (*sm);
-    sm_state_map map2 (*sm);
+    sm_state_map map0 (borrowed_sm);
+    sm_state_map map1 (borrowed_sm);
+    sm_state_map map2 (borrowed_sm);
 
     ASSERT_EQ (map0.hash (), map1.hash ());
     ASSERT_EQ (map0, map1);
@@ -1875,9 +1871,9 @@ test_sm_state_map ()
     const state_machine::state_t TEST_STATE_2 = &test_state_2;
     const state_machine::state test_state_3 ("test state 3", 3);
     const state_machine::state_t TEST_STATE_3 = &test_state_3;
-    sm_state_map map0 (*sm);
-    sm_state_map map1 (*sm);
-    sm_state_map map2 (*sm);
+    sm_state_map map0 (borrowed_sm);
+    sm_state_map map1 (borrowed_sm);
+    sm_state_map map2 (borrowed_sm);
 
     ASSERT_EQ (map0.hash (), map1.hash ());
     ASSERT_EQ (map0, map1);
@@ -1912,14 +1908,12 @@ test_program_state_1 ()
      malloc sm-state, pointing to a region on the heap.  */
   tree p = build_global_decl ("p", ptr_type_node);
 
-  state_machine *sm = make_malloc_state_machine (NULL);
+  std::unique_ptr<state_machine> sm = make_malloc_state_machine (NULL);
   const state_machine::state_t UNCHECKED_STATE
     = sm->get_state_by_name ("unchecked");
-  auto_delete_vec <state_machine> checkers;
-  checkers.safe_push (sm);
 
   engine eng;
-  extrinsic_state ext_state (checkers, &eng);
+  extrinsic_state ext_state (std::move (sm), &eng);
   region_model_manager *mgr = eng.get_model_manager ();
   program_state s (ext_state);
   region_model *model = s.m_region_model;
@@ -1947,9 +1941,9 @@ test_program_state_2 ()
 
   tree string_cst_ptr = build_string_literal (4, "foo");
 
-  auto_delete_vec <state_machine> checkers;
+  std::vector<std::unique_ptr<state_machine>> checkers;
   engine eng;
-  extrinsic_state ext_state (checkers, &eng);
+  extrinsic_state ext_state (std::move (checkers), &eng);
 
   program_state s (ext_state);
   region_model *model = s.m_region_model;
@@ -1971,9 +1965,8 @@ test_program_state_merging ()
   engine eng;
   region_model_manager *mgr = eng.get_model_manager ();
   program_point point (program_point::origin (*mgr));
-  auto_delete_vec <state_machine> checkers;
-  checkers.safe_push (make_malloc_state_machine (NULL));
-  extrinsic_state ext_state (checkers, &eng);
+  extrinsic_state ext_state (make_malloc_state_machine (NULL),
+                            &eng);
 
   program_state s0 (ext_state);
   uncertainty_t uncertainty;
@@ -2039,9 +2032,7 @@ test_program_state_merging_2 ()
   engine eng;
   region_model_manager *mgr = eng.get_model_manager ();
   program_point point (program_point::origin (*mgr));
-  auto_delete_vec <state_machine> checkers;
-  checkers.safe_push (make_signal_state_machine (NULL));
-  extrinsic_state ext_state (checkers, &eng);
+  extrinsic_state ext_state (make_signal_state_machine (NULL), &eng);
 
   const state_machine::state test_state_0 ("test state 0", 0);
   const state_machine::state test_state_1 ("test state 1", 1);
index 48563a93e0917de75fc36a4a0c6c7e3270ad0bfe..269ffde9ee6c7054e331478b60a06aa590c6f2d6 100644 (file)
@@ -30,13 +30,25 @@ namespace ana {
 class extrinsic_state
 {
 public:
-  extrinsic_state (auto_delete_vec <state_machine> &checkers,
+  extrinsic_state (std::vector<std::unique_ptr<state_machine>> &&checkers,
                   engine *eng,
                   logger *logger = NULL)
-  : m_checkers (checkers), m_logger (logger), m_engine (eng)
+  : m_checkers (std::move (checkers)),
+    m_logger (logger),
+    m_engine (eng)
   {
   }
 
+  // For use in selftests that use just one state machine
+  extrinsic_state (std::unique_ptr<state_machine> sm,
+                  engine *eng,
+                  logger *logger = NULL)
+  : m_logger (logger),
+    m_engine (eng)
+  {
+    m_checkers.push_back (std::move (sm));
+  }
+
   const state_machine &get_sm (int idx) const
   {
     return *m_checkers[idx];
@@ -47,7 +59,7 @@ public:
     return m_checkers[idx]->get_name ();
   }
 
-  unsigned get_num_checkers () const { return m_checkers.length (); }
+  unsigned get_num_checkers () const { return m_checkers.size (); }
 
   logger *get_logger () const { return m_logger; }
 
@@ -64,7 +76,7 @@ public:
 
 private:
   /* The state machines.  */
-  auto_delete_vec <state_machine> &m_checkers;
+  std::vector<std::unique_ptr<state_machine>> m_checkers;
 
   logger *m_logger;
   engine *m_engine;
index 3119b13e146c26b0ec862aeae05bdd3cda6a6221..dd9ae93ad6097705a2cb8488049af0c8005e305f 100644 (file)
@@ -2327,10 +2327,10 @@ fd_state_machine::on_leak (tree var) const
 }
 } // namespace
 
-state_machine *
+std::unique_ptr<state_machine>
 make_fd_state_machine (logger *logger)
 {
-  return new fd_state_machine (logger);
+  return std::make_unique<fd_state_machine> (logger);
 }
 
 static bool
index 7de7663c8c238f82079121d39733497c063af764..319ac01b21840ec665d8cc2ad0a503959798d91c 100644 (file)
@@ -500,10 +500,10 @@ fileptr_state_machine::on_leak (tree var) const
 
 /* Internal interface to this file. */
 
-state_machine *
+std::unique_ptr<state_machine>
 make_fileptr_state_machine (logger *logger)
 {
-  return new fileptr_state_machine (logger);
+  return std::make_unique<fileptr_state_machine> (logger);
 }
 
 /* Handler for various stdio-related builtins that merely have external
index aad625eea7715a9ab4b4a41b2742212f12353d38..ad7974e2d3b3f08458eea07cbed931993fb54591 100644 (file)
@@ -2698,10 +2698,10 @@ malloc_state_machine::transition_ptr_sval_non_null (region_model *model,
 
 /* Internal interface to this file. */
 
-state_machine *
+std::unique_ptr<state_machine>
 make_malloc_state_machine (logger *logger)
 {
-  return new malloc_state_machine (logger);
+  return std::make_unique<malloc_state_machine> (logger);
 }
 
 /* Specialcase hook for handling realloc, for use by
index 151e625dc460d6284c81266df3b7695d54cc5183..f24e8df4743ac70815312a18d52139c96f1fed38 100644 (file)
@@ -146,10 +146,10 @@ pattern_test_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
 
 /* Internal interface to this file. */
 
-state_machine *
+std::unique_ptr<state_machine>
 make_pattern_test_state_machine (logger *logger)
 {
-  return new pattern_test_state_machine (logger);
+  return std::make_unique<pattern_test_state_machine> (logger);
 }
 
 } // namespace ana
index 3ffe30d6c4d65e9e8c3b62742cd39cdff1d4466c..385573b178c8e24e73f0a7a60f7ada98c9f2bce1 100644 (file)
@@ -242,10 +242,10 @@ sensitive_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
 
 /* Internal interface to this file. */
 
-state_machine *
+std::unique_ptr<state_machine>
 make_sensitive_state_machine (logger *logger)
 {
-  return new sensitive_state_machine (logger);
+  return std::make_unique<sensitive_state_machine> (logger);
 }
 
 } // namespace ana
index 1e7415149f88bf379a3b454b8fafcf5745a67f0a..2521c7c29eaa371deb34ad35cb774143a693675c 100644 (file)
@@ -369,10 +369,10 @@ signal_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
 
 /* Internal interface to this file. */
 
-state_machine *
+std::unique_ptr<state_machine>
 make_signal_state_machine (logger *logger)
 {
-  return new signal_state_machine (logger);
+  return std::make_unique<signal_state_machine> (logger);
 }
 
 #if CHECKING_P
index efbc483e173ac19d2eff814e63b6da69baaa71bb..21ce68ed7161dae16270b649f26e1c420da42208 100644 (file)
@@ -1518,10 +1518,10 @@ taint_state_machine::check_for_tainted_divisor (sm_context &sm_ctxt,
 
 /* Internal interface to this file. */
 
-state_machine *
+std::unique_ptr<state_machine>
 make_taint_state_machine (logger *logger)
 {
-  return new taint_state_machine (logger);
+  return std::make_unique<taint_state_machine> (logger);
 }
 
 /* A closed concrete range.  */
index f1590f7d5a074d1bae2b89a580612de445a26541..4328e3c7e2d124014c60c9bf31fb9355e567cbdd 100644 (file)
@@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+#define INCLUDE_LIST
 #include "analyzer/common.h"
 
 #include "tree-diagnostic.h"
@@ -169,35 +170,40 @@ sm_context::get_old_region_model () const
 }
 
 /* Create instances of the various state machines, each using LOGGER,
-   and populate OUT with them.  */
+   returning a vector of them.  */
 
-void
-make_checkers (auto_delete_vec <state_machine> &out, logger *logger)
+std::vector<std::unique_ptr<state_machine>>
+make_checkers (logger *logger)
 {
-  out.safe_push (make_malloc_state_machine (logger));
-  out.safe_push (make_fileptr_state_machine (logger));
-  out.safe_push (make_fd_state_machine (logger));
-  out.safe_push (make_taint_state_machine (logger));
-  out.safe_push (make_sensitive_state_machine (logger));
-  out.safe_push (make_signal_state_machine (logger));
-  out.safe_push (make_va_list_state_machine (logger));
+  /* Start with a list so that we can filter it.  */
+  std::list<std::unique_ptr<state_machine>> out;
+  out.push_back (make_malloc_state_machine (logger));
+  out.push_back (make_fileptr_state_machine (logger));
+  out.push_back (make_fd_state_machine (logger));
+  out.push_back (make_taint_state_machine (logger));
+  out.push_back (make_sensitive_state_machine (logger));
+  out.push_back (make_signal_state_machine (logger));
+  out.push_back (make_va_list_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 (make_pattern_test_state_machine (logger));
+    out.push_back (make_pattern_test_state_machine (logger));
 
   if (flag_analyzer_checker)
     {
-      unsigned read_index, write_index;
-      state_machine **sm;
-
-      /* TODO: this leaks the machines
-        Would be nice to log the things that were removed.  */
-      VEC_ORDERED_REMOVE_IF (out, read_index, write_index, sm,
-                            0 != strcmp (flag_analyzer_checker,
-                                         (*sm)->get_name ()));
+      out.remove_if ([] (auto &sm)
+                    {
+                      return 0 != strcmp (flag_analyzer_checker,
+                                          sm->get_name ());
+                    });
     }
+
+  std::vector<std::unique_ptr<state_machine>> out_vec;
+  for (auto &iter: out)
+    out_vec.push_back (std::move (iter));
+
+  return out_vec;
 }
 
 } // namespace ana
index 6cdb161c66eb044229631bbfe58fcb2ca4d0ea8d..a932765131b67883e6e428006bb79d31a4ffd3f1 100644 (file)
@@ -341,17 +341,17 @@ protected:
 /* The various state_machine subclasses are hidden in their respective
    implementation files.  */
 
-extern void make_checkers (auto_delete_vec <state_machine> &out,
-                          logger *logger);
-
-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_signal_state_machine (logger *logger);
-extern state_machine *make_pattern_test_state_machine (logger *logger);
-extern state_machine *make_va_list_state_machine (logger *logger);
-extern state_machine *make_fd_state_machine (logger *logger);
+extern std::vector<std::unique_ptr<state_machine>>
+make_checkers (logger *logger);
+
+extern std::unique_ptr<state_machine> make_malloc_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_fileptr_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_taint_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_sensitive_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_signal_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_pattern_test_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_va_list_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_fd_state_machine (logger *);
 
 } // namespace ana
 
index 7e0854ced5421379a0d991f487768ba9c4151c01..55730a361411b08b7bc11a74daf37e7a88a3a9a4 100644 (file)
@@ -642,10 +642,10 @@ va_list_state_machine::on_leak (tree var) const
 
 /* Internal interface to this file. */
 
-state_machine *
+std::unique_ptr<state_machine>
 make_va_list_state_machine (logger *logger)
 {
-  return new va_list_state_machine (logger);
+  return std::make_unique<va_list_state_machine> (logger);
 }
 
 /* Handler for "__builtin_va_start".  */