aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2022-12-06 13:26:56 -0500
committerDavid Malcolm <dmalcolm@redhat.com>2022-12-06 13:26:56 -0500
commit861c917a972dc90beff7fa5c23a013261894e6a4 (patch)
tree3b38c877d395f7106a0ceec21d7e549dfdcedf7c /gcc
parent81476bc4f4a20bcf3af7ac2548c2322d48499402 (diff)
downloadgcc-861c917a972dc90beff7fa5c23a013261894e6a4.zip
gcc-861c917a972dc90beff7fa5c23a013261894e6a4.tar.gz
gcc-861c917a972dc90beff7fa5c23a013261894e6a4.tar.bz2
analyzer: split out more stuff from region-model-impl-calls.cc
gcc/ChangeLog: * Makefile.in (ANALYZER_OBJS): Add analyzer/call-details.o, analyzer/kf-analyzer.o, and kf-lang-cp.o. gcc/analyzer/ChangeLog: * analyzer.h (register_known_analyzer_functions): New decl. (register_known_functions_lang_cp): New decl. * call-details.cc: New file, split out from region-model-impl-calls.cc. * call-details.h: New file, split out from region-model.h. * call-info.cc: Include "analyzer/call-details.h". * call-summary.h: Likewise. * kf-analyzer.cc: New file, split out from region-model-impl-calls.cc. * kf-lang-cp.cc: Likewise. * known-function-manager.cc: Include "analyzer/call-details.h". * region-model-impl-calls.cc: Move definitions of call_details's member functions to call-details.cc. Move class kf_analyzer_* to kf-analyzer.cc. Move kf_operator_new and kf_operator_delete to kf-lang-cp.cc. Refresh #includes accordingly. (register_known_functions): Replace registration of __analyzer_* functions with a call to register_known_analyzer_functions. Replace registration of C++ support functions with a call to register_known_functions_lang_cp. * region-model.h (class call_details): Move to new call-details.h. * sm-fd.cc: Include "analyzer/call-details.h". * sm-file.cc: Likewise. * sm-malloc.cc: Likewise. * varargs.cc: Likewise. gcc/testsuite/ChangeLog: * gcc.dg/plugin/analyzer_kernel_plugin.c: Include "analyzer/call-details.h". * gcc.dg/plugin/analyzer_known_fns_plugin.c: Likewise. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/Makefile.in3
-rw-r--r--gcc/analyzer/analyzer.h2
-rw-r--r--gcc/analyzer/call-details.cc231
-rw-r--r--gcc/analyzer/call-details.h77
-rw-r--r--gcc/analyzer/call-info.cc1
-rw-r--r--gcc/analyzer/call-summary.h2
-rw-r--r--gcc/analyzer/kf-analyzer.cc386
-rw-r--r--gcc/analyzer/kf-lang-cp.cc111
-rw-r--r--gcc/analyzer/known-function-manager.cc1
-rw-r--r--gcc/analyzer/region-model-impl-calls.cc619
-rw-r--r--gcc/analyzer/region-model.h50
-rw-r--r--gcc/analyzer/sm-fd.cc1
-rw-r--r--gcc/analyzer/sm-file.cc1
-rw-r--r--gcc/analyzer/sm-malloc.cc1
-rw-r--r--gcc/analyzer/varargs.cc1
-rw-r--r--gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c1
-rw-r--r--gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c1
17 files changed, 827 insertions, 662 deletions
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 615a070..7bcc5e5 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1256,6 +1256,7 @@ ANALYZER_OBJS = \
analyzer/analyzer-selftests.o \
analyzer/bar-chart.o \
analyzer/bounds-checking.o \
+ analyzer/call-details.o \
analyzer/call-info.o \
analyzer/call-string.o \
analyzer/call-summary.o \
@@ -1268,6 +1269,8 @@ ANALYZER_OBJS = \
analyzer/feasible-graph.o \
analyzer/function-set.o \
analyzer/infinite-recursion.o \
+ analyzer/kf-analyzer.o \
+ analyzer/kf-lang-cp.o \
analyzer/known-function-manager.o \
analyzer/pending-diagnostic.o \
analyzer/program-point.o \
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index a2d363f..418d421 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -259,8 +259,10 @@ public:
};
extern void register_known_functions (known_function_manager &mgr);
+extern void register_known_analyzer_functions (known_function_manager &kfm);
extern void register_known_fd_functions (known_function_manager &kfm);
extern void register_known_file_functions (known_function_manager &kfm);
+extern void register_known_functions_lang_cp (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/call-details.cc b/gcc/analyzer/call-details.cc
new file mode 100644
index 0000000..b63b8a3
--- /dev/null
+++ b/gcc/analyzer/call-details.cc
@@ -0,0 +1,231 @@
+/* Helper class for handling a call with specific arguments.
+ Copyright (C) 2020-2022 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+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/>. */
+
+#include "config.h"
+#define INCLUDE_MEMORY
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "diagnostic-core.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/analyzer-logging.h"
+#include "diagnostic.h"
+#include "tree-diagnostic.h" /* for default_tree_printer. */
+#include "gimple-pretty-print.h"
+#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* class call_details. */
+
+/* call_details's ctor. */
+
+call_details::call_details (const gcall *call, region_model *model,
+ region_model_context *ctxt)
+: m_call (call), m_model (model), m_ctxt (ctxt),
+ m_lhs_type (NULL_TREE), m_lhs_region (NULL)
+{
+ m_lhs_type = NULL_TREE;
+ if (tree lhs = gimple_call_lhs (call))
+ {
+ m_lhs_region = model->get_lvalue (lhs, ctxt);
+ m_lhs_type = TREE_TYPE (lhs);
+ }
+}
+
+/* Get the manager from m_model. */
+
+region_model_manager *
+call_details::get_manager () const
+{
+ return m_model->get_manager ();
+}
+
+/* Get any logger associated with this object. */
+
+logger *
+call_details::get_logger () const
+{
+ if (m_ctxt)
+ return m_ctxt->get_logger ();
+ else
+ return NULL;
+}
+
+/* Get any uncertainty_t associated with the region_model_context. */
+
+uncertainty_t *
+call_details::get_uncertainty () const
+{
+ if (m_ctxt)
+ return m_ctxt->get_uncertainty ();
+ else
+ return NULL;
+}
+
+/* If the callsite has a left-hand-side region, set it to RESULT
+ and return true.
+ Otherwise do nothing and return false. */
+
+bool
+call_details::maybe_set_lhs (const svalue *result) const
+{
+ gcc_assert (result);
+ if (m_lhs_region)
+ {
+ m_model->set_value (m_lhs_region, result, m_ctxt);
+ return true;
+ }
+ else
+ return false;
+}
+
+/* Return the number of arguments used by the call statement. */
+
+unsigned
+call_details::num_args () const
+{
+ return gimple_call_num_args (m_call);
+}
+
+/* Return true if argument IDX is a size_t (or compatible with it). */
+
+bool
+call_details::arg_is_size_p (unsigned idx) const
+{
+ return types_compatible_p (get_arg_type (idx), size_type_node);
+}
+
+/* Get the location of the call statement. */
+
+location_t
+call_details::get_location () const
+{
+ return m_call->location;
+}
+
+/* Get argument IDX at the callsite as a tree. */
+
+tree
+call_details::get_arg_tree (unsigned idx) const
+{
+ return gimple_call_arg (m_call, idx);
+}
+
+/* Get the type of argument IDX. */
+
+tree
+call_details::get_arg_type (unsigned idx) const
+{
+ return TREE_TYPE (gimple_call_arg (m_call, idx));
+}
+
+/* Get argument IDX at the callsite as an svalue. */
+
+const svalue *
+call_details::get_arg_svalue (unsigned idx) const
+{
+ tree arg = get_arg_tree (idx);
+ return m_model->get_rvalue (arg, m_ctxt);
+}
+
+/* Attempt to get the string literal for argument IDX, or return NULL
+ otherwise.
+ For use when implementing "__analyzer_*" functions that take
+ string literals. */
+
+const char *
+call_details::get_arg_string_literal (unsigned idx) const
+{
+ const svalue *str_arg = get_arg_svalue (idx);
+ if (const region *pointee = str_arg->maybe_get_region ())
+ if (const string_region *string_reg = pointee->dyn_cast_string_region ())
+ {
+ tree string_cst = string_reg->get_string_cst ();
+ return TREE_STRING_POINTER (string_cst);
+ }
+ return NULL;
+}
+
+/* Attempt to get the fndecl used at this call, if known, or NULL_TREE
+ otherwise. */
+
+tree
+call_details::get_fndecl_for_call () const
+{
+ return m_model->get_fndecl_for_call (m_call, m_ctxt);
+}
+
+/* Dump a multiline representation of this call to PP. */
+
+void
+call_details::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+ pp_string (pp, "gcall: ");
+ pp_gimple_stmt_1 (pp, m_call, 0 /* spc */, TDF_NONE /* flags */);
+ pp_newline (pp);
+ pp_string (pp, "return region: ");
+ if (m_lhs_region)
+ m_lhs_region->dump_to_pp (pp, simple);
+ else
+ pp_string (pp, "NULL");
+ pp_newline (pp);
+ for (unsigned i = 0; i < gimple_call_num_args (m_call); i++)
+ {
+ const svalue *arg_sval = get_arg_svalue (i);
+ pp_printf (pp, "arg %i: ", i);
+ arg_sval->dump_to_pp (pp, simple);
+ pp_newline (pp);
+ }
+}
+
+/* Dump a multiline representation of this call to stderr. */
+
+DEBUG_FUNCTION void
+call_details::dump (bool simple) 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_to_pp (&pp, simple);
+ pp_flush (&pp);
+}
+
+/* Get a conjured_svalue for this call for REG,
+ and purge any state already relating to that conjured_svalue. */
+
+const svalue *
+call_details::get_or_create_conjured_svalue (const region *reg) const
+{
+ region_model_manager *mgr = m_model->get_manager ();
+ return mgr->get_or_create_conjured_svalue (reg->get_type (), m_call, reg,
+ conjured_purge (m_model, m_ctxt));
+}
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/call-details.h b/gcc/analyzer/call-details.h
new file mode 100644
index 0000000..144ca0c
--- /dev/null
+++ b/gcc/analyzer/call-details.h
@@ -0,0 +1,77 @@
+/* Helper class for handling a call with specific arguments.
+ Copyright (C) 2019-2022 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+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/>. */
+
+#ifndef GCC_ANALYZER_CALL_DETAILS_H
+#define GCC_ANALYZER_CALL_DETAILS_H
+
+namespace ana {
+
+/* Helper class for handling calls to functions with known behavior. */
+
+class call_details
+{
+public:
+ call_details (const gcall *call, region_model *model,
+ region_model_context *ctxt);
+
+ region_model *get_model () const { return m_model; }
+ region_model_manager *get_manager () const;
+ region_model_context *get_ctxt () const { return m_ctxt; }
+ logger *get_logger () const;
+
+ uncertainty_t *get_uncertainty () const;
+ tree get_lhs_type () const { return m_lhs_type; }
+ const region *get_lhs_region () const { return m_lhs_region; }
+
+ bool maybe_set_lhs (const svalue *result) const;
+
+ unsigned num_args () const;
+ bool arg_is_pointer_p (unsigned idx) const
+ {
+ return POINTER_TYPE_P (get_arg_type (idx));
+ }
+ bool arg_is_size_p (unsigned idx) const;
+
+ const gcall *get_call_stmt () const { return m_call; }
+ location_t get_location () const;
+
+ tree get_arg_tree (unsigned idx) const;
+ tree get_arg_type (unsigned idx) const;
+ const svalue *get_arg_svalue (unsigned idx) const;
+ const char *get_arg_string_literal (unsigned idx) const;
+
+ tree get_fndecl_for_call () const;
+
+ void dump_to_pp (pretty_printer *pp, bool simple) const;
+ void dump (bool simple) const;
+
+ const svalue *get_or_create_conjured_svalue (const region *) const;
+
+private:
+ const gcall *m_call;
+ region_model *m_model;
+ region_model_context *m_ctxt;
+ tree m_lhs_type;
+ const region *m_lhs_region;
+};
+
+} // namespace ana
+
+#endif /* GCC_ANALYZER_CALL_DETAILS_H */
diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc
index 44a66be..cbd21f7 100644
--- a/gcc/analyzer/call-info.cc
+++ b/gcc/analyzer/call-info.cc
@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/checker-path.h"
#include "analyzer/diagnostic-manager.h"
#include "analyzer/exploded-graph.h"
+#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
#include "make-unique.h"
diff --git a/gcc/analyzer/call-summary.h b/gcc/analyzer/call-summary.h
index 07cd3f5..73f21ac 100644
--- a/gcc/analyzer/call-summary.h
+++ b/gcc/analyzer/call-summary.h
@@ -20,6 +20,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ANALYZER_CALL_SUMMARY_H
#define GCC_ANALYZER_CALL_SUMMARY_H
+#include "call-details.h"
+
namespace ana {
/* A class summarizing one particular outcome of a function that
diff --git a/gcc/analyzer/kf-analyzer.cc b/gcc/analyzer/kf-analyzer.cc
new file mode 100644
index 0000000..b233418
--- /dev/null
+++ b/gcc/analyzer/kf-analyzer.cc
@@ -0,0 +1,386 @@
+/* Handling for the various __analyzer_* known functions.
+ Copyright (C) 2020-2022 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+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/>. */
+
+#include "config.h"
+#define INCLUDE_MEMORY
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "diagnostic-core.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/analyzer-logging.h"
+#include "diagnostic.h"
+#include "tree-diagnostic.h" /* for default_tree_printer. */
+#include "analyzer/region-model.h"
+#include "analyzer/pending-diagnostic.h"
+#include "analyzer/call-details.h"
+#include "make-unique.h"
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* Handle calls to "__analyzer_break" by triggering a breakpoint within
+ the analyzer. */
+
+class kf_analyzer_break : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 0;
+ }
+ void impl_call_pre (const call_details &) const final override
+ {
+ /* TODO: is there a good cross-platform way to do this? */
+ raise (SIGINT);
+ }
+};
+
+/* Handler for calls to "__analyzer_describe".
+
+ Emit a warning describing the 2nd argument (which can be of any
+ type), at the given verbosity level. This is for use when
+ debugging, and may be of use in DejaGnu tests. */
+
+class kf_analyzer_describe : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 2;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ if (!cd.get_ctxt ())
+ return;
+ tree t_verbosity = cd.get_arg_tree (0);
+ const svalue *sval = cd.get_arg_svalue (1);
+ bool simple = zerop (t_verbosity);
+ label_text desc = sval->get_desc (simple);
+ warning_at (cd.get_location (), 0, "svalue: %qs", desc.get ());
+ }
+};
+
+/* Handler for calls to "__analyzer_dump_capacity".
+
+ Emit a warning describing the capacity of the base region of
+ the region pointed to by the 1st argument.
+ This is for use when debugging, and may be of use in DejaGnu tests. */
+
+class kf_analyzer_dump_capacity : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return (cd.num_args () == 1
+ && cd.arg_is_pointer_p (0));
+ }
+
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_context *ctxt = cd.get_ctxt ();
+ if (!ctxt)
+ return;
+ region_model *model = cd.get_model ();
+ tree t_ptr = cd.get_arg_tree (0);
+ const svalue *sval_ptr = model->get_rvalue (t_ptr, ctxt);
+ const region *reg = model->deref_rvalue (sval_ptr, t_ptr, ctxt);
+ const region *base_reg = reg->get_base_region ();
+ const svalue *capacity = model->get_capacity (base_reg);
+ label_text desc = capacity->get_desc (true);
+ warning_at (cd.get_call_stmt ()->location, 0,
+ "capacity: %qs", desc.get ());
+ }
+};
+
+/* Compare D1 and D2 using their names, and then IDs to order them. */
+
+static int
+cmp_decls (tree d1, tree d2)
+{
+ gcc_assert (DECL_P (d1));
+ gcc_assert (DECL_P (d2));
+ if (DECL_NAME (d1) && DECL_NAME (d2))
+ if (int cmp = strcmp (IDENTIFIER_POINTER (DECL_NAME (d1)),
+ IDENTIFIER_POINTER (DECL_NAME (d2))))
+ return cmp;
+ return (int)DECL_UID (d1) - (int)DECL_UID (d2);
+}
+
+/* Comparator for use by vec<tree>::qsort,
+ using their names, and then IDs to order them. */
+
+static int
+cmp_decls_ptr_ptr (const void *p1, const void *p2)
+{
+ tree const *d1 = (tree const *)p1;
+ tree const *d2 = (tree const *)p2;
+
+ return cmp_decls (*d1, *d2);
+}
+
+/* Handler for calls to "__analyzer_dump_escaped".
+
+ Emit a warning giving the number of decls that have escaped, followed
+ by a comma-separated list of their names, in alphabetical order.
+
+ This is for use when debugging, and may be of use in DejaGnu tests. */
+
+class kf_analyzer_dump_escaped : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 0;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_context *ctxt = cd.get_ctxt ();
+ if (!ctxt)
+ return;
+ region_model *model = cd.get_model ();
+
+ auto_vec<tree> escaped_decls;
+ for (auto iter : *model->get_store ())
+ {
+ const binding_cluster *c = iter.second;
+ if (!c->escaped_p ())
+ continue;
+ if (tree decl = c->get_base_region ()->maybe_get_decl ())
+ escaped_decls.safe_push (decl);
+ }
+
+ /* Sort them into deterministic order; alphabetical is
+ probably most user-friendly. */
+ escaped_decls.qsort (cmp_decls_ptr_ptr);
+
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_show_color (&pp) = pp_show_color (global_dc->printer);
+ bool first = true;
+ for (auto iter : escaped_decls)
+ {
+ if (first)
+ first = false;
+ else
+ pp_string (&pp, ", ");
+ pp_printf (&pp, "%qD", iter);
+ }
+ /* Print the number to make it easier to write DejaGnu tests for
+ the "nothing has escaped" case. */
+ warning_at (cd.get_location (), 0, "escaped: %i: %s",
+ escaped_decls.length (),
+ pp_formatted_text (&pp));
+ }
+};
+
+/* Placeholder handler for calls to "__analyzer_dump_exploded_nodes".
+ This is a no-op; the real implementation happens when the
+ exploded_graph is postprocessed. */
+
+class kf_analyzer_dump_exploded_nodes : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 1;
+ }
+};
+
+/* Handler for calls to "__analyzer_dump_named_constant".
+
+ Look up the given name, and emit a warning describing the
+ state of the corresponding stashed value.
+
+ This is for use when debugging, and for DejaGnu tests. */
+
+class kf_analyzer_dump_named_constant : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 1;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_context *ctxt = cd.get_ctxt ();
+ if (!ctxt)
+ return;
+
+ const char *name = cd.get_arg_string_literal (0);
+ if (!name)
+ {
+ error_at (cd.get_location (), "cannot determine name");
+ return;
+ }
+ tree value = get_stashed_constant_by_name (name);
+ if (value)
+ warning_at (cd.get_location (), 0, "named constant %qs has value %qE",
+ name, value);
+ else
+ warning_at (cd.get_location (), 0, "named constant %qs has unknown value",
+ name);
+ }
+};
+
+/* A pending_diagnostic subclass for implementing "__analyzer_dump_path". */
+
+class dump_path_diagnostic
+ : public pending_diagnostic_subclass<dump_path_diagnostic>
+{
+public:
+ int get_controlling_option () const final override
+ {
+ return 0;
+ }
+
+ bool emit (rich_location *richloc) final override
+ {
+ inform (richloc, "path");
+ return true;
+ }
+
+ const char *get_kind () const final override
+ {
+ return "dump_path_diagnostic";
+ }
+
+ bool operator== (const dump_path_diagnostic &) const
+ {
+ return true;
+ }
+};
+
+/* Handle calls to "__analyzer_dump_path" by queuing a diagnostic at this
+ exploded_node. */
+
+class kf_analyzer_dump_path : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 0;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_context *ctxt = cd.get_ctxt ();
+ if (!ctxt)
+ return;
+ ctxt->warn (make_unique<dump_path_diagnostic> ());
+ }
+};
+
+/* Handle calls to "__analyzer_dump_region_model" by dumping
+ the region model's state to stderr. */
+
+class kf_analyzer_dump_region_model : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 0;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_context *ctxt = cd.get_ctxt ();
+ if (!ctxt)
+ return;
+ region_model *model = cd.get_model ();
+ model->dump (false);
+ }
+};
+
+/* Handle a call to "__analyzer_eval" by evaluating the input
+ and dumping as a dummy warning, so that test cases can use
+ dg-warning to validate the result (and so unexpected warnings will
+ lead to DejaGnu failures).
+ Broken out as a subroutine to make it easier to put a breakpoint on it
+ - though typically this doesn't help, as we have an SSA name as the arg,
+ and what's more interesting is usually the def stmt for that name. */
+
+class kf_analyzer_eval : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 1;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_context *ctxt = cd.get_ctxt ();
+ if (!ctxt)
+ return;
+ region_model *model = cd.get_model ();
+
+ tree t_arg = cd.get_arg_tree (0);
+ tristate t = model->eval_condition (t_arg, NE_EXPR, integer_zero_node,
+ ctxt);
+ warning_at (cd.get_location (), 0, "%s", t.as_string ());
+ }
+};
+
+/* Handler for "__analyzer_get_unknown_ptr". */
+
+class kf_analyzer_get_unknown_ptr : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 0;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_manager *mgr = cd.get_manager ();
+ const svalue *ptr_sval
+ = mgr->get_or_create_unknown_svalue (cd.get_lhs_type ());
+ cd.maybe_set_lhs (ptr_sval);
+ }
+};
+
+/* Populate KFM with instances of known functions used for debugging the
+ analyzer and for writing DejaGnu tests, all with a "__analyzer_" prefix. */
+
+void
+register_known_analyzer_functions (known_function_manager &kfm)
+{
+ kfm.add ("__analyzer_break", make_unique<kf_analyzer_break> ());
+ kfm.add ("__analyzer_describe", make_unique<kf_analyzer_describe> ());
+ kfm.add ("__analyzer_dump_capacity",
+ make_unique<kf_analyzer_dump_capacity> ());
+ kfm.add ("__analyzer_dump_escaped", make_unique<kf_analyzer_dump_escaped> ());
+ kfm.add ("__analyzer_dump_exploded_nodes",
+ make_unique<kf_analyzer_dump_exploded_nodes> ());
+ kfm.add ("__analyzer_dump_named_constant",
+ make_unique<kf_analyzer_dump_named_constant> ());
+ kfm.add ("__analyzer_dump_path", make_unique<kf_analyzer_dump_path> ());
+ kfm.add ("__analyzer_dump_region_model",
+ make_unique<kf_analyzer_dump_region_model> ());
+ kfm.add ("__analyzer_eval", make_unique<kf_analyzer_eval> ());
+ kfm.add ("__analyzer_get_unknown_ptr",
+ make_unique<kf_analyzer_get_unknown_ptr> ());
+}
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/kf-lang-cp.cc b/gcc/analyzer/kf-lang-cp.cc
new file mode 100644
index 0000000..9dca366
--- /dev/null
+++ b/gcc/analyzer/kf-lang-cp.cc
@@ -0,0 +1,111 @@
+/* Handling for the known behavior of various functions specific to C++.
+ Copyright (C) 2020-2022 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+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/>. */
+
+#include "config.h"
+#define INCLUDE_MEMORY
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/analyzer-logging.h"
+#include "diagnostic.h"
+#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
+#include "make-unique.h"
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* Implementations of specific functions. */
+
+/* Handler for "operator new" and "operator new []". */
+
+class kf_operator_new : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 1;
+ }
+
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model *model = cd.get_model ();
+ region_model_manager *mgr = cd.get_manager ();
+ const svalue *size_sval = cd.get_arg_svalue (0);
+ const region *new_reg
+ = model->get_or_create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
+ if (cd.get_lhs_type ())
+ {
+ const svalue *ptr_sval
+ = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
+ cd.maybe_set_lhs (ptr_sval);
+ }
+ }
+};
+
+/* Handler for "operator delete", both the sized and unsized variants
+ (2 arguments and 1 argument respectively), and for "operator delete []" */
+
+class kf_operator_delete : public known_function
+{
+public:
+ kf_operator_delete (unsigned num_args) : m_num_args (num_args) {}
+
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == m_num_args;
+ }
+
+ void impl_call_post (const call_details &cd) const final override
+ {
+ region_model *model = cd.get_model ();
+ const svalue *ptr_sval = cd.get_arg_svalue (0);
+ if (const region *freed_reg = ptr_sval->maybe_get_region ())
+ {
+ /* If the ptr points to an underlying heap region, delete it,
+ poisoning pointers. */
+ model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
+ }
+ }
+
+private:
+ unsigned m_num_args;
+};
+
+/* Populate KFM with instances of known functions relating to C++. */
+
+void
+register_known_functions_lang_cp (known_function_manager &kfm)
+{
+ kfm.add ("operator new", make_unique<kf_operator_new> ());
+ kfm.add ("operator new []", make_unique<kf_operator_new> ());
+ kfm.add ("operator delete", make_unique<kf_operator_delete> (1));
+ kfm.add ("operator delete", make_unique<kf_operator_delete> (2));
+ kfm.add ("operator delete []", make_unique<kf_operator_delete> (1));
+}
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/known-function-manager.cc b/gcc/analyzer/known-function-manager.cc
index c1074bc..dc514a7 100644
--- a/gcc/analyzer/known-function-manager.cc
+++ b/gcc/analyzer/known-function-manager.cc
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple.h"
#include "analyzer/known-function-manager.h"
#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc
index 8ba644c..6aeb9281 100644
--- a/gcc/analyzer/region-model-impl-calls.cc
+++ b/gcc/analyzer/region-model-impl-calls.cc
@@ -26,228 +26,20 @@ along with GCC; see the file COPYING3. If not see
#include "function.h"
#include "basic-block.h"
#include "gimple.h"
-#include "gimple-iterator.h"
#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
-#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "diagnostic-color.h"
#include "diagnostic-metadata.h"
-#include "bitmap.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
-#include "ordered-hash-map.h"
-#include "options.h"
-#include "analyzer/supergraph.h"
-#include "sbitmap.h"
-#include "analyzer/call-string.h"
-#include "analyzer/program-point.h"
-#include "analyzer/store.h"
+#include "diagnostic.h"
#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
-#include "analyzer/sm.h"
-#include "diagnostic-path.h"
-#include "analyzer/pending-diagnostic.h"
-#include "gimple-pretty-print.h"
#include "make-unique.h"
#if ENABLE_ANALYZER
namespace ana {
-/* class call_details. */
-
-/* call_details's ctor. */
-
-call_details::call_details (const gcall *call, region_model *model,
- region_model_context *ctxt)
-: m_call (call), m_model (model), m_ctxt (ctxt),
- m_lhs_type (NULL_TREE), m_lhs_region (NULL)
-{
- m_lhs_type = NULL_TREE;
- if (tree lhs = gimple_call_lhs (call))
- {
- m_lhs_region = model->get_lvalue (lhs, ctxt);
- m_lhs_type = TREE_TYPE (lhs);
- }
-}
-
-/* Get the manager from m_model. */
-
-region_model_manager *
-call_details::get_manager () const
-{
- return m_model->get_manager ();
-}
-
-/* Get any logger associated with this object. */
-
-logger *
-call_details::get_logger () const
-{
- if (m_ctxt)
- return m_ctxt->get_logger ();
- else
- return NULL;
-}
-
-/* Get any uncertainty_t associated with the region_model_context. */
-
-uncertainty_t *
-call_details::get_uncertainty () const
-{
- if (m_ctxt)
- return m_ctxt->get_uncertainty ();
- else
- return NULL;
-}
-
-/* If the callsite has a left-hand-side region, set it to RESULT
- and return true.
- Otherwise do nothing and return false. */
-
-bool
-call_details::maybe_set_lhs (const svalue *result) const
-{
- gcc_assert (result);
- if (m_lhs_region)
- {
- m_model->set_value (m_lhs_region, result, m_ctxt);
- return true;
- }
- else
- return false;
-}
-
-/* Return the number of arguments used by the call statement. */
-
-unsigned
-call_details::num_args () const
-{
- return gimple_call_num_args (m_call);
-}
-
-/* Return true if argument IDX is a size_t (or compatible with it). */
-
-bool
-call_details::arg_is_size_p (unsigned idx) const
-{
- return types_compatible_p (get_arg_type (idx), size_type_node);
-}
-
-/* Get the location of the call statement. */
-
-location_t
-call_details::get_location () const
-{
- return m_call->location;
-}
-
-/* Get argument IDX at the callsite as a tree. */
-
-tree
-call_details::get_arg_tree (unsigned idx) const
-{
- return gimple_call_arg (m_call, idx);
-}
-
-/* Get the type of argument IDX. */
-
-tree
-call_details::get_arg_type (unsigned idx) const
-{
- return TREE_TYPE (gimple_call_arg (m_call, idx));
-}
-
-/* Get argument IDX at the callsite as an svalue. */
-
-const svalue *
-call_details::get_arg_svalue (unsigned idx) const
-{
- tree arg = get_arg_tree (idx);
- return m_model->get_rvalue (arg, m_ctxt);
-}
-
-/* Attempt to get the string literal for argument IDX, or return NULL
- otherwise.
- For use when implementing "__analyzer_*" functions that take
- string literals. */
-
-const char *
-call_details::get_arg_string_literal (unsigned idx) const
-{
- const svalue *str_arg = get_arg_svalue (idx);
- if (const region *pointee = str_arg->maybe_get_region ())
- if (const string_region *string_reg = pointee->dyn_cast_string_region ())
- {
- tree string_cst = string_reg->get_string_cst ();
- return TREE_STRING_POINTER (string_cst);
- }
- return NULL;
-}
-
-/* Attempt to get the fndecl used at this call, if known, or NULL_TREE
- otherwise. */
-
-tree
-call_details::get_fndecl_for_call () const
-{
- return m_model->get_fndecl_for_call (m_call, m_ctxt);
-}
-
-/* Dump a multiline representation of this call to PP. */
-
-void
-call_details::dump_to_pp (pretty_printer *pp, bool simple) const
-{
- pp_string (pp, "gcall: ");
- pp_gimple_stmt_1 (pp, m_call, 0 /* spc */, TDF_NONE /* flags */);
- pp_newline (pp);
- pp_string (pp, "return region: ");
- if (m_lhs_region)
- m_lhs_region->dump_to_pp (pp, simple);
- else
- pp_string (pp, "NULL");
- pp_newline (pp);
- for (unsigned i = 0; i < gimple_call_num_args (m_call); i++)
- {
- const svalue *arg_sval = get_arg_svalue (i);
- pp_printf (pp, "arg %i: ", i);
- arg_sval->dump_to_pp (pp, simple);
- pp_newline (pp);
- }
-}
-
-/* Dump a multiline representation of this call to stderr. */
-
-DEBUG_FUNCTION void
-call_details::dump (bool simple) 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_to_pp (&pp, simple);
- pp_flush (&pp);
-}
-
-/* Get a conjured_svalue for this call for REG,
- and purge any state already relating to that conjured_svalue. */
-
-const svalue *
-call_details::get_or_create_conjured_svalue (const region *reg) const
-{
- region_model_manager *mgr = m_model->get_manager ();
- return mgr->get_or_create_conjured_svalue (reg->get_type (), m_call, reg,
- conjured_purge (m_model, m_ctxt));
-}
-
/* Implementations of specific functions. */
/* Handler for "alloca". */
@@ -277,324 +69,6 @@ kf_alloca::impl_call_pre (const call_details &cd) const
cd.maybe_set_lhs (ptr_sval);
}
-/* Handle calls to "__analyzer_break" by triggering a breakpoint within
- the analyzer. */
-
-class kf_analyzer_break : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 0;
- }
- void impl_call_pre (const call_details &) const final override
- {
- /* TODO: is there a good cross-platform way to do this? */
- raise (SIGINT);
- }
-};
-
-/* Handler for calls to "__analyzer_describe".
-
- Emit a warning describing the 2nd argument (which can be of any
- type), at the given verbosity level. This is for use when
- debugging, and may be of use in DejaGnu tests. */
-
-class kf_analyzer_describe : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 2;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- if (!cd.get_ctxt ())
- return;
- tree t_verbosity = cd.get_arg_tree (0);
- const svalue *sval = cd.get_arg_svalue (1);
- bool simple = zerop (t_verbosity);
- label_text desc = sval->get_desc (simple);
- warning_at (cd.get_location (), 0, "svalue: %qs", desc.get ());
- }
-};
-
-/* Handler for calls to "__analyzer_dump_capacity".
-
- Emit a warning describing the capacity of the base region of
- the region pointed to by the 1st argument.
- This is for use when debugging, and may be of use in DejaGnu tests. */
-
-class kf_analyzer_dump_capacity : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return (cd.num_args () == 1
- && cd.arg_is_pointer_p (0));
- }
-
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_context *ctxt = cd.get_ctxt ();
- if (!ctxt)
- return;
- region_model *model = cd.get_model ();
- tree t_ptr = cd.get_arg_tree (0);
- const svalue *sval_ptr = model->get_rvalue (t_ptr, ctxt);
- const region *reg = model->deref_rvalue (sval_ptr, t_ptr, ctxt);
- const region *base_reg = reg->get_base_region ();
- const svalue *capacity = model->get_capacity (base_reg);
- label_text desc = capacity->get_desc (true);
- warning_at (cd.get_call_stmt ()->location, 0,
- "capacity: %qs", desc.get ());
- }
-};
-
-/* Compare D1 and D2 using their names, and then IDs to order them. */
-
-static int
-cmp_decls (tree d1, tree d2)
-{
- gcc_assert (DECL_P (d1));
- gcc_assert (DECL_P (d2));
- if (DECL_NAME (d1) && DECL_NAME (d2))
- if (int cmp = strcmp (IDENTIFIER_POINTER (DECL_NAME (d1)),
- IDENTIFIER_POINTER (DECL_NAME (d2))))
- return cmp;
- return (int)DECL_UID (d1) - (int)DECL_UID (d2);
-}
-
-/* Comparator for use by vec<tree>::qsort,
- using their names, and then IDs to order them. */
-
-static int
-cmp_decls_ptr_ptr (const void *p1, const void *p2)
-{
- tree const *d1 = (tree const *)p1;
- tree const *d2 = (tree const *)p2;
-
- return cmp_decls (*d1, *d2);
-}
-
-/* Handler for calls to "__analyzer_dump_escaped".
-
- Emit a warning giving the number of decls that have escaped, followed
- by a comma-separated list of their names, in alphabetical order.
-
- This is for use when debugging, and may be of use in DejaGnu tests. */
-
-class kf_analyzer_dump_escaped : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 0;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_context *ctxt = cd.get_ctxt ();
- if (!ctxt)
- return;
- region_model *model = cd.get_model ();
-
- auto_vec<tree> escaped_decls;
- for (auto iter : *model->get_store ())
- {
- const binding_cluster *c = iter.second;
- if (!c->escaped_p ())
- continue;
- if (tree decl = c->get_base_region ()->maybe_get_decl ())
- escaped_decls.safe_push (decl);
- }
-
- /* Sort them into deterministic order; alphabetical is
- probably most user-friendly. */
- escaped_decls.qsort (cmp_decls_ptr_ptr);
-
- pretty_printer pp;
- pp_format_decoder (&pp) = default_tree_printer;
- pp_show_color (&pp) = pp_show_color (global_dc->printer);
- bool first = true;
- for (auto iter : escaped_decls)
- {
- if (first)
- first = false;
- else
- pp_string (&pp, ", ");
- pp_printf (&pp, "%qD", iter);
- }
- /* Print the number to make it easier to write DejaGnu tests for
- the "nothing has escaped" case. */
- warning_at (cd.get_location (), 0, "escaped: %i: %s",
- escaped_decls.length (),
- pp_formatted_text (&pp));
- }
-};
-
-/* Placeholder handler for calls to "__analyzer_dump_exploded_nodes".
- This is a no-op; the real implementation happens when the
- exploded_graph is postprocessed. */
-
-class kf_analyzer_dump_exploded_nodes : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 1;
- }
-};
-
-/* Handler for calls to "__analyzer_dump_named_constant".
-
- Look up the given name, and emit a warning describing the
- state of the corresponding stashed value.
-
- This is for use when debugging, and for DejaGnu tests. */
-
-class kf_analyzer_dump_named_constant : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 1;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_context *ctxt = cd.get_ctxt ();
- if (!ctxt)
- return;
-
- const char *name = cd.get_arg_string_literal (0);
- if (!name)
- {
- error_at (cd.get_location (), "cannot determine name");
- return;
- }
- tree value = get_stashed_constant_by_name (name);
- if (value)
- warning_at (cd.get_location (), 0, "named constant %qs has value %qE",
- name, value);
- else
- warning_at (cd.get_location (), 0, "named constant %qs has unknown value",
- name);
- }
-};
-
-/* A pending_diagnostic subclass for implementing "__analyzer_dump_path". */
-
-class dump_path_diagnostic
- : public pending_diagnostic_subclass<dump_path_diagnostic>
-{
-public:
- int get_controlling_option () const final override
- {
- return 0;
- }
-
- bool emit (rich_location *richloc) final override
- {
- inform (richloc, "path");
- return true;
- }
-
- const char *get_kind () const final override
- {
- return "dump_path_diagnostic";
- }
-
- bool operator== (const dump_path_diagnostic &) const
- {
- return true;
- }
-};
-
-/* Handle calls to "__analyzer_dump_path" by queuing a diagnostic at this
- exploded_node. */
-
-class kf_analyzer_dump_path : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 0;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_context *ctxt = cd.get_ctxt ();
- if (!ctxt)
- return;
- ctxt->warn (make_unique<dump_path_diagnostic> ());
- }
-};
-
-/* Handle calls to "__analyzer_dump_region_model" by dumping
- the region model's state to stderr. */
-
-class kf_analyzer_dump_region_model : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 0;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_context *ctxt = cd.get_ctxt ();
- if (!ctxt)
- return;
- region_model *model = cd.get_model ();
- model->dump (false);
- }
-};
-
-/* Handle a call to "__analyzer_eval" by evaluating the input
- and dumping as a dummy warning, so that test cases can use
- dg-warning to validate the result (and so unexpected warnings will
- lead to DejaGnu failures).
- Broken out as a subroutine to make it easier to put a breakpoint on it
- - though typically this doesn't help, as we have an SSA name as the arg,
- and what's more interesting is usually the def stmt for that name. */
-
-class kf_analyzer_eval : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 1;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_context *ctxt = cd.get_ctxt ();
- if (!ctxt)
- return;
- region_model *model = cd.get_model ();
-
- tree t_arg = cd.get_arg_tree (0);
- tristate t = model->eval_condition (t_arg, NE_EXPR, integer_zero_node,
- ctxt);
- warning_at (cd.get_location (), 0, "%s", t.as_string ());
- }
-};
-
-/* Handler for "__analyzer_get_unknown_ptr". */
-
-class kf_analyzer_get_unknown_ptr : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 0;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_manager *mgr = cd.get_manager ();
- const svalue *ptr_sval
- = mgr->get_or_create_unknown_svalue (cd.get_lhs_type ());
- cd.maybe_set_lhs (ptr_sval);
- }
-};
-
/* Handler for "__builtin_expect" etc. */
class kf_expect : public internal_known_function
@@ -977,61 +451,6 @@ public:
}
};
-/* Handler for "operator new" and "operator new []". */
-
-class kf_operator_new : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 1;
- }
-
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model *model = cd.get_model ();
- region_model_manager *mgr = cd.get_manager ();
- const svalue *size_sval = cd.get_arg_svalue (0);
- const region *new_reg
- = model->get_or_create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
- if (cd.get_lhs_type ())
- {
- const svalue *ptr_sval
- = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
- cd.maybe_set_lhs (ptr_sval);
- }
- }
-};
-
-/* Handler for "operator delete", both the sized and unsized variants
- (2 arguments and 1 argument respectively), and for "operator delete []" */
-
-class kf_operator_delete : public known_function
-{
-public:
- kf_operator_delete (unsigned num_args) : m_num_args (num_args) {}
-
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == m_num_args;
- }
-
- void impl_call_post (const call_details &cd) const final override
- {
- region_model *model = cd.get_model ();
- const svalue *ptr_sval = cd.get_arg_svalue (0);
- if (const region *freed_reg = ptr_sval->maybe_get_region ())
- {
- /* If the ptr points to an underlying heap region, delete it,
- poisoning pointers. */
- model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
- }
- }
-
-private:
- unsigned m_num_args;
-};
-
/* Handler for "realloc":
void *realloc(void *ptr, size_t size);
@@ -1490,6 +909,9 @@ region_model::impl_deallocation_call (const call_details &cd)
void
register_known_functions (known_function_manager &kfm)
{
+ /* Debugging/test support functions, all with a "__analyzer_" prefix. */
+ register_known_analyzer_functions (kfm);
+
/* Internal fns the analyzer has known_functions for. */
{
kfm.add (IFN_BUILTIN_EXPECT, make_unique<kf_expect> ());
@@ -1520,27 +942,6 @@ register_known_functions (known_function_manager &kfm)
register_varargs_builtins (kfm);
}
- /* Debugging/test support functions, all with a "__analyzer_" prefix. */
- {
- kfm.add ("__analyzer_break", make_unique<kf_analyzer_break> ());
- kfm.add ("__analyzer_describe", make_unique<kf_analyzer_describe> ());
- kfm.add ("__analyzer_dump_capacity",
- make_unique<kf_analyzer_dump_capacity> ());
- kfm.add ("__analyzer_dump_escaped",
- make_unique<kf_analyzer_dump_escaped> ());
- kfm.add ("__analyzer_dump_exploded_nodes",
- make_unique<kf_analyzer_dump_exploded_nodes> ());
- kfm.add ("__analyzer_dump_named_constant",
- make_unique<kf_analyzer_dump_named_constant> ());
- kfm.add ("__analyzer_dump_path", make_unique<kf_analyzer_dump_path> ());
- kfm.add ("__analyzer_dump_region_model",
- make_unique<kf_analyzer_dump_region_model> ());
- kfm.add ("__analyzer_eval",
- make_unique<kf_analyzer_eval> ());
- kfm.add ("__analyzer_get_unknown_ptr",
- make_unique<kf_analyzer_get_unknown_ptr> ());
- }
-
/* Known builtins and C standard library functions. */
{
kfm.add ("memset", make_unique<kf_memset> ());
@@ -1575,14 +976,8 @@ register_known_functions (known_function_manager &kfm)
kfm.add ("__error", make_unique<kf_errno_location> ());
}
- /* C++ support functions. */
- {
- kfm.add ("operator new", make_unique<kf_operator_new> ());
- kfm.add ("operator new []", make_unique<kf_operator_new> ());
- kfm.add ("operator delete", make_unique<kf_operator_delete> (1));
- kfm.add ("operator delete", make_unique<kf_operator_delete> (2));
- kfm.add ("operator delete []", make_unique<kf_operator_delete> (1));
- }
+ /* Language-specific support functions. */
+ register_known_functions_lang_cp (kfm);
}
} // namespace ana
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 86bfb4f..3b93d3e 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -236,56 +236,6 @@ public:
struct append_regions_cb_data;
-/* Helper class for handling calls to functions with known behavior.
- Implemented in region-model-impl-calls.c. */
-
-class call_details
-{
-public:
- call_details (const gcall *call, region_model *model,
- region_model_context *ctxt);
-
- region_model *get_model () const { return m_model; }
- region_model_manager *get_manager () const;
- region_model_context *get_ctxt () const { return m_ctxt; }
- logger *get_logger () const;
-
- uncertainty_t *get_uncertainty () const;
- tree get_lhs_type () const { return m_lhs_type; }
- const region *get_lhs_region () const { return m_lhs_region; }
-
- bool maybe_set_lhs (const svalue *result) const;
-
- unsigned num_args () const;
- bool arg_is_pointer_p (unsigned idx) const
- {
- return POINTER_TYPE_P (get_arg_type (idx));
- }
- bool arg_is_size_p (unsigned idx) const;
-
- const gcall *get_call_stmt () const { return m_call; }
- location_t get_location () const;
-
- tree get_arg_tree (unsigned idx) const;
- tree get_arg_type (unsigned idx) const;
- const svalue *get_arg_svalue (unsigned idx) const;
- const char *get_arg_string_literal (unsigned idx) const;
-
- tree get_fndecl_for_call () const;
-
- void dump_to_pp (pretty_printer *pp, bool simple) const;
- void dump (bool simple) const;
-
- const svalue *get_or_create_conjured_svalue (const region *) const;
-
-private:
- const gcall *m_call;
- region_model *m_model;
- region_model_context *m_ctxt;
- tree m_lhs_type;
- const region *m_lhs_region;
-};
-
/* A region_model encapsulates a representation of the state of memory, with
a tree of regions, along with their associated values.
The representation is graph-like because values can be pointers to
diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc
index 799847c..50e1313 100644
--- a/gcc/analyzer/sm-fd.cc
+++ b/gcc/analyzer/sm-fd.cc
@@ -47,6 +47,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/program-state.h"
#include "analyzer/supergraph.h"
#include "analyzer/analyzer-language.h"
+#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc
index d2dcb43..1bd594b 100644
--- a/gcc/analyzer/sm-file.cc
+++ b/gcc/analyzer/sm-file.cc
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc
index 94ca295..b520c9b 100644
--- a/gcc/analyzer/sm-malloc.cc
+++ b/gcc/analyzer/sm-malloc.cc
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
#include "stringpool.h"
#include "attribs.h"
#include "analyzer/function-set.h"
diff --git a/gcc/analyzer/varargs.cc b/gcc/analyzer/varargs.cc
index 519b32d..1a3bdde 100644
--- a/gcc/analyzer/varargs.cc
+++ b/gcc/analyzer/varargs.cc
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/diagnostic-manager.h"
#include "analyzer/exploded-graph.h"
#include "diagnostic-metadata.h"
+#include "analyzer/call-details.h"
#if ENABLE_ANALYZER
diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c
index b424337..57bccf4 100644
--- a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c
+++ b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c
@@ -41,6 +41,7 @@
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
#include "make-unique.h"
diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c
index 1435b38..de887db 100644
--- a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c
+++ b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c
@@ -41,6 +41,7 @@
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
#include "make-unique.h"