aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer/program-state.cc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2020-03-05 12:06:58 -0500
committerDavid Malcolm <dmalcolm@redhat.com>2020-03-06 16:37:36 -0500
commit41f99ba6c576b84ca0f2de7d66ebc087454e93cf (patch)
treed154bf8465be154a7a5df5673bf4925b8161ff52 /gcc/analyzer/program-state.cc
parent191bcd0f30dd37dec773efb0125afdcae9bd90ef (diff)
downloadgcc-41f99ba6c576b84ca0f2de7d66ebc087454e93cf.zip
gcc-41f99ba6c576b84ca0f2de7d66ebc087454e93cf.tar.gz
gcc-41f99ba6c576b84ca0f2de7d66ebc087454e93cf.tar.bz2
analyzer: improvements to state dumping
This patch fixes a bug in which summarized state dumps involving a non-NULL pointer to a region for which get_representative_path_var returned NULL were erroneously dumped as "NULL". It also extends sm-state dumps so that they show representative tree values, where available. Finally, it adds some selftest coverage for such dumps. Doing so requires replacing some %qE with a dump_quoted_tree, to avoid C vs C++ differences between "make selftest-c" and "make selftest-c++". gcc/analyzer/ChangeLog: * analyzer.h (dump_quoted_tree): New decl. * engine.cc (exploded_node::dump_dot): Pass region model to sm_state_map::print. * program-state.cc: Include diagnostic-core.h. (sm_state_map::print): Add "model" param and use it to print representative trees. Only print origin information if non-null. (sm_state_map::dump): Pass NULL for model to print call. (program_state::print): Pass region model to sm_state_map::print. (program_state::dump_to_pp): Use spaces rather than newlines when summarizing. Pass region_model to sm_state_map::print. (ana::selftest::assert_dump_eq): New function. (ASSERT_DUMP_EQ): New macro. (ana::selftest::test_program_state_dumping): New function. (ana::selftest::analyzer_program_state_cc_tests): Call it. * program-state.h (program_state::print): Add model param. * region-model.cc (dump_quoted_tree): New function. (map_region::print_fields): Use dump_quoted_tree rather than %qE to avoid lang-dependent output. (map_region::dump_child_label): Likewise. (region_model::dump_summary_of_map): For SK_REGION, when get_representative_path_var fails, print the region id rather than erroneously printing NULL. * sm.cc (state_machine::get_state_by_name): New function. * sm.h (state_machine::get_state_by_name): New decl.
Diffstat (limited to 'gcc/analyzer/program-state.cc')
-rw-r--r--gcc/analyzer/program-state.cc128
1 files changed, 116 insertions, 12 deletions
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index 971e8e0..804800f 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "tree.h"
+#include "diagnostic-core.h"
#include "diagnostic.h"
#include "function.h"
#include "analyzer/analyzer.h"
@@ -147,10 +148,13 @@ sm_state_map::clone_with_remapping (const one_way_svalue_id_map &id_map) const
return result;
}
-/* Print this sm_state_map (for SM) to PP. */
+/* Print this sm_state_map (for SM) to PP.
+ If MODEL is non-NULL, print representative tree values where
+ available. */
void
-sm_state_map::print (const state_machine &sm, pretty_printer *pp) const
+sm_state_map::print (const state_machine &sm, const region_model *model,
+ pretty_printer *pp) const
{
bool first = true;
pp_string (pp, "{");
@@ -170,10 +174,27 @@ sm_state_map::print (const state_machine &sm, pretty_printer *pp) const
sid.print (pp);
entry_t e = (*iter).second;
- pp_printf (pp, ": %s (origin: ",
- sm.get_state_name (e.m_state));
- e.m_origin.print (pp);
- pp_string (pp, ")");
+ pp_printf (pp, ": %s", sm.get_state_name (e.m_state));
+ if (model)
+ if (tree rep = model->get_representative_tree (sid))
+ {
+ pp_string (pp, " (");
+ dump_quoted_tree (pp, rep);
+ pp_character (pp, ')');
+ }
+ if (!e.m_origin.null_p ())
+ {
+ pp_string (pp, " (origin: ");
+ e.m_origin.print (pp);
+ if (model)
+ if (tree rep = model->get_representative_tree (e.m_origin))
+ {
+ pp_string (pp, " (");
+ dump_quoted_tree (pp, rep);
+ pp_character (pp, ')');
+ }
+ pp_string (pp, ")");
+ }
}
pp_string (pp, "}");
}
@@ -186,7 +207,7 @@ sm_state_map::dump (const state_machine &sm) const
pretty_printer pp;
pp_show_color (&pp) = pp_show_color (global_dc->printer);
pp.buffer->stream = stderr;
- print (sm, &pp);
+ print (sm, NULL, &pp);
pp_newline (&pp);
pp_flush (&pp);
}
@@ -696,7 +717,7 @@ program_state::print (const extrinsic_state &ext_state,
if (!smap->is_empty_p ())
{
pp_printf (pp, "%s: ", ext_state.get_name (i));
- smap->print (ext_state.get_sm (i), pp);
+ smap->print (ext_state.get_sm (i), m_region_model, pp);
pp_newline (pp);
}
}
@@ -707,7 +728,9 @@ program_state::print (const extrinsic_state &ext_state,
}
}
-/* Dump a multiline representation of this state to PP. */
+/* Dump a representation of this state to PP.
+ If SUMMARIZE is true, print a one-line summary;
+ if false, print a detailed multiline representation. */
void
program_state::dump_to_pp (const extrinsic_state &ext_state,
@@ -723,16 +746,22 @@ program_state::dump_to_pp (const extrinsic_state &ext_state,
{
if (!smap->is_empty_p ())
{
+ if (summarize)
+ pp_space (pp);
pp_printf (pp, "%s: ", ext_state.get_name (i));
- smap->print (ext_state.get_sm (i), pp);
- pp_newline (pp);
+ smap->print (ext_state.get_sm (i), m_region_model, pp);
+ if (!summarize)
+ pp_newline (pp);
}
}
if (!m_valid)
{
+ if (summarize)
+ pp_space (pp);
pp_printf (pp, "invalid state");
- pp_newline (pp);
+ if (!summarize)
+ pp_newline (pp);
}
}
@@ -1231,6 +1260,30 @@ state_change::validate (const program_state &new_state,
namespace selftest {
+/* Implementation detail of ASSERT_DUMP_EQ. */
+
+static void
+assert_dump_eq (const location &loc,
+ const program_state &state,
+ const extrinsic_state &ext_state,
+ bool summarize,
+ const char *expected)
+{
+ auto_fix_quotes sentinel;
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ state.dump_to_pp (ext_state, summarize, &pp);
+ ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected);
+}
+
+/* Assert that STATE.dump_to_pp (SUMMARIZE) is EXPECTED. */
+
+#define ASSERT_DUMP_EQ(STATE, EXT_STATE, SUMMARIZE, EXPECTED) \
+ SELFTEST_BEGIN_STMT \
+ assert_dump_eq ((SELFTEST_LOCATION), (STATE), (EXT_STATE), (SUMMARIZE), \
+ (EXPECTED)); \
+ SELFTEST_END_STMT
+
/* Tests for sm_state_map. */
static void
@@ -1364,6 +1417,56 @@ test_sm_state_map ()
// TODO: coverage for purging
}
+/* Verify that program_state::dump_to_pp works as expected. */
+
+static void
+test_program_state_dumping ()
+{
+ /* Create a program_state for a global ptr "p" that has
+ malloc sm-state, pointing to a region on the heap. */
+ tree p = build_global_decl ("p", ptr_type_node);
+
+ state_machine *sm = make_malloc_state_machine (NULL);
+ const state_machine::state_t UNCHECKED_STATE
+ = sm->get_state_by_name ("unchecked");
+ auto_delete_vec <state_machine> checkers;
+ checkers.safe_push (sm);
+ extrinsic_state ext_state (checkers);
+
+ program_state s (ext_state);
+ region_model *model = s.m_region_model;
+ region_id new_rid = model->add_new_malloc_region ();
+ svalue_id ptr_sid
+ = model->get_or_create_ptr_svalue (ptr_type_node, new_rid);
+ model->set_value (model->get_lvalue (p, NULL),
+ ptr_sid, NULL);
+ sm_state_map *smap = s.m_checker_states[0];
+
+ smap->impl_set_state (ptr_sid, UNCHECKED_STATE, svalue_id::null ());
+ ASSERT_EQ (smap->get_state (ptr_sid), UNCHECKED_STATE);
+
+ ASSERT_DUMP_EQ
+ (s, ext_state, false,
+ "rmodel: r0: {kind: `root', parent: null, sval: null}\n"
+ "|-heap: r1: {kind: `heap', parent: r0, sval: sv0}\n"
+ "| |: sval: sv0: {poisoned: uninit}\n"
+ "| `-r2: {kind: `symbolic', parent: r1, sval: null}\n"
+ "`-globals: r3: {kind: `globals', parent: r0, sval: null, map: {`p': r4}}\n"
+ " `-`p': r4: {kind: `primitive', parent: r3, sval: sv1, type: `void *'}\n"
+ " |: sval: sv1: {type: `void *', &r2}\n"
+ " |: type: `void *'\n"
+ "svalues:\n"
+ " sv0: {poisoned: uninit}\n"
+ " sv1: {type: `void *', &r2}\n"
+ "constraint manager:\n"
+ " equiv classes:\n"
+ " constraints:\n"
+ "malloc: {sv1: unchecked (`p')}\n");
+
+ ASSERT_DUMP_EQ (s, ext_state, true,
+ "rmodel: p: &r2 malloc: {sv1: unchecked (`p')}");
+}
+
/* Verify that program_states with identical sm-state can be merged,
and that the merged program_state preserves the sm-state. */
@@ -1466,6 +1569,7 @@ void
analyzer_program_state_cc_tests ()
{
test_sm_state_map ();
+ test_program_state_dumping ();
test_program_state_merging ();
test_program_state_merging_2 ();
}