aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-10-08 10:19:23 +0200
committerMartin Liska <mliska@suse.cz>2022-10-08 10:19:23 +0200
commitd9e7934d25da4a78ffef1f738206aa1d897911df (patch)
tree1bd1697c14259e095f4b4790946eae7df0c5a2e3 /gcc/analyzer
parentda0970e441345f8349522ff1abac5c223044ebb1 (diff)
parent6ffbf87ca66f4ed9cd79cff675fabe2109e46e85 (diff)
downloadgcc-d9e7934d25da4a78ffef1f738206aa1d897911df.zip
gcc-d9e7934d25da4a78ffef1f738206aa1d897911df.tar.gz
gcc-d9e7934d25da4a78ffef1f738206aa1d897911df.tar.bz2
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc/analyzer')
-rw-r--r--gcc/analyzer/ChangeLog202
-rw-r--r--gcc/analyzer/analysis-plan.cc2
-rw-r--r--gcc/analyzer/analyzer-logging.h2
-rw-r--r--gcc/analyzer/analyzer-pass.cc1
-rw-r--r--gcc/analyzer/analyzer-selftests.cc1
-rw-r--r--gcc/analyzer/analyzer.cc1
-rw-r--r--gcc/analyzer/analyzer.h13
-rw-r--r--gcc/analyzer/call-info.cc19
-rw-r--r--gcc/analyzer/call-string.cc1
-rw-r--r--gcc/analyzer/call-summary.cc889
-rw-r--r--gcc/analyzer/call-summary.h117
-rw-r--r--gcc/analyzer/checker-path.cc8
-rw-r--r--gcc/analyzer/complexity.cc4
-rw-r--r--gcc/analyzer/constraint-manager.cc58
-rw-r--r--gcc/analyzer/constraint-manager.h3
-rw-r--r--gcc/analyzer/diagnostic-manager.cc7
-rw-r--r--gcc/analyzer/engine.cc206
-rw-r--r--gcc/analyzer/exploded-graph.h34
-rw-r--r--gcc/analyzer/feasible-graph.cc7
-rw-r--r--gcc/analyzer/known-function-manager.cc1
-rw-r--r--gcc/analyzer/known-function-manager.h2
-rw-r--r--gcc/analyzer/pending-diagnostic.cc8
-rw-r--r--gcc/analyzer/program-point.cc4
-rw-r--r--gcc/analyzer/program-point.h3
-rw-r--r--gcc/analyzer/program-state.cc54
-rw-r--r--gcc/analyzer/program-state.h6
-rw-r--r--gcc/analyzer/region-model-asm.cc3
-rw-r--r--gcc/analyzer/region-model-impl-calls.cc17
-rw-r--r--gcc/analyzer/region-model-manager.cc54
-rw-r--r--gcc/analyzer/region-model-manager.h318
-rw-r--r--gcc/analyzer/region-model-reachability.cc9
-rw-r--r--gcc/analyzer/region-model.cc113
-rw-r--r--gcc/analyzer/region-model.h300
-rw-r--r--gcc/analyzer/region.cc4
-rw-r--r--gcc/analyzer/sm-fd.cc4
-rw-r--r--gcc/analyzer/sm-file.cc3
-rw-r--r--gcc/analyzer/sm-malloc.cc4
-rw-r--r--gcc/analyzer/sm-pattern-test.cc4
-rw-r--r--gcc/analyzer/sm-sensitive.cc3
-rw-r--r--gcc/analyzer/sm-signal.cc6
-rw-r--r--gcc/analyzer/sm-taint.cc4
-rw-r--r--gcc/analyzer/sm.cc2
-rw-r--r--gcc/analyzer/state-purge.cc10
-rw-r--r--gcc/analyzer/store.cc148
-rw-r--r--gcc/analyzer/store.h14
-rw-r--r--gcc/analyzer/supergraph.cc10
-rw-r--r--gcc/analyzer/supergraph.h10
-rw-r--r--gcc/analyzer/svalue.cc39
-rw-r--r--gcc/analyzer/svalue.h11
-rw-r--r--gcc/analyzer/trimmed-graph.cc13
-rw-r--r--gcc/analyzer/varargs.cc11
51 files changed, 2237 insertions, 530 deletions
diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog
index 3af1a38..33477da 100644
--- a/gcc/analyzer/ChangeLog
+++ b/gcc/analyzer/ChangeLog
@@ -1,3 +1,205 @@
+2022-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/105783
+ * region-model.cc (selftest::get_bit): New function.
+ (selftest::test_bits_within_svalue_folding): New.
+ (selfftest::analyzer_region_model_cc_tests): Call it.
+ * svalue.cc (constant_svalue::maybe_fold_bits_within): Handle the
+ case of extracting a single bit.
+
+2022-10-06 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/107158
+ * store.cc (store::replay_call_summary_cluster): Eliminate
+ special-casing of RK_HEAP_ALLOCATED in favor of sharing code with
+ RK_DECL, avoiding an ICE due to attempting to bind a
+ compound_svalue into a binding_cluster when an svalue in the
+ summary cluster converts to a compound_svalue in the caller.
+
+2022-10-06 David Malcolm <dmalcolm@redhat.com>
+
+ * call-summary.cc (call_summary_replay::dump_to_pp): Bulletproof
+ against NULL caller regions/svalues.
+
+2022-10-05 David Malcolm <dmalcolm@redhat.com>
+
+ * analysis-plan.cc: Simplify includes.
+ * analyzer-pass.cc: Likewise.
+ * analyzer-selftests.cc: Likewise.
+ * analyzer.cc: Likewise.
+ * analyzer.h: Add includes of "json.h" and "tristate.h".
+ * call-info.cc: Simplify includes.
+ * call-string.cc: Likewise.
+ * call-summary.cc: Likewise.
+ * checker-path.cc: Likewise.
+ * complexity.cc: Likewise.
+ * constraint-manager.cc: Likewise.
+ * diagnostic-manager.cc: Likewise.
+ * engine.cc: Likewise.
+ * feasible-graph.cc: Likewise.
+ * known-function-manager.cc: Likewise.
+ * pending-diagnostic.cc: Likewise.
+ * program-point.cc: Likewise.
+ * program-state.cc: Likewise.
+ * region-model-asm.cc: Likewise.
+ * region-model-impl-calls.cc: Likewise.
+ * region-model-manager.cc: Likewise.
+ * region-model-reachability.cc: Likewise.
+ * region-model.cc: Likewise.
+ * region-model.h: Include "selftest.h".
+ * region.cc: Simplify includes.
+ * sm-fd.cc: Likewise.
+ * sm-file.cc: Likewise.
+ * sm-malloc.cc: Likewise.
+ * sm-pattern-test.cc: Likewise.
+ * sm-sensitive.cc: Likewise.
+ * sm-signal.cc: Likewise.
+ * sm-taint.cc: Likewise.
+ * sm.cc: Likewise.
+ * state-purge.cc: Likewise.
+ * store.cc: Likewise.
+ * store.h: Likewise.
+ * supergraph.cc: Likewise.
+ * svalue.cc: Likewise.
+ * svalue.h: Likewise.
+ * trimmed-graph.cc: Likewise.
+ * varargs.cc: Likewise.
+
+2022-10-05 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/107060
+ * call-summary.cc
+ (call_summary_replay::convert_svalue_from_summary_1): Handle NULL
+ results from convert_svalue_from_summary in SK_UNARY_OP and
+ SK_BIN_OP.
+ * engine.cc (impl_region_model_context::on_unknown_change): Bail
+ out on svalues that can't have associated state.
+ * region-model-impl-calls.cc
+ (region_model::impl_call_analyzer_get_unknown_ptr): New.
+ * region-model.cc (region_model::on_stmt_pre): Handle
+ "__analyzer_get_unknown_ptr".
+ * region-model.h
+ (region_model::impl_call_analyzer_get_unknown_ptr): New decl.
+ * store.cc (store::replay_call_summary_cluster): Avoid trying to
+ create binding clusters for base regions that shouldn't have them.
+
+2022-10-05 Martin Liska <mliska@suse.cz>
+
+ * call-summary.cc (call_summary_replay::call_summary_replay):
+ Remove unused variable and arguments.
+ * call-summary.h: Likewise.
+ * engine.cc (exploded_node::on_stmt): Likewise.
+ (exploded_node::replay_call_summaries): Likewise.
+ (exploded_node::replay_call_summary): Likewise.
+ * exploded-graph.h (class exploded_node): Likewise.
+
+2022-10-05 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/107072
+ * analyzer-logging.h: Include "diagnostic-core.h".
+ * analyzer.h: Include "function.h".
+ (class call_summary): New forward decl.
+ (class call_summary_replay): New forward decl.
+ (struct per_function_data): New forward decl.
+ (struct interesting_t): New forward decl.
+ (custom_edge_info::update_state): New vfunc.
+ * call-info.cc (custom_edge_info::update_state): New.
+ * call-summary.cc: New file.
+ * call-summary.h: New file.
+ * constraint-manager.cc: Include "analyzer/call-summary.h".
+ (class replay_fact_visitor): New.
+ (constraint_manager::replay_call_summary): New.
+ * constraint-manager.h (constraint_manager::replay_call_summary):
+ New.
+ * engine.cc: Include "analyzer/call-summary.h".
+ (exploded_node::on_stmt): Handle call summaries.
+ (class call_summary_edge_info): New.
+ (exploded_node::replay_call_summaries): New.
+ (exploded_node::replay_call_summary): New.
+ (per_function_data::~per_function_data): New.
+ (per_function_data::add_call_summary): Move here from header and
+ reimplement.
+ (exploded_graph::process_node): Call update_state rather than
+ update_model when handling bifurcation
+ (viz_callgraph_node::dump_dot): Use a regular label rather
+ than an HTML table; add summaries to dump.
+ * exploded-graph.h: Include "alloc-pool.h", "fibonacci_heap.h",
+ "supergraph.h", "sbitmap.h", "shortest-paths.h", "analyzer/sm.h",
+ "analyzer/program-state.h", and "analyzer/diagnostic-manager.h".
+ (exploded_node::replay_call_summaries): New decl.
+ (exploded_node::replay_call_summary): New decl.
+ (per_function_data::~per_function_data): New decl.
+ (per_function_data::add_call_summary): Move implemention from
+ header.
+ (per_function_data::m_summaries): Update type of element.
+ * known-function-manager.h: Include "analyzer/analyzer-logging.h".
+ * program-point.h: Include "pretty-print.h" and
+ "analyzer/call-string.h".
+ * program-state.cc: Include "analyzer/call-summary.h".
+ (sm_state_map::replay_call_summary): New.
+ (program_state::replay_call_summary): New.
+ * program-state.h (sm_state_map::replay_call_summary): New decl.
+ (program_state::replay_call_summary): New decl.
+ * region-model-manager.cc
+ (region_model_manager::get_or_create_asm_output_svalue): New
+ overload.
+ * region-model-manager.h
+ (region_model_manager::get_or_create_asm_output_svalue): New
+ overload decl.
+ * region-model.cc: Include "analyzer/call-summary.h".
+ (region_model::maybe_update_for_edge): Remove call to
+ region_model::update_for_call_summary on
+ SUPEREDGE_INTRAPROCEDURAL_CALL.
+ (region_model::update_for_call_summary): Delete.
+ (region_model::replay_call_summary): New.
+ * region-model.h (region_model::replay_call_summary): New decl.
+ (region_model::update_for_call_summary): Delete decl.
+ * store.cc: Include "analyzer/call-summary.h".
+ (store::replay_call_summary): New.
+ (store::replay_call_summary_cluster): New.
+ * store.h: Include "tristate.h".
+ (is_a_helper <const ana::concrete_binding *>::test): New.
+ (store::replay_call_summary): New decl.
+ (store::replay_call_summary_cluster): New decl.
+ * supergraph.cc (get_ultimate_function_for_cgraph_edge): Remove
+ "static" from decl.
+ (supergraph_call_edge): Make stmt param const.
+ * supergraph.h: Include "ordered-hash-map.h", "cfg.h",
+ "basic-block.h", "gimple.h", "gimple-iterator.h", and "digraph.h".
+ (supergraph_call_edge): Make stmt param const.
+ (get_ultimate_function_for_cgraph_edge): New decl.
+ * svalue.cc (compound_svalue::compound_svalue): Assert that we're
+ not nesting compound_svalues.
+ * svalue.h: Include "json.h", "analyzer/store.h", and
+ "analyzer/program-point.h".
+ (asm_output_svalue::get_num_outputs): New accessor.
+
+2022-10-05 David Malcolm <dmalcolm@redhat.com>
+
+ * region-model.h: Include "analyzer/region-model-manager.h"
+ (class region_model_manager): Move decl to...
+ * region-model-manager.h: ...this new file.
+
+2022-10-05 David Malcolm <dmalcolm@redhat.com>
+
+ * region-model-manager.cc
+ (region_model_manager::maybe_fold_unaryop): Fold -(-(VAL)) to VAL.
+
+2022-10-05 David Malcolm <dmalcolm@redhat.com>
+
+ * region-model-manager.cc
+ (region_model_manager::get_or_create_widening_svalue): Use a
+ function_point rather than a program_point.
+ * region-model.cc (selftest::test_widening_constraints): Likewise.
+ * region-model.h
+ (region_model_manager::get_or_create_widening_svalue): Likewise.
+ (model_merger::get_function_point): New.
+ * svalue.cc (svalue::can_merge_p): Use a function_point rather
+ than a program_point.
+ (svalue::can_merge_p): Likewise.
+ * svalue.h (widening_svalue::key_t): Likewise.
+ (widening_svalue::widening_svalue): Likewise.
+
2022-09-12 Martin Liska <mliska@suse.cz>
* region-model.cc (region_model::maybe_complain_about_infoleak):
diff --git a/gcc/analyzer/analysis-plan.cc b/gcc/analyzer/analysis-plan.cc
index c488f37..a4a42c5 100644
--- a/gcc/analyzer/analysis-plan.cc
+++ b/gcc/analyzer/analysis-plan.cc
@@ -27,7 +27,6 @@ along with GCC; see the file COPYING3. If not see
#include "timevar.h"
#include "ipa-utils.h"
#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "diagnostic-core.h"
#include "analyzer/analyzer-logging.h"
@@ -35,7 +34,6 @@ along with GCC; see the file COPYING3. If not see
#include "ordered-hash-map.h"
#include "options.h"
#include "cgraph.h"
-#include "function.h"
#include "cfg.h"
#include "basic-block.h"
#include "gimple.h"
diff --git a/gcc/analyzer/analyzer-logging.h b/gcc/analyzer/analyzer-logging.h
index ef14b29..71b540c 100644
--- a/gcc/analyzer/analyzer-logging.h
+++ b/gcc/analyzer/analyzer-logging.h
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef ANALYZER_LOGGING_H
#define ANALYZER_LOGGING_H
+#include "diagnostic-core.h"
+
namespace ana {
/* A logger encapsulates a logging stream: a way to send
diff --git a/gcc/analyzer/analyzer-pass.cc b/gcc/analyzer/analyzer-pass.cc
index f6cef58..fc7098d 100644
--- a/gcc/analyzer/analyzer-pass.cc
+++ b/gcc/analyzer/analyzer-pass.cc
@@ -26,7 +26,6 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h"
#include "options.h"
#include "tree.h"
-#include "function.h"
#include "analyzer/analyzer.h"
#include "analyzer/engine.h"
diff --git a/gcc/analyzer/analyzer-selftests.cc b/gcc/analyzer/analyzer-selftests.cc
index 3765e70..278c245 100644
--- a/gcc/analyzer/analyzer-selftests.cc
+++ b/gcc/analyzer/analyzer-selftests.cc
@@ -23,7 +23,6 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "tree.h"
#include "stringpool.h"
-#include "function.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-selftests.h"
diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
index c85dbf3..8a2a773 100644
--- a/gcc/analyzer/analyzer.cc
+++ b/gcc/analyzer/analyzer.cc
@@ -27,7 +27,6 @@ along with GCC; see the file COPYING3. If not see
#include "gimple.h"
#include "diagnostic.h"
#include "intl.h"
-#include "function.h"
#include "analyzer/analyzer.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index b325aee..a2d79e4 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -21,6 +21,10 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ANALYZER_ANALYZER_H
#define GCC_ANALYZER_ANALYZER_H
+#include "function.h"
+#include "json.h"
+#include "tristate.h"
+
class graphviz_out;
namespace ana {
@@ -114,6 +118,10 @@ class state_machine;
class logger;
class visitor;
class known_function_manager;
+class call_summary;
+class call_summary_replay;
+struct per_function_data;
+struct interesting_t;
/* Forward decls of functions. */
@@ -263,6 +271,11 @@ public:
/* Hook for making .dot label more readable. */
virtual void print (pretty_printer *pp) const = 0;
+ /* Hook for updating STATE when handling bifurcation. */
+ virtual bool update_state (program_state *state,
+ const exploded_edge *eedge,
+ region_model_context *ctxt) const;
+
/* Hook for updating MODEL within exploded_path::feasible_p
and when handling bifurcation. */
virtual bool update_model (region_model *model,
diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc
index efc070b..56059ac 100644
--- a/gcc/analyzer/call-info.cc
+++ b/gcc/analyzer/call-info.cc
@@ -30,11 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "options.h"
#include "cgraph.h"
#include "tree-pretty-print.h"
-#include "tristate.h"
#include "bitmap.h"
-#include "selftest.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "ordered-hash-map.h"
@@ -56,9 +52,6 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-path.h"
#include "analyzer/checker-path.h"
#include "analyzer/diagnostic-manager.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
-#include "shortest-paths.h"
#include "analyzer/exploded-graph.h"
#include "analyzer/call-info.h"
@@ -66,7 +59,17 @@ along with GCC; see the file COPYING3. If not see
namespace ana {
-/* class call_info : public custom_eedge_info_t. */
+/* class custom_edge_info. */
+
+bool
+custom_edge_info::update_state (program_state *state,
+ const exploded_edge *eedge,
+ region_model_context *ctxt) const
+{
+ return update_model (state->m_region_model, eedge, ctxt);
+}
+
+/* class call_info : public custom_edge_info. */
/* Implementation of custom_edge_info::print vfunc for call_info:
use get_desc to get a label_text, and print it to PP. */
diff --git a/gcc/analyzer/call-string.cc b/gcc/analyzer/call-string.cc
index a09f569..f0a30d9 100644
--- a/gcc/analyzer/call-string.cc
+++ b/gcc/analyzer/call-string.cc
@@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see
#include "pretty-print.h"
#include "tree.h"
#include "options.h"
-#include "json.h"
#include "ordered-hash-map.h"
#include "options.h"
#include "cgraph.h"
diff --git a/gcc/analyzer/call-summary.cc b/gcc/analyzer/call-summary.cc
new file mode 100644
index 0000000..12ef82d
--- /dev/null
+++ b/gcc/analyzer/call-summary.cc
@@ -0,0 +1,889 @@
+/* Classes for working with summaries of function calls.
+ Copyright (C) 2022 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"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "tree-dfa.h"
+#include "diagnostic.h"
+#include "tree-diagnostic.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/region-model.h"
+#include "analyzer/call-summary.h"
+#include "analyzer/exploded-graph.h"
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* class call_summary. */
+
+const program_state &
+call_summary::get_state () const
+{
+ return m_enode->get_state ();
+}
+
+tree
+call_summary::get_fndecl () const
+{
+ return m_enode->get_point ().get_fndecl ();
+}
+
+label_text
+call_summary::get_desc () const
+{
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+
+ get_user_facing_desc (&pp);
+ if (flag_analyzer_verbose_edges)
+ pp_printf (&pp, " (call summary; EN: %i)", m_enode->m_index);
+
+ return label_text::take (xstrdup (pp_formatted_text (&pp)));
+}
+
+/* Generate a user-facing description of this call summary.c
+ This has various heuristics for distinguishing between different
+ summaries.
+ This will help with debugging, too. */
+
+void
+call_summary::get_user_facing_desc (pretty_printer *pp) const
+{
+ tree fndecl = get_fndecl ();
+
+ /* If there are multiple summaries, try to use the return value to
+ distinguish between them. */
+ if (m_per_fn_data->m_summaries.length () > 1)
+ {
+ if (tree result = DECL_RESULT (fndecl))
+ {
+ const region *result_reg
+ = get_state ().m_region_model->get_lvalue (result, NULL);
+ const svalue *result_sval
+ = get_state ().m_region_model->get_store_value (result_reg, NULL);
+ switch (result_sval->get_kind ())
+ {
+ default:
+ break;
+ case SK_REGION:
+ {
+ const region_svalue *region_sval
+ = as_a <const region_svalue *> (result_sval);
+ const region *pointee_reg = region_sval->get_pointee ();
+ switch (pointee_reg->get_kind ())
+ {
+ default:
+ break;
+ case RK_HEAP_ALLOCATED:
+ pp_printf (pp,
+ "when %qE returns pointer"
+ " to heap-allocated buffer",
+ fndecl);
+ return;
+ }
+ }
+ break;
+ case SK_CONSTANT:
+ {
+ const constant_svalue *constant_sval
+ = as_a <const constant_svalue *> (result_sval);
+ tree cst = constant_sval->get_constant ();
+ if (POINTER_TYPE_P (TREE_TYPE (result))
+ && zerop (cst))
+ pp_printf (pp, "when %qE returns NULL", fndecl);
+ else
+ pp_printf (pp, "when %qE returns %qE", fndecl, cst);
+ return;
+ }
+ }
+ }
+ }
+
+ /* Fallback. */
+ pp_printf (pp, "when %qE returns", fndecl);
+}
+
+/* Dump a multiline representation of this object to PP. */
+
+void
+call_summary::dump_to_pp (const extrinsic_state &ext_state,
+ pretty_printer *pp,
+ bool simple) const
+{
+ label_text desc = get_desc ();
+ pp_printf (pp, "desc: %qs", desc.get ());
+ pp_newline (pp);
+
+ get_state ().dump_to_pp (ext_state, simple, true, pp);
+}
+
+/* Dump a multiline representation of this object to FILE. */
+
+void
+call_summary::dump (const extrinsic_state &ext_state,
+ FILE *fp,
+ 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 = fp;
+ dump_to_pp (ext_state, &pp, simple);
+ pp_flush (&pp);
+}
+
+/* Dump a multiline representation of this object to stderr. */
+
+DEBUG_FUNCTION void
+call_summary::dump (const extrinsic_state &ext_state, bool simple) const
+{
+ dump (ext_state, stderr, simple);
+}
+
+/* class call_summary_replay. */
+
+/* call_summary_replay's ctor.
+ Populate the cache with params for the summary based on
+ arguments at the caller. */
+
+call_summary_replay::call_summary_replay (const call_details &cd,
+ function *called_fn,
+ call_summary *summary,
+ const extrinsic_state &ext_state)
+: m_cd (cd),
+ m_summary (summary),
+ m_ext_state (ext_state)
+{
+ region_model_manager *mgr = cd.get_manager ();
+
+ // populate params based on args
+ tree fndecl = called_fn->decl;
+
+ /* Get a frame_region for use with respect to the summary.
+ This will be a top-level frame, since that's what's in
+ the summary. */
+ const frame_region *summary_frame
+ = mgr->get_frame_region (NULL, called_fn);
+
+ unsigned idx = 0;
+ for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
+ iter_parm = DECL_CHAIN (iter_parm), ++idx)
+ {
+ /* If there's a mismatching declaration, the call stmt might
+ not have enough args. Handle this case by leaving the
+ rest of the params as uninitialized. */
+ if (idx >= cd.num_args ())
+ break;
+ const svalue *caller_arg_sval = cd.get_arg_svalue (idx);
+ tree parm_lval = iter_parm;
+ if (tree parm_default_ssa = ssa_default_def (called_fn, iter_parm))
+ parm_lval = parm_default_ssa;
+ const region *summary_parm_reg
+ = summary_frame->get_region_for_local (mgr, parm_lval, cd.get_ctxt ());
+ const svalue *summary_initial_parm_reg
+ = mgr->get_or_create_initial_value (summary_parm_reg);
+ add_svalue_mapping (summary_initial_parm_reg, caller_arg_sval);
+ }
+
+ /* Handle any variadic args. */
+ unsigned va_arg_idx = 0;
+ for (; idx < cd.num_args (); idx++, va_arg_idx++)
+ {
+ const svalue *caller_arg_sval = cd.get_arg_svalue (idx);
+ const region *summary_var_arg_reg
+ = mgr->get_var_arg_region (summary_frame, va_arg_idx);
+ const svalue *summary_initial_var_arg_reg
+ = mgr->get_or_create_initial_value (summary_var_arg_reg);
+ add_svalue_mapping (summary_initial_var_arg_reg, caller_arg_sval);
+ }
+}
+
+/* Try to convert SUMMARY_SVAL in the summary to a corresponding svalue
+ in the caller, caching the result.
+
+ Return NULL if the conversion is not possible. */
+
+const svalue *
+call_summary_replay::convert_svalue_from_summary (const svalue *summary_sval)
+{
+ gcc_assert (summary_sval);
+
+ if (const svalue **slot
+ = m_map_svalue_from_summary_to_caller.get (summary_sval))
+ return *slot;
+
+ const svalue *caller_sval = convert_svalue_from_summary_1 (summary_sval);
+
+ /* Add to cache. */
+ add_svalue_mapping (summary_sval, caller_sval);
+
+ return caller_sval;
+}
+
+/* Implementation of call_summary_replay::convert_svalue_from_summary. */
+
+const svalue *
+call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval)
+{
+ gcc_assert (summary_sval);
+
+ switch (summary_sval->get_kind ())
+ {
+ default:
+ gcc_unreachable ();
+ case SK_REGION:
+ {
+ const region_svalue *region_summary_sval
+ = as_a <const region_svalue *> (summary_sval);
+ const region *summary_reg = region_summary_sval->get_pointee ();
+ const region *caller_reg = convert_region_from_summary (summary_reg);
+ if (!caller_reg)
+ return NULL;
+ region_model_manager *mgr = get_manager ();
+ const svalue *caller_ptr
+ = mgr->get_ptr_svalue (summary_sval->get_type (),
+ caller_reg);
+ return caller_ptr;
+ }
+ break;
+
+ case SK_CONSTANT:
+ case SK_PLACEHOLDER:
+ case SK_POISONED:
+ case SK_UNKNOWN:
+ return summary_sval;
+
+ case SK_SETJMP:
+ return NULL; // TODO
+
+ case SK_INITIAL:
+ {
+ const initial_svalue *initial_summary_sval
+ = as_a <const initial_svalue *> (summary_sval);
+ /* Params should already be in the cache, courtesy of the ctor. */
+ gcc_assert (!initial_summary_sval->initial_value_of_param_p ());
+
+ /* Initial value of region within the summary is the value of the
+ region at the point of the call. */
+ const region *summary_reg = initial_summary_sval->get_region ();
+ const region *caller_reg = convert_region_from_summary (summary_reg);
+ if (!caller_reg)
+ return NULL;
+ const svalue *caller_sval
+ = m_cd.get_model ()->get_store_value (caller_reg, m_cd.get_ctxt ());
+ return caller_sval;
+ }
+ break;
+ case SK_UNARYOP:
+ {
+ const unaryop_svalue *unaryop_summary_sval
+ = as_a <const unaryop_svalue *> (summary_sval);
+ const svalue *summary_arg = unaryop_summary_sval->get_arg ();
+ const svalue *caller_arg = convert_svalue_from_summary (summary_arg);
+ if (!caller_arg)
+ return NULL;
+ region_model_manager *mgr = get_manager ();
+ return mgr->get_or_create_unaryop (summary_sval->get_type (),
+ unaryop_summary_sval->get_op (),
+ caller_arg);
+ }
+ break;
+ case SK_BINOP:
+ {
+ const binop_svalue *binop_summary_sval
+ = as_a <const binop_svalue *> (summary_sval);
+ const svalue *summary_arg0 = binop_summary_sval->get_arg0 ();
+ const svalue *caller_arg0 = convert_svalue_from_summary (summary_arg0);
+ if (!caller_arg0)
+ return NULL;
+ const svalue *summary_arg1 = binop_summary_sval->get_arg1 ();
+ const svalue *caller_arg1 = convert_svalue_from_summary (summary_arg1);
+ if (!caller_arg1)
+ return NULL;
+ region_model_manager *mgr = get_manager ();
+ return mgr->get_or_create_binop (summary_sval->get_type (),
+ binop_summary_sval->get_op (),
+ caller_arg0,
+ caller_arg1);
+ }
+ break;
+ case SK_SUB:
+ {
+ const sub_svalue *sub_summary_sval
+ = as_a <const sub_svalue *> (summary_sval);
+ region_model_manager *mgr = get_manager ();
+ const svalue *summary_parent_sval = sub_summary_sval->get_parent ();
+ if (!summary_parent_sval)
+ return NULL;
+ const region *summary_subregion = sub_summary_sval->get_subregion ();
+ if (!summary_subregion)
+ return NULL;
+ return mgr->get_or_create_sub_svalue (summary_sval->get_type (),
+ summary_parent_sval,
+ summary_subregion);
+ }
+ break;
+ case SK_REPEATED:
+ {
+ const repeated_svalue *repeated_summary_sval
+ = as_a <const repeated_svalue *> (summary_sval);
+ const svalue *summary_outer_size
+ = repeated_summary_sval->get_outer_size ();
+ const svalue *caller_outer_size
+ = convert_svalue_from_summary (summary_outer_size);
+ if (!caller_outer_size)
+ return NULL;
+ const svalue *summary_inner_sval
+ = repeated_summary_sval->get_inner_svalue ();
+ const svalue *caller_inner_sval
+ = convert_svalue_from_summary (summary_inner_sval);
+ if (!caller_inner_sval)
+ return NULL;
+ region_model_manager *mgr = get_manager ();
+ return mgr->get_or_create_repeated_svalue (summary_sval->get_type (),
+ caller_outer_size,
+ caller_inner_sval);
+ }
+ break;
+ case SK_BITS_WITHIN:
+ {
+ const bits_within_svalue *bits_within_summary_sval
+ = as_a <const bits_within_svalue *> (summary_sval);
+ const bit_range &bits = bits_within_summary_sval->get_bits ();
+ const svalue *summary_inner_sval
+ = bits_within_summary_sval->get_inner_svalue ();
+ const svalue *caller_inner_sval
+ = convert_svalue_from_summary (summary_inner_sval);
+ if (!caller_inner_sval)
+ return NULL;
+ region_model_manager *mgr = get_manager ();
+ return mgr->get_or_create_bits_within (summary_sval->get_type (),
+ bits,
+ caller_inner_sval);
+ }
+ break;
+ case SK_UNMERGEABLE:
+ {
+ const unmergeable_svalue *unmergeable_summary_sval
+ = as_a <const unmergeable_svalue *> (summary_sval);
+ const svalue *summary_arg_sval = unmergeable_summary_sval->get_arg ();
+ const svalue *caller_arg_sval
+ = convert_svalue_from_summary (summary_arg_sval);
+ if (!caller_arg_sval)
+ return NULL;
+ region_model_manager *mgr = get_manager ();
+ return mgr->get_or_create_unmergeable (caller_arg_sval);
+ }
+ break;
+ case SK_WIDENING:
+ {
+ const widening_svalue *widening_summary_sval
+ = as_a <const widening_svalue *> (summary_sval);
+ const function_point &point = widening_summary_sval->get_point ();
+ const svalue *summary_base_sval
+ = widening_summary_sval->get_base_svalue ();
+ const svalue *caller_base_sval
+ = convert_svalue_from_summary (summary_base_sval);
+ if (!(caller_base_sval
+ && caller_base_sval->can_have_associated_state_p ()))
+ return NULL;
+ const svalue *summary_iter_sval
+ = widening_summary_sval->get_iter_svalue ();
+ const svalue *caller_iter_sval
+ = convert_svalue_from_summary (summary_iter_sval);
+ if (!(caller_iter_sval
+ && caller_iter_sval->can_have_associated_state_p ()))
+ return NULL;
+ region_model_manager *mgr = get_manager ();
+ return mgr->get_or_create_widening_svalue
+ (summary_iter_sval->get_type (),
+ point,
+ caller_base_sval,
+ caller_iter_sval);
+ }
+ break;
+ case SK_COMPOUND:
+ {
+ const compound_svalue *compound_summary_sval
+ = as_a <const compound_svalue *> (summary_sval);
+ region_model_manager *mgr = get_manager ();
+ store_manager *store_mgr = mgr->get_store_manager ();
+ binding_map caller_map;
+ auto_vec <const binding_key *> summary_keys;
+ for (auto kv : *compound_summary_sval)
+ summary_keys.safe_push (kv.first);
+ summary_keys.qsort (binding_key::cmp_ptrs);
+ for (auto key : summary_keys)
+ {
+ gcc_assert (key->concrete_p ());
+ /* No remapping is needed for concrete binding keys. */
+
+ const svalue *bound_summary_sval
+ = compound_summary_sval->get_map ().get (key);
+ const svalue *caller_sval
+ = convert_svalue_from_summary (bound_summary_sval);
+ if (!caller_sval)
+ caller_sval = mgr->get_or_create_unknown_svalue (NULL_TREE);
+
+ if (const compound_svalue *inner_compound_sval
+ = caller_sval->dyn_cast_compound_svalue ())
+ {
+ const concrete_binding *outer_key
+ = as_a <const concrete_binding *> (key);
+ for (auto inner_kv : *inner_compound_sval)
+ {
+ // These should already be mapped to the caller.
+ const binding_key *inner_key = inner_kv.first;
+ const svalue *inner_sval = inner_kv.second;
+ gcc_assert (inner_key->concrete_p ());
+ const concrete_binding *concrete_key
+ = as_a <const concrete_binding *> (inner_key);
+ bit_offset_t effective_start
+ = (concrete_key->get_start_bit_offset ()
+ + outer_key->get_start_bit_offset ());
+ const concrete_binding *effective_concrete_key
+ = store_mgr->get_concrete_binding
+ (effective_start,
+ concrete_key->get_size_in_bits ());
+ caller_map.put (effective_concrete_key, inner_sval);
+ }
+ }
+ else
+ caller_map.put (key, caller_sval);
+ }
+ return mgr->get_or_create_compound_svalue (summary_sval->get_type (),
+ caller_map);
+ }
+ break;
+ case SK_CONJURED:
+ {
+ region_model_manager *mgr = get_manager ();
+ return mgr->get_or_create_unknown_svalue (summary_sval->get_type ());
+ }
+ break;
+ case SK_ASM_OUTPUT:
+ {
+ const asm_output_svalue *asm_output_summary_sval
+ = as_a <const asm_output_svalue *> (summary_sval);
+ const char *asm_string = asm_output_summary_sval->get_asm_string ();
+ unsigned output_idx = asm_output_summary_sval->get_output_idx ();
+ unsigned num_inputs = asm_output_summary_sval->get_num_inputs ();
+ unsigned num_outputs = asm_output_summary_sval->get_num_outputs ();
+ auto_vec<const svalue *> inputs (num_inputs);
+ for (unsigned idx = 0; idx < num_inputs; idx++)
+ {
+ const svalue *summary_input
+ = asm_output_summary_sval->get_input (idx);
+ const svalue *caller_input
+ = convert_svalue_from_summary (summary_input);
+ if (!caller_input)
+ return NULL;
+ inputs.safe_push (caller_input);
+ }
+ region_model_manager *mgr = get_manager ();
+ return mgr->get_or_create_asm_output_svalue (summary_sval->get_type (),
+ asm_string,
+ output_idx,
+ num_outputs,
+ inputs);
+ }
+ break;
+ case SK_CONST_FN_RESULT:
+ {
+ const const_fn_result_svalue *const_fn_result_summary_sval
+ = as_a <const const_fn_result_svalue *> (summary_sval);
+ tree fndecl = const_fn_result_summary_sval->get_fndecl ();
+ unsigned num_inputs = const_fn_result_summary_sval->get_num_inputs ();
+ auto_vec<const svalue *> inputs (num_inputs);
+ for (unsigned idx = 0; idx < num_inputs; idx++)
+ {
+ const svalue *summary_input
+ = const_fn_result_summary_sval->get_input (idx);
+ const svalue *caller_input
+ = convert_svalue_from_summary (summary_input);
+ if (!caller_input)
+ return NULL;
+ inputs.safe_push (caller_input);
+ }
+ region_model_manager *mgr = get_manager ();
+ return mgr->get_or_create_const_fn_result_svalue
+ (summary_sval->get_type (),
+ fndecl,
+ inputs);
+ }
+ break;
+ }
+}
+
+/* Try to convert SUMMARY_REG in the summary to a corresponding region
+ in the caller, caching the result.
+
+ Return NULL if the conversion is not possible. */
+
+const region *
+call_summary_replay::convert_region_from_summary (const region *summary_reg)
+{
+ gcc_assert (summary_reg);
+
+ if (const region **slot
+ = m_map_region_from_summary_to_caller.get (summary_reg))
+ return *slot;
+
+ const region *caller_reg = convert_region_from_summary_1 (summary_reg);
+
+ /* Add to cache. */
+ add_region_mapping (summary_reg, caller_reg);
+
+ return caller_reg;
+}
+
+/* Implementation of call_summary_replay::convert_region_from_summary. */
+
+const region *
+call_summary_replay::convert_region_from_summary_1 (const region *summary_reg)
+{
+ gcc_assert (summary_reg);
+
+ region_model_manager *mgr = get_manager ();
+ switch (summary_reg->get_kind ())
+ {
+ default:
+ gcc_unreachable ();
+ /* Top-level regions. */
+ case RK_FRAME:
+ case RK_GLOBALS:
+ case RK_CODE:
+ case RK_STACK:
+ case RK_HEAP:
+ case RK_ROOT:
+ /* These should never be pointed to by a region_svalue. */
+ gcc_unreachable ();
+
+ case RK_FUNCTION:
+ case RK_LABEL:
+ case RK_STRING:
+ case RK_UNKNOWN:
+ /* We can reuse these regions directly. */
+ return summary_reg;
+
+ case RK_SYMBOLIC:
+ {
+ const symbolic_region *summary_symbolic_reg
+ = as_a <const symbolic_region *> (summary_reg);
+ const svalue *summary_ptr_sval = summary_symbolic_reg->get_pointer ();
+ const svalue *caller_ptr_sval
+ = convert_svalue_from_summary (summary_ptr_sval);
+ if (!caller_ptr_sval)
+ return NULL;
+ const region *caller_reg
+ = get_caller_model ()->deref_rvalue (caller_ptr_sval,
+ NULL_TREE,
+ get_ctxt ());
+ return caller_reg;
+ }
+ break;
+
+ case RK_DECL:
+ {
+ const decl_region *summary_decl_reg
+ = as_a <const decl_region *> (summary_reg);
+ tree decl = summary_decl_reg->get_decl ();
+ switch (TREE_CODE (decl))
+ {
+ default:
+ gcc_unreachable ();
+ case SSA_NAME:
+ /* We don't care about writes to locals within
+ the summary. */
+ return NULL;
+ case VAR_DECL:
+ /* We don't care about writes to locals within
+ the summary. */
+ if (is_global_var (decl))
+ /* If it's a global, we can reuse the region directly. */
+ return summary_reg;
+ else
+ /* Otherwise, we don't care about locals. */
+ return NULL;
+ case RESULT_DECL:
+ return m_cd.get_lhs_region ();
+ case PARM_DECL:
+ /* Writes (by value) to parms should be visible to the caller. */
+ return NULL;
+ }
+ }
+ break;
+ case RK_FIELD:
+ {
+ const field_region *summary_field_reg
+ = as_a <const field_region *> (summary_reg);
+ const region *summary_parent_reg = summary_reg->get_parent_region ();
+ const region *caller_parent_reg
+ = convert_region_from_summary (summary_parent_reg);
+ if (!caller_parent_reg)
+ return NULL;
+ tree field = summary_field_reg->get_field ();
+ return mgr->get_field_region (caller_parent_reg, field);
+ }
+ break;
+ case RK_ELEMENT:
+ {
+ const element_region *summary_element_reg
+ = as_a <const element_region *> (summary_reg);
+ const region *summary_parent_reg = summary_reg->get_parent_region ();
+ const region *caller_parent_reg
+ = convert_region_from_summary (summary_parent_reg);
+ if (!caller_parent_reg)
+ return NULL;
+ const svalue *summary_index = summary_element_reg->get_index ();
+ const svalue *caller_index
+ = convert_svalue_from_summary (summary_index);
+ if (!caller_index)
+ return NULL;
+ return mgr->get_element_region (caller_parent_reg,
+ summary_reg->get_type (),
+ caller_index);
+ }
+ break;
+ case RK_OFFSET:
+ {
+ const offset_region *summary_offset_reg
+ = as_a <const offset_region *> (summary_reg);
+ const region *summary_parent_reg = summary_reg->get_parent_region ();
+ const region *caller_parent_reg
+ = convert_region_from_summary (summary_parent_reg);
+ if (!caller_parent_reg)
+ return NULL;
+ const svalue *summary_byte_offset
+ = summary_offset_reg->get_byte_offset ();
+ const svalue *caller_byte_offset
+ = convert_svalue_from_summary (summary_byte_offset);
+ if (!caller_byte_offset)
+ return NULL;
+ return mgr->get_offset_region (caller_parent_reg,
+ summary_reg->get_type (),
+ caller_byte_offset);
+ }
+ break;
+ case RK_SIZED:
+ {
+ const sized_region *summary_sized_reg
+ = as_a <const sized_region *> (summary_reg);
+ const region *summary_parent_reg = summary_reg->get_parent_region ();
+ const region *caller_parent_reg
+ = convert_region_from_summary (summary_parent_reg);
+ if (!caller_parent_reg)
+ return NULL;
+ const svalue *summary_byte_size
+ = summary_sized_reg->get_byte_size_sval (mgr);
+ const svalue *caller_byte_size
+ = convert_svalue_from_summary (summary_byte_size);
+ if (!caller_byte_size)
+ return NULL;
+ return mgr->get_sized_region (caller_parent_reg,
+ summary_reg->get_type (),
+ caller_byte_size);
+ }
+ break;
+ case RK_CAST:
+ {
+ const cast_region *summary_cast_reg
+ = as_a <const cast_region *> (summary_reg);
+ const region *summary_original_reg
+ = summary_cast_reg->get_original_region ();
+ const region *caller_original_reg
+ = convert_region_from_summary (summary_original_reg);
+ if (!caller_original_reg)
+ return NULL;
+ return mgr->get_cast_region (caller_original_reg,
+ summary_reg->get_type ());
+ }
+ break;
+ case RK_HEAP_ALLOCATED:
+ {
+ /* If we have a heap-allocated region in the summary, then
+ it was allocated within the callee.
+ Create a new heap-allocated region to summarize this. */
+ return mgr->create_region_for_heap_alloc ();
+ }
+ break;
+ case RK_ALLOCA:
+ return NULL;
+ case RK_BIT_RANGE:
+ {
+ const bit_range_region *summary_bit_range_reg
+ = as_a <const bit_range_region *> (summary_reg);
+ const region *summary_parent_reg = summary_reg->get_parent_region ();
+ const region *caller_parent_reg
+ = convert_region_from_summary (summary_parent_reg);
+ if (!caller_parent_reg)
+ return NULL;
+ const bit_range &bits = summary_bit_range_reg->get_bits ();
+ return mgr->get_bit_range (caller_parent_reg,
+ summary_reg->get_type (),
+ bits);
+ }
+ break;
+ case RK_VAR_ARG:
+ return NULL;
+ }
+}
+
+/* Try to convert SUMMARY_KEY in the summary to a corresponding binding key
+ in the caller.
+
+ Return NULL if the conversion is not possible. */
+
+const binding_key *
+call_summary_replay::convert_key_from_summary (const binding_key *summary_key)
+{
+ if (summary_key->concrete_p ())
+ return summary_key;
+
+ const symbolic_binding *symbolic_key = (const symbolic_binding *)summary_key;
+ const region *summary_reg = symbolic_key->get_region ();
+ const region *caller_reg = convert_region_from_summary (summary_reg);
+ if (!caller_reg)
+ return NULL;
+ region_model_manager *mgr = get_manager ();
+ store_manager *store_mgr = mgr->get_store_manager ();
+ return store_mgr->get_symbolic_binding (caller_reg);
+}
+
+/* Record that SUMMARY_SVAL maps to CALLER_SVAL for this replay. */
+
+void
+call_summary_replay::add_svalue_mapping (const svalue *summary_sval,
+ const svalue *caller_sval)
+{
+ gcc_assert (summary_sval);
+ // CALLER_SVAL can be NULL
+ m_map_svalue_from_summary_to_caller.put (summary_sval, caller_sval);
+}
+
+/* Record that SUMMARY_REG maps to CALLER_REG for this replay. */
+
+void
+call_summary_replay::add_region_mapping (const region *summary_reg,
+ const region *caller_reg)
+{
+ gcc_assert (summary_reg);
+ // CALLER_REG can be NULL
+ m_map_region_from_summary_to_caller.put (summary_reg, caller_reg);
+}
+
+/* Dump a multiline representation of this object to PP. */
+
+void
+call_summary_replay::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+ pp_newline (pp);
+ pp_string (pp, "CALL DETAILS:");
+ pp_newline (pp);
+ m_cd.dump_to_pp (pp, simple);
+
+ pp_newline (pp);
+ pp_string (pp, "CALLEE SUMMARY:");
+ pp_newline (pp);
+ m_summary->dump_to_pp (m_ext_state, pp, simple);
+
+ /* Current state of caller (could be in mid-update). */
+ pp_newline (pp);
+ pp_string (pp, "CALLER:");
+ pp_newline (pp);
+ m_cd.get_model ()->dump_to_pp (pp, simple, true);
+
+ pp_newline (pp);
+ pp_string (pp, "REPLAY STATE:");
+ pp_newline (pp);
+ pp_string (pp, "svalue mappings from summary to caller:");
+ pp_newline (pp);
+ auto_vec <const svalue *> summary_svals;
+ for (auto kv : m_map_svalue_from_summary_to_caller)
+ summary_svals.safe_push (kv.first);
+ summary_svals.qsort (svalue::cmp_ptr_ptr);
+ for (auto summary_sval : summary_svals)
+ {
+ pp_string (pp, "sval in summary: ");
+ summary_sval->dump_to_pp (pp, simple);
+ pp_newline (pp);
+
+ const svalue *caller_sval
+ = *((const_cast<svalue_map_t &>
+ (m_map_svalue_from_summary_to_caller)).get (summary_sval));
+ pp_string (pp, " sval in caller: ");
+ caller_sval->dump_to_pp (pp, simple);
+ pp_newline (pp);
+ }
+
+ pp_newline (pp);
+ pp_string (pp, "region mappings from summary to caller:");
+ pp_newline (pp);
+ auto_vec <const region *> summary_regs;
+ for (auto kv : m_map_region_from_summary_to_caller)
+ summary_regs.safe_push (kv.first);
+ summary_regs.qsort (region::cmp_ptr_ptr);
+ for (auto summary_reg : summary_regs)
+ {
+ pp_string (pp, "reg in summary: ");
+ if (summary_reg)
+ summary_reg->dump_to_pp (pp, simple);
+ else
+ pp_string (pp, "(null)");
+ pp_newline (pp);
+
+ const region *caller_reg
+ = *((const_cast<region_map_t &>
+ (m_map_region_from_summary_to_caller)).get (summary_reg));
+ pp_string (pp, " reg in caller: ");
+ if (caller_reg)
+ caller_reg->dump_to_pp (pp, simple);
+ else
+ pp_string (pp, "(null)");
+ pp_newline (pp);
+ }
+}
+
+/* Dump a multiline representation of this object to FILE. */
+
+void
+call_summary_replay::dump (FILE *fp, 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 = fp;
+ dump_to_pp (&pp, simple);
+ pp_flush (&pp);
+}
+
+/* Dump a multiline representation of this object to stderr. */
+
+DEBUG_FUNCTION void
+call_summary_replay::dump (bool simple) const
+{
+ dump (stderr, simple);
+}
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/call-summary.h b/gcc/analyzer/call-summary.h
new file mode 100644
index 0000000..07cd3f5
--- /dev/null
+++ b/gcc/analyzer/call-summary.h
@@ -0,0 +1,117 @@
+/* Classes for working with summaries of function calls.
+ Copyright (C) 2022 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_SUMMARY_H
+#define GCC_ANALYZER_CALL_SUMMARY_H
+
+namespace ana {
+
+/* A class summarizing one particular outcome of a function that
+ we've already analyzed.
+ This lets us efficiently replay the analysis when we see calls
+ to the function, providing an approximation of the behavior of
+ the function without having to execute within the function itself. */
+
+class call_summary
+{
+public:
+ call_summary (per_function_data *per_fn_data,
+ const exploded_node *enode)
+ : m_per_fn_data (per_fn_data),
+ m_enode (enode)
+ {}
+ const program_state &get_state () const;
+ tree get_fndecl () const;
+
+ label_text get_desc () const;
+
+ void dump_to_pp (const extrinsic_state &ext_state,
+ pretty_printer *pp,
+ bool simple) const;
+ void dump (const extrinsic_state &ext_state, FILE *fp, bool simple) const;
+ void dump (const extrinsic_state &ext_state, bool simple) const;
+
+private:
+ void get_user_facing_desc (pretty_printer *pp) const;
+
+ per_function_data *const m_per_fn_data;
+ const exploded_node *const m_enode;
+};
+
+/* A class for handling replaying a specific call summary at
+ a specific call site.
+
+ Supports remapping svalues and regions, e.g. remapping
+ INIT_VAL(param of callee)
+ to:
+ whatever that argument is at the call site. */
+
+class call_summary_replay
+{
+public:
+ call_summary_replay (const call_details &cd,
+ function *called_fn,
+ call_summary *m_summary,
+ const extrinsic_state &ext_state);
+
+ const call_details &get_call_details () const { return m_cd; }
+ const gcall *get_call_stmt () const { return m_cd.get_call_stmt (); }
+ region_model_manager *get_manager () const { return m_cd.get_manager (); }
+ store_manager *get_store_manager () const
+ {
+ return get_manager ()->get_store_manager ();
+ }
+ region_model_context *get_ctxt () const { return m_cd.get_ctxt (); }
+ region_model *get_caller_model () const { return m_cd.get_model (); }
+
+ const svalue *convert_svalue_from_summary (const svalue *);
+ const region *convert_region_from_summary (const region *);
+ const binding_key *convert_key_from_summary (const binding_key *);
+
+ void add_svalue_mapping (const svalue *summary_sval,
+ const svalue *caller_sval);
+ void add_region_mapping (const region *summary_sval,
+ const region *caller_sval);
+
+ void dump_to_pp (pretty_printer *pp, bool simple) const;
+ void dump (FILE *fp, bool simple) const;
+ void dump (bool simple) const;
+
+private:
+ DISABLE_COPY_AND_ASSIGN (call_summary_replay);
+
+ const svalue *convert_svalue_from_summary_1 (const svalue *);
+ const region *convert_region_from_summary_1 (const region *);
+
+ const call_details &m_cd;
+ call_summary *m_summary;
+ const extrinsic_state &m_ext_state;
+
+ // Mapping from svalues in summary to svalues for callsite:
+ typedef hash_map <const svalue *, const svalue *> svalue_map_t;
+ svalue_map_t m_map_svalue_from_summary_to_caller;
+
+ // Mapping from regions in summary to regions for callsite:
+ typedef hash_map <const region *, const region *> region_map_t;
+ region_map_t m_map_region_from_summary_to_caller;
+};
+
+} // namespace ana
+
+#endif /* GCC_ANALYZER_CALL_SUMMARY_H */
diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc
index 22bae2f..371111b 100644
--- a/gcc/analyzer/checker-path.cc
+++ b/gcc/analyzer/checker-path.cc
@@ -28,26 +28,18 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-core.h"
#include "gimple-pretty-print.h"
#include "fold-const.h"
-#include "function.h"
#include "diagnostic-path.h"
#include "options.h"
#include "cgraph.h"
-#include "function.h"
#include "cfg.h"
#include "digraph.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
#include "diagnostic-event-id.h"
-#include "shortest-paths.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "sbitmap.h"
#include "bitmap.h"
-#include "tristate.h"
#include "ordered-hash-map.h"
-#include "selftest.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
diff --git a/gcc/analyzer/complexity.cc b/gcc/analyzer/complexity.cc
index 40ae8f7..39fbbc1 100644
--- a/gcc/analyzer/complexity.cc
+++ b/gcc/analyzer/complexity.cc
@@ -38,11 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "fold-const.h"
#include "tree-pretty-print.h"
-#include "tristate.h"
#include "bitmap.h"
-#include "selftest.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "options.h"
diff --git a/gcc/analyzer/constraint-manager.cc b/gcc/analyzer/constraint-manager.cc
index 4133a13..96ae073 100644
--- a/gcc/analyzer/constraint-manager.cc
+++ b/gcc/analyzer/constraint-manager.cc
@@ -30,8 +30,6 @@ along with GCC; see the file COPYING3. If not see
#include "selftest.h"
#include "diagnostic-core.h"
#include "graphviz.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "ordered-hash-map.h"
#include "options.h"
@@ -41,13 +39,13 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/supergraph.h"
#include "sbitmap.h"
#include "bitmap.h"
-#include "tristate.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/constraint-manager.h"
+#include "analyzer/call-summary.h"
#include "analyzer/analyzer-selftests.h"
#include "tree-pretty-print.h"
@@ -3043,6 +3041,60 @@ constraint_manager::for_each_fact (fact_visitor *visitor) const
}
}
+/* Subclass of fact_visitor for use by
+ constraint_manager::replay_call_summary. */
+
+class replay_fact_visitor : public fact_visitor
+{
+public:
+ replay_fact_visitor (call_summary_replay &r,
+ constraint_manager *out)
+ : m_r (r), m_out (out), m_feasible (true)
+ {}
+
+ bool feasible_p () const { return m_feasible; }
+
+ void on_fact (const svalue *lhs, enum tree_code code, const svalue *rhs)
+ final override
+ {
+ const svalue *caller_lhs = m_r.convert_svalue_from_summary (lhs);
+ if (!caller_lhs)
+ return;
+ const svalue *caller_rhs = m_r.convert_svalue_from_summary (rhs);
+ if (!caller_rhs)
+ return;
+ if (!m_out->add_constraint (caller_lhs, code, caller_rhs))
+ m_feasible = false;
+ }
+
+ void on_ranges (const svalue *lhs_sval,
+ const bounded_ranges *ranges) final override
+ {
+ const svalue *caller_lhs = m_r.convert_svalue_from_summary (lhs_sval);
+ if (!caller_lhs)
+ return;
+ if (!m_out->add_bounded_ranges (caller_lhs, ranges))
+ m_feasible = false;
+ }
+
+private:
+ call_summary_replay &m_r;
+ constraint_manager *m_out;
+ bool m_feasible;
+};
+
+/* Attempt to use R to replay the constraints from SUMMARY into this object.
+ Return true if it is feasible. */
+
+bool
+constraint_manager::replay_call_summary (call_summary_replay &r,
+ const constraint_manager &summary)
+{
+ replay_fact_visitor v (r, this);
+ summary.for_each_fact (&v);
+ return v.feasible_p ();
+}
+
/* Assert that this object is valid. */
void
diff --git a/gcc/analyzer/constraint-manager.h b/gcc/analyzer/constraint-manager.h
index 1271f18..daacaa3 100644
--- a/gcc/analyzer/constraint-manager.h
+++ b/gcc/analyzer/constraint-manager.h
@@ -487,6 +487,9 @@ public:
bounded_ranges_manager *get_range_manager () const;
+ bool replay_call_summary (call_summary_replay &r,
+ const constraint_manager &summary);
+
auto_delete_vec<equiv_class> m_equiv_classes;
auto_vec<constraint> m_constraints;
auto_vec<bounded_ranges_constraint> m_bounded_ranges_constraints;
diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index 2d185a1..695bde5 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -29,15 +29,8 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-core.h"
#include "diagnostic-event-id.h"
#include "diagnostic-path.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
-#include "shortest-paths.h"
-#include "sbitmap.h"
#include "bitmap.h"
-#include "tristate.h"
-#include "selftest.h"
#include "ordered-hash-map.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 742ac02..46bcaed 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -25,9 +25,6 @@ along with GCC; see the file COPYING3. If not see
#include "tree.h"
#include "fold-const.h"
#include "gcc-rich-location.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
-#include "shortest-paths.h"
#include "diagnostic-core.h"
#include "diagnostic-event-id.h"
#include "diagnostic-path.h"
@@ -35,10 +32,7 @@ along with GCC; see the file COPYING3. If not see
#include "pretty-print.h"
#include "sbitmap.h"
#include "bitmap.h"
-#include "tristate.h"
#include "ordered-hash-map.h"
-#include "selftest.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
@@ -72,6 +66,7 @@ along with GCC; see the file COPYING3. If not see
#include "attribs.h"
#include "tree-dfa.h"
#include "analyzer/known-function-manager.h"
+#include "analyzer/call-summary.h"
/* For an overview, see gcc/doc/analyzer.texi. */
@@ -171,6 +166,8 @@ void
impl_region_model_context::on_unknown_change (const svalue *sval,
bool is_mutable)
{
+ if (!sval->can_have_associated_state_p ())
+ return;
for (sm_state_map *smap : m_new_state->m_checker_states)
smap->on_unknown_change (sval, is_mutable, m_ext_state);
}
@@ -1425,6 +1422,25 @@ exploded_node::on_stmt (exploded_graph &eg,
&old_state, state, uncertainty,
path_ctxt, stmt);
+ /* Handle call summaries here. */
+ if (cgraph_edge *cgedge
+ = supergraph_call_edge (snode->get_function (), stmt))
+ if (eg.get_analysis_plan ().use_summary_p (cgedge))
+ {
+ function *called_fn = get_ultimate_function_for_cgraph_edge (cgedge);
+ per_function_data *called_fn_data
+ = eg.get_per_function_data (called_fn);
+ if (called_fn_data)
+ return replay_call_summaries (eg,
+ snode,
+ as_a <const gcall *> (stmt),
+ state,
+ path_ctxt,
+ called_fn,
+ called_fn_data,
+ &ctxt);
+ }
+
bool unknown_side_effects = false;
bool terminate_path = false;
@@ -1520,6 +1536,140 @@ exploded_node::on_stmt_post (const gimple *stmt,
state->m_region_model->on_call_post (call, unknown_side_effects, ctxt);
}
+/* A concrete call_info subclass representing a replay of a call summary. */
+
+class call_summary_edge_info : public call_info
+{
+public:
+ call_summary_edge_info (const call_details &cd,
+ function *called_fn,
+ call_summary *summary,
+ const extrinsic_state &ext_state)
+ : call_info (cd),
+ m_called_fn (called_fn),
+ m_summary (summary),
+ m_ext_state (ext_state)
+ {}
+
+ bool update_state (program_state *state,
+ const exploded_edge *,
+ region_model_context *ctxt) const final override
+ {
+ /* Update STATE based on summary_end_state. */
+ call_details cd (get_call_details (state->m_region_model, ctxt));
+ call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
+ const program_state &summary_end_state = m_summary->get_state ();
+ return state->replay_call_summary (r, summary_end_state);
+ }
+
+ bool update_model (region_model *model,
+ const exploded_edge *,
+ region_model_context *ctxt) const final override
+ {
+ /* Update STATE based on summary_end_state. */
+ call_details cd (get_call_details (model, ctxt));
+ call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
+ const program_state &summary_end_state = m_summary->get_state ();
+ model->replay_call_summary (r, *summary_end_state.m_region_model);
+ return true;
+ }
+
+ label_text get_desc (bool /*can_colorize*/) const final override
+ {
+ return m_summary->get_desc ();
+ }
+
+private:
+ function *m_called_fn;
+ call_summary *m_summary;
+ const extrinsic_state &m_ext_state;
+};
+
+/* Use PATH_CTXT to bifurcate, which when handled will add custom edges
+ for a replay of the various feasible summaries in CALLED_FN_DATA. */
+
+exploded_node::on_stmt_flags
+exploded_node::replay_call_summaries (exploded_graph &eg,
+ const supernode *snode,
+ const gcall *call_stmt,
+ program_state *state,
+ path_context *path_ctxt,
+ function *called_fn,
+ per_function_data *called_fn_data,
+ region_model_context *ctxt)
+{
+ logger *logger = eg.get_logger ();
+ LOG_SCOPE (logger);
+
+ gcc_assert (called_fn);
+ gcc_assert (called_fn_data);
+
+ /* Each summary will call bifurcate on the PATH_CTXT. */
+ for (auto summary : called_fn_data->m_summaries)
+ replay_call_summary (eg, snode, call_stmt, state,
+ path_ctxt, called_fn, summary, ctxt);
+ path_ctxt->terminate_path ();
+
+ return on_stmt_flags ();
+}
+
+/* Use PATH_CTXT to bifurcate, which when handled will add a
+ custom edge for a replay of SUMMARY, if the summary's
+ conditions are feasible based on the current state. */
+
+void
+exploded_node::replay_call_summary (exploded_graph &eg,
+ const supernode *snode,
+ const gcall *call_stmt,
+ program_state *old_state,
+ path_context *path_ctxt,
+ function *called_fn,
+ call_summary *summary,
+ region_model_context *ctxt)
+{
+ logger *logger = eg.get_logger ();
+ LOG_SCOPE (logger);
+ gcc_assert (snode);
+ gcc_assert (call_stmt);
+ gcc_assert (old_state);
+ gcc_assert (called_fn);
+ gcc_assert (summary);
+
+ if (logger)
+ logger->log ("using %s as summary for call to %qE from %qE",
+ summary->get_desc ().get (),
+ called_fn->decl,
+ snode->get_function ()->decl);
+ const extrinsic_state &ext_state = eg.get_ext_state ();
+ const program_state &summary_end_state = summary->get_state ();
+ if (logger)
+ {
+ pretty_printer *pp = logger->get_printer ();
+
+ logger->start_log_line ();
+ pp_string (pp, "callsite state: ");
+ old_state->dump_to_pp (ext_state, true, false, pp);
+ logger->end_log_line ();
+
+ logger->start_log_line ();
+ pp_string (pp, "summary end state: ");
+ summary_end_state.dump_to_pp (ext_state, true, false, pp);
+ logger->end_log_line ();
+ }
+
+ program_state new_state (*old_state);
+
+ call_details cd (call_stmt, new_state.m_region_model, ctxt);
+ call_summary_replay r (cd, called_fn, summary, ext_state);
+
+ if (path_ctxt)
+ path_ctxt->bifurcate (new call_summary_edge_info (cd,
+ called_fn,
+ summary,
+ ext_state));
+}
+
+
/* Consider the effect of following superedge SUCC from this node.
Return true if it's feasible to follow the edge, or false
@@ -2115,6 +2265,20 @@ stats::get_total_enodes () const
return result;
}
+/* struct per_function_data. */
+
+per_function_data::~per_function_data ()
+{
+ for (auto iter : m_summaries)
+ delete iter;
+}
+
+void
+per_function_data::add_call_summary (exploded_node *node)
+{
+ m_summaries.safe_push (new call_summary (this, node));
+}
+
/* strongly_connected_components's ctor. Tarjan's SCC algorithm. */
strongly_connected_components::
@@ -3980,7 +4144,7 @@ exploded_graph::process_node (exploded_node *node)
NULL, // uncertainty_t *uncertainty
NULL, // path_context *path_ctxt
stmt);
- if (edge_info->update_model (bifurcated_new_state.m_region_model,
+ if (edge_info->update_state (&bifurcated_new_state,
NULL, /* no exploded_edge yet. */
&bifurcation_ctxt))
{
@@ -5350,24 +5514,17 @@ public:
pretty_printer *pp = gv->get_pp ();
dump_dot_id (pp);
- pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=<",
+ pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
"lightgrey");
- pp_string (pp, "<TABLE BORDER=\"0\">");
pp_write_text_to_stream (pp);
- gv->begin_trtd ();
pp_printf (pp, "VCG: %i: %s", m_index, function_name (m_fun));
- gv->end_tdtr ();
pp_newline (pp);
- gv->begin_trtd ();
pp_printf (pp, "supernodes: %i\n", m_num_supernodes);
- gv->end_tdtr ();
pp_newline (pp);
- gv->begin_trtd ();
pp_printf (pp, "superedges: %i\n", m_num_superedges);
- gv->end_tdtr ();
pp_newline (pp);
if (args.m_eg)
@@ -5380,9 +5537,7 @@ public:
if (enode->get_point ().get_function () == m_fun)
num_enodes++;
}
- gv->begin_trtd ();
pp_printf (pp, "enodes: %i\n", num_enodes);
- gv->end_tdtr ();
pp_newline (pp);
// TODO: also show the per-callstring breakdown
@@ -5404,11 +5559,8 @@ public:
}
if (num_enodes > 0)
{
- gv->begin_trtd ();
cs->print (pp);
pp_printf (pp, ": %i\n", num_enodes);
- pp_write_text_as_html_like_dot_to_stream (pp);
- gv->end_tdtr ();
}
}
@@ -5417,14 +5569,20 @@ public:
if (data)
{
pp_newline (pp);
- gv->begin_trtd ();
pp_printf (pp, "summaries: %i\n", data->m_summaries.length ());
- pp_write_text_as_html_like_dot_to_stream (pp);
- gv->end_tdtr ();
+ for (auto summary : data->m_summaries)
+ {
+ pp_printf (pp, "\nsummary: %s:\n", summary->get_desc ().get ());
+ const extrinsic_state &ext_state = args.m_eg->get_ext_state ();
+ const program_state &state = summary->get_state ();
+ state.dump_to_pp (ext_state, false, true, pp);
+ pp_newline (pp);
+ }
}
}
- pp_string (pp, "</TABLE>>];\n\n");
+ pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
+ pp_string (pp, "\"];\n\n");
pp_flush (pp);
}
diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h
index f957568..11e46ca 100644
--- a/gcc/analyzer/exploded-graph.h
+++ b/gcc/analyzer/exploded-graph.h
@@ -21,6 +21,15 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ANALYZER_EXPLODED_GRAPH_H
#define GCC_ANALYZER_EXPLODED_GRAPH_H
+#include "alloc-pool.h"
+#include "fibonacci_heap.h"
+#include "supergraph.h"
+#include "sbitmap.h"
+#include "shortest-paths.h"
+#include "analyzer/sm.h"
+#include "analyzer/program-state.h"
+#include "analyzer/diagnostic-manager.h"
+
namespace ana {
/* Concrete implementation of region_model_context, wiring it up to the
@@ -258,6 +267,23 @@ class exploded_node : public dnode<eg_traits>
bool unknown_side_effects,
region_model_context *ctxt);
+ on_stmt_flags replay_call_summaries (exploded_graph &eg,
+ const supernode *snode,
+ const gcall *call_stmt,
+ program_state *state,
+ path_context *path_ctxt,
+ function *called_fn,
+ per_function_data *called_fn_data,
+ region_model_context *ctxt);
+ void replay_call_summary (exploded_graph &eg,
+ const supernode *snode,
+ const gcall *call_stmt,
+ program_state *state,
+ path_context *path_ctxt,
+ function *called_fn,
+ call_summary *summary,
+ region_model_context *ctxt);
+
bool on_edge (exploded_graph &eg,
const superedge *succ,
program_point *next_point,
@@ -611,13 +637,11 @@ struct per_call_string_data
struct per_function_data
{
per_function_data () {}
+ ~per_function_data ();
- void add_call_summary (exploded_node *node)
- {
- m_summaries.safe_push (node);
- }
+ void add_call_summary (exploded_node *node);
- auto_vec<exploded_node *> m_summaries;
+ auto_vec<call_summary *> m_summaries;
};
diff --git a/gcc/analyzer/feasible-graph.cc b/gcc/analyzer/feasible-graph.cc
index fe7e79f..a946e4c 100644
--- a/gcc/analyzer/feasible-graph.cc
+++ b/gcc/analyzer/feasible-graph.cc
@@ -29,15 +29,8 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-core.h"
#include "diagnostic-event-id.h"
#include "diagnostic-path.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
-#include "shortest-paths.h"
-#include "sbitmap.h"
#include "bitmap.h"
-#include "tristate.h"
-#include "selftest.h"
#include "ordered-hash-map.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
diff --git a/gcc/analyzer/known-function-manager.cc b/gcc/analyzer/known-function-manager.cc
index f0fd4fc..48fb005 100644
--- a/gcc/analyzer/known-function-manager.cc
+++ b/gcc/analyzer/known-function-manager.cc
@@ -22,7 +22,6 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "tree.h"
-#include "function.h"
#include "analyzer/analyzer.h"
#include "diagnostic-core.h"
#include "analyzer/analyzer-logging.h"
diff --git a/gcc/analyzer/known-function-manager.h b/gcc/analyzer/known-function-manager.h
index fbde853..2b95b7e 100644
--- a/gcc/analyzer/known-function-manager.h
+++ b/gcc/analyzer/known-function-manager.h
@@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ANALYZER_KNOWN_FUNCTION_MANAGER_H
#define GCC_ANALYZER_KNOWN_FUNCTION_MANAGER_H
+#include "analyzer/analyzer-logging.h"
+
namespace ana {
class known_function_manager : public log_user
diff --git a/gcc/analyzer/pending-diagnostic.cc b/gcc/analyzer/pending-diagnostic.cc
index eff050f..50a8afc 100644
--- a/gcc/analyzer/pending-diagnostic.cc
+++ b/gcc/analyzer/pending-diagnostic.cc
@@ -24,8 +24,6 @@ along with GCC; see the file COPYING3. If not see
#include "tree.h"
#include "intl.h"
#include "diagnostic.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "diagnostic-event-id.h"
#include "analyzer/analyzer-logging.h"
@@ -34,8 +32,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
-#include "selftest.h"
-#include "tristate.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
@@ -50,10 +46,6 @@ along with GCC; see the file COPYING3. If not see
#include "cgraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
-#include "shortest-paths.h"
-#include "sbitmap.h"
#include "analyzer/exploded-graph.h"
#include "diagnostic-path.h"
#include "analyzer/checker-path.h"
diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc
index 6c296d5..cfa4dda 100644
--- a/gcc/analyzer/program-point.cc
+++ b/gcc/analyzer/program-point.cc
@@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see
#include "tree.h"
#include "gimple-pretty-print.h"
#include "gcc-rich-location.h"
-#include "json.h"
#include "ordered-hash-map.h"
#include "options.h"
#include "cgraph.h"
@@ -41,14 +40,11 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/program-point.h"
#include "sbitmap.h"
#include "bitmap.h"
-#include "tristate.h"
#include "selftest.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/sm.h"
#include "analyzer/program-state.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
#include "diagnostic-event-id.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
diff --git a/gcc/analyzer/program-point.h b/gcc/analyzer/program-point.h
index 63f7224..f72b86d 100644
--- a/gcc/analyzer/program-point.h
+++ b/gcc/analyzer/program-point.h
@@ -21,6 +21,9 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ANALYZER_PROGRAM_POINT_H
#define GCC_ANALYZER_PROGRAM_POINT_H
+#include "pretty-print.h"
+#include "analyzer/call-string.h"
+
namespace ana {
class exploded_graph;
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index f0f4046..7537dc0 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -24,14 +24,11 @@ along with GCC; see the file COPYING3. If not see
#include "tree.h"
#include "diagnostic-core.h"
#include "diagnostic.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "sbitmap.h"
#include "bitmap.h"
-#include "tristate.h"
#include "ordered-hash-map.h"
#include "selftest.h"
#include "analyzer/call-string.h"
@@ -40,9 +37,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/region-model.h"
#include "analyzer/program-state.h"
#include "analyzer/constraint-manager.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
-#include "shortest-paths.h"
#include "diagnostic-event-id.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
@@ -56,6 +50,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
#include "analyzer/state-purge.h"
+#include "analyzer/call-summary.h"
#include "analyzer/analyzer-selftests.h"
#if ENABLE_ANALYZER
@@ -743,6 +738,31 @@ program_state::program_state (const extrinsic_state &ext_state)
}
}
+/* Attempt to to use R to replay SUMMARY into this object.
+ Return true if it is possible. */
+
+bool
+sm_state_map::replay_call_summary (call_summary_replay &r,
+ const sm_state_map &summary)
+{
+ for (auto kv : summary.m_map)
+ {
+ const svalue *summary_sval = kv.first;
+ const svalue *caller_sval = r.convert_svalue_from_summary (summary_sval);
+ if (!caller_sval)
+ continue;
+ const svalue *summary_origin = kv.second.m_origin;
+ const svalue *caller_origin
+ = (summary_origin
+ ? r.convert_svalue_from_summary (summary_origin)
+ : NULL);
+ // caller_origin can be NULL.
+ m_map.put (caller_sval, entry_t (kv.second.m_state, caller_origin));
+ }
+ m_global_state = summary.m_global_state;
+ return true;
+}
+
/* program_state's copy ctor. */
program_state::program_state (const program_state &other)
@@ -1437,6 +1457,28 @@ program_state::detect_leaks (const program_state &src_state,
dest_state.m_region_model->unset_dynamic_extents (reg);
}
+/* Attempt to to use R to replay SUMMARY into this object.
+ Return true if it is possible. */
+
+bool
+program_state::replay_call_summary (call_summary_replay &r,
+ const program_state &summary)
+{
+ if (!m_region_model->replay_call_summary (r, *summary.m_region_model))
+ return false;
+
+ for (unsigned sm_idx = 0; sm_idx < m_checker_states.length (); sm_idx++)
+ {
+ const sm_state_map *summary_sm_map = summary.m_checker_states[sm_idx];
+ m_checker_states[sm_idx]->replay_call_summary (r, *summary_sm_map);
+ }
+
+ if (!summary.m_valid)
+ m_valid = false;
+
+ return true;
+}
+
/* Handle calls to "__analyzer_dump_state". */
void
diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h
index baab787..ad40578 100644
--- a/gcc/analyzer/program-state.h
+++ b/gcc/analyzer/program-state.h
@@ -171,6 +171,9 @@ public:
static const svalue *
canonicalize_svalue (const svalue *sval, const extrinsic_state &ext_state);
+ bool replay_call_summary (call_summary_replay &r,
+ const sm_state_map &summary);
+
private:
const state_machine &m_sm;
map_t m_map;
@@ -273,6 +276,9 @@ public:
const extrinsic_state &ext_state,
region_model_context *ctxt);
+ bool replay_call_summary (call_summary_replay &r,
+ const program_state &summary);
+
void impl_call_analyzer_dump_state (const gcall *call,
const extrinsic_state &ext_state,
region_model_context *ctxt);
diff --git a/gcc/analyzer/region-model-asm.cc b/gcc/analyzer/region-model-asm.cc
index bb73e6e..b4c1f91 100644
--- a/gcc/analyzer/region-model-asm.cc
+++ b/gcc/analyzer/region-model-asm.cc
@@ -28,9 +28,6 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-iterator.h"
#include "diagnostic-core.h"
#include "pretty-print.h"
-#include "tristate.h"
-#include "selftest.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "options.h"
diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc
index 71fb277..8f4940a 100644
--- a/gcc/analyzer/region-model-impl-calls.cc
+++ b/gcc/analyzer/region-model-impl-calls.cc
@@ -38,18 +38,11 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print.h"
#include "diagnostic-color.h"
#include "diagnostic-metadata.h"
-#include "tristate.h"
#include "bitmap.h"
-#include "selftest.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "ordered-hash-map.h"
#include "options.h"
-#include "cgraph.h"
-#include "cfg.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "sbitmap.h"
#include "analyzer/call-string.h"
@@ -374,6 +367,16 @@ region_model::impl_call_analyzer_eval (const gcall *call,
warning_at (call->location, 0, "%s", t.as_string ());
}
+/* Handle the on_call_pre part of "__analyzer_get_unknown_ptr". */
+
+void
+region_model::impl_call_analyzer_get_unknown_ptr (const call_details &cd)
+{
+ const svalue *ptr_sval
+ = m_mgr->get_or_create_unknown_svalue (cd.get_lhs_type ());
+ cd.maybe_set_lhs (ptr_sval);
+}
+
/* Handle the on_call_pre part of "__builtin_expect" etc. */
void
diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
index cbda77f..f5999e6 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -38,18 +38,11 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "fold-const.h"
#include "tree-pretty-print.h"
-#include "tristate.h"
#include "bitmap.h"
-#include "selftest.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "ordered-hash-map.h"
#include "options.h"
-#include "cgraph.h"
-#include "cfg.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "sbitmap.h"
#include "analyzer/call-string.h"
@@ -432,6 +425,17 @@ region_model_manager::maybe_fold_unaryop (tree type, enum tree_code op,
}
}
break;
+ case NEGATE_EXPR:
+ {
+ /* -(-(VAL)) is VAL, for integer types. */
+ if (const unaryop_svalue *unaryop = arg->dyn_cast_unaryop_svalue ())
+ if (unaryop->get_op () == NEGATE_EXPR
+ && type == unaryop->get_type ()
+ && type
+ && INTEGRAL_TYPE_P (type))
+ return unaryop->get_arg ();
+ }
+ break;
}
/* Constants. */
@@ -1143,10 +1147,11 @@ region_model_manager::get_or_create_unmergeable (const svalue *arg)
and ITER_SVAL at POINT, creating it if necessary. */
const svalue *
-region_model_manager::get_or_create_widening_svalue (tree type,
- const program_point &point,
- const svalue *base_sval,
- const svalue *iter_sval)
+region_model_manager::
+get_or_create_widening_svalue (tree type,
+ const function_point &point,
+ const svalue *base_sval,
+ const svalue *iter_sval)
{
gcc_assert (base_sval->get_kind () != SK_WIDENING);
gcc_assert (iter_sval->get_kind () != SK_WIDENING);
@@ -1263,6 +1268,33 @@ get_or_create_asm_output_svalue (tree type,
return asm_output_sval;
}
+/* Return the svalue * of type TYPE for OUTPUT_IDX of a deterministic
+ asm stmt with string ASM_STRING with NUM_OUTPUTS outputs, given
+ INPUTS as inputs. */
+
+const svalue *
+region_model_manager::
+get_or_create_asm_output_svalue (tree type,
+ const char *asm_string,
+ unsigned output_idx,
+ unsigned num_outputs,
+ const vec<const svalue *> &inputs)
+{
+ gcc_assert (inputs.length () <= asm_output_svalue::MAX_INPUTS);
+
+ if (const svalue *folded
+ = maybe_fold_asm_output_svalue (type, inputs))
+ return folded;
+
+ asm_output_svalue::key_t key (type, asm_string, output_idx, inputs);
+ if (asm_output_svalue **slot = m_asm_output_values_map.get (key))
+ return *slot;
+ asm_output_svalue *asm_output_sval
+ = new asm_output_svalue (type, asm_string, output_idx, num_outputs, inputs);
+ RETURN_UNKNOWN_IF_TOO_COMPLEX (asm_output_sval);
+ m_asm_output_values_map.put (key, asm_output_sval);
+ return asm_output_sval;
+}
/* Return the svalue * of type TYPE for the result of a call to FNDECL
with __attribute__((const)), given INPUTS as inputs. */
diff --git a/gcc/analyzer/region-model-manager.h b/gcc/analyzer/region-model-manager.h
new file mode 100644
index 0000000..3d8f76e
--- /dev/null
+++ b/gcc/analyzer/region-model-manager.h
@@ -0,0 +1,318 @@
+/* Consolidation of svalues and regions.
+ 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/>. */
+
+#ifndef GCC_ANALYZER_REGION_MODEL_MANAGER_H
+#define GCC_ANALYZER_REGION_MODEL_MANAGER_H
+
+namespace ana {
+
+/* A class responsible for owning and consolidating region and svalue
+ instances.
+ region and svalue instances are immutable as far as clients are
+ concerned, so they are provided as "const" ptrs. */
+
+class region_model_manager
+{
+public:
+ region_model_manager (logger *logger = NULL);
+ ~region_model_manager ();
+
+ /* call_string consolidation. */
+ const call_string &get_empty_call_string () const
+ {
+ return m_empty_call_string;
+ }
+
+ /* svalue consolidation. */
+ const svalue *get_or_create_constant_svalue (tree cst_expr);
+ const svalue *get_or_create_int_cst (tree type, poly_int64);
+ const svalue *get_or_create_unknown_svalue (tree type);
+ const svalue *get_or_create_setjmp_svalue (const setjmp_record &r,
+ tree type);
+ const svalue *get_or_create_poisoned_svalue (enum poison_kind kind,
+ tree type);
+ const svalue *get_or_create_initial_value (const region *reg);
+ const svalue *get_ptr_svalue (tree ptr_type, const region *pointee);
+ const svalue *get_or_create_unaryop (tree type, enum tree_code op,
+ const svalue *arg);
+ const svalue *get_or_create_cast (tree type, const svalue *arg);
+ const svalue *get_or_create_binop (tree type,
+ enum tree_code op,
+ const svalue *arg0, const svalue *arg1);
+ const svalue *get_or_create_sub_svalue (tree type,
+ const svalue *parent_svalue,
+ const region *subregion);
+ const svalue *get_or_create_repeated_svalue (tree type,
+ const svalue *outer_size,
+ const svalue *inner_svalue);
+ const svalue *get_or_create_bits_within (tree type,
+ const bit_range &bits,
+ const svalue *inner_svalue);
+ const svalue *get_or_create_unmergeable (const svalue *arg);
+ const svalue *get_or_create_widening_svalue (tree type,
+ const function_point &point,
+ const svalue *base_svalue,
+ const svalue *iter_svalue);
+ const svalue *get_or_create_compound_svalue (tree type,
+ const binding_map &map);
+ const svalue *get_or_create_conjured_svalue (tree type, const gimple *stmt,
+ const region *id_reg,
+ const conjured_purge &p);
+ const svalue *
+ get_or_create_asm_output_svalue (tree type,
+ const gasm *asm_stmt,
+ unsigned output_idx,
+ const vec<const svalue *> &inputs);
+ const svalue *
+ get_or_create_asm_output_svalue (tree type,
+ const char *asm_string,
+ unsigned output_idx,
+ unsigned num_outputs,
+ const vec<const svalue *> &inputs);
+ const svalue *
+ get_or_create_const_fn_result_svalue (tree type,
+ tree fndecl,
+ const vec<const svalue *> &inputs);
+
+ const svalue *maybe_get_char_from_string_cst (tree string_cst,
+ tree byte_offset_cst);
+
+ /* Dynamically-allocated svalue instances.
+ The number of these within the analysis can grow arbitrarily.
+ They are still owned by the manager. */
+ const svalue *create_unique_svalue (tree type);
+
+ /* region consolidation. */
+ const stack_region * get_stack_region () const { return &m_stack_region; }
+ const heap_region *get_heap_region () const { return &m_heap_region; }
+ const code_region *get_code_region () const { return &m_code_region; }
+ const globals_region *get_globals_region () const
+ {
+ return &m_globals_region;
+ }
+ const function_region *get_region_for_fndecl (tree fndecl);
+ const label_region *get_region_for_label (tree label);
+ const decl_region *get_region_for_global (tree expr);
+ const region *get_field_region (const region *parent, tree field);
+ const region *get_element_region (const region *parent,
+ tree element_type,
+ const svalue *index);
+ const region *get_offset_region (const region *parent,
+ tree type,
+ const svalue *byte_offset);
+ const region *get_sized_region (const region *parent,
+ tree type,
+ const svalue *byte_size_sval);
+ const region *get_cast_region (const region *original_region,
+ tree type);
+ const frame_region *get_frame_region (const frame_region *calling_frame,
+ function *fun);
+ const region *get_symbolic_region (const svalue *sval);
+ const string_region *get_region_for_string (tree string_cst);
+ const region *get_bit_range (const region *parent, tree type,
+ const bit_range &bits);
+ const var_arg_region *get_var_arg_region (const frame_region *parent,
+ unsigned idx);
+
+ const region *get_unknown_symbolic_region (tree region_type);
+
+ const region *
+ get_region_for_unexpected_tree_code (region_model_context *ctxt,
+ tree t,
+ const dump_location_t &loc);
+
+ unsigned alloc_region_id () { return m_next_region_id++; }
+
+ store_manager *get_store_manager () { return &m_store_mgr; }
+ bounded_ranges_manager *get_range_manager () const { return m_range_mgr; }
+
+ known_function_manager *get_known_function_manager ()
+ {
+ return &m_known_fn_mgr;
+ }
+
+ /* Dynamically-allocated region instances.
+ The number of these within the analysis can grow arbitrarily.
+ They are still owned by the manager. */
+ const region *create_region_for_heap_alloc ();
+ const region *create_region_for_alloca (const frame_region *frame);
+
+ void log_stats (logger *logger, bool show_objs) const;
+
+ void begin_checking_feasibility (void) { m_checking_feasibility = true; }
+ void end_checking_feasibility (void) { m_checking_feasibility = false; }
+
+ logger *get_logger () const { return m_logger; }
+
+ void dump_untracked_regions () const;
+
+private:
+ bool too_complex_p (const complexity &c) const;
+ bool reject_if_too_complex (svalue *sval);
+
+ const svalue *maybe_fold_unaryop (tree type, enum tree_code op,
+ const svalue *arg);
+ const svalue *maybe_fold_binop (tree type, enum tree_code op,
+ const svalue *arg0, const svalue *arg1);
+ const svalue *maybe_fold_sub_svalue (tree type,
+ const svalue *parent_svalue,
+ const region *subregion);
+ const svalue *maybe_fold_repeated_svalue (tree type,
+ const svalue *outer_size,
+ const svalue *inner_svalue);
+ const svalue *maybe_fold_bits_within_svalue (tree type,
+ const bit_range &bits,
+ const svalue *inner_svalue);
+ const svalue *maybe_undo_optimize_bit_field_compare (tree type,
+ const compound_svalue *compound_sval,
+ tree cst, const svalue *arg1);
+ const svalue *maybe_fold_asm_output_svalue (tree type,
+ const vec<const svalue *> &inputs);
+
+ logger *m_logger;
+
+ const call_string m_empty_call_string;
+
+ unsigned m_next_region_id;
+ root_region m_root_region;
+ stack_region m_stack_region;
+ heap_region m_heap_region;
+
+ /* svalue consolidation. */
+ typedef hash_map<tree, constant_svalue *> constants_map_t;
+ constants_map_t m_constants_map;
+
+ typedef hash_map<tree, unknown_svalue *> unknowns_map_t;
+ unknowns_map_t m_unknowns_map;
+ const unknown_svalue *m_unknown_NULL;
+
+ typedef hash_map<poisoned_svalue::key_t,
+ poisoned_svalue *> poisoned_values_map_t;
+ poisoned_values_map_t m_poisoned_values_map;
+
+ typedef hash_map<setjmp_svalue::key_t,
+ setjmp_svalue *> setjmp_values_map_t;
+ setjmp_values_map_t m_setjmp_values_map;
+
+ typedef hash_map<const region *, initial_svalue *> initial_values_map_t;
+ initial_values_map_t m_initial_values_map;
+
+ typedef hash_map<region_svalue::key_t, region_svalue *> pointer_values_map_t;
+ pointer_values_map_t m_pointer_values_map;
+
+ typedef hash_map<unaryop_svalue::key_t,
+ unaryop_svalue *> unaryop_values_map_t;
+ unaryop_values_map_t m_unaryop_values_map;
+
+ typedef hash_map<binop_svalue::key_t, binop_svalue *> binop_values_map_t;
+ binop_values_map_t m_binop_values_map;
+
+ typedef hash_map<sub_svalue::key_t, sub_svalue *> sub_values_map_t;
+ sub_values_map_t m_sub_values_map;
+
+ typedef hash_map<repeated_svalue::key_t,
+ repeated_svalue *> repeated_values_map_t;
+ repeated_values_map_t m_repeated_values_map;
+
+ typedef hash_map<bits_within_svalue::key_t,
+ bits_within_svalue *> bits_within_values_map_t;
+ bits_within_values_map_t m_bits_within_values_map;
+
+ typedef hash_map<const svalue *,
+ unmergeable_svalue *> unmergeable_values_map_t;
+ unmergeable_values_map_t m_unmergeable_values_map;
+
+ typedef hash_map<widening_svalue::key_t,
+ widening_svalue */*,
+ widening_svalue::key_t::hash_map_traits*/>
+ widening_values_map_t;
+ widening_values_map_t m_widening_values_map;
+
+ typedef hash_map<compound_svalue::key_t,
+ compound_svalue *> compound_values_map_t;
+ compound_values_map_t m_compound_values_map;
+
+ typedef hash_map<conjured_svalue::key_t,
+ conjured_svalue *> conjured_values_map_t;
+ conjured_values_map_t m_conjured_values_map;
+
+ typedef hash_map<asm_output_svalue::key_t,
+ asm_output_svalue *> asm_output_values_map_t;
+ asm_output_values_map_t m_asm_output_values_map;
+
+ typedef hash_map<const_fn_result_svalue::key_t,
+ const_fn_result_svalue *> const_fn_result_values_map_t;
+ const_fn_result_values_map_t m_const_fn_result_values_map;
+
+ bool m_checking_feasibility;
+
+ /* "Dynamically-allocated" svalue instances.
+ The number of these within the analysis can grow arbitrarily.
+ They are still owned by the manager. */
+ auto_delete_vec<svalue> m_managed_dynamic_svalues;
+
+ /* Maximum complexity of svalues that weren't rejected. */
+ complexity m_max_complexity;
+
+ /* region consolidation. */
+
+ code_region m_code_region;
+ typedef hash_map<tree, function_region *> fndecls_map_t;
+ typedef fndecls_map_t::iterator fndecls_iterator_t;
+ fndecls_map_t m_fndecls_map;
+
+ typedef hash_map<tree, label_region *> labels_map_t;
+ typedef labels_map_t::iterator labels_iterator_t;
+ labels_map_t m_labels_map;
+
+ globals_region m_globals_region;
+ typedef hash_map<tree, decl_region *> globals_map_t;
+ typedef globals_map_t::iterator globals_iterator_t;
+ globals_map_t m_globals_map;
+
+ consolidation_map<field_region> m_field_regions;
+ consolidation_map<element_region> m_element_regions;
+ consolidation_map<offset_region> m_offset_regions;
+ consolidation_map<sized_region> m_sized_regions;
+ consolidation_map<cast_region> m_cast_regions;
+ consolidation_map<frame_region> m_frame_regions;
+ consolidation_map<symbolic_region> m_symbolic_regions;
+
+ typedef hash_map<tree, string_region *> string_map_t;
+ string_map_t m_string_map;
+
+ consolidation_map<bit_range_region> m_bit_range_regions;
+ consolidation_map<var_arg_region> m_var_arg_regions;
+
+ store_manager m_store_mgr;
+
+ bounded_ranges_manager *m_range_mgr;
+
+ known_function_manager m_known_fn_mgr;
+
+ /* "Dynamically-allocated" region instances.
+ The number of these within the analysis can grow arbitrarily.
+ They are still owned by the manager. */
+ auto_delete_vec<region> m_managed_dynamic_regions;
+};
+
+} // namespace ana
+
+#endif /* GCC_ANALYZER_REGION_MODEL_MANAGER_H */
diff --git a/gcc/analyzer/region-model-reachability.cc b/gcc/analyzer/region-model-reachability.cc
index 12d09c3..be1372c 100644
--- a/gcc/analyzer/region-model-reachability.cc
+++ b/gcc/analyzer/region-model-reachability.cc
@@ -36,23 +36,18 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "fold-const.h"
#include "tree-pretty-print.h"
-#include "tristate.h"
#include "bitmap.h"
-#include "selftest.h"
-#include "function.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "ordered-hash-map.h"
#include "options.h"
-#include "cgraph.h"
-#include "cfg.h"
-#include "digraph.h"
-#include "json.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/region-model-reachability.h"
+#include "diagnostic.h"
+#include "tree-diagnostic.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 22c5287..81ef41e 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -39,18 +39,14 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print.h"
#include "diagnostic-color.h"
#include "diagnostic-metadata.h"
-#include "tristate.h"
#include "bitmap.h"
#include "selftest.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "ordered-hash-map.h"
#include "options.h"
#include "cgraph.h"
#include "cfg.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "sbitmap.h"
#include "analyzer/call-string.h"
@@ -66,6 +62,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/region-model-reachability.h"
#include "analyzer/analyzer-selftests.h"
#include "analyzer/program-state.h"
+#include "analyzer/call-summary.h"
#include "stor-layout.h"
#include "attribs.h"
#include "tree-object-size.h"
@@ -1255,6 +1252,12 @@ region_model::on_stmt_pre (const gimple *stmt,
{
/* This is handled elsewhere. */
}
+ else if (is_special_named_call_p (call, "__analyzer_get_unknown_ptr",
+ 0))
+ {
+ call_details cd (call, this, ctxt);
+ impl_call_analyzer_get_unknown_ptr (cd);
+ }
else
*out_unknown_side_effects = on_call_pre (call, ctxt,
out_terminate_path);
@@ -5038,11 +5041,8 @@ region_model::maybe_update_for_edge (const superedge &edge,
break;
case SUPEREDGE_INTRAPROCEDURAL_CALL:
- {
- const callgraph_superedge *cg_sedge
- = as_a <const callgraph_superedge *> (&edge);
- update_for_call_summary (*cg_sedge, ctxt);
- }
+ /* This is a no-op for call summaries; we should already
+ have handled the effect of the call summary at the call stmt. */
break;
}
@@ -5140,25 +5140,34 @@ region_model::update_for_return_superedge (const return_superedge &return_edge,
update_for_return_gcall (call_stmt, ctxt);
}
-/* Update this region_model with a summary of the effect of calling
- and returning from CG_SEDGE.
+/* Attempt to to use R to replay SUMMARY into this object.
+ Return true if it is possible. */
- TODO: Currently this is extremely simplistic: we merely set the
- return value to "unknown". A proper implementation would e.g. update
- sm-state, and presumably be reworked to support multiple outcomes. */
-
-void
-region_model::update_for_call_summary (const callgraph_superedge &cg_sedge,
- region_model_context *ctxt)
+bool
+region_model::replay_call_summary (call_summary_replay &r,
+ const region_model &summary)
{
- /* For now, set any return value to "unknown". */
- const gcall *call_stmt = cg_sedge.get_call_stmt ();
- tree lhs = gimple_call_lhs (call_stmt);
- if (lhs)
- mark_region_as_unknown (get_lvalue (lhs, ctxt),
- ctxt ? ctxt->get_uncertainty () : NULL);
+ gcc_assert (summary.get_stack_depth () == 1);
+
+ m_store.replay_call_summary (r, summary.m_store);
- // TODO: actually implement some kind of summary here
+ if (!m_constraints->replay_call_summary (r, *summary.m_constraints))
+ return false;
+
+ for (auto kv : summary.m_dynamic_extents)
+ {
+ const region *summary_reg = kv.first;
+ const region *caller_reg = r.convert_region_from_summary (summary_reg);
+ if (!caller_reg)
+ continue;
+ const svalue *summary_sval = kv.second;
+ const svalue *caller_sval = r.convert_svalue_from_summary (summary_sval);
+ if (!caller_sval)
+ continue;
+ m_dynamic_extents.put (caller_reg, caller_sval);
+ }
+
+ return true;
}
/* Given a true or false edge guarded by conditional statement COND_STMT,
@@ -7123,6 +7132,57 @@ test_sub_svalue_folding ()
ASSERT_EQ (sub->get_type (), TREE_TYPE (ct.m_x_field));
}
+/* Get BIT within VAL as a symbolic value within MGR. */
+
+static const svalue *
+get_bit (region_model_manager *mgr,
+ bit_offset_t bit,
+ unsigned HOST_WIDE_INT val)
+{
+ const svalue *inner_svalue
+ = mgr->get_or_create_int_cst (unsigned_type_node, val);
+ return mgr->get_or_create_bits_within (boolean_type_node,
+ bit_range (bit, 1),
+ inner_svalue);
+}
+
+/* Verify that bits_within_svalues are folded as expected. */
+
+static void
+test_bits_within_svalue_folding ()
+{
+ region_model_manager mgr;
+
+ const svalue *zero = mgr.get_or_create_int_cst (boolean_type_node, 0);
+ const svalue *one = mgr.get_or_create_int_cst (boolean_type_node, 1);
+
+ {
+ const unsigned val = 0x0000;
+ for (unsigned bit = 0; bit < 16; bit++)
+ ASSERT_EQ (get_bit (&mgr, bit, val), zero);
+ }
+
+ {
+ const unsigned val = 0x0001;
+ ASSERT_EQ (get_bit (&mgr, 0, val), one);
+ for (unsigned bit = 1; bit < 16; bit++)
+ ASSERT_EQ (get_bit (&mgr, bit, val), zero);
+ }
+
+ {
+ const unsigned val = 0x8000;
+ for (unsigned bit = 0; bit < 15; bit++)
+ ASSERT_EQ (get_bit (&mgr, bit, val), zero);
+ ASSERT_EQ (get_bit (&mgr, 15, val), one);
+ }
+
+ {
+ const unsigned val = 0xFFFF;
+ for (unsigned bit = 0; bit < 16; bit++)
+ ASSERT_EQ (get_bit (&mgr, bit, val), one);
+ }
+}
+
/* Test that region::descendent_of_p works as expected. */
static void
@@ -7956,7 +8016,7 @@ static void
test_widening_constraints ()
{
region_model_manager mgr;
- program_point point (program_point::origin (mgr));
+ function_point point (program_point::origin (mgr).get_function_point ());
tree int_0 = build_int_cst (integer_type_node, 0);
tree int_m1 = build_int_cst (integer_type_node, -1);
tree int_1 = build_int_cst (integer_type_node, 1);
@@ -8479,6 +8539,7 @@ analyzer_region_model_cc_tests ()
test_unaryop_svalue_folding ();
test_binop_svalue_folding ();
test_sub_svalue_folding ();
+ test_bits_within_svalue_folding ();
test_descendent_of_p ();
test_bit_range_regions ();
test_assignment ();
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index e86720a..635a0c2 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -26,9 +26,11 @@ along with GCC; see the file COPYING3. If not see
(Zhongxing Xu, Ted Kremenek, and Jian Zhang)
http://lcs.ios.ac.cn/~xuzb/canalyze/memmodel.pdf */
+#include "selftest.h"
#include "analyzer/svalue.h"
#include "analyzer/region.h"
#include "analyzer/known-function-manager.h"
+#include "analyzer/region-model-manager.h"
using namespace ana;
@@ -230,294 +232,6 @@ public:
virtual void visit_region (const region *) {}
};
-} // namespace ana
-
-namespace ana {
-
-/* A class responsible for owning and consolidating region and svalue
- instances.
- region and svalue instances are immutable as far as clients are
- concerned, so they are provided as "const" ptrs. */
-
-class region_model_manager
-{
-public:
- region_model_manager (logger *logger = NULL);
- ~region_model_manager ();
-
- /* call_string consolidation. */
- const call_string &get_empty_call_string () const
- {
- return m_empty_call_string;
- }
-
- /* svalue consolidation. */
- const svalue *get_or_create_constant_svalue (tree cst_expr);
- const svalue *get_or_create_int_cst (tree type, poly_int64);
- const svalue *get_or_create_unknown_svalue (tree type);
- const svalue *get_or_create_setjmp_svalue (const setjmp_record &r,
- tree type);
- const svalue *get_or_create_poisoned_svalue (enum poison_kind kind,
- tree type);
- const svalue *get_or_create_initial_value (const region *reg);
- const svalue *get_ptr_svalue (tree ptr_type, const region *pointee);
- const svalue *get_or_create_unaryop (tree type, enum tree_code op,
- const svalue *arg);
- const svalue *get_or_create_cast (tree type, const svalue *arg);
- const svalue *get_or_create_binop (tree type,
- enum tree_code op,
- const svalue *arg0, const svalue *arg1);
- const svalue *get_or_create_sub_svalue (tree type,
- const svalue *parent_svalue,
- const region *subregion);
- const svalue *get_or_create_repeated_svalue (tree type,
- const svalue *outer_size,
- const svalue *inner_svalue);
- const svalue *get_or_create_bits_within (tree type,
- const bit_range &bits,
- const svalue *inner_svalue);
- const svalue *get_or_create_unmergeable (const svalue *arg);
- const svalue *get_or_create_widening_svalue (tree type,
- const program_point &point,
- const svalue *base_svalue,
- const svalue *iter_svalue);
- const svalue *get_or_create_compound_svalue (tree type,
- const binding_map &map);
- const svalue *get_or_create_conjured_svalue (tree type, const gimple *stmt,
- const region *id_reg,
- const conjured_purge &p);
- const svalue *
- get_or_create_asm_output_svalue (tree type,
- const gasm *asm_stmt,
- unsigned output_idx,
- const vec<const svalue *> &inputs);
- const svalue *
- get_or_create_const_fn_result_svalue (tree type,
- tree fndecl,
- const vec<const svalue *> &inputs);
-
- const svalue *maybe_get_char_from_string_cst (tree string_cst,
- tree byte_offset_cst);
-
- /* Dynamically-allocated svalue instances.
- The number of these within the analysis can grow arbitrarily.
- They are still owned by the manager. */
- const svalue *create_unique_svalue (tree type);
-
- /* region consolidation. */
- const stack_region * get_stack_region () const { return &m_stack_region; }
- const heap_region *get_heap_region () const { return &m_heap_region; }
- const code_region *get_code_region () const { return &m_code_region; }
- const globals_region *get_globals_region () const
- {
- return &m_globals_region;
- }
- const function_region *get_region_for_fndecl (tree fndecl);
- const label_region *get_region_for_label (tree label);
- const decl_region *get_region_for_global (tree expr);
- const region *get_field_region (const region *parent, tree field);
- const region *get_element_region (const region *parent,
- tree element_type,
- const svalue *index);
- const region *get_offset_region (const region *parent,
- tree type,
- const svalue *byte_offset);
- const region *get_sized_region (const region *parent,
- tree type,
- const svalue *byte_size_sval);
- const region *get_cast_region (const region *original_region,
- tree type);
- const frame_region *get_frame_region (const frame_region *calling_frame,
- function *fun);
- const region *get_symbolic_region (const svalue *sval);
- const string_region *get_region_for_string (tree string_cst);
- const region *get_bit_range (const region *parent, tree type,
- const bit_range &bits);
- const var_arg_region *get_var_arg_region (const frame_region *parent,
- unsigned idx);
-
- const region *get_unknown_symbolic_region (tree region_type);
-
- const region *
- get_region_for_unexpected_tree_code (region_model_context *ctxt,
- tree t,
- const dump_location_t &loc);
-
- unsigned alloc_region_id () { return m_next_region_id++; }
-
- store_manager *get_store_manager () { return &m_store_mgr; }
- bounded_ranges_manager *get_range_manager () const { return m_range_mgr; }
-
- known_function_manager *get_known_function_manager ()
- {
- return &m_known_fn_mgr;
- }
-
- /* Dynamically-allocated region instances.
- The number of these within the analysis can grow arbitrarily.
- They are still owned by the manager. */
- const region *create_region_for_heap_alloc ();
- const region *create_region_for_alloca (const frame_region *frame);
-
- void log_stats (logger *logger, bool show_objs) const;
-
- void begin_checking_feasibility (void) { m_checking_feasibility = true; }
- void end_checking_feasibility (void) { m_checking_feasibility = false; }
-
- logger *get_logger () const { return m_logger; }
-
- void dump_untracked_regions () const;
-
-private:
- bool too_complex_p (const complexity &c) const;
- bool reject_if_too_complex (svalue *sval);
-
- const svalue *maybe_fold_unaryop (tree type, enum tree_code op,
- const svalue *arg);
- const svalue *maybe_fold_binop (tree type, enum tree_code op,
- const svalue *arg0, const svalue *arg1);
- const svalue *maybe_fold_sub_svalue (tree type,
- const svalue *parent_svalue,
- const region *subregion);
- const svalue *maybe_fold_repeated_svalue (tree type,
- const svalue *outer_size,
- const svalue *inner_svalue);
- const svalue *maybe_fold_bits_within_svalue (tree type,
- const bit_range &bits,
- const svalue *inner_svalue);
- const svalue *maybe_undo_optimize_bit_field_compare (tree type,
- const compound_svalue *compound_sval,
- tree cst, const svalue *arg1);
- const svalue *maybe_fold_asm_output_svalue (tree type,
- const vec<const svalue *> &inputs);
-
- logger *m_logger;
-
- const call_string m_empty_call_string;
-
- unsigned m_next_region_id;
- root_region m_root_region;
- stack_region m_stack_region;
- heap_region m_heap_region;
-
- /* svalue consolidation. */
- typedef hash_map<tree, constant_svalue *> constants_map_t;
- constants_map_t m_constants_map;
-
- typedef hash_map<tree, unknown_svalue *> unknowns_map_t;
- unknowns_map_t m_unknowns_map;
- const unknown_svalue *m_unknown_NULL;
-
- typedef hash_map<poisoned_svalue::key_t,
- poisoned_svalue *> poisoned_values_map_t;
- poisoned_values_map_t m_poisoned_values_map;
-
- typedef hash_map<setjmp_svalue::key_t,
- setjmp_svalue *> setjmp_values_map_t;
- setjmp_values_map_t m_setjmp_values_map;
-
- typedef hash_map<const region *, initial_svalue *> initial_values_map_t;
- initial_values_map_t m_initial_values_map;
-
- typedef hash_map<region_svalue::key_t, region_svalue *> pointer_values_map_t;
- pointer_values_map_t m_pointer_values_map;
-
- typedef hash_map<unaryop_svalue::key_t,
- unaryop_svalue *> unaryop_values_map_t;
- unaryop_values_map_t m_unaryop_values_map;
-
- typedef hash_map<binop_svalue::key_t, binop_svalue *> binop_values_map_t;
- binop_values_map_t m_binop_values_map;
-
- typedef hash_map<sub_svalue::key_t, sub_svalue *> sub_values_map_t;
- sub_values_map_t m_sub_values_map;
-
- typedef hash_map<repeated_svalue::key_t,
- repeated_svalue *> repeated_values_map_t;
- repeated_values_map_t m_repeated_values_map;
-
- typedef hash_map<bits_within_svalue::key_t,
- bits_within_svalue *> bits_within_values_map_t;
- bits_within_values_map_t m_bits_within_values_map;
-
- typedef hash_map<const svalue *,
- unmergeable_svalue *> unmergeable_values_map_t;
- unmergeable_values_map_t m_unmergeable_values_map;
-
- typedef hash_map<widening_svalue::key_t,
- widening_svalue */*,
- widening_svalue::key_t::hash_map_traits*/>
- widening_values_map_t;
- widening_values_map_t m_widening_values_map;
-
- typedef hash_map<compound_svalue::key_t,
- compound_svalue *> compound_values_map_t;
- compound_values_map_t m_compound_values_map;
-
- typedef hash_map<conjured_svalue::key_t,
- conjured_svalue *> conjured_values_map_t;
- conjured_values_map_t m_conjured_values_map;
-
- typedef hash_map<asm_output_svalue::key_t,
- asm_output_svalue *> asm_output_values_map_t;
- asm_output_values_map_t m_asm_output_values_map;
-
- typedef hash_map<const_fn_result_svalue::key_t,
- const_fn_result_svalue *> const_fn_result_values_map_t;
- const_fn_result_values_map_t m_const_fn_result_values_map;
-
- bool m_checking_feasibility;
-
- /* "Dynamically-allocated" svalue instances.
- The number of these within the analysis can grow arbitrarily.
- They are still owned by the manager. */
- auto_delete_vec<svalue> m_managed_dynamic_svalues;
-
- /* Maximum complexity of svalues that weren't rejected. */
- complexity m_max_complexity;
-
- /* region consolidation. */
-
- code_region m_code_region;
- typedef hash_map<tree, function_region *> fndecls_map_t;
- typedef fndecls_map_t::iterator fndecls_iterator_t;
- fndecls_map_t m_fndecls_map;
-
- typedef hash_map<tree, label_region *> labels_map_t;
- typedef labels_map_t::iterator labels_iterator_t;
- labels_map_t m_labels_map;
-
- globals_region m_globals_region;
- typedef hash_map<tree, decl_region *> globals_map_t;
- typedef globals_map_t::iterator globals_iterator_t;
- globals_map_t m_globals_map;
-
- consolidation_map<field_region> m_field_regions;
- consolidation_map<element_region> m_element_regions;
- consolidation_map<offset_region> m_offset_regions;
- consolidation_map<sized_region> m_sized_regions;
- consolidation_map<cast_region> m_cast_regions;
- consolidation_map<frame_region> m_frame_regions;
- consolidation_map<symbolic_region> m_symbolic_regions;
-
- typedef hash_map<tree, string_region *> string_map_t;
- string_map_t m_string_map;
-
- consolidation_map<bit_range_region> m_bit_range_regions;
- consolidation_map<var_arg_region> m_var_arg_regions;
-
- store_manager m_store_mgr;
-
- bounded_ranges_manager *m_range_mgr;
-
- known_function_manager m_known_fn_mgr;
-
- /* "Dynamically-allocated" region instances.
- The number of these within the analysis can grow arbitrarily.
- They are still owned by the manager. */
- auto_delete_vec<region> m_managed_dynamic_regions;
-};
-
struct append_regions_cb_data;
/* Helper class for handling calls to functions with known behavior.
@@ -631,6 +345,7 @@ class region_model
void impl_call_analyzer_dump_escaped (const gcall *call);
void impl_call_analyzer_eval (const gcall *call,
region_model_context *ctxt);
+ void impl_call_analyzer_get_unknown_ptr (const call_details &cd);
void impl_call_builtin_expect (const call_details &cd);
void impl_call_calloc (const call_details &cd);
bool impl_call_error (const call_details &cd, unsigned min_args,
@@ -816,6 +531,9 @@ class region_model
const svalue *get_string_size (const svalue *sval) const;
const svalue *get_string_size (const region *reg) const;
+ bool replay_call_summary (call_summary_replay &r,
+ const region_model &summary);
+
void maybe_complain_about_infoleak (const region *dst_reg,
const svalue *copied_sval,
const region *src_reg,
@@ -857,8 +575,6 @@ class region_model
region_model_context *ctxt);
void update_for_return_superedge (const return_superedge &return_edge,
region_model_context *ctxt);
- void update_for_call_summary (const callgraph_superedge &cg_sedge,
- region_model_context *ctxt);
bool apply_constraints_for_gcond (const cfg_superedge &edge,
const gcond *cond_stmt,
region_model_context *ctxt,
@@ -1282,6 +998,10 @@ struct model_merger
}
bool mergeable_svalue_p (const svalue *) const;
+ const function_point &get_function_point () const
+ {
+ return m_point.get_function_point ();
+ }
const region_model *m_model_a;
const region_model *m_model_b;
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index 09646bf..da5a13e 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -40,11 +40,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print.h"
#include "diagnostic-color.h"
#include "diagnostic-metadata.h"
-#include "tristate.h"
#include "bitmap.h"
-#include "selftest.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "ordered-hash-map.h"
diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc
index 505d598..c4ad91c 100644
--- a/gcc/analyzer/sm-fd.cc
+++ b/gcc/analyzer/sm-fd.cc
@@ -28,8 +28,6 @@ along with GCC; see the file COPYING3. If not see
#include "options.h"
#include "diagnostic-path.h"
#include "diagnostic-metadata.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "diagnostic-event-id.h"
#include "analyzer/analyzer-logging.h"
@@ -37,8 +35,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/pending-diagnostic.h"
#include "analyzer/function-set.h"
#include "analyzer/analyzer-selftests.h"
-#include "tristate.h"
-#include "selftest.h"
#include "stringpool.h"
#include "attribs.h"
#include "analyzer/call-string.h"
diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc
index f6cb29c..13f2507 100644
--- a/gcc/analyzer/sm-file.cc
+++ b/gcc/analyzer/sm-file.cc
@@ -28,8 +28,6 @@ along with GCC; see the file COPYING3. If not see
#include "options.h"
#include "diagnostic-path.h"
#include "diagnostic-metadata.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "diagnostic-event-id.h"
#include "analyzer/analyzer-logging.h"
@@ -37,7 +35,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/pending-diagnostic.h"
#include "analyzer/function-set.h"
#include "analyzer/analyzer-selftests.h"
-#include "tristate.h"
#include "selftest.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc
index 73c549f..fef6e63 100644
--- a/gcc/analyzer/sm-malloc.cc
+++ b/gcc/analyzer/sm-malloc.cc
@@ -29,15 +29,11 @@ along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
#include "diagnostic-path.h"
#include "diagnostic-metadata.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "diagnostic-event-id.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
-#include "tristate.h"
-#include "selftest.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
diff --git a/gcc/analyzer/sm-pattern-test.cc b/gcc/analyzer/sm-pattern-test.cc
index 9b2ad68..3208132 100644
--- a/gcc/analyzer/sm-pattern-test.cc
+++ b/gcc/analyzer/sm-pattern-test.cc
@@ -30,15 +30,11 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print.h"
#include "diagnostic-path.h"
#include "diagnostic-metadata.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "diagnostic-event-id.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
-#include "tristate.h"
-#include "selftest.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
diff --git a/gcc/analyzer/sm-sensitive.cc b/gcc/analyzer/sm-sensitive.cc
index 83c1906..cb5f859 100644
--- a/gcc/analyzer/sm-sensitive.cc
+++ b/gcc/analyzer/sm-sensitive.cc
@@ -24,14 +24,11 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "tree.h"
#include "function.h"
-#include "function.h"
#include "basic-block.h"
#include "gimple.h"
#include "options.h"
#include "diagnostic-path.h"
#include "diagnostic-metadata.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "diagnostic-event-id.h"
#include "analyzer/analyzer-logging.h"
diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc
index b601f45..e3b08c3 100644
--- a/gcc/analyzer/sm-signal.cc
+++ b/gcc/analyzer/sm-signal.cc
@@ -31,15 +31,12 @@ along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
#include "diagnostic-path.h"
#include "diagnostic-metadata.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "diagnostic-event-id.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "sbitmap.h"
-#include "tristate.h"
#include "ordered-hash-map.h"
#include "selftest.h"
#include "analyzer/call-string.h"
@@ -48,13 +45,10 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/region-model.h"
#include "analyzer/program-state.h"
#include "analyzer/checker-path.h"
-#include "digraph.h"
#include "cfg.h"
#include "gimple-iterator.h"
#include "cgraph.h"
#include "analyzer/supergraph.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
#include "analyzer/diagnostic-manager.h"
#include "shortest-paths.h"
#include "analyzer/exploded-graph.h"
diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc
index f5c0cc1..bc27533 100644
--- a/gcc/analyzer/sm-taint.cc
+++ b/gcc/analyzer/sm-taint.cc
@@ -30,13 +30,9 @@ along with GCC; see the file COPYING3. If not see
#include "options.h"
#include "diagnostic-path.h"
#include "diagnostic-metadata.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "gimple-iterator.h"
-#include "tristate.h"
-#include "selftest.h"
#include "ordered-hash-map.h"
#include "cgraph.h"
#include "cfg.h"
diff --git a/gcc/analyzer/sm.cc b/gcc/analyzer/sm.cc
index d17d5c7..1ab4c21 100644
--- a/gcc/analyzer/sm.cc
+++ b/gcc/analyzer/sm.cc
@@ -31,11 +31,9 @@ along with GCC; see the file COPYING3. If not see
#include "pretty-print.h"
#include "diagnostic.h"
#include "tree-diagnostic.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
-#include "tristate.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc
index 7a061a1..d3f516a 100644
--- a/gcc/analyzer/state-purge.cc
+++ b/gcc/analyzer/state-purge.cc
@@ -36,24 +36,16 @@ along with GCC; see the file COPYING3. If not see
#include "ssa-iterators.h"
#include "diagnostic-core.h"
#include "gimple-pretty-print.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/call-string.h"
-#include "digraph.h"
-#include "ordered-hash-map.h"
-#include "cfg.h"
-#include "gimple-iterator.h"
-#include "cgraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-point.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/state-purge.h"
-#include "tristate.h"
-#include "selftest.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "gimple-walk.h"
+#include "cgraph.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index 1857d95..2631ea2 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -38,24 +38,20 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print.h"
#include "diagnostic-color.h"
#include "diagnostic-metadata.h"
-#include "tristate.h"
#include "bitmap.h"
#include "selftest.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "ordered-hash-map.h"
#include "options.h"
-#include "cgraph.h"
#include "cfg.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "sbitmap.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
+#include "analyzer/call-summary.h"
#include "analyzer/analyzer-selftests.h"
#include "stor-layout.h"
@@ -3130,6 +3126,148 @@ store::loop_replay_fixup (const store *other_store,
}
}
+/* Use R to replay the bindings from SUMMARY into this object. */
+
+void
+store::replay_call_summary (call_summary_replay &r,
+ const store &summary)
+{
+ if (summary.m_called_unknown_fn)
+ {
+ /* A call to an external function occurred in the summary.
+ Hence we need to invalidate our knownledge of globals,
+ escaped regions, etc. */
+ on_unknown_fncall (r.get_call_stmt (),
+ r.get_store_manager (),
+ conjured_purge (r.get_caller_model (),
+ r.get_ctxt ()));
+ }
+
+ auto_vec<const region *> keys (summary.m_cluster_map.elements ());
+ for (auto kv : summary.m_cluster_map)
+ keys.quick_push (kv.first);
+ keys.qsort (region::cmp_ptr_ptr);
+ for (auto base_reg : keys)
+ replay_call_summary_cluster (r, summary, base_reg);
+}
+
+/* Use R and SUMMARY to replay the bindings in SUMMARY_CLUSTER
+ into this object. */
+
+void
+store::replay_call_summary_cluster (call_summary_replay &r,
+ const store &summary,
+ const region *summary_base_reg)
+{
+ const call_details &cd = r.get_call_details ();
+ region_model_manager *reg_mgr = r.get_manager ();
+ store_manager *mgr = reg_mgr->get_store_manager ();
+ const binding_cluster *summary_cluster
+ = summary.get_cluster (summary_base_reg);
+
+ /* Handle "ESCAPED" and "TOUCHED" flags. */
+ if (summary_cluster->escaped_p () || summary_cluster->touched_p ())
+ if (const region *caller_reg
+ = r.convert_region_from_summary (summary_base_reg))
+ {
+ const region *caller_base_reg = caller_reg->get_base_region ();
+ if (caller_base_reg->tracked_p ()
+ && !caller_base_reg->symbolic_for_unknown_ptr_p ())
+ {
+ binding_cluster *caller_cluster
+ = get_or_create_cluster (caller_base_reg);
+ if (summary_cluster->escaped_p ())
+ caller_cluster->mark_as_escaped ();
+ if (summary_cluster->touched_p ())
+ caller_cluster->m_touched = true;
+ }
+ }
+
+ switch (summary_base_reg->get_kind ())
+ {
+ /* Top-level regions. */
+ case RK_FRAME:
+ case RK_GLOBALS:
+ case RK_CODE:
+ case RK_STACK:
+ case RK_HEAP:
+ case RK_ROOT:
+ /* Child regions. */
+ case RK_FIELD:
+ case RK_ELEMENT:
+ case RK_OFFSET:
+ case RK_SIZED:
+ case RK_CAST:
+ case RK_BIT_RANGE:
+ /* Other regions. */
+ case RK_VAR_ARG:
+ case RK_UNKNOWN:
+ /* These should never be the base region of a binding cluster. */
+ gcc_unreachable ();
+ break;
+
+ case RK_FUNCTION:
+ case RK_LABEL:
+ case RK_STRING:
+ /* These can be marked as escaping. */
+ break;
+
+ case RK_SYMBOLIC:
+ {
+ const symbolic_region *summary_symbolic_reg
+ = as_a <const symbolic_region *> (summary_base_reg);
+ const svalue *summary_ptr_sval = summary_symbolic_reg->get_pointer ();
+ const svalue *caller_ptr_sval
+ = r.convert_svalue_from_summary (summary_ptr_sval);
+ if (!caller_ptr_sval)
+ return;
+ const region *caller_dest_reg
+ = cd.get_model ()->deref_rvalue (caller_ptr_sval,
+ NULL_TREE,
+ cd.get_ctxt ());
+ const svalue *summary_sval
+ = summary.get_any_binding (mgr, summary_base_reg);
+ if (!summary_sval)
+ return;
+ const svalue *caller_sval
+ = r.convert_svalue_from_summary (summary_sval);
+ if (!caller_sval)
+ caller_sval =
+ reg_mgr->get_or_create_unknown_svalue (summary_sval->get_type ());
+ set_value (mgr, caller_dest_reg,
+ caller_sval, NULL /* uncertainty_t * */);
+ }
+ break;
+
+ case RK_HEAP_ALLOCATED:
+ case RK_DECL:
+ {
+ const region *caller_dest_reg
+ = r.convert_region_from_summary (summary_base_reg);
+ if (!caller_dest_reg)
+ return;
+ const svalue *summary_sval
+ = summary.get_any_binding (mgr, summary_base_reg);
+ if (!summary_sval)
+ summary_sval = reg_mgr->get_or_create_compound_svalue
+ (summary_base_reg->get_type (),
+ summary_cluster->get_map ());
+ const svalue *caller_sval
+ = r.convert_svalue_from_summary (summary_sval);
+ if (!caller_sval)
+ caller_sval =
+ reg_mgr->get_or_create_unknown_svalue (summary_sval->get_type ());
+ set_value (mgr, caller_dest_reg,
+ caller_sval, NULL /* uncertainty_t * */);
+ }
+ break;
+
+ case RK_ALLOCA:
+ /* Ignore bindings of alloca regions in the summary. */
+ break;
+ }
+}
+
#if CHECKING_P
namespace selftest {
diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h
index d172ee7..1087782 100644
--- a/gcc/analyzer/store.h
+++ b/gcc/analyzer/store.h
@@ -418,6 +418,14 @@ private:
} // namespace ana
+template <>
+template <>
+inline bool
+is_a_helper <const ana::concrete_binding *>::test (const ana::binding_key *key)
+{
+ return key->concrete_p ();
+}
+
template <> struct default_hash_traits<ana::concrete_binding>
: public member_function_hash_traits<ana::concrete_binding>
{
@@ -786,6 +794,12 @@ public:
void loop_replay_fixup (const store *other_store,
region_model_manager *mgr);
+ void replay_call_summary (call_summary_replay &r,
+ const store &summary);
+ void replay_call_summary_cluster (call_summary_replay &r,
+ const store &summary,
+ const region *base_reg);
+
private:
void remove_overlapping_bindings (store_manager *mgr, const region *reg,
uncertainty_t *uncertainty);
diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc
index 01e30f7..0e9a325 100644
--- a/gcc/analyzer/supergraph.cc
+++ b/gcc/analyzer/supergraph.cc
@@ -44,7 +44,6 @@ along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
#include "cfganal.h"
#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "ordered-hash-map.h"
#include "options.h"
@@ -62,7 +61,7 @@ namespace ana {
/* Get the function of the ultimate alias target being called at EDGE,
if any. */
-static function *
+function *
get_ultimate_function_for_cgraph_edge (cgraph_edge *edge)
{
cgraph_node *ultimate_node = edge->callee->ultimate_alias_target ();
@@ -74,12 +73,13 @@ get_ultimate_function_for_cgraph_edge (cgraph_edge *edge)
/* Get the cgraph_edge, but only if there's an underlying function body. */
cgraph_edge *
-supergraph_call_edge (function *fun, gimple *stmt)
+supergraph_call_edge (function *fun, const gimple *stmt)
{
- gcall *call = dyn_cast<gcall *> (stmt);
+ const gcall *call = dyn_cast<const gcall *> (stmt);
if (!call)
return NULL;
- cgraph_edge *edge = cgraph_node::get (fun->decl)->get_edge (stmt);
+ cgraph_edge *edge
+ = cgraph_node::get (fun->decl)->get_edge (const_cast <gimple *> (stmt));
if (!edge)
return NULL;
if (!edge->callee)
diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h
index e9a5be2..f66058c 100644
--- a/gcc/analyzer/supergraph.h
+++ b/gcc/analyzer/supergraph.h
@@ -21,6 +21,13 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ANALYZER_SUPERGRAPH_H
#define GCC_ANALYZER_SUPERGRAPH_H
+#include "ordered-hash-map.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "digraph.h"
+
using namespace ana;
namespace ana {
@@ -605,7 +612,8 @@ class dot_annotator
}
};
-extern cgraph_edge *supergraph_call_edge (function *fun, gimple *stmt);
+extern cgraph_edge *supergraph_call_edge (function *fun, const gimple *stmt);
+extern function *get_ultimate_function_for_cgraph_edge (cgraph_edge *edge);
} // namespace ana
diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc
index f5a5f1c..a0838c0 100644
--- a/gcc/analyzer/svalue.cc
+++ b/gcc/analyzer/svalue.cc
@@ -38,22 +38,16 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "fold-const.h"
#include "tree-pretty-print.h"
-#include "tristate.h"
#include "bitmap.h"
-#include "selftest.h"
-#include "function.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
-#include "options.h"
-#include "cgraph.h"
-#include "cfg.h"
-#include "digraph.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/svalue.h"
#include "analyzer/region-model.h"
+#include "diagnostic.h"
+#include "tree-diagnostic.h"
#if ENABLE_ANALYZER
@@ -207,7 +201,7 @@ svalue::can_merge_p (const svalue *other,
if (maybe_get_constant () && other->maybe_get_constant ())
{
return mgr->get_or_create_widening_svalue (other->get_type (),
- merger->m_point,
+ merger->get_function_point (),
other, this);
}
@@ -220,7 +214,7 @@ svalue::can_merge_p (const svalue *other,
&& binop_sval->get_arg1 ()->get_kind () == SK_CONSTANT
&& other->get_kind () != SK_WIDENING)
return mgr->get_or_create_widening_svalue (other->get_type (),
- merger->m_point,
+ merger->get_function_point (),
other, this);
/* Merge: (Widen(existing_val, V), existing_val) -> Widen (existing_val, V)
@@ -874,7 +868,7 @@ constant_svalue::eval_condition (const constant_svalue *lhs,
const svalue *
constant_svalue::maybe_fold_bits_within (tree type,
- const bit_range &,
+ const bit_range &bits,
region_model_manager *mgr) const
{
/* Bits within an all-zero value are also all zero. */
@@ -885,6 +879,21 @@ constant_svalue::maybe_fold_bits_within (tree type,
else
return this;
}
+
+ /* Handle the case of extracting a single bit. */
+ if (bits.m_size_in_bits == 1
+ && TREE_CODE (m_cst_expr) == INTEGER_CST
+ && type
+ && INTEGRAL_TYPE_P (type))
+ {
+ unsigned HOST_WIDE_INT bit = bits.m_start_bit_offset.to_uhwi ();
+ unsigned HOST_WIDE_INT mask = (1 << bit);
+ unsigned HOST_WIDE_INT val_as_hwi = tree_to_uhwi (m_cst_expr);
+ unsigned HOST_WIDE_INT masked_val = val_as_hwi & mask;
+ int result = masked_val ? 1 : 0;
+ return mgr->get_or_create_int_cst (type, result);
+ }
+
/* Otherwise, don't fold. */
return NULL;
}
@@ -1728,13 +1737,17 @@ unmergeable_svalue::implicitly_live_p (const svalue_set *live_svalues,
compound_svalue::compound_svalue (tree type, const binding_map &map)
: svalue (calc_complexity (map), type), m_map (map)
{
- /* All keys within the underlying binding_map are required to be concrete,
- not symbolic. */
#if CHECKING_P
for (iterator_t iter = begin (); iter != end (); ++iter)
{
+ /* All keys within the underlying binding_map are required to be concrete,
+ not symbolic. */
const binding_key *key = (*iter).first;
gcc_assert (key->concrete_p ());
+
+ /* We don't nest compound svalues. */
+ const svalue *sval = (*iter).second;
+ gcc_assert (sval->get_kind () != SK_COMPOUND);
}
#endif
}
diff --git a/gcc/analyzer/svalue.h b/gcc/analyzer/svalue.h
index f4cab0d..382b083 100644
--- a/gcc/analyzer/svalue.h
+++ b/gcc/analyzer/svalue.h
@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see
#define GCC_ANALYZER_SVALUE_H
#include "analyzer/complexity.h"
+#include "analyzer/store.h"
+#include "analyzer/program-point.h"
using namespace ana;
@@ -1113,9 +1115,9 @@ public:
/* A support class for uniquifying instances of widening_svalue. */
struct key_t
{
- key_t (tree type, const program_point &point,
+ key_t (tree type, const function_point &point,
const svalue *base_sval, const svalue *iter_sval)
- : m_type (type), m_point (point.get_function_point ()),
+ : m_type (type), m_point (point),
m_base_sval (base_sval), m_iter_sval (iter_sval)
{}
@@ -1153,12 +1155,12 @@ public:
DIR_UNKNOWN
};
- widening_svalue (tree type, const program_point &point,
+ widening_svalue (tree type, const function_point &point,
const svalue *base_sval, const svalue *iter_sval)
: svalue (complexity::from_pair (base_sval->get_complexity (),
iter_sval->get_complexity ()),
type),
- m_point (point.get_function_point ()),
+ m_point (point),
m_base_sval (base_sval), m_iter_sval (iter_sval)
{
gcc_assert (base_sval->can_have_associated_state_p ());
@@ -1527,6 +1529,7 @@ public:
const char *get_asm_string () const { return m_asm_string; }
unsigned get_output_idx () const { return m_output_idx; }
+ unsigned get_num_outputs () const { return m_num_outputs; }
unsigned get_num_inputs () const { return m_num_inputs; }
const svalue *get_input (unsigned idx) const { return m_input_arr[idx]; }
diff --git a/gcc/analyzer/trimmed-graph.cc b/gcc/analyzer/trimmed-graph.cc
index 6c85910..9fdb4a9 100644
--- a/gcc/analyzer/trimmed-graph.cc
+++ b/gcc/analyzer/trimmed-graph.cc
@@ -29,15 +29,8 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-core.h"
#include "diagnostic-event-id.h"
#include "diagnostic-path.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
-#include "shortest-paths.h"
-#include "sbitmap.h"
#include "bitmap.h"
-#include "tristate.h"
-#include "selftest.h"
#include "ordered-hash-map.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
@@ -48,12 +41,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/constraint-manager.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "cgraph.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
diff --git a/gcc/analyzer/varargs.cc b/gcc/analyzer/varargs.cc
index 9400086..b2e6cd5 100644
--- a/gcc/analyzer/varargs.cc
+++ b/gcc/analyzer/varargs.cc
@@ -26,28 +26,17 @@ along with GCC; see the file COPYING3. If not see
#include "basic-block.h"
#include "gimple.h"
#include "diagnostic-path.h"
-#include "json.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
-#include "tristate.h"
-#include "selftest.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/program-state.h"
#include "analyzer/checker-path.h"
-#include "digraph.h"
-#include "ordered-hash-map.h"
-#include "cfg.h"
-#include "gimple-iterator.h"
#include "analyzer/supergraph.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
-#include "shortest-paths.h"
-#include "sbitmap.h"
#include "analyzer/diagnostic-manager.h"
#include "analyzer/exploded-graph.h"
#include "diagnostic-metadata.h"