diff options
Diffstat (limited to 'gcc/analyzer')
64 files changed, 2416 insertions, 944 deletions
diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 1fbba5d..d31cbbc 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,240 @@ +2025-06-30 David Malcolm <dmalcolm@redhat.com> + + * access-diagram.cc: Use nullptr rather than NULL where + appropriate. + * analyzer-language.cc: Likewise. + * analyzer-language.h: Likewise. + * analyzer-logging.h: Likewise. + * analyzer-pass.cc: Likewise. + * analyzer.cc: Likewise. + * bounds-checking.cc: Likewise. + * call-details.cc: Likewise. + * call-string.cc: Likewise. + * call-string.h: Likewise. + * call-summary.cc: Likewise. + * checker-event.cc: Likewise. + * common.h: Likewise. + * constraint-manager.cc: Likewise. + * constraint-manager.h: Likewise. + * diagnostic-manager.cc: Likewise. + * engine.cc: Likewise. + * exploded-graph.h: Likewise. + * function-set.cc: Likewise + * infinite-recursion.cc: Likewise + * inlining-iterator.h: Likewise + * kf.cc: Likewise + * known-function-manager.cc: Likewise + * pending-diagnostic.cc: Likewise + * program-point.cc: Likewise + * program-point.h: Likewise + * program-state.cc: Likewise + * program-state.h: Likewise + * record-layout.cc: Likewise + * region-model-asm.cc: Likewise + * region-model-manager.cc: Likewise + * region-model-manager.h: Likewise + * region-model-reachability.cc: Likewise + * region-model.cc: Likewise + * region-model.h: Likewise + * region.cc: Likewise + * region.h: Likewise + * sm-fd.cc: Likewise + * sm-malloc.cc: Likewise + * sm-pattern-test.cc: Likewise + * sm-signal.cc: Likewise + * sm-taint.cc: Likewise + * sm.cc: Likewise + * sm.h: Likewise + * state-purge.cc: Likewise + * state-purge.h: Likewise + * store.cc: Likewise + * store.h: Likewise + * supergraph.cc: Likewise + * supergraph.h: Likewise + * svalue.cc: Likewise + * svalue.h: Likewise + * varargs.cc: Likewise + +2025-06-30 David Malcolm <dmalcolm@redhat.com> + + * checker-event.cc (function_entry_event::get_meaning): Convert + diagnostic_event::meaning enums to enum class. + (cfg_edge_event::get_meaning): Likewise. + (call_event::get_meaning): Likewise. + (return_event::get_meaning): Likewise. + (start_consolidated_cfg_edges_event::get_meaning): Likewise. + (inlined_call_event::get_meaning): Likewise. + (warning_event::get_meaning): Likewise. + * sm-fd.cc (fd_diagnostic::get_meaning_for_state_change): + Likewise. + * sm-file.cc (file_diagnostic::get_meaning_for_state_change): + Likewise. + * sm-malloc.cc (malloc_diagnostic::get_meaning_for_state_change): + Likewise. + * sm-sensitive.cc + (exposure_through_output_file::get_meaning_for_state_change): + Likewise. + * sm-taint.cc (taint_diagnostic::get_meaning_for_state_change): + Likewise. + * varargs.cc + (va_list_sm_diagnostic::get_meaning_for_state_change): Likewise. + +2025-06-30 Jakub Jelinek <jakub@redhat.com> + + PR c/120520 + PR c/117023 + * sm-malloc.cc (malloc_state_machine::on_stmt): Handle 3 argument + nonnull_if_nonzero attribute. + +2025-06-23 David Malcolm <dmalcolm@redhat.com> + + * region-model.cc + (exception_thrown_from_unrecognized_call::print): Add + "final override" to vfunc. + +2025-06-23 David Malcolm <dmalcolm@redhat.com> + + PR other/116792 + * ana-state-to-diagnostic-state.cc: New file. + * ana-state-to-diagnostic-state.h: New file. + * checker-event.cc: Include "xml.h". + (checker_event::checker_event): Initialize m_path. + (checker_event::prepare_for_emission): Store the path pointer into + m_path. + (checker_event::maybe_make_xml_state): New. + (function_entry_event::function_entry_event): Add "state" param + and use it to initialize m_state. + (superedge_event::get_program_state): New. + (call_event::get_program_state): New. + (warning_event::get_program_state): New. + * checker-event.h (checker_event::get_program_state): New vfunc. + (checker_event::maybe_make_xml_state): New decl. + (checker_event::m_path): New field. + (statement_event::get_program_state): New vfunc impl. + (function_entry_event::function_entry_event): Add "state" param. + (function_entry_event::get_program_state): New vfunc impl. + (function_entry_event::m_state): New field. + (state_change_event::get_program_state): New vfunc impl. + (superedge_event::get_program_state): New vfunc decl. + (warning_event::warning_event): Add "program_state_" param and + copy it. + (warning_event::get_program_state): New vfunc decl. + (warning_event::m_program_state): New field. + * checker-path.h (checker_path::checker_path): Add ext_state param. + (checker_path::get_ext_state): New accessor. + (checker_path::m_ext_state): New field. + * common.h: Define INCLUDE_MAP and INCLUDE_STRING. + * diagnostic-manager.cc (saved_diagnostic::operator==): Don't + deduplicate dump_path_diagnostic instances. + (diagnostic_manager::emit_saved_diagnostic): Pass ext_state to + checker_path ctor. + * engine.cc: + (impl_region_model_context::on_state_leak): Pass old and new state + to state_machine::on_leak. + (exploded_node::on_stmt_pre): Implement __analyzer_dump_xml and + __analyzer_dump_dot. + * exploded-graph.h (impl_region_model_context::get_state): New. + * infinite-recursion.cc + (recursive_function_entry_event::recursive_function_entry_event): + Add "dst_state" param and pass to function_entry_event ctor. + (infinite_recursion_diagnostic::add_function_entry_event): Pass state + to event ctor. + * kf-analyzer.cc: Include "analyzer/program-state.h" + (dump_path_diagnostic::dump_path_diagnostic): Add "state" param. + (dump_path_diagnostic::get_final_state): New. + (dump_path_diagnostic::m_state): New field. + (kf_analyzer_dump_path::impl_call_pre): Pass state to warning. + * pending-diagnostic.cc + (pending_diagnostic::add_function_entry_event): Pass state to + function_entry_event. + (pending_diagnostic::add_final_event): Likewise to warning_event. + * pending-diagnostic.h (pending_diagnostic::get_final_state): New + vfunc decl. + * program-state.cc: Include "diagnostic-state.h", "graphviz.h" and + "analyzer/ana-state-to-diagnostic-state.h". + (program_state::dump_dot): New. + * program-state.h: Include "text-art/tree-widget.h" and + "analyzer/store.h". + (class xml::document): New forward decl. + (make_xml): New. + (dump_xml_to_pp): New. + (dump_xml_to_file): New. + (dump_xml): New. + (dump_dot): New. + * record-layout.cc (record_layout::record_layout): Make param + const_tree. + * record-layout.h (item::item): Likewise. + (item::m_field): Likewise. + (record_layout::record_layout): Likewise. + (record_layout::begin): New. + (record_layout::end): New. + * region-model.cc + (exposure_through_uninit_copy::complain_about_fully_uninit_item): + Use const_tree. + (exposure_through_uninit_copy::complain_about_partially_uninit_item): + Likewise. + * region-model.h (region_model_context::get_state): New vfunc. + (noop_region_model_context::get_state): New. + (region_model_context_decorator::get_state): New. + * sm-fd.cc (fd_leak::fd_leak): Add "final_state" param and capture + it if present. + (fd_leak::get_final_state): New. + (fd_leak::m_final_state): New. + (fd_state_machine::on_open): Pass nullptr for new "final_state" + param. + (fd_state_machine::on_creat): Likewise. + (fd_state_machine::on_socket): Likewise. + (fd_state_machine::on_accept): Likewise. + (fd_state_machine::on_leak): Add state params and pass new state + as final state to fd_leak ctor. + * sm-file.cc: Include "analyzer/program-state.h". + (file_leak::file_leak): Add "final_state" param and capture it if + present. + (file_leak::get_final_state): New. + (file_leak::m_final_state): New. + (fileptr_state_machine::on_leak): Add state params and pass new + state as final state to fd_leak ctor. + * sm-malloc.cc: Include + "analyzer/ana-state-to-diagnostic-state.h". + (malloc_leak::malloc_leak): Add "final_state" param and use it. + (malloc_leak::get_final_state): New vfunc impl. + (malloc_leak::m_final_state): New field. + (malloc_state_machine::on_leak): Add state params; capture final + state. + (malloc_state_machine::add_state_to_xml): New. + * sm.cc (state_machine::on_leak): Add "old_state" and "new_state" + params. Use nullptr. + (state_machine::add_state_to_xml): New. + (state_machine::add_global_state_to_xml): New. + * sm.h (class xml_state): New forward decl. + (state_machine::on_leak): Add state params. + (state_machine::add_state_to_xml): New vfunc decl. + (state_machine::add_global_state_to_xml): New vfunc decl. + * store.h (bit_range::operator<): New. + * varargs.cc (va_list_leak::va_list_leak): Add final_state param + and capture it if non-null. + (va_list_leak::get_final_state): New. + (va_list_leak::m_final_state): New. + (va_list_state_machine::on_leak): Add state params and pass final + state to va_list_leak ctor. + +2025-06-18 David Malcolm <dmalcolm@redhat.com> + + * checker-event.h (checker_event::get_kind): New accessor. + (checker_event::m_kind): Make private. + * checker-path.cc (checker_path::maybe_log): Use accessor for + checker_event::m_kind. + (checker_path::add_event): Likewise. + (checker_path::debug): Likewise. + (checker_path::cfg_edge_pair_at_p): Likewise. + (checker_path::inject_any_inlined_call_events): Likewise. + * diagnostic-manager.cc + (diagnostic_manager::prune_for_sm_diagnostic): Likewise. + (diagnostic_manager::prune_for_sm_diagnostic): Likewise. + (diagnostic_manager::consolidate_conditions): Likewise. + (diagnostic_manager::consolidate_unwind_events): Likewise. + (diagnostic_manager::finish_pruning): Likewise. + 2025-05-06 David Malcolm <dmalcolm@redhat.com> * checker-event.cc (checker_event::checker_event): Update diff --git a/gcc/analyzer/access-diagram.cc b/gcc/analyzer/access-diagram.cc index 4283360..90b396c 100644 --- a/gcc/analyzer/access-diagram.cc +++ b/gcc/analyzer/access-diagram.cc @@ -1116,7 +1116,7 @@ public: { logger.start_log_line (); logger.log_partial ("table_x: %i", table_x); - access_range range_for_column (NULL, bit_range (0, 0)); + access_range range_for_column (nullptr, bit_range (0, 0)); if (maybe_get_access_range_for_table_x (table_x, &range_for_column)) { logger.log_partial (": range: "); @@ -2244,7 +2244,7 @@ private: for (int table_x = 0; table_x < t.get_size ().w; table_x++) { const int table_y = 1; - access_range range_for_column (NULL, bit_range (0, 0)); + access_range range_for_column (nullptr, bit_range (0, 0)); if (m_btm.maybe_get_access_range_for_table_x (table_x, &range_for_column)) { @@ -2495,7 +2495,7 @@ private: std::vector<bit_offset_t> bit_sizes (num_columns); for (unsigned table_x = 0; table_x < num_columns; table_x++) { - access_range range_for_column (NULL, bit_range (0, 0)); + access_range range_for_column (nullptr, bit_range (0, 0)); if (m_btm.maybe_get_access_range_for_table_x (table_x, &range_for_column)) { diff --git a/gcc/analyzer/ana-state-to-diagnostic-state.cc b/gcc/analyzer/ana-state-to-diagnostic-state.cc new file mode 100644 index 0000000..b85a2f1 --- /dev/null +++ b/gcc/analyzer/ana-state-to-diagnostic-state.cc @@ -0,0 +1,786 @@ +/* Converting ana::program_state to XML state documents. + Copyright (C) 2025 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/>. */ + +#define INCLUDE_ALGORITHM +#define INCLUDE_MAP +#define INCLUDE_SET +#include "analyzer/common.h" + +#include "xml.h" +#include "xml-printer.h" + +#include "analyzer/region-model.h" +#include "analyzer/program-state.h" +#include "analyzer/record-layout.h" +#include "analyzer/ana-state-to-diagnostic-state.h" + +#if ENABLE_ANALYZER + +#if __GNUC__ >= 10 +#pragma GCC diagnostic ignored "-Wformat" +#endif + +namespace ana { + +static void +set_wi_attr (xml::element &e, + const char *attr_name, + const wide_int_ref &w, + signop sgn) +{ + pretty_printer pp; + pp_wide_int (&pp, w, sgn); + e.set_attr (attr_name, pp_formatted_text (&pp)); +} + +static void +set_type_attr (xml::element &e, const_tree type) +{ + gcc_assert (type); + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + pp_printf (&pp, "%T", type); + e.set_attr ("type", pp_formatted_text (&pp)); +} + +static void +set_bits_attr (xml::element &e, + bit_range bits) +{ + pretty_printer pp; + bits.dump_to_pp (&pp); + e.set_attr ("bits", pp_formatted_text (&pp)); +} + +static void +set_region_id_attr (xml::element &e, + const region ®) +{ + e.set_attr ("region_id", std::to_string (reg.get_id ())); +} + +// class xml_state : public xml::document + +xml_state::xml_state (const program_state &state, + const extrinsic_state &ext_state) +: xml::document (), + m_state (state), + m_ext_state (ext_state), + m_mgr (*ext_state.get_engine ()->get_model_manager ()), + m_root (nullptr) +{ + auto root = std::make_unique<xml::element> ("state-diagram", false); + m_root = root.get (); + add_child (std::move (root)); + + /* Find pointers to heap-allocated regions, and record their types, + so that we have a user-friendly way of showing the memory + (by field, rather than by byte offset). */ + for (auto cluster_iter : *state.m_region_model->get_store ()) + for (auto binding_iter : *cluster_iter.second) + { + const svalue *svalue = binding_iter.second; + if (const region *reg = svalue->maybe_get_region ()) + if (svalue->get_type () && !reg->get_type ()) + { + tree pointed_to_type = TREE_TYPE (svalue->get_type ()); + if (!VOID_TYPE_P (pointed_to_type)) + m_types_for_untyped_regions[reg] = pointed_to_type; + } + } + + /* TODO: look for vtable pointers at the top of dynamically-allocated + regions and use that type as a fallback. */ + + /* Find regions of interest. + Create elements per region, and build into hierarchy. + Add edges for pointers. */ + + /* Create stack, from top to bottom. */ + for (int i = state.m_region_model->get_stack_depth () - 1; i >= 0; --i) + { + const frame_region *reg = state.m_region_model->get_frame_at_index (i); + get_or_create_element (*reg); + } + + /* Create bound memory. */ + for (auto iter : *state.m_region_model->get_store ()) + { + const bool create_all = false; // "true" for verbose, for debugging + create_elements_for_binding_cluster (*iter.second, create_all); + } + + /* TODO: Constraints. */ + + /* Annotate with information from state machines. */ + { + int i; + sm_state_map *smap; + FOR_EACH_VEC_ELT (state.m_checker_states, i, smap) + { + auto &sm = ext_state.get_sm (i); + for (const auto &iter : *smap) + sm.add_state_to_xml (*this, *iter.first, iter.second.m_state); + if (auto s = smap->get_global_state ()) + sm.add_global_state_to_xml (*this, s); + } + } +} + +xml::element & +xml_state::get_or_create_element (const region ®) +{ + auto existing = m_region_to_element_map.find (®); + if (existing != m_region_to_element_map.end ()) + return *existing->second; + + auto &e = create_and_add_element (reg); + m_region_to_element_map[®] = &e; + return e; +} + +xml::element& +xml_state::create_and_add_element (const region ®) +{ + auto e = create_element (reg); + xml::element &result = *e; + if (auto parent_reg = reg.get_parent_region ()) + { + auto parent_element = &get_or_create_element (*parent_reg); + parent_element->add_child (std::move (e)); + } + else + m_root->add_child (std::move (e)); + return result; +} + +std::unique_ptr<xml::element> +xml_state::make_memory_space_element (const char *label) +{ + auto e = std::make_unique<xml::element> ("memory-space", false); + e->set_attr ("label", label); + return e; +} + +std::unique_ptr<xml::element> +xml_state::create_element (const region ®) +{ + std::unique_ptr<xml::element> e; + switch (reg.get_kind ()) + { + default: + gcc_unreachable (); + + case RK_FRAME: + { + e = std::make_unique<xml::element> ("stack-frame", false); + const frame_region &frame_reg + = static_cast<const frame_region &> (reg); + { + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + pp_printf (&pp, "%E", frame_reg.get_fndecl ()); + e->set_attr ("function", pp_formatted_text (&pp)); + } + } + break; + case RK_GLOBALS: + e = make_memory_space_element ("Globals"); + break; + case RK_CODE: + e = make_memory_space_element ("Code"); + break; + case RK_FUNCTION: + e = std::make_unique<xml::element> ("function", false); + // TODO + break; + case RK_LABEL: + e = std::make_unique<xml::element> ("label", false); + // TODO + break; + case RK_STACK: + e = std::make_unique<xml::element> ("stack", false); + break; + case RK_HEAP: + e = make_memory_space_element ("Heap"); + break; + case RK_THREAD_LOCAL: + e = make_memory_space_element ("Thread-local"); + break; + case RK_ROOT: + e = std::make_unique<xml::element> ("memory-regions", false); + break; + case RK_SYMBOLIC: + e = std::make_unique<xml::element> ("symbolic-region", false); + // TODO + break; + case RK_DECL: + { + e = std::make_unique<xml::element> ("variable", false); + const decl_region &decl_reg + = static_cast<const decl_region &> (reg); + { + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + pp_printf (&pp, "%E", decl_reg.get_decl ()); + e->set_attr ("name", pp_formatted_text (&pp)); + } + set_type_attr (*e, TREE_TYPE (decl_reg.get_decl ())); + } + break; + case RK_FIELD: + e = std::make_unique<xml::element> ("field", false); + break; + case RK_ELEMENT: + e = std::make_unique<xml::element> ("element", false); + break; + case RK_OFFSET: + e = std::make_unique<xml::element> ("offset-region", false); + // TODO + break; + case RK_SIZED: + e = std::make_unique<xml::element> ("sized-region", false); + // TODO + break; + case RK_CAST: + e = std::make_unique<xml::element> ("cast-region", false); + // TODO + break; + case RK_HEAP_ALLOCATED: + e = std::make_unique<xml::element> ("heap-buffer", false); + set_attr_for_dynamic_extents (reg, *e); + break; + case RK_ALLOCA: + e = std::make_unique<xml::element> ("alloca-buffer", false); + set_attr_for_dynamic_extents (reg, *e); + break; + case RK_STRING: + e = std::make_unique<xml::element> ("string-region", false); + // TODO + break; + case RK_BIT_RANGE: + e = std::make_unique<xml::element> ("RK_BIT_RANGE", false); // TODO + break; + case RK_VAR_ARG: + e = std::make_unique<xml::element> ("RK_VAR_ARG", false); // TODO + break; + case RK_ERRNO: + e = std::make_unique<xml::element> ("errno", false); + break; + case RK_PRIVATE: + e = std::make_unique<xml::element> ("RK_PRIVATE", false); // TODO + break; + case RK_UNKNOWN: + e = std::make_unique<xml::element> ("RK_UNKNOWN", false); // TODO + break; + } + gcc_assert (e); + + set_region_id_attr (*e, reg); + + if (reg.get_base_region () == ®) + if (!reg.get_type ()) + { + auto search + = m_types_for_untyped_regions.find (®); + if (search != m_types_for_untyped_regions.end ()) + { + tree type_to_use = search->second; + set_type_attr (*e, type_to_use); + } + } + + return e; +} + +void +xml_state::create_elements_for_binding_cluster (const binding_cluster &cluster, + bool create_all) +{ + /* TODO: + - symbolic bindings + - get current svalue, so as to get "zeros" and "uninitialized". */ + + concrete_bindings_t conc_bindings; + for (auto iter : cluster) + { + const binding_key *key = iter.first; + const svalue *svalue = iter.second; + if (auto conc_key = key->dyn_cast_concrete_binding ()) + conc_bindings[conc_key->get_bit_range ()] = svalue; + if (const region *reg = svalue->maybe_get_region ()) + get_or_create_element (*reg); + } + + auto &e = get_or_create_element (*cluster.get_base_region ()); + + e.add_child (create_element_for_conc_bindings (conc_bindings)); + + const region *typed_reg = cluster.get_base_region (); + if (!typed_reg->get_type ()) + { + auto search + = m_types_for_untyped_regions.find (cluster.get_base_region ()); + if (search != m_types_for_untyped_regions.end ()) + { + tree type_to_use = search->second; + typed_reg = m_mgr.get_cast_region (typed_reg, type_to_use); + } + } + + if (typed_reg->get_type ()) + populate_element_for_typed_region (e, + *typed_reg, + conc_bindings, + create_all); + else + { + // TODO + } +} + +std::unique_ptr<xml::element> +xml_state::create_element_for_conc_bindings (const concrete_bindings_t &conc_bindings) +{ + auto e = std::make_unique<xml::element> ("concrete-bindings", false); + for (auto iter : conc_bindings) + { + const bit_range bits = iter.first; + const svalue *sval = iter.second; + auto binding_element + = std::make_unique<xml::element> ("binding", false); + set_bits_attr (*binding_element, bits); + { + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + sval->dump_to_pp (&pp, true); + binding_element->set_attr ("value", pp_formatted_text (&pp)); + if (auto svalue_element = create_element_for_svalue (sval)) + binding_element->add_child (std::move (svalue_element)); + } + e->add_child (std::move (binding_element)); + } + return e; +} + +// Try to get the bit_range of REG within its base region +bool +xml_state::get_bit_range_within_base_region (const region ®, + bit_range &out) +{ + region_offset start_offset = reg.get_offset (&m_mgr); + if (!start_offset.concrete_p ()) + return false; + region_offset next_offset = reg.get_next_offset (&m_mgr); + if (!next_offset.concrete_p ()) + return false; + out = bit_range (start_offset.get_bit_offset (), + next_offset.get_bit_offset () + - start_offset.get_bit_offset ()); + return true; +} + +void +xml_state::populate_element_for_typed_region (xml::element &e, + const region ®, + const concrete_bindings_t &conc_bindings, + bool create_all) +{ + const_tree reg_type = reg.get_type (); + gcc_assert (reg_type); + set_type_attr (e, reg_type); + + bit_range bits (0, 0); + if (get_bit_range_within_base_region (reg, bits)) + { + set_bits_attr (e, bits); + + auto search = conc_bindings.find (bits); + if (search != conc_bindings.end ()) + { + const svalue *bound_sval = search->second; + if (auto svalue_element = create_element_for_svalue (bound_sval)) + { + xml::printer xp (e); + xp.push_tag ("value-of-region"); + xp.append (std::move (svalue_element)); + } + } + } + + switch (TREE_CODE (reg_type)) + { + default: + break; + + case ARRAY_TYPE: + { + tree domain = TYPE_DOMAIN (reg_type); + if (!domain) + return; + const_tree max_idx = TYPE_MAX_VALUE (domain); + if (!max_idx) + return; + if (TREE_CODE (max_idx) != INTEGER_CST) + return; + const_tree min_idx = TYPE_MIN_VALUE (domain); + if (TREE_CODE (min_idx) != INTEGER_CST) + return; + for (offset_int idx = wi::to_offset (min_idx); + idx <= wi::to_offset (max_idx); + ++idx) + { + const_tree element_type = TREE_TYPE (reg_type); + const svalue *sval_index + = m_mgr.get_or_create_int_cst (domain, idx); + const region *child_reg + = m_mgr.get_element_region (®, + const_cast<tree> (element_type), + sval_index); + if (show_child_element_for_child_region_p (*child_reg, + conc_bindings, + create_all)) + { + // Here "element" is in the xml sense + auto child_element + = std::make_unique<xml::element> ("element", false); + set_wi_attr (*child_element, "index", idx, UNSIGNED); + set_region_id_attr (*child_element, *child_reg); + // Recurse: + gcc_assert (element_type); + populate_element_for_typed_region (*child_element, + *child_reg, + conc_bindings, + create_all); + e.add_child (std::move (child_element)); + } + } + } + break; + + case RECORD_TYPE: + { + const record_layout layout (reg_type); + for (auto item : layout) + { + if (item.m_is_padding) + { + const bit_range bits (0, item.m_bit_range.m_size_in_bits); + const region *child_reg + = m_mgr.get_bit_range (®, NULL_TREE, bits); + if (show_child_element_for_child_region_p (*child_reg, + conc_bindings, + create_all)) + { + auto child_element + = std::make_unique<xml::element> ("padding", false); + set_wi_attr (*child_element, "num_bits", + item.m_bit_range.m_size_in_bits, SIGNED); + e.add_child (std::move (child_element)); + } + } + else + { + const region *child_reg + = m_mgr.get_field_region (®, + const_cast<tree> (item.m_field)); + if (show_child_element_for_child_region_p (*child_reg, + conc_bindings, + create_all)) + { + auto child_element + = std::make_unique<xml::element> ("field", false); + { + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + pp_printf (&pp, "%D", item.m_field); + child_element->set_attr ("name", + pp_formatted_text (&pp)); + } + set_region_id_attr (*child_element, *child_reg); + // Recurse: + populate_element_for_typed_region (*child_element, + *child_reg, + conc_bindings, + create_all); + e.add_child (std::move (child_element)); + } + } + } + } + break; + } +} + +void +xml_state::set_attr_for_dynamic_extents (const region ®, xml::element &e) +{ + const svalue *sval = m_state.m_region_model->get_dynamic_extents (®); + if (sval) + { + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + if (auto cst = sval->maybe_get_constant ()) + pp_wide_int (&pp, wi::to_wide (cst), UNSIGNED); + else + sval->dump_to_pp (&pp, true); + e.set_attr ("dynamic-extents", pp_formatted_text (&pp)); + } +} + +bool +xml_state:: +show_child_element_for_child_region_p (const region ®, + const concrete_bindings_t &conc_bindings, + bool create_all) +{ + if (create_all) + return true; + bit_range reg_bits (0, 0); + if (!get_bit_range_within_base_region (reg, reg_bits)) + return true; + + /* Is any of "bits" bound? + TODO: ideally there would be a more efficient way to do this, using + spatial relationships. */ + for (auto iter : conc_bindings) + { + const bit_range bound_bits = iter.first; + if (bound_bits.intersects_p (reg_bits)) + return true; + } + return false; +} + +std::unique_ptr<xml::element> +xml_state::create_element_for_svalue (const svalue *sval) +{ + if (!sval) + return nullptr; + + std::unique_ptr<xml::element> result; + switch (sval->get_kind ()) + { + default: + gcc_unreachable (); + case SK_REGION: + { + const region_svalue *region_sval = (const region_svalue *)sval; + result + = std::make_unique<xml::element> ("pointer-to-region", false); + set_region_id_attr (*result, *region_sval->get_pointee ()); + } + break; + case SK_CONSTANT: + { + const constant_svalue *constant_sval = (const constant_svalue *)sval; + result = std::make_unique<xml::element> ("constant", false); + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + pp_printf (&pp, "%E", constant_sval->get_constant ()); + result->set_attr ("value", pp_formatted_text (&pp)); + } + break; + case SK_UNKNOWN: + result = std::make_unique<xml::element> ("unknown", false); + break; + case SK_POISONED: + { + const poisoned_svalue *poisoned_sval = (const poisoned_svalue *)sval; + switch (poisoned_sval->get_poison_kind ()) + { + default: + gcc_unreachable (); + case poison_kind::uninit: + result = std::make_unique<xml::element> ("uninitialized", false); + break; + case poison_kind::freed: + result = std::make_unique<xml::element> ("freed", false); + break; + case poison_kind::deleted: + result = std::make_unique<xml::element> ("deleted", false); + break; + case poison_kind::popped_stack: + result = std::make_unique<xml::element> ("popped-stack", false); + break; + } + } + break; + case SK_SETJMP: + { + //const setjmp_svalue *setjmp_sval = (const setjmp_svalue *)sval; + result = std::make_unique<xml::element> ("setjmp-buffer", false); + // TODO + } + break; + case SK_INITIAL: + { + const initial_svalue *initial_sval = (const initial_svalue *)sval; + result = std::make_unique<xml::element> ("initial-value-of", false); + set_region_id_attr (*result, *initial_sval->get_region ()); + } + break; + case SK_UNARYOP: + { + const unaryop_svalue *unaryop_sval = (const unaryop_svalue *)sval; + result = std::make_unique<xml::element> ("unary-op", false); + result->set_attr ("op", get_tree_code_name (unaryop_sval->get_op ())); + result->add_child + (create_element_for_svalue (unaryop_sval->get_arg ())); + } + break; + case SK_BINOP: + { + const binop_svalue *binop_sval = (const binop_svalue *)sval; + result = std::make_unique<xml::element> ("binary-op", false); + result->set_attr ("op", get_tree_code_name (binop_sval->get_op ())); + result->add_child (create_element_for_svalue (binop_sval->get_arg0 ())); + result->add_child (create_element_for_svalue (binop_sval->get_arg1 ())); + } + break; + case SK_SUB: + { + //const sub_svalue *sub_sval = (const sub_svalue *)sval; + result = std::make_unique<xml::element> ("subregion-value", false); + // TODO + } + break; + case SK_REPEATED: + { + const repeated_svalue *repeated_sval = (const repeated_svalue *)sval; + result = std::make_unique<xml::element> ("repeated-value", false); + result->add_child + (create_element_for_svalue (repeated_sval->get_outer_size ())); + result->add_child + (create_element_for_svalue (repeated_sval->get_inner_svalue ())); + } + break; + case SK_BITS_WITHIN: + { + const bits_within_svalue *bits_within_sval + = (const bits_within_svalue *)sval; + result = std::make_unique<xml::element> ("bits-within", false); + set_bits_attr (*result, bits_within_sval->get_bits ()); + result->add_child + (create_element_for_svalue (bits_within_sval->get_inner_svalue ())); + } + break; + case SK_UNMERGEABLE: + { + const unmergeable_svalue *unmergeable_sval + = (const unmergeable_svalue *)sval; + result = std::make_unique<xml::element> ("unmergeable", false); + result->add_child + (create_element_for_svalue (unmergeable_sval->get_arg ())); + } + break; + case SK_PLACEHOLDER: + { + const placeholder_svalue *placeholder_sval + = (const placeholder_svalue *)sval; + result = std::make_unique<xml::element> ("placeholder", false); + result->set_attr ("name", placeholder_sval->get_name ()); + } + break; + case SK_WIDENING: + { + //const widening_svalue *widening_sval = (const widening_svalue *)sval; + result = std::make_unique<xml::element> ("iterating-value", false); + // TODO + } + break; + case SK_COMPOUND: + { + //const compound_svalue *compound_sval = (const compound_svalue *)sval; + result = std::make_unique<xml::element> ("compound-value", false); + // TODO + } + break; + case SK_CONJURED: + { + //const conjured_svalue *conjured_sval = (const conjured_svalue *)sval; + result = std::make_unique<xml::element> ("conjured-value", false); + // TODO + } + break; + case SK_ASM_OUTPUT: + { + /* const asm_output_svalue *asm_output_sval + = (const asm_output_svalue *)sval; */ + result = std::make_unique<xml::element> ("asm-output", false); + // TODO + } + break; + case SK_CONST_FN_RESULT: + { + /* const const_fn_result_svalue *const_fn_result_sval + = (const const_fn_result_svalue *)sval; */ + result = std::make_unique<xml::element> ("const-fn-result", false); + // TODO + } + } + + if (result) + { + if (sval->get_type ()) + set_type_attr (*result, sval->get_type ()); + + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + sval->dump_to_pp (&pp, true); + result->set_attr ("dump-text", pp_formatted_text (&pp)); + } + + return result; +} + +std::unique_ptr<xml::document> +program_state::make_xml (const extrinsic_state &ext_state) const +{ + return std::make_unique<xml_state> (*this, ext_state); +} + +void +program_state::dump_xml_to_pp (const extrinsic_state &ext_state, + pretty_printer *pp) const +{ + auto doc = make_xml (ext_state); + doc->write_as_xml (pp, 0, true); +} + +void +program_state::dump_xml_to_file (const extrinsic_state &ext_state, + FILE *outf) const +{ + pretty_printer pp; + pp.set_output_stream (outf); + dump_xml_to_pp (ext_state, &pp); + pp_flush (&pp); +} + +void +program_state::dump_xml (const extrinsic_state &ext_state) const +{ + dump_xml_to_file (ext_state, stderr); +} + +} // namespace ana + +#endif /* #if ENABLE_ANALYZER */ diff --git a/gcc/analyzer/ana-state-to-diagnostic-state.h b/gcc/analyzer/ana-state-to-diagnostic-state.h new file mode 100644 index 0000000..bd6aa46 --- /dev/null +++ b/gcc/analyzer/ana-state-to-diagnostic-state.h @@ -0,0 +1,89 @@ +/* XML documents for dumping state in an easier-to-read form. + Copyright (C) 2025 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_ANA_STATE_TO_XML_STATE_H +#define GCC_ANALYZER_ANA_STATE_TO_XML_STATE_H + +#include "xml.h" + +namespace ana { + +class xml_state : public xml::document +{ +public: + xml_state (const program_state &state, + const extrinsic_state &ext_state); + + xml::element & + get_or_create_element (const region ®); + +private: + xml::element& + create_and_add_element (const region ®); + + static std::unique_ptr<xml::element> + make_memory_space_element (const char *label); + + std::unique_ptr<xml::element> + create_element (const region ®); + + /* Spatially sorted concrete bindings. */ + typedef std::map<bit_range, const svalue *> concrete_bindings_t; + + void + create_elements_for_binding_cluster (const binding_cluster &cluster, + bool create_all); + + std::unique_ptr<xml::element> + create_element_for_conc_bindings (const concrete_bindings_t &conc_bindings); + + // Try to get the bit_range of REG within its base region + bool + get_bit_range_within_base_region (const region ®, + bit_range &out); + + void + populate_element_for_typed_region (xml::element &e, + const region ®, + const concrete_bindings_t &conc_bindings, + bool create_all); + + void + set_attr_for_dynamic_extents (const region ®, xml::element &e); + + bool + show_child_element_for_child_region_p (const region ®, + const concrete_bindings_t &conc_bindings, + bool create_all); + + std::unique_ptr<xml::element> + create_element_for_svalue (const svalue *sval); + + const program_state &m_state; + const extrinsic_state &m_ext_state; + region_model_manager &m_mgr; + xml::element *m_root; + std::map<const region *, xml::element *> m_region_to_element_map; + std::map<const region *, tree> m_types_for_untyped_regions; +}; + +} // namespace ana + +#endif /* GCC_ANALYZER_ANA_STATE_TO_XML_STATE_H */ diff --git a/gcc/analyzer/analyzer-language.cc b/gcc/analyzer/analyzer-language.cc index 9a25baf..d4169f7 100644 --- a/gcc/analyzer/analyzer-language.cc +++ b/gcc/analyzer/analyzer-language.cc @@ -114,7 +114,7 @@ on_finish_translation_unit (const translation_unit &tu) return; FILE *logfile = get_or_create_any_logfile (); - log_user the_logger (NULL); + log_user the_logger (nullptr); if (logfile) the_logger.set_logger (new logger (logfile, 0, 0, *global_dc->get_reference_printer ())); diff --git a/gcc/analyzer/analyzer-language.h b/gcc/analyzer/analyzer-language.h index 1987ee0..a0c85a8 100644 --- a/gcc/analyzer/analyzer-language.h +++ b/gcc/analyzer/analyzer-language.h @@ -35,7 +35,7 @@ class translation_unit public: /* Attempt to look up an value for identifier ID (e.g. in the headers that have been seen). If it is defined and an integer (e.g. either as a - macro or enum), return the INTEGER_CST value, otherwise return NULL. */ + macro or enum), return the INTEGER_CST value, otherwise return NULL_TREE. */ virtual tree lookup_constant_by_id (tree id) const = 0; virtual tree lookup_type_by_id (tree id) const = 0; virtual tree lookup_global_var_by_id (tree id) const = 0; diff --git a/gcc/analyzer/analyzer-logging.h b/gcc/analyzer/analyzer-logging.h index 3208989..e85d293 100644 --- a/gcc/analyzer/analyzer-logging.h +++ b/gcc/analyzer/analyzer-logging.h @@ -91,7 +91,7 @@ public: /* The constructor for log_scope. - The normal case is that the logger is NULL, in which case this should + The normal case is that the logger is nullptr, in which case this should be largely a no-op. If we do have a logger, notify it that we're entering the given scope. @@ -139,7 +139,8 @@ log_scope::~log_scope () } } -/* A log_user is something that potentially uses a logger (which could be NULL). +/* A log_user is something that potentially uses a logger (which could be + nullptr). The log_user class keeps the reference-count of a logger up-to-date. */ @@ -169,8 +170,8 @@ class log_user FILE *get_logger_file () const { - if (m_logger == NULL) - return NULL; + if (m_logger == nullptr) + return nullptr; return m_logger->get_file (); } @@ -181,7 +182,7 @@ class log_user }; /* A shortcut for calling log from a log_user, handling the common - case where the underlying logger is NULL via a no-op. */ + case where the underlying logger is nullptr via a no-op. */ inline void log_user::log (const char *fmt, ...) const @@ -196,7 +197,7 @@ log_user::log (const char *fmt, ...) const } /* A shortcut for starting a log line from a log_user, - handling the common case where the underlying logger is NULL via + handling the common case where the underlying logger is nullptr via a no-op. */ inline void @@ -207,7 +208,7 @@ log_user::start_log_line () const } /* A shortcut for ending a log line from a log_user, - handling the common case where the underlying logger is NULL via + handling the common case where the underlying logger is nullptr via a no-op. */ inline void @@ -218,7 +219,7 @@ log_user::end_log_line () const } /* A shortcut for recording entry into a scope from a log_user, - handling the common case where the underlying logger is NULL via + handling the common case where the underlying logger is nullptr via a no-op. */ inline void @@ -229,7 +230,7 @@ log_user::enter_scope (const char *scope_name) } /* A shortcut for recording exit from a scope from a log_user, - handling the common case where the underlying logger is NULL via + handling the common case where the underlying logger is nullptr via a no-op. */ inline void diff --git a/gcc/analyzer/analyzer-pass.cc b/gcc/analyzer/analyzer-pass.cc index b3a0dfd..559fb94 100644 --- a/gcc/analyzer/analyzer-pass.cc +++ b/gcc/analyzer/analyzer-pass.cc @@ -48,15 +48,15 @@ class pass_analyzer : public ipa_opt_pass_d public: pass_analyzer(gcc::context *ctxt) : ipa_opt_pass_d (pass_data_analyzer, ctxt, - NULL, /* generate_summary */ - NULL, /* write_summary */ - NULL, /* read_summary */ - NULL, /* write_optimization_summary */ - NULL, /* read_optimization_summary */ - NULL, /* stmt_fixup */ + nullptr, /* generate_summary */ + nullptr, /* write_summary */ + nullptr, /* read_summary */ + nullptr, /* write_optimization_summary */ + nullptr, /* read_optimization_summary */ + nullptr, /* stmt_fixup */ 0, /* function_transform_todo_flags_start */ - NULL, /* function_transform */ - NULL) /* variable_transform */ + nullptr, /* function_transform */ + nullptr) /* variable_transform */ {} /* opt_pass methods: */ diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc index 56cb370..938ad6d 100644 --- a/gcc/analyzer/analyzer.cc +++ b/gcc/analyzer/analyzer.cc @@ -518,7 +518,7 @@ make_label_text (bool can_colorize, const char *fmt, ...) va_start (ap, fmt); - text_info ti (_(fmt), &ap, 0, NULL, &rich_loc); + text_info ti (_(fmt), &ap, 0, nullptr, &rich_loc); pp_format (pp.get (), &ti); pp_output_formatted_text (pp.get ()); @@ -549,7 +549,7 @@ make_label_text_n (bool can_colorize, unsigned HOST_WIDE_INT n, const char *fmt = ngettext (singular_fmt, plural_fmt, n); - text_info ti (fmt, &ap, 0, NULL, &rich_loc); + text_info ti (fmt, &ap, 0, nullptr, &rich_loc); pp_format (pp.get (), &ti); pp_output_formatted_text (pp.get ()); diff --git a/gcc/analyzer/bounds-checking.cc b/gcc/analyzer/bounds-checking.cc index a3b1345..d2e2b34 100644 --- a/gcc/analyzer/bounds-checking.cc +++ b/gcc/analyzer/bounds-checking.cc @@ -507,7 +507,7 @@ public: concrete_buffer_over_read (const region_model &model, const region *reg, tree diag_arg, bit_range range, tree bit_bound) - : concrete_past_the_end (model, reg, diag_arg, range, bit_bound, NULL) + : concrete_past_the_end (model, reg, diag_arg, range, bit_bound, nullptr) {} const char *get_kind () const final override @@ -819,7 +819,7 @@ public: concrete_buffer_under_read (const region_model &model, const region *reg, tree diag_arg, bit_range range) - : concrete_out_of_bounds (model, reg, diag_arg, range, NULL) + : concrete_out_of_bounds (model, reg, diag_arg, range, nullptr) {} const char *get_kind () const final override @@ -1119,7 +1119,7 @@ public: const region *reg, tree diag_arg, tree offset, tree num_bytes, tree capacity) : symbolic_past_the_end (model, reg, diag_arg, offset, num_bytes, capacity, - NULL) + nullptr) { } diff --git a/gcc/analyzer/call-details.cc b/gcc/analyzer/call-details.cc index bca8658..cb95843 100644 --- a/gcc/analyzer/call-details.cc +++ b/gcc/analyzer/call-details.cc @@ -43,7 +43,7 @@ namespace ana { call_details::call_details (const gcall &call, region_model *model, region_model_context *ctxt) : m_call (call), m_model (model), m_ctxt (ctxt), - m_lhs_type (NULL_TREE), m_lhs_region (NULL) + m_lhs_type (NULL_TREE), m_lhs_region (nullptr) { m_lhs_type = NULL_TREE; if (tree lhs = gimple_call_lhs (&call)) @@ -81,7 +81,7 @@ call_details::get_logger () const if (m_ctxt) return m_ctxt->get_logger (); else - return NULL; + return nullptr; } /* Get any uncertainty_t associated with the region_model_context. */ @@ -92,7 +92,7 @@ call_details::get_uncertainty () const if (m_ctxt) return m_ctxt->get_uncertainty (); else - return NULL; + return nullptr; } /* If the callsite has a left-hand-side region, set it to RESULT @@ -127,25 +127,25 @@ const_fn_p (const call_details &cd) /* If this CD is known to be a call to a function with __attribute__((const)), attempt to get a const_fn_result_svalue - based on the arguments, or return NULL otherwise. */ + based on the arguments, or return nullptr otherwise. */ static const svalue * maybe_get_const_fn_result (const call_details &cd) { if (!const_fn_p (cd)) - return NULL; + return nullptr; unsigned num_args = cd.num_args (); if (num_args > const_fn_result_svalue::MAX_INPUTS) /* Too many arguments. */ - return NULL; + return nullptr; auto_vec<const svalue *> inputs (num_args); for (unsigned arg_idx = 0; arg_idx < num_args; arg_idx++) { const svalue *arg_sval = cd.get_arg_svalue (arg_idx); if (!arg_sval->can_have_associated_state_p ()) - return NULL; + return nullptr; inputs.quick_push (arg_sval); } @@ -222,8 +222,8 @@ call_details::set_any_lhs_with_defaults () const if (lookup_function_attribute ("malloc")) { const region *new_reg - = m_model->get_or_create_region_for_heap_alloc (NULL, m_ctxt); - m_model->mark_region_as_unknown (new_reg, NULL); + = m_model->get_or_create_region_for_heap_alloc (nullptr, m_ctxt); + m_model->mark_region_as_unknown (new_reg, nullptr); sval = mgr->get_ptr_svalue (get_lhs_type (), new_reg); } else @@ -292,7 +292,7 @@ call_details::get_arg_svalue (unsigned idx) const /* If argument IDX's svalue at the callsite is of pointer type, return the region it points to. - Otherwise return NULL. */ + Otherwise return nullptr. */ const region * call_details::deref_ptr_arg (unsigned idx) const @@ -301,7 +301,7 @@ call_details::deref_ptr_arg (unsigned idx) const return m_model->deref_rvalue (ptr_sval, get_arg_tree (idx), m_ctxt); } -/* Attempt to get the string literal for argument IDX, or return NULL +/* Attempt to get the string literal for argument IDX, or return nullptr otherwise. For use when implementing "__analyzer_*" functions that take string literals. */ @@ -316,7 +316,7 @@ call_details::get_arg_string_literal (unsigned idx) const tree string_cst = string_reg->get_string_cst (); return TREE_STRING_POINTER (string_cst); } - return NULL; + return nullptr; } /* Attempt to get the fndecl used at this call, if known, or NULL_TREE diff --git a/gcc/analyzer/call-string.cc b/gcc/analyzer/call-string.cc index afa8004..0bac8b4 100644 --- a/gcc/analyzer/call-string.cc +++ b/gcc/analyzer/call-string.cc @@ -223,22 +223,22 @@ call_string::cmp_ptr_ptr (const void *pa, const void *pb) } /* Return the pointer to callee of the topmost call in the stack, - or NULL if stack is empty. */ + or nullptr if stack is empty. */ const supernode * call_string::get_callee_node () const { if(m_elements.is_empty ()) - return NULL; + return nullptr; return m_elements[m_elements.length () - 1].m_callee; } /* Return the pointer to caller of the topmost call in the stack, - or NULL if stack is empty. */ + or nullptr if stack is empty. */ const supernode * call_string::get_caller_node () const { if(m_elements.is_empty ()) - return NULL; + return nullptr; return m_elements[m_elements.length () - 1].m_caller; } @@ -266,7 +266,7 @@ call_string::validate () const /* ctor for the root/empty call_string. */ call_string::call_string () -: m_parent (NULL), m_elements () +: m_parent (nullptr), m_elements () { } diff --git a/gcc/analyzer/call-string.h b/gcc/analyzer/call-string.h index 642cf76..f8c6a25 100644 --- a/gcc/analyzer/call-string.h +++ b/gcc/analyzer/call-string.h @@ -129,12 +129,12 @@ private: } template <typename T> static inline void remove (T &entry) { - entry.m_key = element_t (NULL, NULL); + entry.m_key = element_t (nullptr, nullptr); } static const bool empty_zero_p = true; template <typename T> static inline bool is_empty (const T &entry) { - return entry.m_key.m_caller == NULL; + return entry.m_key.m_caller == nullptr; } template <typename T> static inline bool is_deleted (const T &entry) { @@ -142,8 +142,8 @@ private: } template <typename T> static inline void mark_empty (T &entry) { - entry.m_key = element_t (NULL, NULL); - entry.m_value = NULL; + entry.m_key = element_t (nullptr, nullptr); + entry.m_value = nullptr; } template <typename T> static inline void mark_deleted (T &entry) { diff --git a/gcc/analyzer/call-summary.cc b/gcc/analyzer/call-summary.cc index 33de3d6..a094cba 100644 --- a/gcc/analyzer/call-summary.cc +++ b/gcc/analyzer/call-summary.cc @@ -71,9 +71,9 @@ call_summary::get_user_facing_desc (pretty_printer *pp) const if (tree result = DECL_RESULT (fndecl)) { const region *result_reg - = get_state ().m_region_model->get_lvalue (result, NULL); + = get_state ().m_region_model->get_lvalue (result, nullptr); const svalue *result_sval - = get_state ().m_region_model->get_store_value (result_reg, NULL); + = get_state ().m_region_model->get_store_value (result_reg, nullptr); switch (result_sval->get_kind ()) { default: @@ -172,7 +172,7 @@ call_summary_replay::call_summary_replay (const call_details &cd, 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); + = mgr->get_frame_region (nullptr, called_fn); unsigned idx = 0; for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm; @@ -210,7 +210,7 @@ call_summary_replay::call_summary_replay (const call_details &cd, /* 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. */ + Return nullptr if the conversion is not possible. */ const svalue * call_summary_replay::convert_svalue_from_summary (const svalue *summary_sval) @@ -252,7 +252,7 @@ call_summary_replay::convert_svalue_from_summary_1 (const 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; + return nullptr; region_model_manager *mgr = get_manager (); const svalue *caller_ptr = mgr->get_ptr_svalue (summary_sval->get_type (), @@ -268,7 +268,7 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval) return summary_sval; case SK_SETJMP: - return NULL; // TODO + return nullptr; // TODO case SK_INITIAL: { @@ -282,7 +282,7 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval) const region *summary_reg = initial_summary_sval->get_region (); const region *caller_reg = convert_region_from_summary (summary_reg); if (!caller_reg) - return NULL; + return nullptr; const svalue *caller_sval = m_cd.get_model ()->get_store_value (caller_reg, m_cd.get_ctxt ()); return caller_sval; @@ -295,7 +295,7 @@ call_summary_replay::convert_svalue_from_summary_1 (const 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; + return nullptr; region_model_manager *mgr = get_manager (); return mgr->get_or_create_unaryop (summary_sval->get_type (), unaryop_summary_sval->get_op (), @@ -309,11 +309,11 @@ call_summary_replay::convert_svalue_from_summary_1 (const 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; + return nullptr; const svalue *summary_arg1 = binop_summary_sval->get_arg1 (); const svalue *caller_arg1 = convert_svalue_from_summary (summary_arg1); if (!caller_arg1) - return NULL; + return nullptr; region_model_manager *mgr = get_manager (); return mgr->get_or_create_binop (summary_sval->get_type (), binop_summary_sval->get_op (), @@ -328,10 +328,10 @@ call_summary_replay::convert_svalue_from_summary_1 (const 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; + return nullptr; const region *summary_subregion = sub_summary_sval->get_subregion (); if (!summary_subregion) - return NULL; + return nullptr; return mgr->get_or_create_sub_svalue (summary_sval->get_type (), summary_parent_sval, summary_subregion); @@ -346,13 +346,13 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval) const svalue *caller_outer_size = convert_svalue_from_summary (summary_outer_size); if (!caller_outer_size) - return NULL; + return nullptr; 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; + return nullptr; region_model_manager *mgr = get_manager (); return mgr->get_or_create_repeated_svalue (summary_sval->get_type (), caller_outer_size, @@ -369,7 +369,7 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval) const svalue *caller_inner_sval = convert_svalue_from_summary (summary_inner_sval); if (!caller_inner_sval) - return NULL; + return nullptr; region_model_manager *mgr = get_manager (); return mgr->get_or_create_bits_within (summary_sval->get_type (), bits, @@ -384,7 +384,7 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval) const svalue *caller_arg_sval = convert_svalue_from_summary (summary_arg_sval); if (!caller_arg_sval) - return NULL; + return nullptr; region_model_manager *mgr = get_manager (); return mgr->get_or_create_unmergeable (caller_arg_sval); } @@ -400,14 +400,14 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval) = convert_svalue_from_summary (summary_base_sval); if (!(caller_base_sval && caller_base_sval->can_have_associated_state_p ())) - return NULL; + return nullptr; 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; + return nullptr; region_model_manager *mgr = get_manager (); return mgr->get_or_create_widening_svalue (summary_iter_sval->get_type (), @@ -491,7 +491,7 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval) const svalue *caller_input = convert_svalue_from_summary (summary_input); if (!caller_input) - return NULL; + return nullptr; inputs.safe_push (caller_input); } region_model_manager *mgr = get_manager (); @@ -516,7 +516,7 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval) const svalue *caller_input = convert_svalue_from_summary (summary_input); if (!caller_input) - return NULL; + return nullptr; inputs.safe_push (caller_input); } region_model_manager *mgr = get_manager (); @@ -532,7 +532,7 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval) /* 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. */ + Return nullptr if the conversion is not possible. */ const region * call_summary_replay::convert_region_from_summary (const region *summary_reg) @@ -596,7 +596,7 @@ call_summary_replay::convert_region_from_summary_1 (const region *summary_reg) const svalue *caller_ptr_sval = convert_svalue_from_summary (summary_ptr_sval); if (!caller_ptr_sval) - return NULL; + return nullptr; const region *caller_reg = get_caller_model ()->deref_rvalue (caller_ptr_sval, NULL_TREE, @@ -619,7 +619,7 @@ call_summary_replay::convert_region_from_summary_1 (const region *summary_reg) case SSA_NAME: /* We don't care about writes to locals within the summary. */ - return NULL; + return nullptr; case VAR_DECL: /* We don't care about writes to locals within the summary. */ @@ -628,12 +628,12 @@ call_summary_replay::convert_region_from_summary_1 (const region *summary_reg) return summary_reg; else /* Otherwise, we don't care about locals. */ - return NULL; + return nullptr; 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; + return nullptr; } } break; @@ -645,7 +645,7 @@ call_summary_replay::convert_region_from_summary_1 (const region *summary_reg) const region *caller_parent_reg = convert_region_from_summary (summary_parent_reg); if (!caller_parent_reg) - return NULL; + return nullptr; tree field = summary_field_reg->get_field (); return mgr->get_field_region (caller_parent_reg, field); } @@ -658,12 +658,12 @@ call_summary_replay::convert_region_from_summary_1 (const region *summary_reg) const region *caller_parent_reg = convert_region_from_summary (summary_parent_reg); if (!caller_parent_reg) - return NULL; + return nullptr; 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 nullptr; return mgr->get_element_region (caller_parent_reg, summary_reg->get_type (), caller_index); @@ -677,13 +677,13 @@ call_summary_replay::convert_region_from_summary_1 (const region *summary_reg) const region *caller_parent_reg = convert_region_from_summary (summary_parent_reg); if (!caller_parent_reg) - return NULL; + return nullptr; 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 nullptr; return mgr->get_offset_region (caller_parent_reg, summary_reg->get_type (), caller_byte_offset); @@ -697,13 +697,13 @@ call_summary_replay::convert_region_from_summary_1 (const region *summary_reg) const region *caller_parent_reg = convert_region_from_summary (summary_parent_reg); if (!caller_parent_reg) - return NULL; + return nullptr; 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 nullptr; return mgr->get_sized_region (caller_parent_reg, summary_reg->get_type (), caller_byte_size); @@ -715,7 +715,7 @@ call_summary_replay::convert_region_from_summary_1 (const region *summary_reg) const region *caller_parent_reg = convert_region_from_summary (summary_parent_reg); if (!caller_parent_reg) - return NULL; + return nullptr; return mgr->get_cast_region (caller_parent_reg, summary_reg->get_type ()); } @@ -731,7 +731,7 @@ call_summary_replay::convert_region_from_summary_1 (const region *summary_reg) } break; case RK_ALLOCA: - return NULL; + return nullptr; case RK_BIT_RANGE: { const bit_range_region *summary_bit_range_reg @@ -740,7 +740,7 @@ call_summary_replay::convert_region_from_summary_1 (const region *summary_reg) const region *caller_parent_reg = convert_region_from_summary (summary_parent_reg); if (!caller_parent_reg) - return NULL; + return nullptr; const bit_range &bits = summary_bit_range_reg->get_bits (); return mgr->get_bit_range (caller_parent_reg, summary_reg->get_type (), @@ -748,14 +748,14 @@ call_summary_replay::convert_region_from_summary_1 (const region *summary_reg) } break; case RK_VAR_ARG: - return NULL; + return nullptr; } } /* Try to convert SUMMARY_KEY in the summary to a corresponding binding key in the caller. - Return NULL if the conversion is not possible. */ + Return nullptr if the conversion is not possible. */ const binding_key * call_summary_replay::convert_key_from_summary (const binding_key *summary_key) @@ -767,7 +767,7 @@ call_summary_replay::convert_key_from_summary (const binding_key *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; + return nullptr; region_model_manager *mgr = get_manager (); store_manager *store_mgr = mgr->get_store_manager (); return store_mgr->get_symbolic_binding (caller_reg); @@ -780,7 +780,7 @@ call_summary_replay::add_svalue_mapping (const svalue *summary_sval, const svalue *caller_sval) { gcc_assert (summary_sval); - // CALLER_SVAL can be NULL + // CALLER_SVAL can be nullptr m_map_svalue_from_summary_to_caller.put (summary_sval, caller_sval); } @@ -791,7 +791,7 @@ call_summary_replay::add_region_mapping (const region *summary_reg, const region *caller_reg) { gcc_assert (summary_reg); - // CALLER_REG can be NULL + // CALLER_REG can be nullptr m_map_region_from_summary_to_caller.put (summary_reg, caller_reg); } diff --git a/gcc/analyzer/checker-event.cc b/gcc/analyzer/checker-event.cc index e041778..af336df 100644 --- a/gcc/analyzer/checker-event.cc +++ b/gcc/analyzer/checker-event.cc @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see #include "inlining-iterator.h" #include "tree-logical-location.h" #include "diagnostic-format-sarif.h" +#include "xml.h" #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" @@ -106,12 +107,13 @@ event_kind_to_string (enum event_kind ek) checker_event::checker_event (enum event_kind kind, const event_loc_info &loc_info) -: m_kind (kind), m_loc (loc_info.m_loc), +: m_path (nullptr), + m_kind (kind), m_loc (loc_info.m_loc), m_original_fndecl (loc_info.m_fndecl), m_effective_fndecl (loc_info.m_fndecl), m_original_depth (loc_info.m_depth), m_effective_depth (loc_info.m_depth), - m_pending_diagnostic (NULL), m_emission_id (), + m_pending_diagnostic (nullptr), m_emission_id (), m_logical_loc (tree_logical_location_manager::key_from_tree (loc_info.m_fndecl)) { @@ -211,10 +213,11 @@ checker_event::debug () const pertinent data within the sm-state). */ void -checker_event::prepare_for_emission (checker_path *, +checker_event::prepare_for_emission (checker_path *path, pending_diagnostic *pd, diagnostic_event_id_t emission_id) { + m_path = path; m_pending_diagnostic = pd; m_emission_id = emission_id; @@ -222,6 +225,29 @@ checker_event::prepare_for_emission (checker_path *, print_desc (*pp.get ()); } +std::unique_ptr<xml::document> +checker_event::maybe_make_xml_state (bool debug) const +{ + const program_state *state = get_program_state (); + if (!state) + return nullptr; + + gcc_assert (m_path); + const extrinsic_state &ext_state = m_path->get_ext_state (); + + auto result = state->make_xml (ext_state); + + if (debug) + { + pretty_printer pp; + text_art::theme *theme = global_dc->get_diagram_theme (); + text_art::dump_to_pp (*state, theme, &pp); + result->add_comment (pp_formatted_text (&pp)); + } + + return result; +} + /* class debug_event : public checker_event. */ /* Implementation of diagnostic_event::print_desc vfunc for @@ -344,12 +370,14 @@ region_creation_event_debug::print_desc (pretty_printer &pp) const /* class function_entry_event : public checker_event. */ -function_entry_event::function_entry_event (const program_point &dst_point) +function_entry_event::function_entry_event (const program_point &dst_point, + const program_state &state) : checker_event (event_kind::function_entry, event_loc_info (dst_point.get_supernode ()->get_start_location (), dst_point.get_fndecl (), - dst_point.get_stack_depth ())) + dst_point.get_stack_depth ())), + m_state (state) { } @@ -370,7 +398,7 @@ function_entry_event::print_desc (pretty_printer &pp) const diagnostic_event::meaning function_entry_event::get_meaning () const { - return meaning (VERB_enter, NOUN_function); + return meaning (verb::enter, noun::function); } /* class state_change_event : public checker_event. */ @@ -470,7 +498,7 @@ state_change_event::print_desc (pretty_printer &pp) const } else { - gcc_assert (m_origin == NULL); + gcc_assert (m_origin == nullptr); pp_printf (&pp, "global state: %qs -> %qs", m_from->get_name (), @@ -557,6 +585,12 @@ superedge_event::should_filter_p (int verbosity) const return false; } +const program_state * +superedge_event::get_program_state () const +{ + return &m_eedge.m_dest->get_state (); +} + /* superedge_event's ctor. */ superedge_event::superedge_event (enum event_kind kind, @@ -598,9 +632,9 @@ cfg_edge_event::get_meaning () const { const cfg_superedge& cfg_sedge = get_cfg_superedge (); if (cfg_sedge.true_value_p ()) - return meaning (VERB_branch, PROPERTY_true); + return meaning (verb::branch, property::true_); else if (cfg_sedge.false_value_p ()) - return meaning (VERB_branch, PROPERTY_false); + return meaning (verb::branch, property::false_); else return meaning (); } @@ -710,7 +744,7 @@ start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const lhs, op, rhs); } } - return label_text::borrow (NULL); + return label_text::borrow (nullptr); } /* Subroutine of maybe_describe_condition above. @@ -747,9 +781,9 @@ start_cfg_edge_event::maybe_describe_condition (bool can_colorize, /* Only attempt to generate text for sufficiently simple expressions. */ if (!should_print_expr_p (lhs)) - return label_text::borrow (NULL); + return label_text::borrow (nullptr); if (!should_print_expr_p (rhs)) - return label_text::borrow (NULL); + return label_text::borrow (nullptr); /* Special cases for pointer comparisons against NULL. */ if (POINTER_TYPE_P (TREE_TYPE (lhs)) @@ -846,7 +880,7 @@ call_event::print_desc (pretty_printer &pp) const diagnostic_event::meaning call_event::get_meaning () const { - return meaning (VERB_call, NOUN_function); + return meaning (verb::call, noun::function); } /* Override of checker_event::is_call_p for calls. */ @@ -869,6 +903,14 @@ call_event::get_callee_fndecl () const return m_dest_snode->m_fun->decl; } +const program_state * +call_event::get_program_state () const +{ + /* Use the state at the source (at the caller), + rather than the one at the dest, which has a frame for the callee. */ + return &m_eedge.m_src->get_state (); +} + /* class return_event : public superedge_event. */ /* return_event's ctor. */ @@ -922,7 +964,7 @@ return_event::print_desc (pretty_printer &pp) const diagnostic_event::meaning return_event::get_meaning () const { - return meaning (VERB_return, NOUN_function); + return meaning (verb::return_, noun::function); } /* Override of checker_event::is_return_p for returns. */ @@ -949,8 +991,8 @@ start_consolidated_cfg_edges_event::print_desc (pretty_printer &pp) const diagnostic_event::meaning start_consolidated_cfg_edges_event::get_meaning () const { - return meaning (VERB_branch, - (m_edge_sense ? PROPERTY_true : PROPERTY_false)); + return meaning (verb::branch, + (m_edge_sense ? property::true_ : property::false_)); } /* class inlined_call_event : public checker_event. */ @@ -970,7 +1012,7 @@ inlined_call_event::print_desc (pretty_printer &pp) const diagnostic_event::meaning inlined_call_event::get_meaning () const { - return meaning (VERB_call, NOUN_function); + return meaning (verb::call, noun::function); } /* class setjmp_event : public checker_event. */ @@ -1210,7 +1252,16 @@ warning_event::print_desc (pretty_printer &pp) const diagnostic_event::meaning warning_event::get_meaning () const { - return meaning (VERB_danger, NOUN_unknown); + return meaning (verb::danger, noun::unknown); +} + +const program_state * +warning_event::get_program_state () const +{ + if (m_program_state) + return m_program_state.get (); + else + return &m_enode->get_state (); } } // namespace ana diff --git a/gcc/analyzer/checker-event.h b/gcc/analyzer/checker-event.h index 2f26b8d..7c44f1e 100644 --- a/gcc/analyzer/checker-event.h +++ b/gcc/analyzer/checker-event.h @@ -116,6 +116,7 @@ public: sarif_object &thread_flow_loc_obj) const override; /* Additional functionality. */ + enum event_kind get_kind () const { return m_kind; } tree get_fndecl () const { return m_effective_fndecl; } int get_original_stack_depth () const { return m_original_depth; } @@ -127,6 +128,12 @@ public: virtual bool is_function_entry_p () const { return false; } virtual bool is_return_p () const { return false; } + virtual const program_state * + get_program_state () const { return nullptr; } + + std::unique_ptr<xml::document> + maybe_make_xml_state (bool debug) const final override; + /* For use with %@. */ const diagnostic_event_id_t *get_id_ptr () const { @@ -142,7 +149,8 @@ protected: checker_event (enum event_kind kind, const event_loc_info &loc_info); - public: + private: + const checker_path *m_path; const enum event_kind m_kind; protected: location_t m_loc; @@ -224,6 +232,12 @@ public: void print_desc (pretty_printer &) const final override; + const program_state * + get_program_state () const final override + { + return &m_dst_state; + } + const gimple * const m_stmt; const program_state m_dst_state; }; @@ -334,17 +348,29 @@ private: class function_entry_event : public checker_event { public: - function_entry_event (const event_loc_info &loc_info) - : checker_event (event_kind::function_entry, loc_info) + function_entry_event (const event_loc_info &loc_info, + const program_state &state) + : checker_event (event_kind::function_entry, loc_info), + m_state (state) { } - function_entry_event (const program_point &dst_point); + function_entry_event (const program_point &dst_point, + const program_state &state); void print_desc (pretty_printer &pp) const override; meaning get_meaning () const override; bool is_function_entry_p () const final override { return true; } + + const program_state * + get_program_state () const final override + { + return &m_state; + } + +private: + const program_state &m_state; }; /* Subclass of checker_event describing a state change. */ @@ -365,6 +391,12 @@ public: void print_desc (pretty_printer &pp) const final override; meaning get_meaning () const override; + const program_state * + get_program_state () const final override + { + return &m_dst_state; + } + const function *get_dest_function () const { return m_dst_state.get_current_function (); @@ -407,6 +439,9 @@ public: bool should_filter_p (int verbosity) const; + const program_state * + get_program_state () const override; + protected: superedge_event (enum event_kind kind, const exploded_edge &eedge, const event_loc_info &loc_info); @@ -517,6 +552,9 @@ public: bool is_call_p () const final override; + const program_state * + get_program_state () const final override; + protected: tree get_caller_fndecl () const; tree get_callee_fndecl () const; @@ -791,16 +829,22 @@ public: warning_event (const event_loc_info &loc_info, const exploded_node *enode, const state_machine *sm, - tree var, state_machine::state_t state) + tree var, state_machine::state_t state, + const program_state *program_state_ = nullptr) : checker_event (event_kind::warning, loc_info), m_enode (enode), m_sm (sm), m_var (var), m_state (state) { + if (program_state_) + m_program_state = std::make_unique<program_state> (*program_state_); } void print_desc (pretty_printer &pp) const final override; meaning get_meaning () const override; + const program_state * + get_program_state () const final override; + const exploded_node *get_exploded_node () const { return m_enode; } private: @@ -808,6 +852,9 @@ private: const state_machine *m_sm; tree m_var; state_machine::state_t m_state; + /* Optional copy of program state, for when this is different from + m_enode's state: */ + std::unique_ptr<program_state> m_program_state; }; } // namespace ana diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc index 9bde6f2..45593e0 100644 --- a/gcc/analyzer/checker-path.cc +++ b/gcc/analyzer/checker-path.cc @@ -89,7 +89,7 @@ checker_path::maybe_log (logger *logger, const char *desc) const { logger->start_log_line (); logger->log_partial ("%s[%i]: %s ", desc, i, - event_kind_to_string (m_events[i]->m_kind)); + event_kind_to_string (m_events[i]->get_kind ())); m_events[i]->dump (logger->get_printer ()); logger->end_log_line (); } @@ -103,7 +103,7 @@ checker_path::add_event (std::unique_ptr<checker_event> event) m_logger->start_log_line (); m_logger->log_partial ("added event[%i]: %s ", m_events.length (), - event_kind_to_string (event.get ()->m_kind)); + event_kind_to_string (event.get ()->get_kind ())); event.get ()->dump (m_logger->get_printer ()); m_logger->end_log_line (); } @@ -123,7 +123,7 @@ checker_path::debug () const fprintf (stderr, "[%i]: %s \"%s\"\n", i, - event_kind_to_string (m_events[i]->m_kind), + event_kind_to_string (m_events[i]->get_kind ()), event_desc.get ()); } } @@ -167,8 +167,8 @@ checker_path::cfg_edge_pair_at_p (unsigned idx) const { if (m_events.length () < idx + 1) return false; - return (m_events[idx]->m_kind == event_kind::start_cfg_edge - && m_events[idx + 1]->m_kind == event_kind::end_cfg_edge); + return (m_events[idx]->get_kind () == event_kind::start_cfg_edge + && m_events[idx + 1]->get_kind () == event_kind::end_cfg_edge); } /* Consider a call from "outer" to "middle" which calls "inner", @@ -254,7 +254,7 @@ checker_path::inject_any_inlined_call_events (logger *logger) { logger->start_log_line (); logger->log_partial ("event[%i]: %s ", ev_idx, - event_kind_to_string (curr_event->m_kind)); + event_kind_to_string (curr_event->get_kind ())); curr_event->dump (logger->get_printer ()); logger->end_log_line (); for (inlining_iterator iter (curr_event->get_location ()); diff --git a/gcc/analyzer/checker-path.h b/gcc/analyzer/checker-path.h index 80c975c..3c174bf 100644 --- a/gcc/analyzer/checker-path.h +++ b/gcc/analyzer/checker-path.h @@ -32,8 +32,10 @@ class checker_path : public diagnostic_path { public: checker_path (const logical_location_manager &logical_loc_mgr, + const extrinsic_state &ext_state, logger *logger) : diagnostic_path (logical_loc_mgr), + m_ext_state (ext_state), m_thread ("main"), m_logger (logger) {} @@ -59,6 +61,8 @@ public: return m_thread; } + const extrinsic_state &get_ext_state () const { return m_ext_state; } + checker_event *get_checker_event (int idx) { return m_events[idx]; @@ -140,6 +144,8 @@ public: private: DISABLE_COPY_AND_ASSIGN(checker_path); + const extrinsic_state &m_ext_state; + simple_diagnostic_thread m_thread; /* The events that have occurred along this path. */ diff --git a/gcc/analyzer/common.h b/gcc/analyzer/common.h index cb03004..148bfdd 100644 --- a/gcc/analyzer/common.h +++ b/gcc/analyzer/common.h @@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see #define GCC_ANALYZER_COMMON_H #include "config.h" +#define INCLUDE_MAP +#define INCLUDE_STRING #define INCLUDE_VECTOR #include "system.h" #include "coretypes.h" @@ -207,14 +209,14 @@ class region_offset { public: region_offset () - : m_base_region (NULL), m_offset (0), m_sym_offset (NULL) + : m_base_region (nullptr), m_offset (0), m_sym_offset (nullptr) { } static region_offset make_concrete (const region *base_region, bit_offset_t offset) { - return region_offset (base_region, offset, NULL); + return region_offset (base_region, offset, nullptr); } static region_offset make_symbolic (const region *base_region, const svalue *sym_offset) @@ -226,8 +228,8 @@ public: const region *get_base_region () const { return m_base_region; } - bool concrete_p () const { return m_sym_offset == NULL; } - bool symbolic_p () const { return m_sym_offset != NULL; } + bool concrete_p () const { return m_sym_offset == nullptr; } + bool symbolic_p () const { return m_sym_offset != nullptr; } bit_offset_t get_bit_offset () const { @@ -304,7 +306,7 @@ public: } virtual const builtin_known_function * - dyn_cast_builtin_kf () const { return NULL; } + dyn_cast_builtin_kf () const { return nullptr; } }; /* Subclass of known_function for builtin functions. */ @@ -565,13 +567,13 @@ public: delete (*iter).second; } - /* Get the instance of T for K if one exists, or NULL. */ + /* Get the instance of T for K if one exists, or nullptr. */ T *get (const key_t &k) const { if (instance_t **slot = const_cast<inner_map_t &> (m_inner_map).get (k)) return *slot; - return NULL; + return nullptr; } /* Take ownership of INSTANCE. */ diff --git a/gcc/analyzer/constraint-manager.cc b/gcc/analyzer/constraint-manager.cc index 869e437..58c60fe 100644 --- a/gcc/analyzer/constraint-manager.cc +++ b/gcc/analyzer/constraint-manager.cc @@ -609,7 +609,7 @@ bounded_ranges::canonicalize () { bounded_range *prev = &m_ranges[i - 1]; const bounded_range *next = &m_ranges[i]; - if (prev->intersects_p (*next, NULL) + if (prev->intersects_p (*next, nullptr) || (can_plus_one_p (prev->m_upper) && tree_int_cst_equal (plus_one (prev->m_upper), next->m_lower))) @@ -1058,7 +1058,7 @@ bounded_ranges_manager::log_stats (logger *logger, bool show_objs) const /* equiv_class's default ctor. */ equiv_class::equiv_class () -: m_constant (NULL_TREE), m_cst_sval (NULL), m_vars () +: m_constant (NULL_TREE), m_cst_sval (nullptr), m_vars () { } @@ -3024,7 +3024,7 @@ on_liveness_change (const svalue_set &live_svalues, const region_model *model) { dead_svalue_purger p (live_svalues, model); - purge (p, NULL); + purge (p, nullptr); } class svalue_purger @@ -3047,7 +3047,7 @@ void constraint_manager::purge_state_involving (const svalue *sval) { svalue_purger p (sval); - purge (p, NULL); + purge (p, nullptr); } /* Comparator for use by constraint_manager::canonicalize. @@ -3191,7 +3191,7 @@ public: { /* Special-case for widening. */ if (lhs->get_kind () == SK_WIDENING) - if (!m_cm_b->get_equiv_class_by_svalue (lhs, NULL)) + if (!m_cm_b->get_equiv_class_by_svalue (lhs, nullptr)) { /* LHS isn't constrained within m_cm_b. */ bool sat = m_out->add_constraint (lhs, code, rhs); @@ -3515,7 +3515,7 @@ test_constraint_conditions () ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, x); ADD_SAT_CONSTRAINT (model, int_42, EQ_EXPR, int_42); /* ...even when done directly via svalues: */ - const svalue *sval_int_42 = model.get_rvalue (int_42, NULL); + const svalue *sval_int_42 = model.get_rvalue (int_42, nullptr); bool sat = model.get_constraints ()->add_constraint (sval_int_42, EQ_EXPR, sval_int_42); @@ -4304,8 +4304,8 @@ test_purging (void) ASSERT_EQ (model.get_constraints ()->m_constraints.length (), 1); /* Purge state for "a". */ - const svalue *sval_a = model.get_rvalue (a, NULL); - model.purge_state_involving (sval_a, NULL); + const svalue *sval_a = model.get_rvalue (a, nullptr); + model.purge_state_involving (sval_a, nullptr); model.canonicalize (); /* We should have an empty constraint_manager. */ ASSERT_EQ (model.get_constraints ()->m_equiv_classes.length (), 0); @@ -4322,8 +4322,8 @@ test_purging (void) ASSERT_EQ (model.get_constraints ()->m_constraints.length (), 2); /* Purge state for "a". */ - const svalue *sval_a = model.get_rvalue (a, NULL); - model.purge_state_involving (sval_a, NULL); + const svalue *sval_a = model.get_rvalue (a, nullptr); + model.purge_state_involving (sval_a, nullptr); model.canonicalize (); /* We should just have the constraint/ECs involving b != 0. */ ASSERT_EQ (model.get_constraints ()->m_equiv_classes.length (), 2); @@ -4341,8 +4341,8 @@ test_purging (void) ASSERT_EQ (model.get_constraints ()->m_constraints.length (), 1); /* Purge state for "a". */ - const svalue *sval_a = model.get_rvalue (a, NULL); - model.purge_state_involving (sval_a, NULL); + const svalue *sval_a = model.get_rvalue (a, nullptr); + model.purge_state_involving (sval_a, nullptr); model.canonicalize (); /* We should just have the EC involving b == 0. */ ASSERT_EQ (model.get_constraints ()->m_equiv_classes.length (), 1); @@ -4359,8 +4359,8 @@ test_purging (void) ASSERT_EQ (model.get_constraints ()->m_constraints.length (), 0); /* Purge state for "a". */ - const svalue *sval_a = model.get_rvalue (a, NULL); - model.purge_state_involving (sval_a, NULL); + const svalue *sval_a = model.get_rvalue (a, nullptr); + model.purge_state_involving (sval_a, nullptr); model.canonicalize (); /* We should have an empty constraint_manager. */ ASSERT_EQ (model.get_constraints ()->m_equiv_classes.length (), 0); @@ -4377,8 +4377,8 @@ test_purging (void) ASSERT_EQ (model.get_constraints ()->m_constraints.length (), 1); /* Purge state for "a". */ - const svalue *sval_a = model.get_rvalue (a, NULL); - model.purge_state_involving (sval_a, NULL); + const svalue *sval_a = model.get_rvalue (a, nullptr); + model.purge_state_involving (sval_a, nullptr); model.canonicalize (); /* We should just have the constraint/ECs involving b != 0. */ ASSERT_EQ (model.get_constraints ()->m_equiv_classes.length (), 2); @@ -4396,8 +4396,8 @@ test_purging (void) ASSERT_EQ (model.get_constraints ()->m_constraints.length (), 0); /* Purge state for "a". */ - const svalue *sval_a = model.get_rvalue (a, NULL); - model.purge_state_involving (sval_a, NULL); + const svalue *sval_a = model.get_rvalue (a, nullptr); + model.purge_state_involving (sval_a, nullptr); model.canonicalize (); /* We should just have the EC involving b == 0. */ ASSERT_EQ (model.get_constraints ()->m_equiv_classes.length (), 1); @@ -4459,8 +4459,8 @@ test_bounded_range () bounded_range br_u8_64_128 (u8_64, u8_128); ASSERT_DUMP_BOUNDED_RANGE_EQ (br_u8_64_128, "[64, 128]"); - ASSERT_FALSE (br_u8_0.intersects_p (br_u8_64_128, NULL)); - ASSERT_FALSE (br_u8_64_128.intersects_p (br_u8_0, NULL)); + ASSERT_FALSE (br_u8_0.intersects_p (br_u8_64_128, nullptr)); + ASSERT_FALSE (br_u8_64_128.intersects_p (br_u8_0, nullptr)); bounded_range br_u8_128_255 (u8_128, u8_255); ASSERT_DUMP_BOUNDED_RANGE_EQ (br_u8_128_255, "[128, 255]"); diff --git a/gcc/analyzer/constraint-manager.h b/gcc/analyzer/constraint-manager.h index a26b48d..4339ea6 100644 --- a/gcc/analyzer/constraint-manager.h +++ b/gcc/analyzer/constraint-manager.h @@ -226,8 +226,8 @@ private: { return k->get_hash (); } - static inline bool is_empty (key_type k) { return k == NULL; } - static inline void mark_empty (key_type &k) { k = NULL; } + static inline bool is_empty (key_type k) { return k == nullptr; } + static inline void mark_empty (key_type &k) { k = nullptr; } static inline bool is_deleted (key_type k) { return k == reinterpret_cast<key_type> (1); diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index e5d1a25..c083b8c 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -63,7 +63,7 @@ class epath_finder public: epath_finder (const exploded_graph &eg) : m_eg (eg), - m_sep (NULL) + m_sep (nullptr) { /* This is shared by all diagnostics, but only needed if !flag_analyzer_feasibility. */ @@ -125,7 +125,7 @@ private: within ENODE. Ideally we want to report the shortest feasible path. - Return NULL if we could not find a feasible path + Return nullptr if we could not find a feasible path (when flag_analyzer_feasibility is true). If flag_analyzer_feasibility is false, then simply return the @@ -177,7 +177,7 @@ epath_finder::get_best_epath (const exploded_node *enode, logger->log ("rejecting %qs at EN: %i, SN: %i (sd: %i)" " due to not finding feasible path", desc, enode->m_index, snode_idx, diag_idx); - return NULL; + return nullptr; } } else @@ -221,7 +221,7 @@ class feasible_worklist { public: feasible_worklist (const shortest_paths<eg_traits, exploded_path> &sep) - : m_queue (key_t (*this, NULL)), + : m_queue (key_t (*this, nullptr)), m_sep (sep) { } @@ -416,7 +416,7 @@ epath_finder::explore_feasible_paths (const exploded_node *target_enode, a limit. */ /* Set this if we find a feasible path to TARGET_ENODE. */ - std::unique_ptr<exploded_path> best_path = NULL; + std::unique_ptr<exploded_path> best_path = nullptr; { auto_checking_feasibility sentinel (mgr); @@ -508,7 +508,7 @@ process_worklist_item (feasible_worklist *worklist, std::unique_ptr<rejected_constraint> rc; if (succ_state.maybe_update_for_edge (logger, succ_eedge, nullptr, &rc)) { - gcc_assert (rc == NULL); + gcc_assert (rc == nullptr); feasible_node *succ_fnode = fg->add_node (succ_eedge->m_dest, succ_state, @@ -612,7 +612,7 @@ dump_trimmed_graph (const exploded_node *target_enode, pp_printf (&pp, "%s.%s.%i.to-en%i.tg.dot", dump_base_name, desc, diag_idx, target_enode->m_index); char *filename = xstrdup (pp_formatted_text (&pp)); - tg.dump_dot (filename, NULL, args); + tg.dump_dot (filename, nullptr, args); free (filename); } @@ -630,7 +630,7 @@ epath_finder::dump_feasible_graph (const exploded_node *target_enode, pp_printf (&pp, "%s.%s.%i.to-en%i.fg.dot", dump_base_name, desc, diag_idx, target_enode->m_index); char *filename = xstrdup (pp_formatted_text (&pp)); - fg.dump_dot (filename, NULL, args); + fg.dump_dot (filename, nullptr, args); free (filename); } @@ -687,6 +687,11 @@ saved_diagnostic::operator== (const saved_diagnostic &other) const for (unsigned i = 0; i < m_notes.length (); i++) if (!m_notes[i]->equal_p (*other.m_notes[i])) return false; + + // Don't deduplicate dump_path_diagnostic instances + if (!strcmp (m_d->get_kind (), "dump_path_diagnostic")) + return this == &other; + return (m_sm == other.m_sm /* We don't compare m_enode. */ && m_snode == other.m_snode @@ -822,7 +827,7 @@ saved_diagnostic::dump_as_dot_node (pretty_printer *pp) const /* Use PF to find the best exploded_path for this saved_diagnostic, and store it in m_best_epath. - If we don't have a specific location in m_loc and m_stmt is still NULL, + If we don't have a specific location in m_loc and m_stmt is still nullptr, use m_stmt_finder on the epath to populate m_stmt. Return true if a best path was found. */ @@ -831,20 +836,20 @@ saved_diagnostic::calc_best_epath (epath_finder *pf) { logger *logger = pf->get_logger (); LOG_SCOPE (logger); - m_problem = NULL; + m_problem = nullptr; m_best_epath = pf->get_best_epath (m_enode, m_stmt, *m_d, m_d->get_kind (), m_idx, &m_problem); /* Handle failure to find a feasible path. */ - if (m_best_epath == NULL) + if (m_best_epath == nullptr) return false; gcc_assert (m_best_epath); if (m_loc == UNKNOWN_LOCATION) { - if (m_stmt == NULL) + if (m_stmt == nullptr) { gcc_assert (m_stmt_finder); m_stmt = m_stmt_finder->find_stmt (*m_best_epath); @@ -1193,7 +1198,7 @@ diagnostic_manager::add_diagnostic (const pending_location &ploc, std::unique_ptr<pending_diagnostic> d) { gcc_assert (ploc.m_enode); - return add_diagnostic (NULL, ploc, NULL_TREE, NULL, 0, std::move (d)); + return add_diagnostic (nullptr, ploc, NULL_TREE, nullptr, 0, std::move (d)); } /* Add PN to the most recent saved_diagnostic. */ @@ -1338,7 +1343,7 @@ public: template <typename T> static inline void mark_empty (T &entry) { - entry.m_key = NULL; + entry.m_key = nullptr; } template <typename T> static inline bool is_deleted (const T &entry) @@ -1348,7 +1353,7 @@ public: template <typename T> static inline bool is_empty (const T &entry) { - return entry.m_key == NULL; + return entry.m_key == nullptr; } static const bool empty_zero_p = true; }; @@ -1581,6 +1586,7 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg, /* This is the diagnostic_path subclass that will be built for the diagnostic. */ checker_path emission_path (get_logical_location_manager (), + eg.get_ext_state (), get_logger ()); /* Populate emission_path with a full description of EPATH. */ @@ -1614,7 +1620,7 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg, trailing eedge stashed, add any events for it. This is for use in handling longjmp, to show where a longjmp is rewinding to. */ if (sd.m_trailing_eedge) - add_events_for_eedge (pb, *sd.m_trailing_eedge, &emission_path, NULL); + add_events_for_eedge (pb, *sd.m_trailing_eedge, &emission_path, nullptr); emission_path.inject_any_inlined_call_events (get_logger ()); @@ -1698,7 +1704,7 @@ diagnostic_manager::build_emission_path (const path_builder &pb, { emission_path->add_region_creation_events (pb.get_pending_diagnostic (), - reg, NULL, + reg, nullptr, event_loc_info (DECL_SOURCE_LOCATION (decl), NULL_TREE, 0), @@ -1757,7 +1763,7 @@ diagnostic_manager::add_event_on_final_node (const path_builder &pb, = src_model->get_dynamic_extents (base_reg); const svalue *new_extents = dst_model->get_dynamic_extents (base_reg); - if (old_extents == NULL && new_extents != NULL) + if (old_extents == nullptr && new_extents != nullptr) switch (base_reg->get_kind ()) { default: @@ -1970,7 +1976,7 @@ struct null_assignment_sm_context : public sm_context tree var) final override { const svalue *var_old_sval - = m_old_state->m_region_model->get_rvalue (var, NULL); + = m_old_state->m_region_model->get_rvalue (var, nullptr); const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx]; state_machine::state_t current @@ -1999,7 +2005,7 @@ struct null_assignment_sm_context : public sm_context return; const svalue *var_new_sval - = m_new_state->m_region_model->get_rvalue (var, NULL); + = m_new_state->m_region_model->get_rvalue (var, nullptr); const supernode *supernode = m_point->get_supernode (); int stack_depth = m_point->get_stack_depth (); @@ -2086,7 +2092,7 @@ struct null_assignment_sm_context : public sm_context if (!assign_stmt) return NULL_TREE; if (const svalue *sval - = m_new_state->m_region_model->get_gassign_result (assign_stmt, NULL)) + = m_new_state->m_region_model->get_gassign_result (assign_stmt, nullptr)) if (tree cst = sval->maybe_get_constant ()) if (::zerop(cst)) return gimple_assign_lhs (assign_stmt); @@ -2247,7 +2253,7 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb, { const extrinsic_state &ext_state = pb.get_ext_state (); program_state old_state (iter_state); - iter_state.m_region_model->on_assignment (assign, NULL); + iter_state.m_region_model->on_assignment (assign, nullptr); for (unsigned i = 0; i < ext_state.get_num_checkers (); i++) { const state_machine &sm = ext_state.get_sm (i); @@ -2293,7 +2299,7 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb, = src_model->get_dynamic_extents (base_reg); const svalue *new_extents = dst_model->get_dynamic_extents (base_reg); - if (old_extents == NULL && new_extents != NULL) + if (old_extents == nullptr && new_extents != nullptr) switch (base_reg->get_kind ()) { default: @@ -2599,19 +2605,19 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, { label_text sval_desc = sval->get_desc (); log ("considering event %i (%s), with sval: %qs, state: %qs", - idx, event_kind_to_string (base_event->m_kind), + idx, event_kind_to_string (base_event->get_kind ()), sval_desc.get (), state->get_name ()); } else log ("considering event %i (%s), with global state: %qs", - idx, event_kind_to_string (base_event->m_kind), + idx, event_kind_to_string (base_event->get_kind ()), state->get_name ()); } else log ("considering event %i", idx); } - switch (base_event->m_kind) + switch (base_event->get_kind ()) { default: gcc_unreachable (); @@ -2718,7 +2724,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, log ("filtering events %i and %i: CFG edge", idx, idx + 1); path->delete_event (idx); /* Also delete the corresponding event_kind::end_cfg_edge. */ - gcc_assert (path->get_checker_event (idx)->m_kind + gcc_assert (path->get_checker_event (idx)->get_kind () == event_kind::end_cfg_edge); path->delete_event (idx); } @@ -3038,7 +3044,7 @@ same_line_as_p (const expanded_location &ref_exp_loc, const checker_event *ev = path->get_checker_event (idx); expanded_location idx_exp_loc = expand_location (ev->get_location ()); gcc_assert (ref_exp_loc.file); - if (idx_exp_loc.file == NULL) + if (idx_exp_loc.file == nullptr) return false; if (strcmp (ref_exp_loc.file, idx_exp_loc.file)) return false; @@ -3103,13 +3109,13 @@ diagnostic_manager::consolidate_conditions (checker_path *path) const = path->get_checker_event (start_idx); expanded_location start_exp_loc = expand_location (old_start_ev->get_location ()); - if (start_exp_loc.file == NULL) + if (start_exp_loc.file == nullptr) continue; if (!same_line_as_p (start_exp_loc, path, start_idx + 1)) continue; /* Are we looking for a run of all TRUE edges, or all FALSE edges? */ - gcc_assert (old_start_ev->m_kind == event_kind::start_cfg_edge); + gcc_assert (old_start_ev->get_kind () == event_kind::start_cfg_edge); const start_cfg_edge_event *old_start_cfg_ev = (const start_cfg_edge_event *)old_start_ev; const cfg_superedge& first_cfg_sedge @@ -3132,7 +3138,7 @@ diagnostic_manager::consolidate_conditions (checker_path *path) const { const checker_event *iter_ev = path->get_checker_event (next_idx); - gcc_assert (iter_ev->m_kind == event_kind::start_cfg_edge); + gcc_assert (iter_ev->get_kind () == event_kind::start_cfg_edge); const start_cfg_edge_event *iter_cfg_ev = (const start_cfg_edge_event *)iter_ev; const cfg_superedge& iter_cfg_sedge @@ -3190,11 +3196,13 @@ diagnostic_manager::consolidate_unwind_events (checker_path *path) const start_idx++) { /* Find a run of consecutive unwind_event instances. */ - if (path->get_checker_event (start_idx)->m_kind != event_kind::unwind) + if (path->get_checker_event (start_idx)->get_kind () + != event_kind::unwind) continue; int iter_idx = start_idx + 1; while (iter_idx < (int)path->num_events ()) - if (path->get_checker_event (iter_idx)->m_kind == event_kind::unwind) + if (path->get_checker_event (iter_idx)->get_kind () + == event_kind::unwind) ++iter_idx; else break; @@ -3232,7 +3240,7 @@ diagnostic_manager::finish_pruning (checker_path *path) const while (idx >= 0 && idx < (signed)path->num_events ()) { checker_event *base_event = path->get_checker_event (idx); - if (base_event->m_kind == event_kind::function_entry) + if (base_event->get_kind () == event_kind::function_entry) { log ("filtering event %i:" " function entry for purely intraprocedural path", idx); diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index c3e4800..67024e9 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -95,14 +95,14 @@ impl_region_model_context (program_state *state, const extrinsic_state &ext_state, uncertainty_t *uncertainty, logger *logger) -: m_eg (NULL), m_logger (logger), m_enode_for_diag (NULL), - m_old_state (NULL), +: m_eg (nullptr), m_logger (logger), m_enode_for_diag (nullptr), + m_old_state (nullptr), m_new_state (state), - m_stmt (NULL), - m_stmt_finder (NULL), + m_stmt (nullptr), + m_stmt_finder (nullptr), m_ext_state (ext_state), m_uncertainty (uncertainty), - m_path_ctxt (NULL), + m_path_ctxt (nullptr), m_out_could_have_done_work (nullptr) { } @@ -113,7 +113,7 @@ impl_region_model_context::warn (std::unique_ptr<pending_diagnostic> d, { LOG_FUNC (get_logger ()); auto curr_stmt_finder = custom_finder ? custom_finder : m_stmt_finder; - if (m_stmt == NULL && curr_stmt_finder == NULL) + if (m_stmt == nullptr && curr_stmt_finder == nullptr) { if (get_logger ()) get_logger ()->log ("rejecting diagnostic: no stmt"); @@ -296,7 +296,7 @@ public: const sm_state_map *old_smap, sm_state_map *new_smap, path_context *path_ctxt, - const stmt_finder *stmt_finder = NULL, + const stmt_finder *stmt_finder = nullptr, bool unknown_side_effects = false) : sm_context (sm_idx, sm), m_logger (eg.get_logger ()), @@ -314,8 +314,8 @@ public: tree get_fndecl_for_call (const gcall &call) final override { impl_region_model_context old_ctxt - (m_eg, m_enode_for_diag, NULL, NULL, NULL/*m_enode->get_state ()*/, - NULL, &call); + (m_eg, m_enode_for_diag, nullptr, nullptr, nullptr/*m_enode->get_state ()*/, + nullptr, &call); region_model *model = m_new_state->m_region_model; return model->get_fndecl_for_call (call, &old_ctxt); } @@ -325,10 +325,10 @@ public: { logger * const logger = get_logger (); LOG_FUNC (logger); - /* Use NULL ctxt on this get_rvalue call to avoid triggering + /* Use nullptr ctxt on this get_rvalue call to avoid triggering uninitialized value warnings. */ const svalue *var_old_sval - = m_old_state->m_region_model->get_rvalue (var, NULL); + = m_old_state->m_region_model->get_rvalue (var, nullptr); state_machine::state_t current = m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ()); @@ -353,9 +353,9 @@ public: logger * const logger = get_logger (); LOG_FUNC (logger); const svalue *var_new_sval - = m_new_state->m_region_model->get_rvalue (var, NULL); + = m_new_state->m_region_model->get_rvalue (var, nullptr); const svalue *origin_new_sval - = m_new_state->m_region_model->get_rvalue (origin, NULL); + = m_new_state->m_region_model->get_rvalue (origin, nullptr); /* We use the new sval here to avoid issues with uninitialized values. */ state_machine::state_t current @@ -378,11 +378,11 @@ public: logger * const logger = get_logger (); LOG_FUNC (logger); impl_region_model_context old_ctxt - (m_eg, m_enode_for_diag, NULL, NULL, NULL/*m_enode->get_state ()*/, - NULL, stmt); + (m_eg, m_enode_for_diag, nullptr, nullptr, nullptr/*m_enode->get_state ()*/, + nullptr, stmt); const svalue *origin_new_sval - = m_new_state->m_region_model->get_rvalue (origin, NULL); + = m_new_state->m_region_model->get_rvalue (origin, nullptr); state_machine::state_t current = m_old_smap->get_state (sval, m_eg.get_ext_state ()); @@ -408,7 +408,7 @@ public: LOG_FUNC (get_logger ()); gcc_assert (d); const svalue *var_old_sval - = m_old_state->m_region_model->get_rvalue (var, NULL); + = m_old_state->m_region_model->get_rvalue (var, nullptr); state_machine::state_t current = (var ? m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ()) @@ -461,7 +461,7 @@ public: return expr; gcc_assert (m_new_state); - const svalue *sval = m_new_state->m_region_model->get_rvalue (expr, NULL); + const svalue *sval = m_new_state->m_region_model->get_rvalue (expr, nullptr); /* Find trees for all regions storing the value. */ if (tree t = m_new_state->m_region_model->get_representative_tree (sval)) return t; @@ -502,7 +502,7 @@ public: if (!assign_stmt) return NULL_TREE; impl_region_model_context old_ctxt - (m_eg, m_enode_for_diag, m_old_state, m_new_state, NULL, NULL, stmt); + (m_eg, m_enode_for_diag, m_old_state, m_new_state, nullptr, nullptr, stmt); if (const svalue *sval = m_new_state->m_region_model->get_gassign_result (assign_stmt, &old_ctxt)) @@ -666,7 +666,7 @@ public: } gcc_unreachable (); - return NULL; + return nullptr; } void update_event_loc_info (event_loc_info &) final override @@ -925,7 +925,9 @@ impl_region_model_context::on_state_leak (const state_machine &sm, } tree leaked_tree_for_diag = fixup_tree_for_diagnostic (leaked_tree); - std::unique_ptr<pending_diagnostic> pd = sm.on_leak (leaked_tree_for_diag); + std::unique_ptr<pending_diagnostic> pd = sm.on_leak (leaked_tree_for_diag, + m_old_state, + m_new_state); if (pd) { pending_location ploc (m_enode_for_diag, @@ -960,7 +962,7 @@ impl_region_model_context::on_condition (const svalue *lhs, sm.on_condition (sm_ctxt, (m_enode_for_diag ? m_enode_for_diag->get_supernode () - : NULL), + : nullptr), m_stmt, lhs, op, rhs); } @@ -987,7 +989,7 @@ impl_region_model_context::on_bounded_ranges (const svalue &sval, sm.on_bounded_ranges (sm_ctxt, (m_enode_for_diag ? m_enode_for_diag->get_supernode () - : NULL), + : nullptr), m_stmt, sval, ranges); } } @@ -1538,7 +1540,7 @@ exploded_node::on_stmt (exploded_graph &eg, = old_state.m_checker_states[sm_idx]; sm_state_map *new_smap = state->m_checker_states[sm_idx]; impl_sm_context sm_ctxt (eg, sm_idx, sm, this, &old_state, state, - old_smap, new_smap, path_ctxt, NULL, + old_smap, new_smap, path_ctxt, nullptr, unknown_side_effects); /* Allow the state_machine to handle the stmt. */ @@ -1578,6 +1580,16 @@ exploded_node::on_stmt_pre (exploded_graph &eg, state->dump (eg.get_ext_state (), true); return; } + else if (is_special_named_call_p (call, "__analyzer_dump_xml", 0)) + { + state->dump_xml (eg.get_ext_state ()); + return; + } + else if (is_special_named_call_p (call, "__analyzer_dump_dot", 0)) + { + state->dump_dot (eg.get_ext_state ()); + return; + } else if (is_special_named_call_p (call, "__analyzer_dump_state", 2)) { state->impl_call_analyzer_dump_state (call, eg.get_ext_state (), @@ -1839,7 +1851,7 @@ public: stale_jmp_buf (const gcall &setjmp_call, const gcall &longjmp_call, const program_point &setjmp_point) : m_setjmp_call (setjmp_call), m_longjmp_call (longjmp_call), - m_setjmp_point (setjmp_point), m_stack_pop_event (NULL) + m_setjmp_point (setjmp_point), m_stack_pop_event (nullptr) {} int get_controlling_option () const final override @@ -1981,7 +1993,7 @@ exploded_node::on_longjmp (exploded_graph &eg, setjmp_point.get_stack_depth (), ctxt); /* Detect leaks in the new state relative to the old state. */ - program_state::detect_leaks (get_state (), *new_state, NULL, + program_state::detect_leaks (get_state (), *new_state, nullptr, eg.get_ext_state (), ctxt); program_point next_point @@ -1995,7 +2007,7 @@ exploded_node::on_longjmp (exploded_graph &eg, if (next) { exploded_edge *eedge - = eg.add_edge (const_cast<exploded_node *> (this), next, NULL, true, + = eg.add_edge (const_cast<exploded_node *> (this), next, nullptr, true, std::make_unique<rewind_info_t> (tmp_setjmp_record, longjmp_call)); @@ -2226,7 +2238,7 @@ exploded_graph::unwind_from_exception (exploded_node &thrown_enode, if (!next_enode) return; - add_edge (iter_enode, next_enode, NULL, false, nullptr); + add_edge (iter_enode, next_enode, nullptr, false, nullptr); return; } else @@ -2254,7 +2266,7 @@ exploded_graph::unwind_from_exception (exploded_node &thrown_enode, throw_stmt); program_state::detect_leaks (iter_enode->get_state (), unwound_state, - NULL, + nullptr, get_ext_state (), &ctxt); } const call_string &cs = iter_enode->get_point ().get_call_string (); @@ -2284,7 +2296,7 @@ exploded_graph::unwind_from_exception (exploded_node &thrown_enode, if (!after_unwind_enode) return; - add_edge (iter_enode, after_unwind_enode, NULL, true, + add_edge (iter_enode, after_unwind_enode, nullptr, true, std::move (unwind_edge_info)); iter_enode = after_unwind_enode; } @@ -2339,7 +2351,7 @@ exploded_node::on_throw (exploded_graph &eg, return; /* Create custom exploded_edge for a throw. */ - eg.add_edge (this, after_throw_enode, NULL, true, + eg.add_edge (this, after_throw_enode, nullptr, true, std::move (throw_edge_info)); eg.unwind_from_exception (*after_throw_enode, &throw_call, ctxt); @@ -2392,10 +2404,10 @@ exploded_node::detect_leaks (exploded_graph &eg) uncertainty_t uncertainty; impl_region_model_context ctxt (eg, this, - &old_state, &new_state, &uncertainty, NULL, + &old_state, &new_state, &uncertainty, nullptr, get_stmt ()); - const svalue *result = NULL; - new_state.m_region_model->pop_frame (NULL, &result, &ctxt, nullptr); + const svalue *result = nullptr; + new_state.m_region_model->pop_frame (nullptr, &result, &ctxt, nullptr); program_state::detect_leaks (old_state, new_state, result, eg.get_ext_state (), &ctxt); } @@ -2502,7 +2514,7 @@ rewind_info_t::update_model (region_model *model, model->on_longjmp (get_longjmp_call (), get_setjmp_call (), - setjmp_point.get_stack_depth (), NULL); + setjmp_point.get_stack_depth (), nullptr); return true; } @@ -2817,7 +2829,7 @@ strongly_connected_components::strong_connect (unsigned index) worklist::worklist (const exploded_graph &eg, const analysis_plan &plan) : m_scc (eg.get_supergraph (), eg.get_logger ()), m_plan (plan), - m_queue (key_t (*this, NULL)) + m_queue (key_t (*this, nullptr)) { } @@ -2879,8 +2891,8 @@ worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb) if (flag_analyzer_call_summaries && call_string_a.empty_p () && call_string_b.empty_p () - && point_a.get_function () != NULL - && point_b.get_function () != NULL + && point_a.get_function () != nullptr + && point_b.get_function () != nullptr && point_a.get_function () != point_b.get_function ()) { if (int cmp = ka.m_worklist.m_plan.cmp_function (point_a.get_function (), @@ -2916,19 +2928,19 @@ worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb) ordering). */ const supernode *snode_a = ka.m_enode->get_supernode (); const supernode *snode_b = kb.m_enode->get_supernode (); - if (snode_a == NULL) + if (snode_a == nullptr) { - if (snode_b != NULL) - /* One is NULL. */ + if (snode_b != nullptr) + /* One is nullptr. */ return -1; else - /* Both are NULL. */ + /* Both are nullptr. */ return 0; } - if (snode_b == NULL) - /* One is NULL. */ + if (snode_b == nullptr) + /* One is nullptr. */ return 1; - /* Neither are NULL. */ + /* Neither are nullptr. */ gcc_assert (snode_a && snode_b); if (snode_a->m_index != snode_b->m_index) return snode_a->m_index - snode_b->m_index; @@ -3002,7 +3014,7 @@ exploded_graph::exploded_graph (const supergraph &sg, logger *logger, { m_origin = get_or_create_node (program_point::origin (*ext_state.get_model_manager ()), - program_state (ext_state), NULL); + program_state (ext_state), nullptr); for (int i = 0; i < m_sg.num_nodes (); i++) m_PK_AFTER_SUPERNODE_per_snode.quick_push (i); } @@ -3054,10 +3066,10 @@ mark_params_as_tainted (program_state *state, tree fndecl, tree param = iter_parm; if (tree parm_default_ssa = ssa_default_def (fun, iter_parm)) param = parm_default_ssa; - const region *param_reg = state->m_region_model->get_lvalue (param, NULL); + const region *param_reg = state->m_region_model->get_lvalue (param, nullptr); const svalue *init_sval = mgr->get_or_create_initial_value (param_reg); smap->set_state (state->m_region_model, init_sval, - tainted, NULL /*origin_new_sval*/, ext_state); + tainted, nullptr /*origin_new_sval*/, ext_state); if (POINTER_TYPE_P (TREE_TYPE (param))) { const region *pointee_reg = mgr->get_symbolic_region (init_sval); @@ -3065,7 +3077,7 @@ mark_params_as_tainted (program_state *state, tree fndecl, const svalue *init_pointee_sval = mgr->get_or_create_initial_value (pointee_reg); smap->set_state (state->m_region_model, init_pointee_sval, - tainted, NULL /*origin_new_sval*/, ext_state); + tainted, nullptr /*origin_new_sval*/, ext_state); } } @@ -3151,7 +3163,7 @@ exploded_graph::add_function_entry (const function &fun) logger * const logger = get_logger (); if (logger) logger->log ("entrypoint for %qE already exists", fun.decl); - return NULL; + return nullptr; } program_point point @@ -3160,7 +3172,7 @@ exploded_graph::add_function_entry (const function &fun) program_state state (m_ext_state); state.push_frame (m_ext_state, fun); - std::unique_ptr<custom_edge_info> edge_info = NULL; + std::unique_ptr<custom_edge_info> edge_info = nullptr; if (lookup_attribute ("tainted_args", DECL_ATTRIBUTES (fun.decl))) { @@ -3169,13 +3181,13 @@ exploded_graph::add_function_entry (const function &fun) } if (!state.m_valid) - return NULL; + return nullptr; - exploded_node *enode = get_or_create_node (point, state, NULL); + exploded_node *enode = get_or_create_node (point, state, nullptr); if (!enode) - return NULL; + return nullptr; - add_edge (m_origin, enode, NULL, false, std::move (edge_info)); + add_edge (m_origin, enode, nullptr, false, std::move (edge_info)); m_functions_with_enodes.add (key); @@ -3218,7 +3230,7 @@ exploded_graph::get_or_create_node (const program_point &point, { if (logger) logger->log ("invalid state; not creating node"); - return NULL; + return nullptr; } auto_cfun sentinel (point.get_function ()); @@ -3332,7 +3344,7 @@ exploded_graph::get_or_create_node (const program_point &point, "terminating analysis for this program point: %s", pp_formatted_text (&pp)); per_point_data->m_excess_enodes++; - return NULL; + return nullptr; } ps.validate (m_ext_state); @@ -3412,7 +3424,7 @@ get_or_create_per_program_point_data (const program_point &point) } /* Get this graph's per-program-point-data for POINT if there is any, - otherwise NULL. */ + otherwise nullptr. */ per_program_point_data * exploded_graph::get_per_program_point_data (const program_point &point) const @@ -3421,7 +3433,7 @@ exploded_graph::get_per_program_point_data (const program_point &point) const = const_cast <point_map_t &> (m_per_point_data).get (&point)) return *slot; - return NULL; + return nullptr; } /* Ensure that this graph has per-call_string-data for CS; @@ -3454,7 +3466,7 @@ exploded_graph::get_or_create_per_function_data (function *fun) } /* Get this graph's per-function-data for FUN if there is any, - otherwise NULL. */ + otherwise nullptr. */ per_function_data * exploded_graph::get_per_function_data (function *fun) const @@ -3463,7 +3475,7 @@ exploded_graph::get_per_function_data (function *fun) const = const_cast <per_function_data_t &> (m_per_function_data).get (fun)) return *slot; - return NULL; + return nullptr; } /* Return true if FUN should be traversed directly, rather than only as @@ -3626,7 +3638,7 @@ add_tainted_args_callback (exploded_graph *eg, tree field, tree fndecl, if (!state.m_valid) return; - exploded_node *enode = eg->get_or_create_node (point, state, NULL); + exploded_node *enode = eg->get_or_create_node (point, state, nullptr); if (logger) { if (enode) @@ -3640,7 +3652,7 @@ add_tainted_args_callback (exploded_graph *eg, tree field, tree fndecl, } } - eg->add_edge (eg->get_origin (), enode, NULL, false, + eg->add_edge (eg->get_origin (), enode, nullptr, false, std::make_unique<tainted_args_call_info> (field, fndecl, loc)); } @@ -3714,7 +3726,7 @@ exploded_graph::build_initial_worklist () tree init = DECL_INITIAL (decl); if (!init) continue; - walk_tree (&init, add_any_callbacks, this, NULL); + walk_tree (&init, add_any_callbacks, this, nullptr); } } @@ -3795,7 +3807,7 @@ exploded_graph::process_worklist () if (merged_state == state) { /* Then merge node_2 into node by adding an edge. */ - add_edge (node_2, node, NULL, false); + add_edge (node_2, node, nullptr, false); /* Remove node_2 from the worklist. */ m_worklist.take_next (); @@ -3808,7 +3820,7 @@ exploded_graph::process_worklist () /* Then merge node into node_2, and leave node_2 in the worklist, to be processed on the next iteration. */ - add_edge (node, node_2, NULL, false); + add_edge (node, node_2, nullptr, false); node->set_status (exploded_node::status::merger); continue; } @@ -3825,7 +3837,7 @@ exploded_graph::process_worklist () exploded_node *merged_enode = get_or_create_node (node->get_point (), merged_state, node); - if (merged_enode == NULL) + if (merged_enode == nullptr) continue; if (logger) @@ -3853,7 +3865,7 @@ exploded_graph::process_worklist () m_worklist.add_node (merged_enode); else { - add_edge (node, merged_enode, NULL, false); + add_edge (node, merged_enode, nullptr, false); node->set_status (exploded_node::status::merger); } @@ -3861,7 +3873,7 @@ exploded_graph::process_worklist () m_worklist.add_node (merged_enode); else { - add_edge (node_2, merged_enode, NULL, false); + add_edge (node_2, merged_enode, nullptr, false); node_2->set_status (exploded_node::status::merger); } @@ -4016,7 +4028,7 @@ maybe_process_run_of_before_supernode_enodes (exploded_node *enode) uncertainty_t uncertainty; impl_region_model_context ctxt (*this, iter_enode, &state, next_state, - &uncertainty, NULL, NULL); + &uncertainty, nullptr, nullptr); const cfg_superedge *last_cfg_superedge = iter_sedge->dyn_cast_cfg_superedge (); if (last_cfg_superedge) @@ -4079,7 +4091,7 @@ maybe_process_run_of_before_supernode_enodes (exploded_node *enode) = first_item_for_each_merged_state[i]->m_input_enode; exploded_node *next = get_or_create_node (next_point, *merged_state, src_enode); - /* "next" could be NULL; we handle that when adding the edges below. */ + /* "next" could be nullptr; we handle that when adding the edges below. */ next_enodes.quick_push (next); if (logger) { @@ -4096,7 +4108,7 @@ maybe_process_run_of_before_supernode_enodes (exploded_node *enode) { exploded_node *next = next_enodes[it->m_merger_idx]; if (next) - add_edge (it->m_input_enode, next, NULL, + add_edge (it->m_input_enode, next, nullptr, false); /* no "work" is done during merger. */ it->m_input_enode->set_status (exploded_node::status::bulk_merged); } @@ -4207,7 +4219,7 @@ exploded_graph::maybe_create_dynamic_call (const gcall &call, program_point new_point = program_point::before_supernode (sn_entry, - NULL, + nullptr, this_point->get_call_string ()); new_point.push_to_call_stack (sn_exit, @@ -4240,7 +4252,7 @@ exploded_graph::maybe_create_dynamic_call (const gcall &call, next_state, node); if (enode) - add_edge (node,enode, NULL, + add_edge (node,enode, nullptr, false, /* No work is done by the call itself. */ std::make_unique<dynamic_call_info_t> (call)); return true; @@ -4420,7 +4432,7 @@ exploded_graph::process_node (exploded_node *node) { impl_region_model_context ctxt (*this, node, &state, &next_state, - &uncertainty, NULL, NULL); + &uncertainty, nullptr, nullptr); const cfg_superedge *last_cfg_superedge = point.get_from_edge ()->dyn_cast_cfg_superedge (); if (last_cfg_superedge) @@ -4428,14 +4440,14 @@ exploded_graph::process_node (exploded_node *node) (node->get_supernode (), last_cfg_superedge, &ctxt); - program_state::detect_leaks (state, next_state, NULL, + program_state::detect_leaks (state, next_state, nullptr, get_ext_state (), &ctxt); } program_point next_point (point.get_next ()); exploded_node *next = get_or_create_node (next_point, next_state, node); if (next) - add_edge (node, next, NULL, + add_edge (node, next, nullptr, false); /* Assume no work is done at phi nodes. */ } break; @@ -4468,7 +4480,7 @@ exploded_graph::process_node (exploded_node *node) uncertainty_t uncertainty; const supernode *snode = point.get_supernode (); unsigned stmt_idx; - const gimple *prev_stmt = NULL; + const gimple *prev_stmt = nullptr; for (stmt_idx = point.get_stmt_idx (); stmt_idx < snode->m_stmts.length (); stmt_idx++) @@ -4500,8 +4512,8 @@ exploded_graph::process_node (exploded_node *node) { impl_region_model_context ctxt (*this, node, &old_state, &next_state, - &uncertainty, NULL, stmt); - program_state::detect_leaks (old_state, next_state, NULL, + &uncertainty, nullptr, stmt); + program_state::detect_leaks (old_state, next_state, nullptr, get_ext_state (), &ctxt); } @@ -4545,7 +4557,7 @@ exploded_graph::process_node (exploded_node *node) node->m_num_processed_stmts--; if (logger) logger->log ("creating edge to split_enode"); - add_edge (node, split_enode, NULL, could_have_done_work); + add_edge (node, split_enode, nullptr, could_have_done_work); return; } else @@ -4572,7 +4584,7 @@ exploded_graph::process_node (exploded_node *node) exploded_node *next = get_or_create_node (next_point, next_state, node); if (next) - add_edge (node, next, NULL, could_have_done_work); + add_edge (node, next, nullptr, could_have_done_work); } /* If we have custom edge infos, "bifurcate" the state @@ -4600,11 +4612,11 @@ exploded_graph::process_node (exploded_node *node) node, // enode_for_diag &path_ctxt.get_state_at_bifurcation (), &bifurcated_new_state, - NULL, // uncertainty_t *uncertainty - NULL, // path_context *path_ctxt + nullptr, // uncertainty_t *uncertainty + nullptr, // path_context *path_ctxt stmt); if (edge_info->update_state (&bifurcated_new_state, - NULL, /* no exploded_edge yet. */ + nullptr, /* no exploded_edge yet. */ &bifurcation_ctxt)) { if (exploded_node *next2 @@ -4615,7 +4627,7 @@ exploded_graph::process_node (exploded_node *node) node, &bifurcation_ctxt)) { - add_edge (node, next2, NULL, + add_edge (node, next2, nullptr, true /* assume that work could be done */, std::move (edge_info)); } @@ -4696,7 +4708,7 @@ exploded_graph::process_node (exploded_node *node) &state, &next_state, &uncertainty, - NULL, + nullptr, point.get_stmt()); region_model *model = state.m_region_model; @@ -4712,7 +4724,7 @@ exploded_graph::process_node (exploded_node *node) logger); if (!call_discovered) { - /* Check for jump through NULL. */ + /* Check for jump through nullptr. */ if (tree fn_ptr = gimple_call_fn (&call)) { const svalue *fn_ptr_sval @@ -4779,7 +4791,7 @@ exploded_graph::process_node (exploded_node *node) const call_string &cs = point.get_call_string (); program_point next_point = program_point::before_supernode (cs.get_caller_node (), - NULL, + nullptr, cs); program_state next_state (state); uncertainty_t uncertainty; @@ -4797,7 +4809,7 @@ exploded_graph::process_node (exploded_node *node) next_state, node); if (enode) - add_edge (node, enode, NULL, false, + add_edge (node, enode, nullptr, false, std::make_unique<dynamic_call_info_t> (*call, true)); } } @@ -4807,7 +4819,7 @@ exploded_graph::process_node (exploded_node *node) } /* Ensure that this graph has a stats instance for FN, return it. - FN can be NULL, in which case a stats instances is returned covering + FN can be nullptr, in which case a stats instances is returned covering "functionless" parts of the graph (the origin node). */ stats * @@ -5389,16 +5401,16 @@ void feasibility_state::update_for_stmt (const gimple *stmt) { if (const gassign *assign = dyn_cast <const gassign *> (stmt)) - m_model.on_assignment (assign, NULL); + m_model.on_assignment (assign, nullptr); else if (const gasm *asm_stmt = dyn_cast <const gasm *> (stmt)) - m_model.on_asm_stmt (asm_stmt, NULL); + m_model.on_asm_stmt (asm_stmt, nullptr); else if (const gcall *call = dyn_cast <const gcall *> (stmt)) { - bool unknown_side_effects = m_model.on_call_pre (*call, NULL); - m_model.on_call_post (*call, unknown_side_effects, NULL); + bool unknown_side_effects = m_model.on_call_pre (*call, nullptr); + m_model.on_call_post (*call, unknown_side_effects, nullptr); } else if (const greturn *return_ = dyn_cast <const greturn *> (stmt)) - m_model.on_return (return_, NULL); + m_model.on_return (return_, nullptr); } /* Dump this object to PP. */ @@ -5613,7 +5625,7 @@ template <> inline void pod_hash_traits<function_call_string>::mark_empty (value_type &v) { - v.m_fun = NULL; + v.m_fun = nullptr; } template <> inline bool @@ -5625,7 +5637,7 @@ template <> inline bool pod_hash_traits<function_call_string>::is_empty (value_type v) { - return v.m_fun == NULL; + return v.m_fun == nullptr; } namespace ana { @@ -5781,7 +5793,7 @@ exploded_graph::dump_exploded_nodes () const { auto_timevar tv (TV_ANALYZER_DUMP); char *filename - = concat (dump_base_name, ".eg.txt", NULL); + = concat (dump_base_name, ".eg.txt", nullptr); FILE *outf = fopen (filename, "w"); if (!outf) error_at (UNKNOWN_LOCATION, "unable to open %qs for writing", filename); @@ -6208,7 +6220,7 @@ dump_callgraph (const supergraph &sg, const char *filename, // TODO viz_callgraph vcg (sg); - vcg.dump_dot (filename, NULL, viz_callgraph_traits::dump_args_t (eg)); + vcg.dump_dot (filename, nullptr, viz_callgraph_traits::dump_args_t (eg)); fclose (outf); } @@ -6219,7 +6231,7 @@ static void dump_callgraph (const supergraph &sg, const exploded_graph *eg) { auto_timevar tv (TV_ANALYZER_DUMP); - char *filename = concat (dump_base_name, ".callgraph.dot", NULL); + char *filename = concat (dump_base_name, ".callgraph.dot", nullptr); dump_callgraph (sg, filename, eg); free (filename); } @@ -6445,7 +6457,7 @@ dump_analyzer_json (const supergraph &sg, const exploded_graph &eg) { auto_timevar tv (TV_ANALYZER_DUMP); - char *filename = concat (dump_base_name, ".analyzer.json.gz", NULL); + char *filename = concat (dump_base_name, ".analyzer.json.gz", nullptr); gzFile output = gzopen (filename, "w"); if (!output) { @@ -6532,7 +6544,7 @@ impl_run_checkers (logger *logger) engine eng (&sg, logger); - state_purge_map *purge_map = NULL; + state_purge_map *purge_map = nullptr; if (flag_analyzer_state_purge) purge_map = new state_purge_map (sg, eng.get_model_manager (), logger); @@ -6541,8 +6553,8 @@ impl_run_checkers (logger *logger) { /* Dump supergraph pre-analysis. */ auto_timevar tv (TV_ANALYZER_DUMP); - char *filename = concat (dump_base_name, ".supergraph.dot", NULL); - supergraph::dump_args_t args ((enum supergraph_dot_flags)0, NULL); + char *filename = concat (dump_base_name, ".supergraph.dot", nullptr); + supergraph::dump_args_t args ((enum supergraph_dot_flags)0, nullptr); sg.dump_dot (filename, args); free (filename); } @@ -6551,7 +6563,7 @@ impl_run_checkers (logger *logger) { auto_timevar tv (TV_ANALYZER_DUMP); state_purge_annotator a (purge_map); - char *filename = concat (dump_base_name, ".state-purge.dot", NULL); + char *filename = concat (dump_base_name, ".state-purge.dot", nullptr); supergraph::dump_args_t args ((enum supergraph_dot_flags)0, &a); sg.dump_dot (filename, args); free (filename); @@ -6596,7 +6608,7 @@ impl_run_checkers (logger *logger) { auto_timevar tv (TV_ANALYZER_DUMP); char *filename - = concat (dump_base_name, ".eg.dot", NULL); + = concat (dump_base_name, ".eg.dot", nullptr); exploded_graph::dump_args_t args (eg); root_cluster c; eg.dump_dot (filename, &c, args); @@ -6617,7 +6629,7 @@ impl_run_checkers (logger *logger) { /* Dump post-analysis form of supergraph. */ auto_timevar tv (TV_ANALYZER_DUMP); - char *filename = concat (dump_base_name, ".supergraph-eg.dot", NULL); + char *filename = concat (dump_base_name, ".supergraph-eg.dot", nullptr); exploded_graph_annotator a (eg); supergraph::dump_args_t args ((enum supergraph_dot_flags)0, &a); sg.dump_dot (filename, args); @@ -6641,7 +6653,7 @@ impl_run_checkers (logger *logger) } /* Handle -fdump-analyzer and -fdump-analyzer-stderr. */ -static FILE *dump_fout = NULL; +static FILE *dump_fout = nullptr; /* Track if we're responsible for closing dump_fout. */ static bool owns_dump_fout = false; @@ -6658,7 +6670,7 @@ get_or_create_any_logfile () dump_fout = stderr; else if (flag_dump_analyzer) { - char *dump_filename = concat (dump_base_name, ".analyzer.txt", NULL); + char *dump_filename = concat (dump_base_name, ".analyzer.txt", nullptr); dump_fout = fopen (dump_filename, "w"); free (dump_filename); if (dump_fout) @@ -6678,7 +6690,7 @@ run_checkers () location_t saved_input_location = input_location; { - log_user the_logger (NULL); + log_user the_logger (nullptr); get_or_create_any_logfile (); if (dump_fout) the_logger.set_logger (new logger (dump_fout, 0, 0, @@ -6695,7 +6707,7 @@ run_checkers () { fclose (dump_fout); owns_dump_fout = false; - dump_fout = NULL; + dump_fout = nullptr; } /* Restore input_location. Subsequent passes may assume that input_location diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h index 23e344d..1d31097 100644 --- a/gcc/analyzer/exploded-graph.h +++ b/gcc/analyzer/exploded-graph.h @@ -49,17 +49,17 @@ class impl_region_model_context : public region_model_context path_context *path_ctxt, const gimple *stmt, - stmt_finder *stmt_finder = NULL, + stmt_finder *stmt_finder = nullptr, bool *out_could_have_done_work = nullptr); impl_region_model_context (program_state *state, const extrinsic_state &ext_state, uncertainty_t *uncertainty, - logger *logger = NULL); + logger *logger = nullptr); bool warn (std::unique_ptr<pending_diagnostic> d, - const stmt_finder *custom_finder = NULL) final override; + const stmt_finder *custom_finder = nullptr) final override; void add_note (std::unique_ptr<pending_note> pn) final override; void add_event (std::unique_ptr<checker_event> event) final override; void on_svalue_leak (const svalue *) override; @@ -112,6 +112,8 @@ class impl_region_model_context : public region_model_context const gimple *get_stmt () const override { return m_stmt; } const exploded_graph *get_eg () const override { return m_eg; } + const program_state *get_state () const override { return m_new_state; } + void maybe_did_work () override; bool checking_for_infinite_loop_p () const override { return false; } void on_unusable_in_infinite_loop () override {} @@ -405,7 +407,7 @@ class exploded_edge : public dedge<eg_traits> //private: const superedge *const m_sedge; - /* NULL for most edges; will be non-NULL for special cases + /* nullptr for most edges; will be non-NULL for special cases such as an unwind from a longjmp to a setjmp, or when a signal is delivered to a signal-handler. */ std::unique_ptr<custom_edge_info> m_custom_info; @@ -546,14 +548,14 @@ struct eg_hash_map_traits static inline hashval_t hash (const key_type &k) { - gcc_assert (k != NULL); + gcc_assert (k != nullptr); gcc_assert (k != reinterpret_cast<key_type> (1)); return k->hash (); } static inline bool equal_keys (const key_type &k1, const key_type &k2) { - gcc_assert (k1 != NULL); - gcc_assert (k2 != NULL); + gcc_assert (k1 != nullptr); + gcc_assert (k2 != nullptr); gcc_assert (k1 != reinterpret_cast<key_type> (1)); gcc_assert (k2 != reinterpret_cast<key_type> (1)); if (k1 && k2) @@ -575,7 +577,7 @@ struct eg_hash_map_traits template <typename T> static inline void mark_empty (T &entry) { - entry.m_key = NULL; + entry.m_key = nullptr; } template <typename T> static inline bool is_deleted (const T &entry) @@ -585,7 +587,7 @@ struct eg_hash_map_traits template <typename T> static inline bool is_empty (const T &entry) { - return entry.m_key == NULL; + return entry.m_key == nullptr; } static const bool empty_zero_p = false; }; @@ -616,14 +618,14 @@ struct eg_point_hash_map_traits static inline hashval_t hash (const key_type &k) { - gcc_assert (k != NULL); + gcc_assert (k != nullptr); gcc_assert (k != reinterpret_cast<key_type> (1)); return k->hash (); } static inline bool equal_keys (const key_type &k1, const key_type &k2) { - gcc_assert (k1 != NULL); - gcc_assert (k2 != NULL); + gcc_assert (k1 != nullptr); + gcc_assert (k2 != nullptr); gcc_assert (k1 != reinterpret_cast<key_type> (1)); gcc_assert (k2 != reinterpret_cast<key_type> (1)); if (k1 && k2) @@ -645,7 +647,7 @@ struct eg_point_hash_map_traits template <typename T> static inline void mark_empty (T &entry) { - entry.m_key = NULL; + entry.m_key = nullptr; } template <typename T> static inline bool is_deleted (const T &entry) @@ -655,7 +657,7 @@ struct eg_point_hash_map_traits template <typename T> static inline bool is_empty (const T &entry) { - return entry.m_key == NULL; + return entry.m_key == nullptr; } static const bool empty_zero_p = false; }; @@ -776,7 +778,7 @@ private: int get_scc_id (const exploded_node *enode) const { const supernode *snode = enode->get_supernode (); - if (snode == NULL) + if (snode == nullptr) return 0; return m_worklist.m_scc.get_scc_id (snode->m_index); } @@ -844,7 +846,7 @@ public: bool add_to_worklist = true); exploded_edge *add_edge (exploded_node *src, exploded_node *dest, const superedge *sedge, bool could_do_work, - std::unique_ptr<custom_edge_info> custom = NULL); + std::unique_ptr<custom_edge_info> custom = nullptr); per_program_point_data * get_or_create_per_program_point_data (const program_point &); @@ -977,7 +979,7 @@ public: void dump_to_pp (pretty_printer *pp, const extrinsic_state *ext_state) const; void dump (FILE *fp, const extrinsic_state *ext_state) const; - void dump (const extrinsic_state *ext_state = NULL) const; + void dump (const extrinsic_state *ext_state = nullptr) const; void dump_to_file (const char *filename, const extrinsic_state &ext_state) const; @@ -1042,7 +1044,7 @@ private: typedef shortest_paths<eg_traits, exploded_path> shortest_exploded_paths; -/* Abstract base class for use when passing NULL as the stmt for +/* Abstract base class for use when passing nullptr as the stmt for a possible warning, allowing the choice of stmt to be deferred until after we have an emission path (and know we're emitting a warning). */ diff --git a/gcc/analyzer/function-set.cc b/gcc/analyzer/function-set.cc index 817a512..530e0ad 100644 --- a/gcc/analyzer/function-set.cc +++ b/gcc/analyzer/function-set.cc @@ -95,7 +95,7 @@ namespace selftest { static void test_empty () { - function_set fs (NULL, 0); + function_set fs (nullptr, 0); fs.assert_sorted (); fs.assert_sane (); ASSERT_FALSE (fs.contains_name_p ("")); diff --git a/gcc/analyzer/infinite-recursion.cc b/gcc/analyzer/infinite-recursion.cc index 0641117..b80b94a 100644 --- a/gcc/analyzer/infinite-recursion.cc +++ b/gcc/analyzer/infinite-recursion.cc @@ -55,7 +55,7 @@ public: : m_prev_entry_enode (prev_entry_enode), m_new_entry_enode (new_entry_enode), m_callee_fndecl (callee_fndecl), - m_prev_entry_event (NULL) + m_prev_entry_event (nullptr) {} const char *get_kind () const final override @@ -108,9 +108,10 @@ public: { public: recursive_function_entry_event (const program_point &dst_point, + const program_state &dst_state, const infinite_recursion_diagnostic &pd, bool topmost) - : function_entry_event (dst_point), + : function_entry_event (dst_point, dst_state), m_pd (pd), m_topmost (topmost) { @@ -146,17 +147,19 @@ public: const program_point &dst_point = dst_node->get_point (); if (eedge.m_dest == m_prev_entry_enode) { - gcc_assert (m_prev_entry_event == NULL); + gcc_assert (m_prev_entry_event == nullptr); std::unique_ptr<checker_event> prev_entry_event - = std::make_unique <recursive_function_entry_event> (dst_point, - *this, false); + = std::make_unique <recursive_function_entry_event> + (dst_point, + dst_node->get_state (), + *this, false); m_prev_entry_event = prev_entry_event.get (); emission_path->add_event (std::move (prev_entry_event)); } else if (eedge.m_dest == m_new_entry_enode) emission_path->add_event (std::make_unique<recursive_function_entry_event> - (dst_point, *this, true)); + (dst_point, dst_node->get_state (), *this, true)); else pending_diagnostic::add_function_entry_event (eedge, emission_path); } @@ -288,7 +291,7 @@ private: bool m_found_conjured_svalues; }; - const svalue *sval = model.get_rvalue (expr, NULL); + const svalue *sval = model.get_rvalue (expr, nullptr); conjured_svalue_finder v; sval->accept (&v); return v.m_found_conjured_svalues; @@ -348,7 +351,7 @@ exploded_graph::find_previous_entry_to (function *top_of_stack_fun, } /* Not found. */ - return NULL; + return nullptr; } /* Given BASE_REG within ENCLOSING_FRAME (such as a function parameter), @@ -382,7 +385,7 @@ remap_enclosing_frame (const region *base_reg, const decl_region *decl_reg = (const decl_region *)base_reg; return equiv_prev_frame->get_region_for_local (mgr, decl_reg->get_decl (), - NULL); + nullptr); } } } @@ -424,7 +427,7 @@ sufficiently_different_region_binding_p (exploded_node *new_entry_enode, /* Get the value within the new frame. */ const svalue *new_sval - = new_model.get_store_value (base_reg, NULL); + = new_model.get_store_value (base_reg, nullptr); /* If any part of the value is UNKNOWN (e.g. due to hitting complexity limits) assume that it differs from the previous @@ -444,7 +447,7 @@ sufficiently_different_region_binding_p (exploded_node *new_entry_enode, to the recursion. */ const int old_stack_depth = prev_entry_enode->get_stack_depth (); if (enclosing_frame->get_stack_depth () < old_stack_depth) - prev_sval = prev_model.get_store_value (base_reg, NULL); + prev_sval = prev_model.get_store_value (base_reg, nullptr); else { /* Ignore bindings within frames below the new entry node. */ @@ -466,11 +469,11 @@ sufficiently_different_region_binding_p (exploded_node *new_entry_enode, equiv_prev_frame, new_model.get_manager ()); prev_sval - = prev_model.get_store_value (equiv_prev_base_reg, NULL); + = prev_model.get_store_value (equiv_prev_base_reg, nullptr); } } else - prev_sval = prev_model.get_store_value (base_reg, NULL); + prev_sval = prev_model.get_store_value (base_reg, nullptr); /* If the prev_sval contains UNKNOWN (e.g. due to hitting complexity limits) assume that it will differ from any new value. */ diff --git a/gcc/analyzer/inlining-iterator.h b/gcc/analyzer/inlining-iterator.h index ac1463d..20d1d2b 100644 --- a/gcc/analyzer/inlining-iterator.h +++ b/gcc/analyzer/inlining-iterator.h @@ -46,7 +46,7 @@ class inlining_iterator public: inlining_iterator (location_t loc) : m_abstract_origin (LOCATION_BLOCK (loc)), - m_callsite (UNKNOWN_LOCATION), m_fndecl (NULL), + m_callsite (UNKNOWN_LOCATION), m_fndecl (NULL_TREE), m_next_abstract_origin (NULL) { prepare_iteration (); @@ -71,7 +71,7 @@ private: return; tree block = m_abstract_origin; m_callsite = BLOCK_SOURCE_LOCATION (block); - m_fndecl = NULL; + m_fndecl = NULL_TREE; block = BLOCK_SUPERCONTEXT (block); while (block && TREE_CODE (block) == BLOCK && BLOCK_ABSTRACT_ORIGIN (block)) diff --git a/gcc/analyzer/kf-analyzer.cc b/gcc/analyzer/kf-analyzer.cc index 3e671e5..13476de 100644 --- a/gcc/analyzer/kf-analyzer.cc +++ b/gcc/analyzer/kf-analyzer.cc @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/region-model.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/call-details.h" +#include "analyzer/program-state.h" #if ENABLE_ANALYZER @@ -260,6 +261,11 @@ class dump_path_diagnostic : public pending_diagnostic_subclass<dump_path_diagnostic> { public: + dump_path_diagnostic (const program_state &state) + : m_state (state) + { + } + int get_controlling_option () const final override { return 0; @@ -280,6 +286,15 @@ public: { return true; } + + const program_state * + get_final_state () const final override + { + return &m_state; + } + +private: + program_state m_state; }; /* Handle calls to "__analyzer_dump_path" by queuing a diagnostic at this @@ -297,7 +312,8 @@ public: region_model_context *ctxt = cd.get_ctxt (); if (!ctxt) return; - ctxt->warn (std::make_unique<dump_path_diagnostic> ()); + if (const program_state *state = ctxt->get_state ()) + ctxt->warn (std::make_unique<dump_path_diagnostic> (*state)); } }; diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc index 75b6279..fe25520 100644 --- a/gcc/analyzer/kf.cc +++ b/gcc/analyzer/kf.cc @@ -1053,11 +1053,11 @@ kf_realloc::impl_call_post (const call_details &cd) const const svalue *copied_size_sval = get_copied_size (model, old_size_sval, new_size_sval); const region *copied_old_reg - = mgr->get_sized_region (freed_reg, NULL, copied_size_sval); + = mgr->get_sized_region (freed_reg, nullptr, copied_size_sval); const svalue *buffer_content_sval = model->get_store_value (copied_old_reg, cd.get_ctxt ()); const region *copied_new_reg - = mgr->get_sized_region (new_reg, NULL, copied_size_sval); + = mgr->get_sized_region (new_reg, nullptr, copied_size_sval); model->set_value (copied_new_reg, buffer_content_sval, cd.get_ctxt ()); } @@ -1636,7 +1636,7 @@ kf_strncpy::impl_call_post (const call_details &cd) const } private: /* (strlen + 1) of the source string if it has a terminator, - or NULL for the case where UB would happen before + or nullptr for the case where UB would happen before finding any terminator. */ const svalue *m_num_bytes_with_terminator_sval; @@ -1691,8 +1691,8 @@ public: region_model_manager *mgr = cd.get_manager (); /* Ideally we'd get the size here, and simulate copying the bytes. */ const region *new_reg - = model->get_or_create_region_for_heap_alloc (NULL, cd.get_ctxt ()); - model->mark_region_as_unknown (new_reg, NULL); + = model->get_or_create_region_for_heap_alloc (nullptr, cd.get_ctxt ()); + model->mark_region_as_unknown (new_reg, nullptr); if (cd.get_lhs_type ()) { const svalue *ptr_sval diff --git a/gcc/analyzer/known-function-manager.cc b/gcc/analyzer/known-function-manager.cc index 1a2930e..3b645a8 100644 --- a/gcc/analyzer/known-function-manager.cc +++ b/gcc/analyzer/known-function-manager.cc @@ -92,7 +92,7 @@ known_function_manager::add (enum internal_fn ifn, The call must match all assumptions made by the known_function (such as e.g. "argument 1's type must be a pointer type"). - Return NULL if no known_function is found, or it does not match the + Return nullptr if no known_function is found, or it does not match the assumption(s). */ const known_function * @@ -122,16 +122,16 @@ known_function_manager::get_match (tree fndecl, const call_details &cd) const if (DECL_CONTEXT (fndecl) && TREE_CODE (DECL_CONTEXT (fndecl)) != TRANSLATION_UNIT_DECL) - return NULL; + return nullptr; if (tree identifier = DECL_NAME (fndecl)) if (const known_function *candidate = get_by_identifier (identifier)) if (candidate->matches_call_types_p (cd)) return candidate; - return NULL; + return nullptr; } -/* Get any known_function for IFN, or NULL. */ +/* Get any known_function for IFN, or nullptr. */ const known_function * known_function_manager::get_internal_fn (enum internal_fn ifn) const @@ -141,7 +141,7 @@ known_function_manager::get_internal_fn (enum internal_fn ifn) const } /* Get any known_function for NAME, without type-checking. - Return NULL if there isn't one. */ + Return nullptr if there isn't one. */ const known_function * known_function_manager::get_normal_builtin (enum built_in_function name) const @@ -160,7 +160,7 @@ get_normal_builtin (const builtin_known_function *builtin_kf) const } /* Get any known_function matching IDENTIFIER, without type-checking. - Return NULL if there isn't one. */ + Return nullptr if there isn't one. */ const known_function * known_function_manager::get_by_identifier (tree identifier) const @@ -170,7 +170,7 @@ known_function_manager::get_by_identifier (tree identifier) const if (slot) return *slot; else - return NULL; + return nullptr; } /* Get any known_function in C++ std:: namespace matching IDENTIFIER, without diff --git a/gcc/analyzer/pending-diagnostic.cc b/gcc/analyzer/pending-diagnostic.cc index 70dc815..5e95edd 100644 --- a/gcc/analyzer/pending-diagnostic.cc +++ b/gcc/analyzer/pending-diagnostic.cc @@ -171,7 +171,7 @@ pending_diagnostic::fixup_location (location_t loc, bool) const const line_map_macro *macro_map = linemap_check_macro (map); if (fixup_location_in_macro_p (macro_map->macro)) loc = linemap_resolve_location (line_table, loc, - LRK_MACRO_EXPANSION_POINT, NULL); + LRK_MACRO_EXPANSION_POINT, nullptr); } return loc; } @@ -185,7 +185,10 @@ pending_diagnostic::add_function_entry_event (const exploded_edge &eedge, { const exploded_node *dst_node = eedge.m_dest; const program_point &dst_point = dst_node->get_point (); - emission_path->add_event (std::make_unique<function_entry_event> (dst_point)); + const program_state &dst_state = dst_node->get_state (); + emission_path->add_event + (std::make_unique<function_entry_event> (dst_point, + dst_state)); } /* Base implementation of pending_diagnostic::add_call_event. @@ -241,7 +244,8 @@ pending_diagnostic::add_final_event (const state_machine *sm, (std::make_unique<warning_event> (loc_info, enode, - sm, var, state)); + sm, var, state, + get_final_state ())); } } // namespace ana diff --git a/gcc/analyzer/pending-diagnostic.h b/gcc/analyzer/pending-diagnostic.h index 6a0289e..469513c 100644 --- a/gcc/analyzer/pending-diagnostic.h +++ b/gcc/analyzer/pending-diagnostic.h @@ -364,6 +364,12 @@ class pending_diagnostic tree var, state_machine::state_t state, checker_path *emission_path); + virtual const program_state * + get_final_state () const + { + return nullptr; + } + /* Vfunc for determining that this pending_diagnostic supercedes OTHER, and that OTHER should therefore not be emitted. They have already been tested for being at the same stmt. */ diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc index c95f863..1f82559 100644 --- a/gcc/analyzer/program-point.cc +++ b/gcc/analyzer/program-point.cc @@ -171,7 +171,7 @@ function_point::get_function () const if (m_supernode) return m_supernode->m_fun; else - return NULL; + return nullptr; } /* Get the gimple stmt for this function_point, if any. */ @@ -184,7 +184,7 @@ function_point::get_stmt () const else if (m_kind == PK_AFTER_SUPERNODE) return m_supernode->get_last_stmt (); else - return NULL; + return nullptr; } /* Get a location for this function_point, if any. */ @@ -219,18 +219,18 @@ function_point::final_stmt_p () const function_point function_point::from_function_entry (const supergraph &sg, const function &fun) { - return before_supernode (sg.get_node_for_function_entry (fun), NULL); + return before_supernode (sg.get_node_for_function_entry (fun), nullptr); } /* Create a function_point representing entering supernode SUPERNODE, - having reached it via FROM_EDGE (which could be NULL). */ + having reached it via FROM_EDGE (which could be nullptr). */ function_point function_point::before_supernode (const supernode *supernode, const superedge *from_edge) { if (from_edge && from_edge->get_kind () != SUPEREDGE_CFG_EDGE) - from_edge = NULL; + from_edge = nullptr; return function_point (supernode, from_edge, 0, PK_BEFORE_SUPERNODE); } @@ -673,7 +673,7 @@ function_point::get_next () const program_point program_point::origin (const region_model_manager &mgr) { - return program_point (function_point (NULL, NULL, + return program_point (function_point (nullptr, nullptr, 0, PK_ORIGIN), mgr.get_empty_call_string ()); } @@ -766,11 +766,11 @@ namespace selftest { static void test_function_point_equality () { - const supernode *snode = NULL; + const supernode *snode = nullptr; - function_point a = function_point (snode, NULL, 0, + function_point a = function_point (snode, nullptr, 0, PK_BEFORE_SUPERNODE); - function_point b = function_point::before_supernode (snode, NULL); + function_point b = function_point::before_supernode (snode, nullptr); ASSERT_EQ (a, b); } @@ -779,12 +779,12 @@ test_function_point_equality () static void test_function_point_ordering () { - const supernode *snode = NULL; + const supernode *snode = nullptr; /* Populate an array with various points within the same snode, in order. */ auto_vec<function_point> points; - points.safe_push (function_point::before_supernode (snode, NULL)); + points.safe_push (function_point::before_supernode (snode, nullptr)); points.safe_push (function_point::before_stmt (snode, 0)); points.safe_push (function_point::before_stmt (snode, 1)); points.safe_push (function_point::after_supernode (snode)); @@ -816,14 +816,14 @@ test_program_point_equality () { region_model_manager mgr; - const supernode *snode = NULL; + const supernode *snode = nullptr; const call_string &cs = mgr.get_empty_call_string (); - program_point a = program_point::before_supernode (snode, NULL, + program_point a = program_point::before_supernode (snode, nullptr, cs); - program_point b = program_point::before_supernode (snode, NULL, + program_point b = program_point::before_supernode (snode, nullptr, cs); ASSERT_EQ (a, b); diff --git a/gcc/analyzer/program-point.h b/gcc/analyzer/program-point.h index 38d83197..fc543c0 100644 --- a/gcc/analyzer/program-point.h +++ b/gcc/analyzer/program-point.h @@ -120,23 +120,23 @@ public: static function_point before_stmt (const supernode *supernode, unsigned stmt_idx) { - return function_point (supernode, NULL, stmt_idx, PK_BEFORE_STMT); + return function_point (supernode, nullptr, stmt_idx, PK_BEFORE_STMT); } static function_point after_supernode (const supernode *supernode) { - return function_point (supernode, NULL, 0, PK_AFTER_SUPERNODE); + return function_point (supernode, nullptr, 0, PK_AFTER_SUPERNODE); } /* Support for hash_map. */ static function_point empty () { - return function_point (NULL, NULL, 0, PK_EMPTY); + return function_point (nullptr, nullptr, 0, PK_EMPTY); } static function_point deleted () { - return function_point (NULL, NULL, 0, PK_DELETED); + return function_point (nullptr, nullptr, 0, PK_DELETED); } static int cmp_within_supernode_1 (const function_point &point_a, @@ -305,7 +305,7 @@ public: private: program_point (const function_point &fn_point) : m_function_point (fn_point), - m_call_string (NULL) + m_call_string (nullptr) { } diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index 21f78e5..c0befac 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -28,6 +28,8 @@ along with GCC; see the file COPYING3. If not see #include "cgraph.h" #include "digraph.h" #include "diagnostic-event-id.h" +#include "diagnostic-state.h" +#include "graphviz.h" #include "text-art/tree-widget.h" #include "text-art/dump.h" @@ -48,6 +50,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/state-purge.h" #include "analyzer/call-summary.h" #include "analyzer/analyzer-selftests.h" +#include "analyzer/ana-state-to-diagnostic-state.h" #if ENABLE_ANALYZER @@ -112,7 +115,7 @@ extrinsic_state::get_model_manager () const if (m_engine) return m_engine->get_model_manager (); else - return NULL; /* for selftests. */ + return nullptr; /* for selftests. */ } /* Try to find a state machine named NAME. @@ -255,7 +258,7 @@ DEBUG_FUNCTION void sm_state_map::dump (bool simple) const { tree_dump_pretty_printer pp (stderr); - print (NULL, simple, true, &pp); + print (nullptr, simple, true, &pp); pp_newline (&pp); } @@ -417,7 +420,7 @@ sm_state_map::operator== (const sm_state_map &other) const const svalue *sval = (*iter).first; entry_t e = (*iter).second; entry_t *other_slot = const_cast <map_t &> (other.m_map).get (sval); - if (other_slot == NULL) + if (other_slot == nullptr) return false; if (e != *other_slot) return false; @@ -498,7 +501,7 @@ sm_state_map::get_origin (const svalue *sval, if (slot) return slot->m_origin; else - return NULL; + return nullptr; } /* Set the state of SID within MODEL to STATE, recording that @@ -511,7 +514,7 @@ sm_state_map::set_state (region_model *model, const svalue *origin, const extrinsic_state &ext_state) { - if (model == NULL) + if (model == nullptr) return; /* Reject attempts to set state on UNKNOWN/POISONED. */ @@ -768,7 +771,7 @@ sm_state_map::on_unknown_change (const svalue *sval, for (svalue_set::iterator iter = svals_to_unset.begin (); iter != svals_to_unset.end (); ++iter) - impl_set_state (*iter, (state_machine::state_t)0, NULL, ext_state); + impl_set_state (*iter, (state_machine::state_t)0, nullptr, ext_state); } /* Purge state for things involving SVAL. @@ -799,7 +802,7 @@ sm_state_map::purge_state_involving (const svalue *sval, for (svalue_set::iterator iter = svals_to_unset.begin (); iter != svals_to_unset.end (); ++iter) - impl_set_state (*iter, (state_machine::state_t)0, NULL, ext_state); + impl_set_state (*iter, (state_machine::state_t)0, nullptr, ext_state); } /* Comparator for imposing an order on sm_state_map instances. */ @@ -909,7 +912,7 @@ sm_state_map::can_merge_with_p (const sm_state_map &other, state_machine::state_t other_state = other.get_state (sval, ext_state); if (state_machine::state_t merged_state = sm.maybe_get_merged_state (this_state, other_state)) - (*out)->impl_set_state (sval, merged_state, NULL, ext_state); + (*out)->impl_set_state (sval, merged_state, nullptr, ext_state); else return false; } @@ -923,7 +926,7 @@ sm_state_map::can_merge_with_p (const sm_state_map &other, /* program_state's ctor. */ program_state::program_state (const extrinsic_state &ext_state) -: m_region_model (NULL), +: m_region_model (nullptr), m_checker_states (ext_state.get_num_checkers ()), m_valid (true) { @@ -957,8 +960,8 @@ sm_state_map::replay_call_summary (call_summary_replay &r, const svalue *caller_origin = (summary_origin ? r.convert_svalue_from_summary (summary_origin) - : NULL); - // caller_origin can be NULL. + : nullptr); + // caller_origin can be nullptr. m_map.put (caller_sval, entry_t (kv.second.m_state, caller_origin)); } m_global_state = summary.m_global_state; @@ -1006,7 +1009,7 @@ program_state::program_state (program_state &&other) : m_region_model (other.m_region_model), m_checker_states (other.m_checker_states.length ()) { - other.m_region_model = NULL; + other.m_region_model = nullptr; int i; sm_state_map *smap; @@ -1224,6 +1227,18 @@ program_state::make_dump_widget (const text_art::dump_widget_info &dwi) const return state_widget; } +void +program_state::dump_dot (const extrinsic_state &ext_state) const +{ + auto doc = make_xml (ext_state); + auto graph = make_dot_graph_from_xml_state (*doc); + + pretty_printer pp; + dot::writer w (pp); + graph->print (w); + pp_flush (&pp); +} + /* Update this program_state to reflect a top-level call to FUN. The params will have initial_svalues. */ @@ -1322,7 +1337,7 @@ program_state::on_edge (exploded_graph &eg, return false; program_state::detect_leaks (enode->get_state (), *this, - NULL, eg.get_ext_state (), + nullptr, eg.get_ext_state (), &ctxt); return true; @@ -1346,7 +1361,7 @@ program_state::push_call (exploded_graph &eg, &enode->get_state (), this, uncertainty, - NULL, + nullptr, last_stmt); m_region_model->update_for_gcall (call_stmt, &ctxt); } @@ -1369,7 +1384,7 @@ program_state::returning_call (exploded_graph &eg, &enode->get_state (), this, uncertainty, - NULL, + nullptr, last_stmt); m_region_model->update_for_return_gcall (call_stmt, &ctxt); } @@ -1427,7 +1442,7 @@ program_state::prune_for_point (exploded_graph &eg, temporaries keep the value reachable until the frame is popped. */ const svalue *sval - = new_state.m_region_model->get_store_value (reg, NULL); + = new_state.m_region_model->get_store_value (reg, nullptr); if (!new_state.can_purge_p (eg.get_ext_state (), sval) && SSA_NAME_VAR (ssa_name)) { @@ -1486,9 +1501,9 @@ program_state::prune_for_point (exploded_graph &eg, impl_region_model_context ctxt (eg, enode_for_diag, this, &new_state, - uncertainty, NULL, + uncertainty, nullptr, point.get_stmt ()); - detect_leaks (*this, new_state, NULL, eg.get_ext_state (), &ctxt); + detect_leaks (*this, new_state, nullptr, eg.get_ext_state (), &ctxt); } } @@ -1660,7 +1675,7 @@ program_state::detect_leaks (const program_state &src_state, *might* still be reachable in dst_state. */ svalue_set known_src_svalues; src_state.m_region_model->get_reachable_svalues (&known_src_svalues, - NULL, NULL); + nullptr, nullptr); svalue_set maybe_dest_svalues; dest_state.m_region_model->get_reachable_svalues (&maybe_dest_svalues, extra_sval, uncertainty); @@ -1778,7 +1793,7 @@ test_sm_state_map () tree y = build_global_decl ("y", integer_type_node); tree z = build_global_decl ("z", integer_type_node); - std::unique_ptr<state_machine> sm = make_malloc_state_machine (NULL); + std::unique_ptr<state_machine> sm = make_malloc_state_machine (nullptr); state_machine::state_t start = sm->get_start_state (); std::vector<std::unique_ptr<state_machine>> checkers; const state_machine &borrowed_sm = *sm.get (); @@ -1792,9 +1807,9 @@ test_sm_state_map () const state_machine::state_t TEST_STATE_42 = &test_state_42; region_model_manager mgr; region_model model (&mgr); - const svalue *x_sval = model.get_rvalue (x, NULL); - const svalue *y_sval = model.get_rvalue (y, NULL); - const svalue *z_sval = model.get_rvalue (z, NULL); + const svalue *x_sval = model.get_rvalue (x, nullptr); + const svalue *y_sval = model.get_rvalue (y, nullptr); + const svalue *z_sval = model.get_rvalue (z, nullptr); sm_state_map map (borrowed_sm); ASSERT_TRUE (map.is_empty_p ()); @@ -1821,16 +1836,16 @@ test_sm_state_map () { region_model_manager mgr; region_model model (&mgr); - const svalue *x_sval = model.get_rvalue (x, NULL); - const svalue *y_sval = model.get_rvalue (y, NULL); - const svalue *z_sval = model.get_rvalue (z, NULL); + const svalue *x_sval = model.get_rvalue (x, nullptr); + const svalue *y_sval = model.get_rvalue (y, nullptr); + const svalue *z_sval = model.get_rvalue (z, nullptr); sm_state_map map (borrowed_sm); ASSERT_TRUE (map.is_empty_p ()); ASSERT_EQ (map.get_state (x_sval, ext_state), start); ASSERT_EQ (map.get_state (y_sval, ext_state), start); - model.add_constraint (x, EQ_EXPR, y, NULL); + model.add_constraint (x, EQ_EXPR, y, nullptr); /* Setting x to a state should also update y, as they are in the same equivalence class. */ @@ -1845,8 +1860,8 @@ test_sm_state_map () { region_model_manager mgr; region_model model (&mgr); - const svalue *y_sval = model.get_rvalue (y, NULL); - const svalue *z_sval = model.get_rvalue (z, NULL); + const svalue *y_sval = model.get_rvalue (y, nullptr); + const svalue *z_sval = model.get_rvalue (z, nullptr); sm_state_map map0 (borrowed_sm); sm_state_map map1 (borrowed_sm); @@ -1880,17 +1895,17 @@ test_sm_state_map () region_model_manager mgr; region_model model (&mgr); - const svalue *x_sval = model.get_rvalue (x, NULL); - const svalue *y_sval = model.get_rvalue (y, NULL); - const svalue *z_sval = model.get_rvalue (z, NULL); + const svalue *x_sval = model.get_rvalue (x, nullptr); + const svalue *y_sval = model.get_rvalue (y, nullptr); + const svalue *z_sval = model.get_rvalue (z, nullptr); - map1.impl_set_state (x_sval, TEST_STATE_2, NULL, ext_state); - map1.impl_set_state (y_sval, TEST_STATE_3, NULL, ext_state); - map1.impl_set_state (z_sval, TEST_STATE_2, NULL, ext_state); + map1.impl_set_state (x_sval, TEST_STATE_2, nullptr, ext_state); + map1.impl_set_state (y_sval, TEST_STATE_3, nullptr, ext_state); + map1.impl_set_state (z_sval, TEST_STATE_2, nullptr, ext_state); - map2.impl_set_state (z_sval, TEST_STATE_2, NULL, ext_state); - map2.impl_set_state (y_sval, TEST_STATE_3, NULL, ext_state); - map2.impl_set_state (x_sval, TEST_STATE_2, NULL, ext_state); + map2.impl_set_state (z_sval, TEST_STATE_2, nullptr, ext_state); + map2.impl_set_state (y_sval, TEST_STATE_3, nullptr, ext_state); + map2.impl_set_state (x_sval, TEST_STATE_2, nullptr, ext_state); ASSERT_EQ (map1.hash (), map2.hash ()); ASSERT_EQ (map1, map2); @@ -1908,7 +1923,7 @@ test_program_state_1 () malloc sm-state, pointing to a region on the heap. */ tree p = build_global_decl ("p", ptr_type_node); - std::unique_ptr<state_machine> sm = make_malloc_state_machine (NULL); + std::unique_ptr<state_machine> sm = make_malloc_state_machine (nullptr); const state_machine::state_t UNCHECKED_STATE = sm->get_state_by_name ("unchecked"); @@ -1920,13 +1935,13 @@ test_program_state_1 () const svalue *size_in_bytes = mgr->get_or_create_unknown_svalue (size_type_node); const region *new_reg - = model->get_or_create_region_for_heap_alloc (size_in_bytes, NULL); + = model->get_or_create_region_for_heap_alloc (size_in_bytes, nullptr); const svalue *ptr_sval = mgr->get_ptr_svalue (ptr_type_node, new_reg); - model->set_value (model->get_lvalue (p, NULL), - ptr_sval, NULL); + model->set_value (model->get_lvalue (p, nullptr), + ptr_sval, nullptr); sm_state_map *smap = s.m_checker_states[0]; - smap->impl_set_state (ptr_sval, UNCHECKED_STATE, NULL, ext_state); + smap->impl_set_state (ptr_sval, UNCHECKED_STATE, nullptr, ext_state); ASSERT_EQ (smap->get_state (ptr_sval, ext_state), UNCHECKED_STATE); } @@ -1947,9 +1962,9 @@ test_program_state_2 () program_state s (ext_state); region_model *model = s.m_region_model; - const region *p_reg = model->get_lvalue (p, NULL); - const svalue *str_sval = model->get_rvalue (string_cst_ptr, NULL); - model->set_value (p_reg, str_sval, NULL); + const region *p_reg = model->get_lvalue (p, nullptr); + const svalue *str_sval = model->get_rvalue (string_cst_ptr, nullptr); + model->set_value (p_reg, str_sval, nullptr); } /* Verify that program_states with identical sm-state can be merged, @@ -1965,7 +1980,7 @@ test_program_state_merging () engine eng; region_model_manager *mgr = eng.get_model_manager (); program_point point (program_point::origin (*mgr)); - extrinsic_state ext_state (make_malloc_state_machine (NULL), + extrinsic_state ext_state (make_malloc_state_machine (nullptr), &eng); program_state s0 (ext_state); @@ -1976,20 +1991,20 @@ test_program_state_merging () const svalue *size_in_bytes = mgr->get_or_create_unknown_svalue (size_type_node); const region *new_reg - = model0->get_or_create_region_for_heap_alloc (size_in_bytes, NULL); + = model0->get_or_create_region_for_heap_alloc (size_in_bytes, nullptr); const svalue *ptr_sval = mgr->get_ptr_svalue (ptr_type_node, new_reg); model0->set_value (model0->get_lvalue (p, &ctxt), ptr_sval, &ctxt); sm_state_map *smap = s0.m_checker_states[0]; const state_machine::state test_state ("test state", 0); const state_machine::state_t TEST_STATE = &test_state; - smap->impl_set_state (ptr_sval, TEST_STATE, NULL, ext_state); + smap->impl_set_state (ptr_sval, TEST_STATE, nullptr, ext_state); ASSERT_EQ (smap->get_state (ptr_sval, ext_state), TEST_STATE); model0->canonicalize (); /* Verify that canonicalization preserves sm-state. */ - ASSERT_EQ (smap->get_state (model0->get_rvalue (p, NULL), ext_state), + ASSERT_EQ (smap->get_state (model0->get_rvalue (p, nullptr), ext_state), TEST_STATE); /* Make a copy of the program_state. */ @@ -2006,7 +2021,7 @@ test_program_state_merging () /* Verify that the merged state has the sm-state for "p". */ region_model *merged_model = merged.m_region_model; sm_state_map *merged_smap = merged.m_checker_states[0]; - ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, NULL), + ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, nullptr), ext_state), TEST_STATE); @@ -2015,7 +2030,7 @@ test_program_state_merging () merged.validate (ext_state); /* Verify that the merged state still has the sm-state for "p". */ - ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, NULL), + ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, nullptr), ext_state), TEST_STATE); @@ -2032,7 +2047,7 @@ test_program_state_merging_2 () engine eng; region_model_manager *mgr = eng.get_model_manager (); program_point point (program_point::origin (*mgr)); - extrinsic_state ext_state (make_signal_state_machine (NULL), &eng); + extrinsic_state ext_state (make_signal_state_machine (nullptr), &eng); const state_machine::state test_state_0 ("test state 0", 0); const state_machine::state test_state_1 ("test state 1", 1); diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h index 269ffde..e2076c1 100644 --- a/gcc/analyzer/program-state.h +++ b/gcc/analyzer/program-state.h @@ -22,6 +22,11 @@ along with GCC; see the file COPYING3. If not see #define GCC_ANALYZER_PROGRAM_STATE_H #include "text-art/widget.h" +#include "text-art/tree-widget.h" + +#include "analyzer/store.h" + +namespace xml { class document; } namespace ana { @@ -32,7 +37,7 @@ class extrinsic_state public: extrinsic_state (std::vector<std::unique_ptr<state_machine>> &&checkers, engine *eng, - logger *logger = NULL) + logger *logger = nullptr) : m_checkers (std::move (checkers)), m_logger (logger), m_engine (eng) @@ -42,7 +47,7 @@ public: // For use in selftests that use just one state machine extrinsic_state (std::unique_ptr<state_machine> sm, engine *eng, - logger *logger = NULL) + logger *logger = nullptr) : m_logger (logger), m_engine (eng) { @@ -93,7 +98,7 @@ public: { /* Default ctor needed by hash_map::empty. */ entry_t () - : m_state (0), m_origin (NULL) + : m_state (0), m_origin (nullptr) { } @@ -243,6 +248,12 @@ public: void dump (const extrinsic_state &ext_state, bool simple) const; void dump () const; + std::unique_ptr<xml::document> make_xml (const extrinsic_state &ext_state) const; + void dump_xml_to_pp (const extrinsic_state &ext_state, pretty_printer *pp) const; + void dump_xml_to_file (const extrinsic_state &ext_state, FILE *outf) const; + void dump_xml (const extrinsic_state &ext_state) const; + void dump_dot (const extrinsic_state &ext_state) const; + std::unique_ptr<json::object> to_json (const extrinsic_state &ext_state) const; diff --git a/gcc/analyzer/record-layout.cc b/gcc/analyzer/record-layout.cc index aaf8ccd..3446536 100644 --- a/gcc/analyzer/record-layout.cc +++ b/gcc/analyzer/record-layout.cc @@ -30,7 +30,7 @@ namespace ana { /* class record_layout. */ -record_layout::record_layout (tree record_type) +record_layout::record_layout (const_tree record_type) { gcc_assert (TREE_CODE (record_type) == RECORD_TYPE); @@ -86,7 +86,7 @@ record_layout::get_item_at (bit_offset_t offset) const FOR_EACH_VEC_ELT (m_items, i, it) if (it->contains_p (offset)) return it; - return NULL; + return nullptr; } /* Subroutine of ctor. Add padding item to NEXT_OFFSET if necessary. */ diff --git a/gcc/analyzer/record-layout.h b/gcc/analyzer/record-layout.h index c1c4189..8649d1d 100644 --- a/gcc/analyzer/record-layout.h +++ b/gcc/analyzer/record-layout.h @@ -36,7 +36,7 @@ public: { public: item (const bit_range &br, - tree field, + const_tree field, bool is_padding) : m_bit_range (br), m_field (field), @@ -69,17 +69,20 @@ public: } bit_range m_bit_range; - tree m_field; + const_tree m_field; bool m_is_padding; }; - record_layout (tree record_type); + record_layout (const_tree record_type); void dump_to_pp (pretty_printer *pp) const; DEBUG_FUNCTION void dump () const; const record_layout::item *get_item_at (bit_offset_t offset) const; + auto begin () const { return m_items.begin (); } + auto end () const { return m_items.end (); } + private: void maybe_pad_to (bit_offset_t next_offset); diff --git a/gcc/analyzer/region-model-asm.cc b/gcc/analyzer/region-model-asm.cc index 7d7e3b9..d280ae2 100644 --- a/gcc/analyzer/region-model-asm.cc +++ b/gcc/analyzer/region-model-asm.cc @@ -119,7 +119,7 @@ deterministic_p (const gasm *asm_stmt) void region_model::on_asm_stmt (const gasm *stmt, region_model_context *ctxt) { - logger *logger = ctxt ? ctxt->get_logger () : NULL; + logger *logger = ctxt ? ctxt->get_logger () : nullptr; LOG_SCOPE (logger); const unsigned noutputs = gimple_asm_noutputs (stmt); @@ -216,7 +216,7 @@ region_model::on_asm_stmt (const gasm *stmt, region_model_context *ctxt) tree src_expr = input_tvec[i]; const svalue *src_sval = get_rvalue (src_expr, ctxt); - check_for_poison (src_sval, src_expr, NULL, ctxt); + check_for_poison (src_sval, src_expr, nullptr, ctxt); input_svals.quick_push (src_sval); reachable_regs.handle_sval (src_sval); diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc index df92503..872b1d6 100644 --- a/gcc/analyzer/region-model-manager.cc +++ b/gcc/analyzer/region-model-manager.cc @@ -49,7 +49,7 @@ region_model_manager::region_model_manager (logger *logger) m_root_region (alloc_symbol_id ()), m_stack_region (alloc_symbol_id (), &m_root_region), m_heap_region (alloc_symbol_id (), &m_root_region), - m_unknown_NULL (NULL), + m_unknown_NULL (nullptr), m_checking_feasibility (false), m_max_complexity (0, 0), m_code_region (alloc_symbol_id (), &m_root_region), @@ -259,7 +259,7 @@ region_model_manager::get_or_create_null_ptr (tree pointer_type) return get_or_create_int_cst (pointer_type, 0); } -/* Return the svalue * for a unknown_svalue for TYPE (which can be NULL), +/* Return the svalue * for a unknown_svalue for TYPE (which can be NULL_TREE), creating it if necessary. The unknown_svalue instances are reused, based on pointer equality of the types */ @@ -407,7 +407,7 @@ region_model_manager::get_ptr_svalue (tree ptr_type, const region *pointee) /* Subroutine of region_model_manager::get_or_create_unaryop. Attempt to fold the inputs and return a simpler svalue *. - Otherwise, return NULL. */ + Otherwise, return nullptr. */ const svalue * region_model_manager::maybe_fold_unaryop (tree type, enum tree_code op, @@ -516,7 +516,7 @@ region_model_manager::maybe_fold_unaryop (tree type, enum tree_code op, } } - return NULL; + return nullptr; } /* Return the svalue * for an unary operation OP on ARG with a result of @@ -594,7 +594,7 @@ region_model_manager::get_or_create_cast (tree type, const svalue *arg) If COMPOUND_SVAL has a value for the appropriate bits, return it, shifted accordingly. - Otherwise return NULL. */ + Otherwise return nullptr. */ const svalue * region_model_manager:: @@ -606,7 +606,7 @@ maybe_undo_optimize_bit_field_compare (tree type, if (!type) return nullptr; if (!INTEGRAL_TYPE_P (type)) - return NULL; + return nullptr; const binding_map &map = compound_sval->get_map (); unsigned HOST_WIDE_INT mask = TREE_INT_CST_LOW (cst); @@ -614,7 +614,7 @@ maybe_undo_optimize_bit_field_compare (tree type, compound_sval has a value for those bits. */ bit_range bits (0, 0); if (!bit_range::from_mask (mask, &bits)) - return NULL; + return nullptr; bit_range bound_bits (bits); if (BYTES_BIG_ENDIAN) @@ -624,7 +624,7 @@ maybe_undo_optimize_bit_field_compare (tree type, = get_store_manager ()->get_concrete_binding (bound_bits); const svalue *sval = map.get (conc); if (!sval) - return NULL; + return nullptr; /* We have a value; shift it by the correct number of bits. */ @@ -641,7 +641,7 @@ maybe_undo_optimize_bit_field_compare (tree type, /* Subroutine of region_model_manager::get_or_create_binop. Attempt to fold the inputs and return a simpler svalue *. - Otherwise, return NULL. */ + Otherwise, return nullptr. */ const svalue * region_model_manager::maybe_fold_binop (tree type, enum tree_code op, @@ -669,7 +669,7 @@ region_model_manager::maybe_fold_binop (tree type, enum tree_code op, if ((type && FLOAT_TYPE_P (type)) || (arg0->get_type () && FLOAT_TYPE_P (arg0->get_type ())) || (arg1->get_type () && FLOAT_TYPE_P (arg1->get_type ()))) - return NULL; + return nullptr; switch (op) { @@ -898,7 +898,7 @@ region_model_manager::maybe_fold_binop (tree type, enum tree_code op, /* etc. */ - return NULL; + return nullptr; } /* Return the svalue * for an binary operation OP on ARG0 and ARG1 @@ -933,7 +933,7 @@ region_model_manager::get_or_create_binop (tree type, enum tree_code op, } /* Subroutine of region_model_manager::get_or_create_sub_svalue. - Return a folded svalue, or NULL. */ + Return a folded svalue, or nullptr. */ const svalue * region_model_manager::maybe_fold_sub_svalue (tree type, @@ -1020,7 +1020,7 @@ region_model_manager::maybe_fold_sub_svalue (tree type, if (type) return get_or_create_cast (type, repeated_sval->get_inner_svalue ()); - return NULL; + return nullptr; } /* Return the svalue * for extracting a subvalue of type TYPE from @@ -1046,7 +1046,7 @@ region_model_manager::get_or_create_sub_svalue (tree type, } /* Subroutine of region_model_manager::get_or_create_repeated_svalue. - Return a folded svalue, or NULL. */ + Return a folded svalue, or nullptr. */ const svalue * region_model_manager::maybe_fold_repeated_svalue (tree type, @@ -1080,7 +1080,7 @@ region_model_manager::maybe_fold_repeated_svalue (tree type, if (zerop (cst) && type) return get_or_create_cast (type, inner_svalue); - return NULL; + return nullptr; } /* Return the svalue * of type TYPE in which INNER_SVALUE is repeated @@ -1274,7 +1274,7 @@ region_model_manager::maybe_fold_bits_within_svalue (tree type, } break; } - return NULL; + return nullptr; } /* Return the svalue * of type TYPE for extracting BITS from INNER_SVALUE, @@ -1401,7 +1401,7 @@ region_model_manager::get_or_create_conjured_svalue (tree type, } /* Subroutine of region_model_manager::get_or_create_asm_output_svalue. - Return a folded svalue, or NULL. */ + Return a folded svalue, or nullptr. */ const svalue * region_model_manager:: @@ -1413,7 +1413,7 @@ maybe_fold_asm_output_svalue (tree type, if (iter->get_kind () == SK_UNKNOWN) return get_or_create_unknown_svalue (type); - return NULL; + return nullptr; } /* Return the svalue * of type TYPE for OUTPUT_IDX of the deterministic @@ -1501,7 +1501,7 @@ get_or_create_const_fn_result_svalue (tree type, /* Given DATA_CST (a STRING_CST or RAW_DATA_CST) and BYTE_OFFSET_CST a constant, attempt to get the character at that offset, returning either - the svalue for the character constant, or NULL if unsuccessful. */ + the svalue for the character constant, or nullptr if unsuccessful. */ const svalue * region_model_manager::maybe_get_char_from_cst (tree data_cst, @@ -1533,7 +1533,7 @@ get_string_cst_size (const_tree string_cst) /* Given STRING_CST, a STRING_CST and BYTE_OFFSET_CST a constant, attempt to get the character at that offset, returning either - the svalue for the character constant, or NULL if unsuccessful. */ + the svalue for the character constant, or nullptr if unsuccessful. */ const svalue * region_model_manager::maybe_get_char_from_string_cst (tree string_cst, @@ -1552,7 +1552,7 @@ region_model_manager::maybe_get_char_from_string_cst (tree string_cst, if (compare_constants (byte_offset_cst, GE_EXPR, get_string_cst_size (string_cst)).is_true ()) - return NULL; + return nullptr; int char_val; if (compare_tree_int (byte_offset_cst, @@ -1567,12 +1567,12 @@ region_model_manager::maybe_get_char_from_string_cst (tree string_cst, = build_int_cst_type (TREE_TYPE (TREE_TYPE (string_cst)), char_val); return get_or_create_constant_svalue (char_cst); } - return NULL; + return nullptr; } /* Given RAW_DATA_CST, a RAW_DATA_CST and BYTE_OFFSET_CST a constant, attempt to get the character at that offset, returning either - the svalue for the character constant, or NULL if unsuccessful. */ + the svalue for the character constant, or nullptr if unsuccessful. */ const svalue * region_model_manager::maybe_get_char_from_raw_data_cst (tree raw_data_cst, @@ -1801,7 +1801,7 @@ region_model_manager::get_cast_region (const region *original_region, } /* Return the frame_region for call to FUN from CALLING_FRAME, creating it - if necessary. CALLING_FRAME may be NULL. */ + if necessary. CALLING_FRAME may be nullptr. */ const frame_region * region_model_manager::get_frame_region (const frame_region *calling_frame, diff --git a/gcc/analyzer/region-model-manager.h b/gcc/analyzer/region-model-manager.h index c3f0a64..865bedf 100644 --- a/gcc/analyzer/region-model-manager.h +++ b/gcc/analyzer/region-model-manager.h @@ -31,7 +31,7 @@ namespace ana { class region_model_manager { public: - region_model_manager (logger *logger = NULL); + region_model_manager (logger *logger = nullptr); ~region_model_manager (); unsigned get_num_symbols () const { return m_next_symbol_id; } diff --git a/gcc/analyzer/region-model-reachability.cc b/gcc/analyzer/region-model-reachability.cc index d3bfeb7..0fe324d 100644 --- a/gcc/analyzer/region-model-reachability.cc +++ b/gcc/analyzer/region-model-reachability.cc @@ -68,7 +68,7 @@ reachable_regions::init_cluster (const region *base_reg) if (const symbolic_region *sym_reg = base_reg->dyn_cast_symbolic_region ()) { const svalue *ptr = sym_reg->get_pointer (); - if (ptr->implicitly_live_p (NULL, m_model)) + if (ptr->implicitly_live_p (nullptr, m_model)) add (base_reg, true); switch (ptr->get_kind ()) { @@ -84,7 +84,7 @@ reachable_regions::init_cluster (const region *base_reg) const region *other_base_reg = init_sval_reg->get_base_region (); const binding_cluster *other_cluster = m_store->get_cluster (other_base_reg); - if (other_cluster == NULL + if (other_cluster == nullptr || !other_cluster->touched_p ()) add (base_reg, true); } @@ -131,7 +131,7 @@ reachable_regions::add (const region *reg, bool is_mutable) if (binding_cluster *bind_cluster = m_store->get_cluster (base_reg)) bind_cluster->for_each_value (handle_sval_cb, this); else - handle_sval (m_model->get_store_value (reg, NULL)); + handle_sval (m_model->get_store_value (reg, nullptr)); } void diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 1ee882c..6df3842 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -159,7 +159,7 @@ region_to_value_map::operator== (const region_to_value_map &other) const const region *reg = iter.first; const svalue *sval = iter.second; const svalue * const *other_slot = other.get (reg); - if (other_slot == NULL) + if (other_slot == nullptr) return false; if (sval != *other_slot) return false; @@ -403,7 +403,7 @@ exception_node::add_to_reachable_regions (reachable_regions ®s) const /* Ctor for region_model: construct an "empty" model. */ region_model::region_model (region_model_manager *mgr) -: m_mgr (mgr), m_store (), m_current_frame (NULL), +: m_mgr (mgr), m_store (), m_current_frame (nullptr), m_thrown_exceptions_stack (), m_caught_exceptions_stack (), m_dynamic_extents () @@ -895,7 +895,7 @@ public: /* Couldn't get state; accept this diagnostic. */ return true; - const svalue *fsval = emission_model.get_rvalue (m_check_expr, NULL); + const svalue *fsval = emission_model.get_rvalue (m_check_expr, nullptr); /* Check to see if the expr is also poisoned in FNODE (and in the same way). */ const poisoned_svalue * fspval = fsval->dyn_cast_poisoned_svalue (); @@ -1173,7 +1173,7 @@ check_for_invalid_ptrdiff (const gassign *assign, /* If ASSIGN is a stmt that can be modelled via set_value (lhs_reg, SVALUE, CTXT) for some SVALUE, get the SVALUE. - Otherwise return NULL. */ + Otherwise return nullptr. */ const svalue * region_model::get_gassign_result (const gassign *assign, @@ -1196,7 +1196,7 @@ region_model::get_gassign_result (const gassign *assign, switch (op) { default: - return NULL; + return nullptr; case POINTER_PLUS_EXPR: { @@ -1461,8 +1461,8 @@ within_short_circuited_stmt_p (const region_model *model, that implies that the value of the second arg doesn't matter, i.e. 1 for bitwise or, 0 for bitwise and. */ tree other_arg = gimple_assign_rhs1 (use_assign); - /* Use a NULL ctxt here to avoid generating warnings. */ - const svalue *other_arg_sval = model->get_rvalue (other_arg, NULL); + /* Use a nullptr ctxt here to avoid generating warnings. */ + const svalue *other_arg_sval = model->get_rvalue (other_arg, nullptr); tree other_arg_cst = other_arg_sval->maybe_get_constant (); if (!other_arg_cst) return false; @@ -1529,7 +1529,7 @@ due_to_ifn_deferred_init_p (const gassign *assign_stmt) /* Check for SVAL being poisoned, adding a warning to CTXT. Return SVAL, or, if a warning is added, another value, to avoid repeatedly complaining about the same poisoned value in followup code. - SRC_REGION is a hint about where SVAL came from, and can be NULL. */ + SRC_REGION is a hint about where SVAL came from, and can be nullptr. */ const svalue * region_model::check_for_poison (const svalue *sval, @@ -1572,7 +1572,7 @@ region_model::check_for_poison (const svalue *sval, the tree other than via the def stmts, using fixup_tree_for_diagnostic. */ tree diag_arg = fixup_tree_for_diagnostic (expr); - if (src_region == NULL && pkind == poison_kind::uninit) + if (src_region == nullptr && pkind == poison_kind::uninit) src_region = get_region_for_poisoned_expr (expr); /* Can we reliably get the poisoned value from "expr"? @@ -1581,11 +1581,11 @@ region_model::check_for_poison (const svalue *sval, Hence we only query its value now, and only use it if we get the poisoned value back again. */ tree check_expr = expr; - const svalue *foo_sval = get_rvalue (expr, NULL); + const svalue *foo_sval = get_rvalue (expr, nullptr); if (foo_sval == sval) check_expr = expr; else - check_expr = NULL; + check_expr = nullptr; if (ctxt->warn (std::make_unique<poisoned_value_diagnostic> (diag_arg, pkind, @@ -1606,7 +1606,7 @@ region_model::check_for_poison (const svalue *sval, /* Attempt to get a region for describing EXPR, the source of region of a poisoned_svalue for use in a poisoned_value_diagnostic. - Return NULL if there is no good region to use. */ + Return nullptr if there is no good region to use. */ const region * region_model::get_region_for_poisoned_expr (tree expr) const @@ -1617,9 +1617,9 @@ region_model::get_region_for_poisoned_expr (tree expr) const if (decl && DECL_P (decl)) expr = decl; else - return NULL; + return nullptr; } - return get_lvalue (expr, NULL); + return get_lvalue (expr, nullptr); } /* Update this model for the ASSIGN stmt, using CTXT to report any @@ -1648,7 +1648,7 @@ region_model::on_assignment (const gassign *assign, region_model_context *ctxt) if (const svalue *sval = get_gassign_result (assign, ctxt)) { tree expr = get_diagnostic_tree_for_gassign (assign); - check_for_poison (sval, expr, NULL, ctxt); + check_for_poison (sval, expr, nullptr, ctxt); set_value (lhs_reg, sval, ctxt); return; } @@ -1708,7 +1708,7 @@ region_model::on_assignment (const gassign *assign, region_model_context *ctxt) /* e.g. "struct s2 x = {{'A', 'B', 'C', 'D'}};". */ const svalue *rhs_sval = get_rvalue (rhs1, ctxt); m_store.set_value (m_mgr->get_store_manager(), lhs_reg, rhs_sval, - ctxt ? ctxt->get_uncertainty () : NULL); + ctxt ? ctxt->get_uncertainty () : nullptr); } break; } @@ -1939,7 +1939,7 @@ region_model::update_for_nonzero_return (const call_details &cd) to set an upper bound on the size of a copy_to_user. Attempt to simplify such sizes by trying to get the upper bound as a constant. - Return the simplified svalue if possible, or NULL otherwise. */ + Return the simplified svalue if possible, or nullptr otherwise. */ static const svalue * maybe_simplify_upper_bound (const svalue *num_bytes_sval, @@ -1957,7 +1957,7 @@ maybe_simplify_upper_bound (const svalue *num_bytes_sval, when recording the diagnostic, or note that we're using the upper bound. */ } - return NULL; + return nullptr; } /* Attempt to get an upper bound for the size of a copy when simulating a @@ -1968,7 +1968,7 @@ maybe_simplify_upper_bound (const svalue *num_bytes_sval, that, use the size of SRC_REG if constant. Return a symbolic value for an upper limit on the number of bytes - copied, or NULL if no such value could be determined. */ + copied, or nullptr if no such value could be determined. */ const svalue * region_model::maybe_get_copy_bounds (const region *src_reg, @@ -1994,7 +1994,7 @@ region_model::maybe_get_copy_bounds (const region *src_reg, return num_bytes_sval; /* Non-constant: give up. */ - return NULL; + return nullptr; } /* Get any known_function for FNDECL for call CD. @@ -2002,7 +2002,7 @@ region_model::maybe_get_copy_bounds (const region *src_reg, The call must match all assumptions made by the known_function (such as e.g. "argument 1's type must be a pointer type"). - Return NULL if no known_function is found, or it does not match the + Return nullptr if no known_function is found, or it does not match the assumption(s). */ const known_function * @@ -2012,7 +2012,7 @@ region_model::get_known_function (tree fndecl, const call_details &cd) const return known_fn_mgr->get_match (fndecl, cd); } -/* Get any known_function for IFN, or NULL. */ +/* Get any known_function for IFN, or nullptr. */ const known_function * region_model::get_known_function (enum internal_fn ifn) const @@ -2022,12 +2022,12 @@ region_model::get_known_function (enum internal_fn ifn) const } /* Get any builtin_known_function for CALL and emit any warning to CTXT - if not NULL. + if not nullptr. The call must match all assumptions made by the known_function (such as e.g. "argument 1's type must be a pointer type"). - Return NULL if no builtin_known_function is found, or it does + Return nullptr if no builtin_known_function is found, or it does not match the assumption(s). Internally calls get_known_function to find a known_function and cast it @@ -2063,18 +2063,18 @@ region_model::get_known_function (enum internal_fn ifn) const const builtin_known_function * region_model::get_builtin_kf (const gcall &call, - region_model_context *ctxt /* = NULL */) const + region_model_context *ctxt /* = nullptr */) const { region_model *mut_this = const_cast <region_model *> (this); tree callee_fndecl = mut_this->get_fndecl_for_call (call, ctxt); if (! callee_fndecl) - return NULL; + return nullptr; call_details cd (call, mut_this, ctxt); if (const known_function *kf = get_known_function (callee_fndecl, cd)) return kf->dyn_cast_builtin_kf (); - return NULL; + return nullptr; } /* Subclass of custom_edge_info for use by exploded_edges that represent @@ -2090,7 +2090,7 @@ public: { } - void print (pretty_printer *pp) const + void print (pretty_printer *pp) const final override { if (m_fndecl) pp_printf (pp, "if %qD throws an exception...", m_fndecl); @@ -2677,7 +2677,7 @@ region_model::handle_unrecognized_call (const gcall &call, } } - uncertainty_t *uncertainty = ctxt ? ctxt->get_uncertainty () : NULL; + uncertainty_t *uncertainty = ctxt ? ctxt->get_uncertainty () : nullptr; /* Purge sm-state for the svalues that were reachable, both in non-mutable and mutable form. */ @@ -2839,7 +2839,7 @@ region_model::on_longjmp (const gcall &longjmp_call, const gcall &setjmp_call, setjmp was called. */ gcc_assert (get_stack_depth () >= setjmp_stack_depth); while (get_stack_depth () > setjmp_stack_depth) - pop_frame (NULL, NULL, ctxt, nullptr, false); + pop_frame (nullptr, nullptr, ctxt, nullptr, false); gcc_assert (get_stack_depth () == setjmp_stack_depth); @@ -3040,7 +3040,7 @@ const region * region_model::get_lvalue (path_var pv, region_model_context *ctxt) const { if (pv.m_tree == NULL_TREE) - return NULL; + return nullptr; const region *result_reg = get_lvalue_1 (pv, ctxt); assert_compat_types (result_reg->get_type (), TREE_TYPE (pv.m_tree)); @@ -3185,13 +3185,13 @@ const svalue * region_model::get_rvalue (path_var pv, region_model_context *ctxt) const { if (pv.m_tree == NULL_TREE) - return NULL; + return nullptr; const svalue *result_sval = get_rvalue_1 (pv, ctxt); assert_compat_types (result_sval->get_type (), TREE_TYPE (pv.m_tree)); - result_sval = check_for_poison (result_sval, pv.m_tree, NULL, ctxt); + result_sval = check_for_poison (result_sval, pv.m_tree, nullptr, ctxt); return result_sval; } @@ -3579,7 +3579,7 @@ void region_model::check_for_writable_region (const region* dest_reg, region_model_context *ctxt) const { - /* Fail gracefully if CTXT is NULL. */ + /* Fail gracefully if CTXT is nullptr. */ if (!ctxt) return; @@ -3644,13 +3644,13 @@ region_model::get_capacity (const region *reg) const { tree type = TREE_TYPE (decl); tree size = TYPE_SIZE (type); - return get_rvalue (size, NULL); + return get_rvalue (size, nullptr); } else { tree size = decl_init_size (decl, false); if (size) - return get_rvalue (size, NULL); + return get_rvalue (size, nullptr); } } break; @@ -3727,7 +3727,7 @@ bool region_model::check_region_for_read (const region *src_reg, region_model_context *ctxt) const { - return check_region_access (src_reg, access_direction::read, NULL, ctxt); + return check_region_access (src_reg, access_direction::read, nullptr, ctxt); } /* Concrete subclass for casts of pointers that lead to trailing bytes. */ @@ -4115,7 +4115,7 @@ void region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval, region_model_context *ctxt) const { - if (!ctxt || ctxt->get_stmt () == NULL) + if (!ctxt || ctxt->get_stmt () == nullptr) return; /* Only report warnings on assignments that actually change the type. */ if (!is_any_cast_p (ctxt->get_stmt ())) @@ -4208,7 +4208,7 @@ region_model::set_value (const region *lhs_reg, const svalue *rhs_sval, check_region_for_write (lhs_reg, rhs_sval, ctxt); m_store.set_value (m_mgr->get_store_manager(), lhs_reg, rhs_sval, - ctxt ? ctxt->get_uncertainty () : NULL); + ctxt ? ctxt->get_uncertainty () : nullptr); } /* Set the value of the region given by LHS to the value given by RHS. */ @@ -4845,7 +4845,7 @@ region_model::scan_for_null_terminator (const region *reg, Simulate scanning through the buffer, reading until we find a 0 byte (equivalent to calling strlen). - Complain and return NULL if: + Complain and return nullptr if: - the buffer pointed to isn't null-terminated - the buffer pointed to has any uninitalized bytes before any 0-terminator - any of the reads aren't within the bounds of the underlying base region @@ -4873,7 +4873,7 @@ region_model::check_for_null_terminated_string_arg (const call_details &cd, Simulate scanning through the buffer, reading until we find a 0 byte (equivalent to calling strlen). - Complain and return NULL if: + Complain and return nullptr if: - the buffer pointed to isn't null-terminated - the buffer pointed to has any uninitalized bytes before any 0-terminator - any of the reads aren't within the bounds of the underlying base region @@ -4882,7 +4882,7 @@ region_model::check_for_null_terminated_string_arg (const call_details &cd, (including the null terminator) if INCLUDE_TERMINATOR is true, or strlen of the buffer (not including the null terminator) if it is false. - Also, when returning an svalue, if OUT_SVAL is non-NULL, write to + Also, when returning an svalue, if OUT_SVAL is non-nullptr, write to *OUT_SVAL with an svalue representing the content of the buffer up to and including the terminator. @@ -5845,7 +5845,7 @@ region_model::get_representative_path_var (const svalue *sval, svalue_set *visited, logger *logger) const { - if (sval == NULL) + if (sval == nullptr) return path_var (NULL_TREE, 0); LOG_SCOPE (logger); @@ -6204,7 +6204,7 @@ region_model::maybe_update_for_edge (const superedge &edge, break; } - if (last_stmt == NULL) + if (last_stmt == nullptr) return true; /* Apply any constraints for conditionals/switch/computed-goto statements. */ @@ -6285,7 +6285,7 @@ region_model::update_for_return_gcall (const gcall &call_stmt, so that pop_frame can determine the region with respect to the *caller* frame. */ tree lhs = gimple_call_lhs (&call_stmt); - pop_frame (lhs, NULL, ctxt, &call_stmt); + pop_frame (lhs, nullptr, ctxt, &call_stmt); } /* Extract calling information from the superedge and update the model for the @@ -6361,7 +6361,7 @@ apply_constraints_for_gcond (const cfg_superedge &sedge, std::unique_ptr<rejected_constraint> *out) { ::edge cfg_edge = sedge.get_cfg_edge (); - gcc_assert (cfg_edge != NULL); + gcc_assert (cfg_edge != nullptr); gcc_assert (cfg_edge->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)); enum tree_code op = gimple_cond_code (cond_stmt); @@ -6379,7 +6379,7 @@ static bool has_nondefault_case_for_value_p (const gswitch *switch_stmt, tree int_cst) { /* We expect the initial label to be the default; skip it. */ - gcc_assert (CASE_LOW (gimple_switch_label (switch_stmt, 0)) == NULL); + gcc_assert (CASE_LOW (gimple_switch_label (switch_stmt, 0)) == NULL_TREE); unsigned min_idx = 1; unsigned max_idx = gimple_switch_num_labels (switch_stmt) - 1; @@ -6981,7 +6981,7 @@ region_model::pop_frame (tree result_lvalue, /* Evaluate the result, within the callee frame. */ tree fndecl = m_current_frame->get_function ().decl; tree result = DECL_RESULT (fndecl); - const svalue *retval = NULL; + const svalue *retval = nullptr; if (result && TREE_TYPE (result) != void_type_node && eval_return_svalue) @@ -7312,7 +7312,7 @@ private: class contains_floating_point_visitor : public visitor { public: - contains_floating_point_visitor (const svalue *root_sval) : m_result (NULL) + contains_floating_point_visitor (const svalue *root_sval) : m_result (nullptr) { root_sval->accept (this); } @@ -7476,7 +7476,7 @@ region_model::set_dynamic_extents (const region *reg, m_dynamic_extents.put (reg, size_in_bytes); } -/* Get the recording of REG in bytes, or NULL if no dynamic size was +/* Get the recording of REG in bytes, or nullptr if no dynamic size was recorded. */ const svalue * @@ -7484,7 +7484,7 @@ region_model::get_dynamic_extents (const region *reg) const { if (const svalue * const *slot = m_dynamic_extents.get (reg)) return *slot; - return NULL; + return nullptr; } /* Unset any recorded dynamic size of REG. */ @@ -7798,7 +7798,7 @@ private: static void complain_about_fully_uninit_item (const record_layout::item &item) { - tree field = item.m_field; + const_tree field = item.m_field; bit_size_t num_bits = item.m_bit_range.m_size_in_bits; if (item.m_is_padding) { @@ -7859,7 +7859,7 @@ private: static void complain_about_partially_uninit_item (const record_layout::item &item) { - tree field = item.m_field; + const_tree field = item.m_field; if (item.m_is_padding) inform (DECL_SOURCE_LOCATION (field), "padding after field %qD is partially uninitialized", @@ -7930,7 +7930,7 @@ contains_uninit_p (const svalue *sval) Check that COPIED_SVAL is fully initialized. If not, complain about an infoleak to CTXT. - SRC_REG can be NULL; if non-NULL it is used as a hint in the diagnostic + SRC_REG can be nullptr; if non-NULL it is used as a hint in the diagnostic as to where COPIED_SVAL came from. */ void @@ -8083,8 +8083,8 @@ void rejected_op_constraint::dump_to_pp (pretty_printer *pp) const { region_model m (m_model); - const svalue *lhs_sval = m.get_rvalue (m_lhs, NULL); - const svalue *rhs_sval = m.get_rvalue (m_rhs, NULL); + const svalue *lhs_sval = m.get_rvalue (m_lhs, nullptr); + const svalue *rhs_sval = m.get_rvalue (m_rhs, nullptr); lhs_sval->dump_to_pp (pp, true); pp_printf (pp, " %s ", op_symbol_code (m_op)); rhs_sval->dump_to_pp (pp, true); @@ -8104,7 +8104,7 @@ void rejected_ranges_constraint::dump_to_pp (pretty_printer *pp) const { region_model m (m_model); - const svalue *sval = m.get_rvalue (m_expr, NULL); + const svalue *sval = m.get_rvalue (m_expr, nullptr); sval->dump_to_pp (pp, true); pp_string (pp, " in "); m_ranges->dump_to_pp (pp, true); @@ -8205,7 +8205,7 @@ assert_condition (const location &loc, tree lhs, tree_code op, tree rhs, tristate expected) { - tristate actual = model.eval_condition (lhs, op, rhs, NULL); + tristate actual = model.eval_condition (lhs, op, rhs, nullptr); ASSERT_EQ_AT (loc, actual, expected); } @@ -8294,7 +8294,7 @@ make_test_compound_type (const char *name, bool is_struct, TYPE_NAME (t) = get_identifier (name); TYPE_SIZE (t) = 0; - tree fieldlist = NULL; + tree fieldlist = NULL_TREE; int i; tree field; FOR_EACH_VEC_ELT (*fields, i, field) @@ -8349,22 +8349,22 @@ test_struct () region_model_manager mgr; region_model model (&mgr); - model.set_value (c_x, int_17, NULL); - model.set_value (c_y, int_m3, NULL); + model.set_value (c_x, int_17, nullptr); + model.set_value (c_y, int_m3, nullptr); /* Verify get_offset for "c.x". */ { - const region *c_x_reg = model.get_lvalue (c_x, NULL); + const region *c_x_reg = model.get_lvalue (c_x, nullptr); region_offset offset = c_x_reg->get_offset (&mgr); - ASSERT_EQ (offset.get_base_region (), model.get_lvalue (c, NULL)); + ASSERT_EQ (offset.get_base_region (), model.get_lvalue (c, nullptr)); ASSERT_EQ (offset.get_bit_offset (), 0); } /* Verify get_offset for "c.y". */ { - const region *c_y_reg = model.get_lvalue (c_y, NULL); + const region *c_y_reg = model.get_lvalue (c_y, nullptr); region_offset offset = c_y_reg->get_offset (&mgr); - ASSERT_EQ (offset.get_base_region (), model.get_lvalue (c, NULL)); + ASSERT_EQ (offset.get_base_region (), model.get_lvalue (c, nullptr)); ASSERT_EQ (offset.get_bit_offset (), INT_TYPE_SIZE); } } @@ -8385,7 +8385,7 @@ test_array_1 () tree a_0 = build4 (ARRAY_REF, char_type_node, a, int_0, NULL_TREE, NULL_TREE); tree char_A = build_int_cst (char_type_node, 'A'); - model.set_value (a_0, char_A, NULL); + model.set_value (a_0, char_A, nullptr); } /* Verify that region_model::get_representative_tree works as expected. */ @@ -8399,7 +8399,7 @@ test_get_representative_tree () { tree string_cst = build_string (4, "foo"); region_model m (&mgr); - const svalue *str_sval = m.get_rvalue (string_cst, NULL); + const svalue *str_sval = m.get_rvalue (string_cst, nullptr); tree rep = m.get_representative_tree (str_sval); ASSERT_EQ (rep, string_cst); } @@ -8408,7 +8408,7 @@ test_get_representative_tree () { tree string_cst_ptr = build_string_literal (4, "foo"); region_model m (&mgr); - const svalue *str_sval = m.get_rvalue (string_cst_ptr, NULL); + const svalue *str_sval = m.get_rvalue (string_cst_ptr, nullptr); tree rep = m.get_representative_tree (str_sval); ASSERT_DUMP_TREE_EQ (rep, "&\"foo\"[0]"); } @@ -8533,12 +8533,12 @@ test_unique_unknowns () /* Different types (or the NULL type) should have different unknown_svalues. */ - const svalue *unknown_NULL_type = mgr.get_or_create_unknown_svalue (NULL); + const svalue *unknown_NULL_type = mgr.get_or_create_unknown_svalue (nullptr); ASSERT_NE (unknown_NULL_type, unknown_int); /* Repeated calls with NULL for the type should get the same "unknown" svalue. */ - const svalue *unknown_NULL_type_2 = mgr.get_or_create_unknown_svalue (NULL); + const svalue *unknown_NULL_type_2 = mgr.get_or_create_unknown_svalue (nullptr); ASSERT_EQ (unknown_NULL_type, unknown_NULL_type_2); } @@ -8882,9 +8882,9 @@ test_assignment () region_model model (&mgr); ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0); ASSERT_CONDITION_UNKNOWN (model, y, EQ_EXPR, int_0); - model.set_value (model.get_lvalue (y, NULL), - model.get_rvalue (int_0, NULL), - NULL); + model.set_value (model.get_lvalue (y, nullptr), + model.get_rvalue (int_0, nullptr), + nullptr); ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, int_0); ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, x); } @@ -8912,16 +8912,16 @@ test_compound_assignment () region_model_manager mgr; region_model model (&mgr); - model.set_value (c_x, int_17, NULL); - model.set_value (c_y, int_m3, NULL); + model.set_value (c_x, int_17, nullptr); + model.set_value (c_y, int_m3, nullptr); /* Copy c to d. */ - const svalue *sval = model.get_rvalue (c, NULL); - model.set_value (model.get_lvalue (d, NULL), sval, NULL); + const svalue *sval = model.get_rvalue (c, nullptr); + model.set_value (model.get_lvalue (d, nullptr), sval, nullptr); /* Check that the fields have the same svalues. */ - ASSERT_EQ (model.get_rvalue (c_x, NULL), model.get_rvalue (d_x, NULL)); - ASSERT_EQ (model.get_rvalue (c_y, NULL), model.get_rvalue (d_y, NULL)); + ASSERT_EQ (model.get_rvalue (c_x, nullptr), model.get_rvalue (d_x, nullptr)); + ASSERT_EQ (model.get_rvalue (c_y, nullptr), model.get_rvalue (d_y, nullptr)); } /* Verify the details of pushing and popping stack frames. */ @@ -9011,7 +9011,7 @@ test_stack_frames () model.set_value (p_in_globals_reg, mgr.get_ptr_svalue (ptr_type_node, x_in_child_reg), &ctxt); - ASSERT_EQ (p_in_globals_reg->maybe_get_frame_region (), NULL); + ASSERT_EQ (p_in_globals_reg->maybe_get_frame_region (), nullptr); /* Point another global pointer at p: q = &p. */ const region *q_in_globals_reg = model.get_lvalue (q, &ctxt); @@ -9025,13 +9025,13 @@ test_stack_frames () ASSERT_FALSE (a_in_parent_reg->descendent_of_p (child_frame_reg)); /* Pop the "child_fn" frame from the stack. */ - model.pop_frame (NULL, NULL, &ctxt, nullptr); + model.pop_frame (nullptr, nullptr, &ctxt, nullptr); ASSERT_FALSE (model.region_exists_p (child_frame_reg)); ASSERT_TRUE (model.region_exists_p (parent_frame_reg)); /* Verify that p (which was pointing at the local "x" in the popped frame) has been poisoned. */ - const svalue *new_p_sval = model.get_rvalue (p, NULL); + const svalue *new_p_sval = model.get_rvalue (p, nullptr); ASSERT_EQ (new_p_sval->get_kind (), SK_POISONED); ASSERT_EQ (new_p_sval->dyn_cast_poisoned_svalue ()->get_poison_kind (), poison_kind::popped_stack); @@ -9109,7 +9109,7 @@ test_get_representative_path_var () } /* ...and that we can lookup lvalues for locals for all frames, not just the top. */ - ASSERT_EQ (model.get_lvalue (path_var (n, depth), NULL), + ASSERT_EQ (model.get_lvalue (path_var (n, depth), nullptr), parm_regs[depth]); /* ...and that we can locate the svalues. */ { @@ -9138,22 +9138,22 @@ test_equality_1 () /* Verify that setting state in model1 makes the models non-equal. */ tree x = build_global_decl ("x", integer_type_node); - model0.set_value (x, int_42, NULL); - ASSERT_EQ (model0.get_rvalue (x, NULL)->maybe_get_constant (), int_42); + model0.set_value (x, int_42, nullptr); + ASSERT_EQ (model0.get_rvalue (x, nullptr)->maybe_get_constant (), int_42); ASSERT_NE (model0, model1); /* Verify the copy-ctor. */ region_model model2 (model0); ASSERT_EQ (model0, model2); - ASSERT_EQ (model2.get_rvalue (x, NULL)->maybe_get_constant (), int_42); + ASSERT_EQ (model2.get_rvalue (x, nullptr)->maybe_get_constant (), int_42); ASSERT_NE (model1, model2); /* Verify that models obtained from copy-ctor are independently editable w/o affecting the original model. */ - model2.set_value (x, int_17, NULL); + model2.set_value (x, int_17, nullptr); ASSERT_NE (model0, model2); - ASSERT_EQ (model2.get_rvalue (x, NULL)->maybe_get_constant (), int_17); - ASSERT_EQ (model0.get_rvalue (x, NULL)->maybe_get_constant (), int_42); + ASSERT_EQ (model2.get_rvalue (x, nullptr)->maybe_get_constant (), int_17); + ASSERT_EQ (model0.get_rvalue (x, nullptr)->maybe_get_constant (), int_42); } /* Verify that region models for @@ -9172,20 +9172,20 @@ test_canonicalization_2 () region_model_manager mgr; region_model model0 (&mgr); - model0.set_value (model0.get_lvalue (x, NULL), - model0.get_rvalue (int_42, NULL), - NULL); - model0.set_value (model0.get_lvalue (y, NULL), - model0.get_rvalue (int_113, NULL), - NULL); + model0.set_value (model0.get_lvalue (x, nullptr), + model0.get_rvalue (int_42, nullptr), + nullptr); + model0.set_value (model0.get_lvalue (y, nullptr), + model0.get_rvalue (int_113, nullptr), + nullptr); region_model model1 (&mgr); - model1.set_value (model1.get_lvalue (y, NULL), - model1.get_rvalue (int_113, NULL), - NULL); - model1.set_value (model1.get_lvalue (x, NULL), - model1.get_rvalue (int_42, NULL), - NULL); + model1.set_value (model1.get_lvalue (y, nullptr), + model1.get_rvalue (int_113, nullptr), + nullptr); + model1.set_value (model1.get_lvalue (x, nullptr), + model1.get_rvalue (int_42, nullptr), + nullptr); ASSERT_EQ (model0, model1); } @@ -9206,12 +9206,12 @@ test_canonicalization_3 () region_model_manager mgr; region_model model0 (&mgr); - model0.add_constraint (x, GT_EXPR, int_3, NULL); - model0.add_constraint (y, GT_EXPR, int_42, NULL); + model0.add_constraint (x, GT_EXPR, int_3, nullptr); + model0.add_constraint (y, GT_EXPR, int_42, nullptr); region_model model1 (&mgr); - model1.add_constraint (y, GT_EXPR, int_42, NULL); - model1.add_constraint (x, GT_EXPR, int_3, NULL); + model1.add_constraint (y, GT_EXPR, int_42, nullptr); + model1.add_constraint (x, GT_EXPR, int_3, nullptr); model0.canonicalize (); model1.canonicalize (); @@ -9231,7 +9231,7 @@ test_canonicalization_4 () region_model model (&mgr); for (tree cst : csts) - model.get_rvalue (cst, NULL); + model.get_rvalue (cst, nullptr); model.canonicalize (); } @@ -9240,7 +9240,7 @@ test_canonicalization_4 () with values VAL_A and VAL_B for EXPR that they are mergable. Write the merged model to *OUT_MERGED_MODEL, and the merged svalue ptr to *OUT_MERGED_SVALUE. - If VAL_A or VAL_B are NULL_TREE, don't populate EXPR + If VAL_A or VAL_B are nullptr_TREE, don't populate EXPR for that region_model. */ static void @@ -9431,8 +9431,8 @@ test_state_merging () region_model model0 (&mgr); model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), nullptr, nullptr, nullptr); - model0.set_value (model0.get_lvalue (p, NULL), - model0.get_rvalue (addr_of_a, NULL), NULL); + model0.set_value (model0.get_lvalue (p, nullptr), + model0.get_rvalue (addr_of_a, nullptr), nullptr); region_model model1 (model0); ASSERT_EQ (model0, model1); @@ -9456,7 +9456,7 @@ test_state_merging () const region_svalue *merged_p_ptr = merged_p_sval->dyn_cast_region_svalue (); const region *merged_p_star_reg = merged_p_ptr->get_pointee (); - ASSERT_EQ (merged_p_star_reg, merged.get_lvalue (y, NULL)); + ASSERT_EQ (merged_p_star_reg, merged.get_lvalue (y, nullptr)); } /* Pointers: non-NULL ptrs to different globals: should be unknown. */ @@ -9571,7 +9571,7 @@ test_state_merging () region_model model0 (&mgr); model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), nullptr, nullptr, nullptr); - const region *q_in_first_frame = model0.get_lvalue (q, NULL); + const region *q_in_first_frame = model0.get_lvalue (q, nullptr); /* Push a second frame. */ const region *reg_2nd_frame @@ -9580,8 +9580,8 @@ test_state_merging () /* Have a pointer in the older frame point to a local in the more recent frame. */ - const svalue *sval_ptr = model0.get_rvalue (addr_of_a, NULL); - model0.set_value (q_in_first_frame, sval_ptr, NULL); + const svalue *sval_ptr = model0.get_rvalue (addr_of_a, nullptr); + model0.set_value (q_in_first_frame, sval_ptr, nullptr); /* Verify that it's pointing at the newer frame. */ const region *reg_pointee = sval_ptr->maybe_get_region (); @@ -9605,8 +9605,8 @@ test_state_merging () region_model model0 (&mgr); model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), nullptr, nullptr, nullptr); - model0.set_value (model0.get_lvalue (q, NULL), - model0.get_rvalue (addr_of_y, NULL), NULL); + model0.set_value (model0.get_lvalue (q, nullptr), + model0.get_rvalue (addr_of_y, nullptr), nullptr); region_model model1 (model0); ASSERT_EQ (model0, model1); @@ -9638,14 +9638,14 @@ test_constraint_merging () /* model0: 0 <= (x == y) < n. */ region_model model0 (&mgr); model0.add_constraint (x, EQ_EXPR, y, &ctxt); - model0.add_constraint (x, GE_EXPR, int_0, NULL); - model0.add_constraint (x, LT_EXPR, n, NULL); + model0.add_constraint (x, GE_EXPR, int_0, nullptr); + model0.add_constraint (x, LT_EXPR, n, nullptr); /* model1: z != 5 && (0 <= x < n). */ region_model model1 (&mgr); - model1.add_constraint (z, NE_EXPR, int_5, NULL); - model1.add_constraint (x, GE_EXPR, int_0, NULL); - model1.add_constraint (x, LT_EXPR, n, NULL); + model1.add_constraint (z, NE_EXPR, int_5, nullptr); + model1.add_constraint (x, GE_EXPR, int_0, nullptr); + model1.add_constraint (x, LT_EXPR, n, nullptr); /* They should be mergeable; the merged constraints should be: (0 <= x < n). */ @@ -9870,17 +9870,17 @@ test_malloc_constraints () const svalue *size_in_bytes = mgr.get_or_create_unknown_svalue (size_type_node); const region *reg - = model.get_or_create_region_for_heap_alloc (size_in_bytes, NULL); + = model.get_or_create_region_for_heap_alloc (size_in_bytes, nullptr); const svalue *sval = mgr.get_ptr_svalue (ptr_type_node, reg); - model.set_value (model.get_lvalue (p, NULL), sval, NULL); - model.set_value (q, p, NULL); + model.set_value (model.get_lvalue (p, nullptr), sval, nullptr); + model.set_value (q, p, nullptr); ASSERT_CONDITION_UNKNOWN (model, p, NE_EXPR, null_ptr); ASSERT_CONDITION_UNKNOWN (model, p, EQ_EXPR, null_ptr); ASSERT_CONDITION_UNKNOWN (model, q, NE_EXPR, null_ptr); ASSERT_CONDITION_UNKNOWN (model, q, EQ_EXPR, null_ptr); - model.add_constraint (p, NE_EXPR, null_ptr, NULL); + model.add_constraint (p, NE_EXPR, null_ptr, nullptr); ASSERT_CONDITION_TRUE (model, p, NE_EXPR, null_ptr); ASSERT_CONDITION_FALSE (model, p, EQ_EXPR, null_ptr); @@ -9902,25 +9902,25 @@ test_var () region_model_manager mgr; region_model model (&mgr); - const region *i_reg = model.get_lvalue (i, NULL); + const region *i_reg = model.get_lvalue (i, nullptr); ASSERT_EQ (i_reg->get_kind (), RK_DECL); /* Reading "i" should give a symbolic "initial value". */ - const svalue *sval_init = model.get_rvalue (i, NULL); + const svalue *sval_init = model.get_rvalue (i, nullptr); ASSERT_EQ (sval_init->get_kind (), SK_INITIAL); ASSERT_EQ (sval_init->dyn_cast_initial_svalue ()->get_region (), i_reg); /* ..and doing it again should give the same "initial value". */ - ASSERT_EQ (model.get_rvalue (i, NULL), sval_init); + ASSERT_EQ (model.get_rvalue (i, nullptr), sval_init); /* "i = 17;". */ - model.set_value (i, int_17, NULL); - ASSERT_EQ (model.get_rvalue (i, NULL), - model.get_rvalue (int_17, NULL)); + model.set_value (i, int_17, nullptr); + ASSERT_EQ (model.get_rvalue (i, nullptr), + model.get_rvalue (int_17, nullptr)); /* "i = -3;". */ - model.set_value (i, int_m3, NULL); - ASSERT_EQ (model.get_rvalue (i, NULL), - model.get_rvalue (int_m3, NULL)); + model.set_value (i, int_m3, nullptr); + ASSERT_EQ (model.get_rvalue (i, nullptr), + model.get_rvalue (int_m3, nullptr)); /* Verify get_offset for "i". */ { @@ -9959,38 +9959,41 @@ test_array_2 () region_model_manager mgr; region_model model (&mgr); /* "arr[0] = 17;". */ - model.set_value (arr_0, int_17, NULL); + model.set_value (arr_0, int_17, nullptr); /* "arr[1] = -3;". */ - model.set_value (arr_1, int_m3, NULL); + model.set_value (arr_1, int_m3, nullptr); - ASSERT_EQ (model.get_rvalue (arr_0, NULL), model.get_rvalue (int_17, NULL)); - ASSERT_EQ (model.get_rvalue (arr_1, NULL), model.get_rvalue (int_m3, NULL)); + ASSERT_EQ (model.get_rvalue (arr_0, nullptr), + model.get_rvalue (int_17, nullptr)); + ASSERT_EQ (model.get_rvalue (arr_1, nullptr), + model.get_rvalue (int_m3, nullptr)); /* Overwrite a pre-existing binding: "arr[1] = 42;". */ - model.set_value (arr_1, int_42, NULL); - ASSERT_EQ (model.get_rvalue (arr_1, NULL), model.get_rvalue (int_42, NULL)); + model.set_value (arr_1, int_42, nullptr); + ASSERT_EQ (model.get_rvalue (arr_1, nullptr), + model.get_rvalue (int_42, nullptr)); /* Verify get_offset for "arr[0]". */ { - const region *arr_0_reg = model.get_lvalue (arr_0, NULL); + const region *arr_0_reg = model.get_lvalue (arr_0, nullptr); region_offset offset = arr_0_reg->get_offset (&mgr); - ASSERT_EQ (offset.get_base_region (), model.get_lvalue (arr, NULL)); + ASSERT_EQ (offset.get_base_region (), model.get_lvalue (arr, nullptr)); ASSERT_EQ (offset.get_bit_offset (), 0); } /* Verify get_offset for "arr[1]". */ { - const region *arr_1_reg = model.get_lvalue (arr_1, NULL); + const region *arr_1_reg = model.get_lvalue (arr_1, nullptr); region_offset offset = arr_1_reg->get_offset (&mgr); - ASSERT_EQ (offset.get_base_region (), model.get_lvalue (arr, NULL)); + ASSERT_EQ (offset.get_base_region (), model.get_lvalue (arr, nullptr)); ASSERT_EQ (offset.get_bit_offset (), INT_TYPE_SIZE); } /* Verify get_offset for "arr[i]". */ { - const region *arr_i_reg = model.get_lvalue (arr_i, NULL); + const region *arr_i_reg = model.get_lvalue (arr_i, nullptr); region_offset offset = arr_i_reg->get_offset (&mgr); - ASSERT_EQ (offset.get_base_region (), model.get_lvalue (arr, NULL)); + ASSERT_EQ (offset.get_base_region (), model.get_lvalue (arr, nullptr)); const svalue *offset_sval = offset.get_symbolic_byte_offset (); if (const svalue *cast = offset_sval->maybe_undo_cast ()) offset_sval = cast; @@ -9998,14 +10001,15 @@ test_array_2 () } /* "arr[i] = i;" - this should remove the earlier bindings. */ - model.set_value (arr_i, i, NULL); - ASSERT_EQ (model.get_rvalue (arr_i, NULL), model.get_rvalue (i, NULL)); - ASSERT_EQ (model.get_rvalue (arr_0, NULL)->get_kind (), SK_UNKNOWN); + model.set_value (arr_i, i, nullptr); + ASSERT_EQ (model.get_rvalue (arr_i, nullptr), model.get_rvalue (i, nullptr)); + ASSERT_EQ (model.get_rvalue (arr_0, nullptr)->get_kind (), SK_UNKNOWN); /* "arr[0] = 17;" - this should remove the arr[i] binding. */ - model.set_value (arr_0, int_17, NULL); - ASSERT_EQ (model.get_rvalue (arr_0, NULL), model.get_rvalue (int_17, NULL)); - ASSERT_EQ (model.get_rvalue (arr_i, NULL)->get_kind (), SK_UNKNOWN); + model.set_value (arr_0, int_17, nullptr); + ASSERT_EQ (model.get_rvalue (arr_0, nullptr), + model.get_rvalue (int_17, nullptr)); + ASSERT_EQ (model.get_rvalue (arr_i, nullptr)->get_kind (), SK_UNKNOWN); } /* Smoketest of dereferencing a pointer via MEM_REF. */ @@ -10032,12 +10036,12 @@ test_mem_ref () region_model model (&mgr); /* "x = 17;". */ - model.set_value (x, int_17, NULL); + model.set_value (x, int_17, nullptr); /* "p = &x;". */ - model.set_value (p, addr_of_x, NULL); + model.set_value (p, addr_of_x, nullptr); - const svalue *sval = model.get_rvalue (star_p, NULL); + const svalue *sval = model.get_rvalue (star_p, nullptr); ASSERT_EQ (sval->maybe_get_constant (), int_17); } @@ -10083,8 +10087,8 @@ test_POINTER_PLUS_EXPR_then_MEM_REF () region_model m (&mgr); tree int_42 = build_int_cst (integer_type_node, 42); - m.set_value (mem_ref, int_42, NULL); - ASSERT_EQ (m.get_rvalue (mem_ref, NULL)->maybe_get_constant (), int_42); + m.set_value (mem_ref, int_42, nullptr); + ASSERT_EQ (m.get_rvalue (mem_ref, nullptr)->maybe_get_constant (), int_42); } /* Verify that malloc works. */ @@ -10147,8 +10151,8 @@ test_alloca () /* Verify that the pointers to the alloca region are replaced by poisoned values when the frame is popped. */ - model.pop_frame (NULL, NULL, &ctxt, nullptr); - ASSERT_EQ (model.get_rvalue (p, NULL)->get_kind (), SK_POISONED); + model.pop_frame (nullptr, nullptr, &ctxt, nullptr); + ASSERT_EQ (model.get_rvalue (p, nullptr)->get_kind (), SK_POISONED); } /* Verify that svalue::involves_p works. */ diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 2c7f737..6271ea2 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -385,11 +385,11 @@ class region_model std::unique_ptr<rejected_constraint> *out); void update_for_gcall (const gcall &call_stmt, - region_model_context *ctxt, - function *callee = NULL); + region_model_context *ctxt, + function *callee = nullptr); void update_for_return_gcall (const gcall &call_stmt, - region_model_context *ctxt); + region_model_context *ctxt); const region *push_frame (const function &fun, const gcall *call_stmt, @@ -517,9 +517,9 @@ class region_model bool can_merge_with_p (const region_model &other_model, const program_point &point, region_model *out_model, - const extrinsic_state *ext_state = NULL, - const program_state *state_a = NULL, - const program_state *state_b = NULL) const; + const extrinsic_state *ext_state = nullptr, + const program_state *state_a = nullptr, + const program_state *state_b = nullptr) const; tree get_fndecl_for_call (const gcall &call, region_model_context *ctxt); @@ -600,7 +600,7 @@ class region_model const builtin_known_function * get_builtin_kf (const gcall &call, - region_model_context *ctxt = NULL) const; + region_model_context *ctxt = nullptr) const; static void register_pop_frame_callback (const pop_frame_callback &callback) @@ -818,7 +818,7 @@ class region_model_context Return true if the diagnostic was stored, or false if it was deleted. Optionally provide a custom stmt_finder. */ virtual bool warn (std::unique_ptr<pending_diagnostic> d, - const stmt_finder *custom_finder = NULL) = 0; + const stmt_finder *custom_finder = nullptr) = 0; /* Hook for clients to add a note to the last previously stored pending diagnostic. */ @@ -912,13 +912,15 @@ class region_model_context const state_machine **out_sm, unsigned *out_sm_idx) { - return get_state_map_by_name ("malloc", out_smap, out_sm, out_sm_idx, NULL); + return get_state_map_by_name ("malloc", out_smap, out_sm, out_sm_idx, + nullptr); } bool get_taint_map (sm_state_map **out_smap, const state_machine **out_sm, unsigned *out_sm_idx) { - return get_state_map_by_name ("taint", out_smap, out_sm, out_sm_idx, NULL); + return get_state_map_by_name ("taint", out_smap, out_sm, out_sm_idx, + nullptr); } bool possibly_tainted_p (const svalue *sval); @@ -928,6 +930,8 @@ class region_model_context virtual const exploded_graph *get_eg () const = 0; + virtual const program_state *get_state () const = 0; + /* Hooks for detecting infinite loops. */ virtual void maybe_did_work () = 0; virtual bool checking_for_infinite_loop_p () const = 0; @@ -946,7 +950,7 @@ public: void on_svalue_leak (const svalue *) override {} void on_liveness_change (const svalue_set &, const region_model *) override {} - logger *get_logger () override { return NULL; } + logger *get_logger () override { return nullptr; } void on_condition (const svalue *lhs ATTRIBUTE_UNUSED, enum tree_code op ATTRIBUTE_UNUSED, const svalue *rhs ATTRIBUTE_UNUSED) override @@ -969,14 +973,14 @@ public: void on_escaped_function (tree) override {} - uncertainty_t *get_uncertainty () override { return NULL; } + uncertainty_t *get_uncertainty () override { return nullptr; } void purge_state_involving (const svalue *sval ATTRIBUTE_UNUSED) override {} void bifurcate (std::unique_ptr<custom_edge_info> info) override; void terminate_path () override; - const extrinsic_state *get_ext_state () const override { return NULL; } + const extrinsic_state *get_ext_state () const override { return nullptr; } bool get_state_map_by_name (const char *, sm_state_map **, @@ -987,8 +991,10 @@ public: return false; } - const gimple *get_stmt () const override { return NULL; } - const exploded_graph *get_eg () const override { return NULL; } + const gimple *get_stmt () const override { return nullptr; } + const exploded_graph *get_eg () const override { return nullptr; } + const program_state *get_state () const override { return nullptr; } + void maybe_did_work () override {} bool checking_for_infinite_loop_p () const override { return false; } void on_unusable_in_infinite_loop () override {} @@ -1167,6 +1173,14 @@ class region_model_context_decorator : public region_model_context return nullptr; } + const program_state *get_state () const override + { + if (m_inner) + return m_inner->get_state (); + else + return nullptr; + } + void maybe_did_work () override { if (m_inner) @@ -1337,7 +1351,7 @@ private: class engine { public: - engine (const supergraph *sg = NULL, logger *logger = NULL); + engine (const supergraph *sg = nullptr, logger *logger = nullptr); const supergraph *get_supergraph () { return m_sg; } region_model_manager *get_model_manager () { return &m_mgr; } known_function_manager *get_known_function_manager () @@ -1396,7 +1410,7 @@ private: #define ADD_SAT_CONSTRAINT(MODEL, LHS, OP, RHS) \ SELFTEST_BEGIN_STMT \ - bool sat = (MODEL).add_constraint (LHS, OP, RHS, NULL); \ + bool sat = (MODEL).add_constraint (LHS, OP, RHS, nullptr); \ ASSERT_TRUE (sat); \ SELFTEST_END_STMT @@ -1405,7 +1419,7 @@ private: #define ADD_UNSAT_CONSTRAINT(MODEL, LHS, OP, RHS) \ SELFTEST_BEGIN_STMT \ - bool sat = (MODEL).add_constraint (LHS, OP, RHS, NULL); \ + bool sat = (MODEL).add_constraint (LHS, OP, RHS, nullptr); \ ASSERT_FALSE (sat); \ SELFTEST_END_STMT diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc index efbbca0..e27fc6e 100644 --- a/gcc/analyzer/region.cc +++ b/gcc/analyzer/region.cc @@ -124,7 +124,7 @@ region_offset::dump (bool simple) const } /* An svalue that matches the pattern (BASE * FACTOR) + OFFSET - where FACTOR or OFFSET could be the identity (represented as NULL). */ + where FACTOR or OFFSET could be the identity (represented as nullptr). */ struct linear_op { @@ -231,7 +231,7 @@ struct linear_op { *out = linear_op (binop_sval.get_arg0 (), binop_sval.get_arg1 (), - NULL); + nullptr); return true; } else if (binop_sval.get_op () == PLUS_EXPR) @@ -250,7 +250,7 @@ struct linear_op } *out = linear_op (binop_sval.get_arg0 (), - NULL, + nullptr, binop_sval.get_arg1 ()); return true; } @@ -276,8 +276,8 @@ operator< (const region_offset &a, const region_offset &b) const svalue &a_sval = *a.get_symbolic_byte_offset (); const svalue &b_sval = *b.get_symbolic_byte_offset (); - linear_op op_a (NULL, NULL, NULL); - linear_op op_b (NULL, NULL, NULL); + linear_op op_a (nullptr, nullptr, nullptr); + linear_op op_b (nullptr, nullptr, nullptr); if (linear_op::from_svalue (a_sval, &op_a) && linear_op::from_svalue (b_sval, &op_b)) { @@ -318,8 +318,8 @@ operator<= (const region_offset &a, const region_offset &b) const svalue &a_sval = *a.get_symbolic_byte_offset (); const svalue &b_sval = *b.get_symbolic_byte_offset (); - linear_op op_a (NULL, NULL, NULL); - linear_op op_b (NULL, NULL, NULL); + linear_op op_a (nullptr, nullptr, nullptr); + linear_op op_b (nullptr, nullptr, nullptr); if (linear_op::from_svalue (a_sval, &op_a) && linear_op::from_svalue (b_sval, &op_b)) { @@ -448,7 +448,7 @@ region::descendent_of_p (const region *elder) const } /* If this region is a frame_region, or a descendent of one, return it. - Otherwise return NULL. */ + Otherwise return nullptr. */ const frame_region * region::maybe_get_frame_region () const @@ -460,7 +460,7 @@ region::maybe_get_frame_region () const return frame_reg; iter = iter->get_parent_region (); } - return NULL; + return nullptr; } /* Get the memory space of this region. */ @@ -609,7 +609,7 @@ region::calc_initial_value_at_main (region_model_manager *mgr) const } /* If this region is a decl_region, return the decl. - Otherwise return NULL. */ + Otherwise return NULL_TREE. */ tree region::maybe_get_decl () const @@ -769,7 +769,7 @@ get_field_at_bit_offset (tree record_type, bit_offset_t bit_offset) { gcc_assert (TREE_CODE (record_type) == RECORD_TYPE); if (bit_offset < 0) - return NULL; + return nullptr; /* Find the first field that has an offset > BIT_OFFSET, then return the one preceding it. @@ -879,7 +879,7 @@ region::calc_offset (region_model_manager *mgr) const { const region *iter_region = this; bit_offset_t accum_bit_offset = 0; - const svalue *accum_byte_sval = NULL; + const svalue *accum_byte_sval = nullptr; while (iter_region) { @@ -1155,7 +1155,7 @@ region::is_named_decl_p (const char *decl_name) const region::region (complexity c, symbol::id_t id, const region *parent, tree type) : symbol (c, id), m_parent (parent), m_type (type), - m_cached_offset (NULL), m_cached_init_sval_at_main (NULL) + m_cached_offset (nullptr), m_cached_init_sval_at_main (nullptr) { gcc_assert (type == NULL_TREE || TYPE_P (type)); } @@ -1548,7 +1548,7 @@ heap_region::print_dump_widget_label (pretty_printer *pp) const /* root_region's ctor. */ root_region::root_region (symbol::id_t id) -: region (complexity (1, 1), id, NULL, NULL_TREE) +: region (complexity (1, 1), id, nullptr, NULL_TREE) { } @@ -1680,7 +1680,7 @@ decl_region::print_dump_widget_label (pretty_printer *pp) const int decl_region::get_stack_depth () const { - if (get_parent_region () == NULL) + if (get_parent_region () == nullptr) return 0; if (const frame_region *frame_reg = get_parent_region ()->dyn_cast_frame_region ()) @@ -1690,7 +1690,7 @@ decl_region::get_stack_depth () const /* If the underlying decl is in the global constant pool, return an svalue representing the constant value. - Otherwise return NULL. */ + Otherwise return nullptr. */ const svalue * decl_region::maybe_get_constant_value (region_model_manager *mgr) const @@ -1700,7 +1700,7 @@ decl_region::maybe_get_constant_value (region_model_manager *mgr) const && DECL_INITIAL (m_decl) && TREE_CODE (DECL_INITIAL (m_decl)) == CONSTRUCTOR) return get_svalue_for_constructor (DECL_INITIAL (m_decl), mgr); - return NULL; + return nullptr; } /* Implementation of decl_region::get_svalue_for_constructor @@ -1742,7 +1742,7 @@ decl_region::get_svalue_for_constructor (tree ctor, "main" (either based on DECL_INITIAL, or implicit initialization to zero. - Return NULL if there is a problem. */ + Return nullptr if there is a problem. */ const svalue * decl_region::get_svalue_for_initializer (region_model_manager *mgr) const @@ -1753,10 +1753,10 @@ decl_region::get_svalue_for_initializer (region_model_manager *mgr) const /* If we have an "extern" decl then there may be an initializer in another TU. */ if (DECL_EXTERNAL (m_decl)) - return NULL; + return nullptr; if (empty_p ()) - return NULL; + return nullptr; /* Implicit initialization to zero; use a compound_svalue for it. Doing so requires that we have a concrete binding for this region, @@ -1765,12 +1765,12 @@ decl_region::get_svalue_for_initializer (region_model_manager *mgr) const const binding_key *binding = binding_key::make (mgr->get_store_manager (), this); if (binding->symbolic_p ()) - return NULL; + return nullptr; /* If we don't care about tracking the content of this region, then it's unused, and the value doesn't matter. */ if (!tracked_p ()) - return NULL; + return nullptr; binding_cluster c (this); c.zero_fill_region (mgr->get_store_manager (), this); @@ -1781,14 +1781,14 @@ decl_region::get_svalue_for_initializer (region_model_manager *mgr) const /* LTO can write out error_mark_node as the DECL_INITIAL for simple scalar values (to avoid writing out an extra section). */ if (init == error_mark_node) - return NULL; + return nullptr; if (TREE_CODE (init) == CONSTRUCTOR) return get_svalue_for_constructor (init, mgr); /* Reuse the get_rvalue logic from region_model. */ region_model m (mgr); - return m.get_rvalue (path_var (init, 0), NULL); + return m.get_rvalue (path_var (init, 0), nullptr); } /* Subroutine of symnode_requires_tracking_p; return true if REF @@ -1802,7 +1802,7 @@ ipa_ref_requires_tracking (ipa_ref *ref) if (ref->use != IPA_REF_ADDR) return true; - if (ref->stmt == NULL) + if (ref->stmt == nullptr) return true; switch (ref->stmt->code) @@ -1812,12 +1812,12 @@ ipa_ref_requires_tracking (ipa_ref *ref) case GIMPLE_CALL: { cgraph_node *caller_cnode = dyn_cast <cgraph_node *> (ref->referring); - if (caller_cnode == NULL) + if (caller_cnode == nullptr) return true; cgraph_edge *edge = caller_cnode->get_edge (ref->stmt); if (!edge) return true; - if (edge->callee == NULL) + if (edge->callee == nullptr) return true; /* e.g. call through function ptr. */ if (edge->callee->definition) return true; @@ -1852,7 +1852,7 @@ symnode_requires_tracking_p (symtab_node *symnode) if (symnode->externally_visible) return true; tree context_fndecl = DECL_CONTEXT (symnode->decl); - if (context_fndecl == NULL) + if (context_fndecl == nullptr) return true; if (TREE_CODE (context_fndecl) != FUNCTION_DECL) return true; diff --git a/gcc/analyzer/region.h b/gcc/analyzer/region.h index 801a8d3..e01a2e2 100644 --- a/gcc/analyzer/region.h +++ b/gcc/analyzer/region.h @@ -129,29 +129,29 @@ public: virtual enum region_kind get_kind () const = 0; virtual const frame_region * - dyn_cast_frame_region () const { return NULL; } + dyn_cast_frame_region () const { return nullptr; } virtual const function_region * - dyn_cast_function_region () const { return NULL; } + dyn_cast_function_region () const { return nullptr; } virtual const symbolic_region * - dyn_cast_symbolic_region () const { return NULL; } + dyn_cast_symbolic_region () const { return nullptr; } virtual const decl_region * - dyn_cast_decl_region () const { return NULL; } + dyn_cast_decl_region () const { return nullptr; } virtual const field_region * - dyn_cast_field_region () const { return NULL; } + dyn_cast_field_region () const { return nullptr; } virtual const element_region * - dyn_cast_element_region () const { return NULL; } + dyn_cast_element_region () const { return nullptr; } virtual const offset_region * - dyn_cast_offset_region () const { return NULL; } + dyn_cast_offset_region () const { return nullptr; } virtual const sized_region * - dyn_cast_sized_region () const { return NULL; } + dyn_cast_sized_region () const { return nullptr; } virtual const cast_region * - dyn_cast_cast_region () const { return NULL; } + dyn_cast_cast_region () const { return nullptr; } virtual const string_region * - dyn_cast_string_region () const { return NULL; } + dyn_cast_string_region () const { return nullptr; } virtual const bit_range_region * - dyn_cast_bit_range_region () const { return NULL; } + dyn_cast_bit_range_region () const { return nullptr; } virtual const var_arg_region * - dyn_cast_var_arg_region () const { return NULL; } + dyn_cast_var_arg_region () const { return nullptr; } virtual void accept (visitor *v) const; @@ -324,7 +324,7 @@ public: key_t (const frame_region *calling_frame, const function &fun) : m_calling_frame (calling_frame), m_fun (&fun) { - /* calling_frame can be NULL. */ + /* calling_frame can be nullptr. */ } hashval_t hash () const @@ -342,12 +342,12 @@ public: } void mark_deleted () { m_fun = reinterpret_cast<function *> (1); } - void mark_empty () { m_fun = NULL; } + void mark_empty () { m_fun = nullptr; } bool is_deleted () const { return m_fun == reinterpret_cast<function *> (1); } - bool is_empty () const { return m_fun == NULL; } + bool is_empty () const { return m_fun == nullptr; } const frame_region *m_calling_frame; const function *m_fun; @@ -685,12 +685,12 @@ public: } void mark_deleted () { m_sval_ptr = reinterpret_cast<const svalue *> (1); } - void mark_empty () { m_sval_ptr = NULL; } + void mark_empty () { m_sval_ptr = nullptr; } bool is_deleted () const { return m_sval_ptr == reinterpret_cast<const svalue *> (1); } - bool is_empty () const { return m_sval_ptr == NULL; } + bool is_empty () const { return m_sval_ptr == nullptr; } const region *m_parent; const svalue *m_sval_ptr; @@ -744,7 +744,7 @@ public: decl_region (symbol::id_t id, const region *parent, tree decl) : region (complexity (parent), id, parent, TREE_TYPE (decl)), m_decl (decl), m_tracked (calc_tracked_p (decl)), - m_ctor_svalue (NULL) + m_ctor_svalue (nullptr) {} enum region_kind get_kind () const final override { return RK_DECL; } @@ -904,12 +904,12 @@ public: } void mark_deleted () { m_index = reinterpret_cast<const svalue *> (1); } - void mark_empty () { m_index = NULL; } + void mark_empty () { m_index = nullptr; } bool is_deleted () const { return m_index == reinterpret_cast<const svalue *> (1); } - bool is_empty () const { return m_index == NULL; } + bool is_empty () const { return m_index == nullptr; } const region *m_parent; tree m_element_type; @@ -998,12 +998,12 @@ public: } void mark_deleted () { m_byte_offset = reinterpret_cast<const svalue *> (1); } - void mark_empty () { m_byte_offset = NULL; } + void mark_empty () { m_byte_offset = nullptr; } bool is_deleted () const { return m_byte_offset == reinterpret_cast<const svalue *> (1); } - bool is_empty () const { return m_byte_offset == NULL; } + bool is_empty () const { return m_byte_offset == nullptr; } const region *m_parent; tree m_element_type; @@ -1094,12 +1094,12 @@ public: } void mark_deleted () { m_byte_size_sval = reinterpret_cast<const svalue *> (1); } - void mark_empty () { m_byte_size_sval = NULL; } + void mark_empty () { m_byte_size_sval = nullptr; } bool is_deleted () const { return m_byte_size_sval == reinterpret_cast<const svalue *> (1); } - bool is_empty () const { return m_byte_size_sval == NULL; } + bool is_empty () const { return m_byte_size_sval == nullptr; } const region *m_parent; tree m_element_type; @@ -1342,12 +1342,12 @@ public: } void mark_deleted () { m_parent = reinterpret_cast<const region *> (1); } - void mark_empty () { m_parent = NULL; } + void mark_empty () { m_parent = nullptr; } bool is_deleted () const { return m_parent == reinterpret_cast<const region *> (1); } - bool is_empty () const { return m_parent == NULL; } + bool is_empty () const { return m_parent == nullptr; } const region *m_parent; tree m_type; @@ -1432,12 +1432,12 @@ public: { m_parent = reinterpret_cast<const frame_region *> (1); } - void mark_empty () { m_parent = NULL; } + void mark_empty () { m_parent = nullptr; } bool is_deleted () const { return m_parent == reinterpret_cast<const frame_region *> (1); } - bool is_empty () const { return m_parent == NULL; } + bool is_empty () const { return m_parent == nullptr; } const frame_region *m_parent; unsigned m_idx; diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc index cee8d2d..370d7a0 100644 --- a/gcc/analyzer/sm-fd.cc +++ b/gcc/analyzer/sm-fd.cc @@ -116,7 +116,11 @@ public: const svalue *rhs) const final override; bool can_purge_p (state_t s) const final override; - std::unique_ptr<pending_diagnostic> on_leak (tree var) const final override; + + std::unique_ptr<pending_diagnostic> + on_leak (tree var, + const program_state *old_state, + const program_state *new_state) const final override; bool is_unchecked_fd_p (state_t s) const; bool is_valid_fd_p (state_t s) const; @@ -210,7 +214,7 @@ public: /* State for a file descriptor that we do not want to track anymore . */ state_t m_stop; - /* Stashed constant values from the frontend. These could be NULL. */ + /* Stashed constant values from the frontend. These could be NULL_TREE. */ tree m_O_ACCMODE; tree m_O_RDONLY; tree m_O_WRONLY; @@ -257,7 +261,7 @@ private: const svalue *fd_sval, const supernode *node, state_t old_state, - bool *complained = NULL) const; + bool *complained = nullptr) const; bool check_for_new_socket_fd (const call_details &cd, bool successful, sm_context &sm_ctxt, @@ -397,11 +401,11 @@ public: || change.m_new_state == m_sm.m_new_datagram_socket || change.m_new_state == m_sm.m_new_stream_socket || change.m_new_state == m_sm.m_new_unknown_socket)) - return diagnostic_event::meaning (diagnostic_event::VERB_acquire, - diagnostic_event::NOUN_resource); + return diagnostic_event::meaning (diagnostic_event::verb::acquire, + diagnostic_event::noun::resource); if (change.m_new_state == m_sm.m_closed) - return diagnostic_event::meaning (diagnostic_event::VERB_release, - diagnostic_event::NOUN_resource); + return diagnostic_event::meaning (diagnostic_event::verb::release, + diagnostic_event::noun::resource); return diagnostic_event::meaning (); } @@ -422,7 +426,7 @@ public: fd_param_diagnostic (const fd_state_machine &sm, tree arg, tree callee_fndecl) : fd_diagnostic (sm, arg), m_callee_fndecl (callee_fndecl), - m_attr_name (NULL), m_arg_idx (-1) + m_attr_name (nullptr), m_arg_idx (-1) { } @@ -477,7 +481,14 @@ protected: class fd_leak : public fd_diagnostic { public: - fd_leak (const fd_state_machine &sm, tree arg) : fd_diagnostic (sm, arg) {} + fd_leak (const fd_state_machine &sm, tree arg, + const program_state *final_state) + : fd_diagnostic (sm, arg), + m_final_state () + { + if (final_state) + m_final_state = std::make_unique<program_state> (*final_state); + } const char * get_kind () const final override @@ -543,8 +554,15 @@ public: return true; } + const program_state * + get_final_state () const final override + { + return m_final_state.get (); + } + private: diagnostic_event_id_t m_open_event; + std::unique_ptr<program_state> m_final_state; }; class fd_access_mode_mismatch : public fd_param_diagnostic @@ -1296,7 +1314,7 @@ fd_state_machine::valid_to_unchecked_state (state_t state) const return m_unchecked_read_only; else gcc_unreachable (); - return NULL; + return nullptr; } void @@ -1305,7 +1323,7 @@ fd_state_machine::mark_as_valid_fd (region_model *model, const svalue *fd_sval, const extrinsic_state &ext_state) const { - smap->set_state (model, fd_sval, m_valid_read_write, NULL, ext_state); + smap->set_state (model, fd_sval, m_valid_read_write, nullptr, ext_state); } bool @@ -1528,7 +1546,7 @@ fd_state_machine::on_open (sm_context &sm_ctxt, const supernode *node, else { sm_ctxt.warn (node, stmt, NULL_TREE, - std::make_unique<fd_leak> (*this, NULL_TREE)); + std::make_unique<fd_leak> (*this, NULL_TREE, nullptr)); } } @@ -1541,7 +1559,7 @@ fd_state_machine::on_creat (sm_context &sm_ctxt, const supernode *node, sm_ctxt.on_transition (node, stmt, lhs, m_start, m_unchecked_write_only); else sm_ctxt.warn (node, stmt, NULL_TREE, - std::make_unique<fd_leak> (*this, NULL_TREE)); + std::make_unique<fd_leak> (*this, NULL_TREE, nullptr)); } void @@ -1792,7 +1810,7 @@ fd_state_machine::on_socket (const call_details &cd, } else sm_ctxt.warn (node, &call, NULL_TREE, - std::make_unique<fd_leak> (*this, NULL_TREE)); + std::make_unique<fd_leak> (*this, NULL_TREE, nullptr)); } else { @@ -1967,7 +1985,7 @@ fd_state_machine::on_bind (const call_details &cd, if (successful) { - state_t next_state = NULL; + state_t next_state = nullptr; if (old_state == m_new_stream_socket) next_state = m_bound_stream_socket; else if (old_state == m_new_datagram_socket) @@ -2185,7 +2203,7 @@ fd_state_machine::on_accept (const call_details &cd, } else sm_ctxt.warn (node, &call, NULL_TREE, - std::make_unique<fd_leak> (*this, NULL_TREE)); + std::make_unique<fd_leak> (*this, NULL_TREE, nullptr)); } else { @@ -2223,7 +2241,7 @@ fd_state_machine::on_connect (const call_details &cd, if (successful) { model->update_for_zero_return (cd, true); - state_t next_state = NULL; + state_t next_state = nullptr; if (old_state == m_new_stream_socket) next_state = m_connected_stream_socket; else if (old_state == m_new_datagram_socket) @@ -2321,9 +2339,11 @@ fd_state_machine::can_purge_p (state_t s) const } std::unique_ptr<pending_diagnostic> -fd_state_machine::on_leak (tree var) const +fd_state_machine::on_leak (tree var, + const program_state *, + const program_state *new_state) const { - return std::make_unique<fd_leak> (*this, var); + return std::make_unique<fd_leak> (*this, var, new_state); } } // namespace @@ -2361,7 +2381,7 @@ region_model::mark_as_valid_fd (const svalue *sval, region_model_context *ctxt) { sm_state_map *smap; const fd_state_machine *fd_sm; - if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, NULL)) + if (!get_fd_state (ctxt, &smap, &fd_sm, nullptr, nullptr)) return; const extrinsic_state *ext_state = ctxt->get_ext_state (); if (!ext_state) @@ -2390,7 +2410,7 @@ public: sm_state_map *smap; const fd_state_machine *fd_sm; std::unique_ptr<sm_context> sm_ctxt; - if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) + if (!get_fd_state (ctxt, &smap, &fd_sm, nullptr, &sm_ctxt)) { cd.set_any_lhs_with_defaults (); return true; @@ -2445,7 +2465,7 @@ public: sm_state_map *smap; const fd_state_machine *fd_sm; std::unique_ptr<sm_context> sm_ctxt; - if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) + if (!get_fd_state (ctxt, &smap, &fd_sm, nullptr, &sm_ctxt)) { cd.set_any_lhs_with_defaults (); return true; @@ -2498,7 +2518,7 @@ class kf_listen : public known_function sm_state_map *smap; const fd_state_machine *fd_sm; std::unique_ptr<sm_context> sm_ctxt; - if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) + if (!get_fd_state (ctxt, &smap, &fd_sm, nullptr, &sm_ctxt)) { cd.set_any_lhs_with_defaults (); return true; @@ -2552,7 +2572,7 @@ class kf_accept : public known_function sm_state_map *smap; const fd_state_machine *fd_sm; std::unique_ptr<sm_context> sm_ctxt; - if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) + if (!get_fd_state (ctxt, &smap, &fd_sm, nullptr, &sm_ctxt)) { cd.set_any_lhs_with_defaults (); return true; @@ -2609,7 +2629,7 @@ public: sm_state_map *smap; const fd_state_machine *fd_sm; std::unique_ptr<sm_context> sm_ctxt; - if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) + if (!get_fd_state (ctxt, &smap, &fd_sm, nullptr, &sm_ctxt)) { cd.set_any_lhs_with_defaults (); return true; @@ -2687,7 +2707,7 @@ class kf_isatty : public known_function sm_state_map *smap; const fd_state_machine *fd_sm; std::unique_ptr<sm_context> sm_ctxt; - if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) + if (!get_fd_state (ctxt, &smap, &fd_sm, nullptr, &sm_ctxt)) return true; const extrinsic_state *ext_state = ctxt->get_ext_state (); if (!ext_state) diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc index d7dbe2f..4b1fc77 100644 --- a/gcc/analyzer/sm-file.cc +++ b/gcc/analyzer/sm-file.cc @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/analyzer-selftests.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" +#include "analyzer/program-state.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/call-details.h" @@ -72,7 +73,11 @@ public: const svalue *rhs) const final override; bool can_purge_p (state_t s) const final override; - std::unique_ptr<pending_diagnostic> on_leak (tree var) const final override; + + std::unique_ptr<pending_diagnostic> + on_leak (tree var, + const program_state *old_state, + const program_state *new_state) const final override; /* State for a FILE * returned from fopen that hasn't been checked for NULL. @@ -156,11 +161,11 @@ public: { if (change.m_old_state == m_sm.get_start_state () && change.m_new_state == m_sm.m_unchecked) - return diagnostic_event::meaning (diagnostic_event::VERB_acquire, - diagnostic_event::NOUN_resource); + return diagnostic_event::meaning (diagnostic_event::verb::acquire, + diagnostic_event::noun::resource); if (change.m_new_state == m_sm.m_closed) - return diagnostic_event::meaning (diagnostic_event::VERB_release, - diagnostic_event::NOUN_resource); + return diagnostic_event::meaning (diagnostic_event::verb::release, + diagnostic_event::noun::resource); return diagnostic_event::meaning (); } @@ -226,9 +231,14 @@ private: class file_leak : public file_diagnostic { public: - file_leak (const fileptr_state_machine &sm, tree arg) - : file_diagnostic (sm, arg) - {} + file_leak (const fileptr_state_machine &sm, tree arg, + const program_state *final_state) + : file_diagnostic (sm, arg), + m_final_state () + { + if (final_state) + m_final_state = std::make_unique<program_state> (*final_state); + } const char *get_kind () const final override { return "file_leak"; } @@ -286,8 +296,15 @@ public: return true; } + const program_state * + get_final_state () const final override + { + return m_final_state.get (); + } + private: diagnostic_event_id_t m_fopen_event; + std::unique_ptr<program_state> m_final_state; }; /* fileptr_state_machine's ctor. */ @@ -492,9 +509,11 @@ fileptr_state_machine::can_purge_p (state_t s) const state 'unchecked' and 'nonnull'. */ std::unique_ptr<pending_diagnostic> -fileptr_state_machine::on_leak (tree var) const +fileptr_state_machine::on_leak (tree var, + const program_state *, + const program_state *new_state) const { - return std::make_unique<file_leak> (*this, var); + return std::make_unique<file_leak> (*this, var, new_state); } } // anonymous namespace diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc index 333dfea..3581dbb 100644 --- a/gcc/analyzer/sm-malloc.cc +++ b/gcc/analyzer/sm-malloc.cc @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-event-id.h" #include "stringpool.h" #include "attribs.h" +#include "xml-printer.h" #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" @@ -37,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/checker-event.h" #include "analyzer/exploded-graph.h" #include "analyzer/inlining-iterator.h" +#include "analyzer/ana-state-to-diagnostic-state.h" #if ENABLE_ANALYZER @@ -139,7 +141,7 @@ struct assumed_non_null_state : public allocation_state assumed_non_null_state (const char *name, unsigned id, const frame_region *frame) : allocation_state (name, id, RS_ASSUMED_NON_NULL, - NULL, NULL), + nullptr, nullptr), m_frame (frame) { gcc_assert (m_frame); @@ -290,7 +292,7 @@ struct deallocator_set_map_traits static inline hashval_t hash (const key_type &k) { - gcc_assert (k != NULL); + gcc_assert (k != nullptr); gcc_assert (k != reinterpret_cast<key_type> (1)); hashval_t result = 0; @@ -324,7 +326,7 @@ struct deallocator_set_map_traits template <typename T> static inline void mark_empty (T &entry) { - entry.m_key = NULL; + entry.m_key = nullptr; } template <typename T> static inline bool is_deleted (const T &entry) @@ -334,7 +336,7 @@ struct deallocator_set_map_traits template <typename T> static inline bool is_empty (const T &entry) { - return entry.m_key == NULL; + return entry.m_key == nullptr; } static const bool empty_zero_p = false; }; @@ -403,7 +405,11 @@ public: const frame_region *) const final override; bool can_purge_p (state_t s) const final override; - std::unique_ptr<pending_diagnostic> on_leak (tree var) const final override; + + std::unique_ptr<pending_diagnostic> + on_leak (tree var, + const program_state *old_state, + const program_state *new_state) const final override; bool reset_when_passed_to_unknown_fn_p (state_t s, bool is_mutable) const final override; @@ -429,6 +435,11 @@ public: const svalue *new_ptr_sval, const extrinsic_state &ext_state) const; + void + add_state_to_xml (xml_state &out_xml, + const svalue &sval, + state_machine::state_t state) const final override; + standard_deallocator_set m_free; standard_deallocator_set m_scalar_delete; standard_deallocator_set m_vector_delete; @@ -524,7 +535,7 @@ deallocator::deallocator (malloc_state_machine *sm, enum wording wording) : m_name (name), m_wording (wording), - m_freed (sm->add_state ("freed", RS_FREED, NULL, this)) + m_freed (sm->add_state ("freed", RS_FREED, nullptr, this)) { } @@ -568,8 +579,8 @@ standard_deallocator::standard_deallocator (malloc_state_machine *sm, deallocator_set::deallocator_set (malloc_state_machine *sm, enum wording wording) : m_wording (wording), - m_unchecked (sm->add_state ("unchecked", RS_UNCHECKED, this, NULL)), - m_nonnull (sm->add_state ("nonnull", RS_NONNULL, this, NULL)) + m_unchecked (sm->add_state ("unchecked", RS_UNCHECKED, this, nullptr)), + m_nonnull (sm->add_state ("nonnull", RS_NONNULL, this, nullptr)) { } @@ -614,7 +625,7 @@ custom_deallocator_set::maybe_get_single () const { if (m_deallocator_vec.length () == 1) return m_deallocator_vec[0]; - return NULL; + return nullptr; } void @@ -662,14 +673,15 @@ standard_deallocator_set::dump_to_pp (pretty_printer *pp) const pp_character (pp, '}'); } -/* Return STATE cast to the custom state subclass, or NULL for the start state. +/* Return STATE cast to the custom state subclass, or nullptr for the + start state. Everything should be an allocation_state apart from the start state. */ static const allocation_state * dyn_cast_allocation_state (state_machine::state_t state) { if (state->get_id () == 0) - return NULL; + return nullptr; return static_cast <const allocation_state *> (state); } @@ -808,11 +820,11 @@ public: { if (change.m_old_state == m_sm.get_start_state () && unchecked_p (change.m_new_state)) - return diagnostic_event::meaning (diagnostic_event::VERB_acquire, - diagnostic_event::NOUN_memory); + return diagnostic_event::meaning (diagnostic_event::verb::acquire, + diagnostic_event::noun::memory); if (freed_p (change.m_new_state)) - return diagnostic_event::meaning (diagnostic_event::VERB_release, - diagnostic_event::NOUN_memory); + return diagnostic_event::meaning (diagnostic_event::verb::release, + diagnostic_event::noun::memory); return diagnostic_event::meaning (); } @@ -1414,8 +1426,14 @@ private: class malloc_leak : public malloc_diagnostic { public: - malloc_leak (const malloc_state_machine &sm, tree arg) - : malloc_diagnostic (sm, arg) {} + malloc_leak (const malloc_state_machine &sm, tree arg, + const program_state *final_state) + : malloc_diagnostic (sm, arg), + m_final_state () + { + if (final_state) + m_final_state = std::make_unique<program_state> (*final_state); + } const char *get_kind () const final override { return "malloc_leak"; } @@ -1475,8 +1493,15 @@ public: return true; } + const program_state * + get_final_state () const final override + { + return m_final_state.get (); + } + private: diagnostic_event_id_t m_alloc_event; + std::unique_ptr<program_state> m_final_state; }; class free_of_non_heap : public malloc_diagnostic @@ -1571,9 +1596,9 @@ class deref_before_check : public malloc_diagnostic public: deref_before_check (const malloc_state_machine &sm, tree arg) : malloc_diagnostic (sm, arg), - m_deref_enode (NULL), - m_deref_expr (NULL), - m_check_enode (NULL) + m_deref_enode (nullptr), + m_deref_expr (nullptr), + m_check_enode (nullptr) { gcc_assert (arg); } @@ -1798,9 +1823,9 @@ malloc_state_machine::malloc_state_machine (logger *logger) m_realloc (this, "realloc", WORDING_REALLOCATED) { gcc_assert (m_start->get_id () == 0); - m_null = add_state ("null", RS_FREED, NULL, NULL); - m_non_heap = add_state ("non-heap", RS_NON_HEAP, NULL, NULL); - m_stop = add_state ("stop", RS_STOP, NULL, NULL); + m_null = add_state ("null", RS_FREED, nullptr, nullptr); + m_non_heap = add_state ("non-heap", RS_NON_HEAP, nullptr, nullptr); + m_stop = add_state ("stop", RS_STOP, nullptr, nullptr); } malloc_state_machine::~malloc_state_machine () @@ -1828,7 +1853,7 @@ malloc_state_machine::add_state (const char *name, enum resource_state rs, return a custom_deallocator_set for them, consolidating them to ensure uniqueness of the sets. - Return NULL if it has no such attributes. */ + Return nullptr if it has no such attributes. */ const custom_deallocator_set * malloc_state_machine:: @@ -1837,7 +1862,7 @@ get_or_create_custom_deallocator_set (tree allocator_fndecl) /* Early rejection of decls without attributes. */ tree attrs = DECL_ATTRIBUTES (allocator_fndecl); if (!attrs) - return NULL; + return nullptr; /* Otherwise, call maybe_create_custom_deallocator_set, memoizing the result. */ @@ -1855,7 +1880,7 @@ get_or_create_custom_deallocator_set (tree allocator_fndecl) custom_deallocator_set for them, consolidating them to ensure uniqueness of the sets. - Return NULL if it has no such attributes. + Return nullptr if it has no such attributes. Subroutine of get_or_create_custom_deallocator_set which memoizes the result. */ @@ -1886,7 +1911,7 @@ maybe_create_custom_deallocator_set (tree allocator_fndecl) /* If there weren't any deallocators, bail. */ if (deallocator_vec.length () == 0) - return NULL; + return nullptr; /* Consolidate, so that we reuse existing deallocator_set instances. */ @@ -1991,7 +2016,7 @@ malloc_state_machine::maybe_assume_non_null (sm_context &sm_ctxt, tree null_ptr_cst = build_int_cst (TREE_TYPE (ptr), 0); tristate known_non_null - = old_model->eval_condition (ptr, NE_EXPR, null_ptr_cst, NULL); + = old_model->eval_condition (ptr, NE_EXPR, null_ptr_cst, nullptr); if (known_non_null.is_unknown ()) { /* Cast away const-ness for cache-like operations. */ @@ -2172,19 +2197,27 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt, unsigned int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1; unsigned int idx2 = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1; + unsigned int idx3 = idx2; + if (tree chain2 = TREE_CHAIN (TREE_CHAIN (args))) + idx3 = TREE_INT_CST_LOW (TREE_VALUE (chain2)) - 1; if (idx < gimple_call_num_args (stmt) - && idx2 < gimple_call_num_args (stmt)) + && idx2 < gimple_call_num_args (stmt) + && idx3 < gimple_call_num_args (stmt)) { tree arg = gimple_call_arg (stmt, idx); tree arg2 = gimple_call_arg (stmt, idx2); + tree arg3 = gimple_call_arg (stmt, idx3); if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE || !INTEGRAL_TYPE_P (TREE_TYPE (arg2)) - || integer_zerop (arg2)) + || !INTEGRAL_TYPE_P (TREE_TYPE (arg3)) + || integer_zerop (arg2) + || integer_zerop (arg3)) continue; - if (integer_nonzerop (arg2)) + if (integer_nonzerop (arg2) && integer_nonzerop (arg3)) ; else - /* FIXME: Use ranger here to query arg2 range? */ + /* FIXME: Use ranger here to query arg2 and arg3 + ranges? */ continue; handle_nonnull (sm_ctxt, node, stmt, fndecl, arg, idx); } @@ -2376,12 +2409,12 @@ malloc_state_machine::handle_free_of_non_heap (sm_context &sm_ctxt, const deallocator *d) const { tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); - const region *freed_reg = NULL; + const region *freed_reg = nullptr; if (const program_state *old_state = sm_ctxt.get_old_program_state ()) { const region_model *old_model = old_state->m_region_model; - const svalue *ptr_sval = old_model->get_rvalue (arg, NULL); - freed_reg = old_model->deref_rvalue (ptr_sval, arg, NULL); + const svalue *ptr_sval = old_model->get_rvalue (arg, nullptr); + freed_reg = old_model->deref_rvalue (ptr_sval, arg, nullptr); } sm_ctxt.warn (node, &call, arg, std::make_unique<free_of_non_heap> @@ -2589,9 +2622,11 @@ malloc_state_machine::can_purge_p (state_t s) const 'nonnull'). */ std::unique_ptr<pending_diagnostic> -malloc_state_machine::on_leak (tree var) const +malloc_state_machine::on_leak (tree var, + const program_state *, + const program_state *new_state) const { - return std::make_unique<malloc_leak> (*this, var); + return std::make_unique<malloc_leak> (*this, var, new_state); } /* Implementation of state_machine::reset_when_passed_to_unknown_fn_p vfunc @@ -2624,7 +2659,7 @@ malloc_state_machine::maybe_get_merged_states_nonequal (state_t state_a, return m_start; if (state_a == m_start && assumed_non_null_p (state_b)) return m_start; - return NULL; + return nullptr; } /* Return true if calls to FNDECL are known to not affect this sm-state. */ @@ -2682,11 +2717,11 @@ on_realloc_with_move (region_model *model, { smap->set_state (model, old_ptr_sval, m_free.m_deallocator.m_freed, - NULL, ext_state); + nullptr, ext_state); smap->set_state (model, new_ptr_sval, m_free.m_nonnull, - NULL, ext_state); + nullptr, ext_state); } /* Hook for get_or_create_region_for_heap_alloc for the case when we want @@ -2697,7 +2732,31 @@ malloc_state_machine::transition_ptr_sval_non_null (region_model *model, const svalue *new_ptr_sval, const extrinsic_state &ext_state) const { - smap->set_state (model, new_ptr_sval, m_free.m_nonnull, NULL, ext_state); + smap->set_state (model, new_ptr_sval, m_free.m_nonnull, nullptr, ext_state); +} + +void +malloc_state_machine::add_state_to_xml (xml_state &out_xml, + const svalue &sval, + state_machine::state_t state) const +{ + if (const region *reg = sval.maybe_get_region ()) + { + auto ®_element = out_xml.get_or_create_element (*reg); + auto alloc_state = as_a_allocation_state (state); + gcc_assert (alloc_state); + + reg_element.set_attr ("dynamic-alloc-state", state->get_name ()); + if (alloc_state->m_deallocators) + { + pretty_printer pp; + alloc_state->m_deallocators->dump_to_pp (&pp); + reg_element.set_attr ("expected-deallocators", pp_formatted_text (&pp)); + } + if (alloc_state->m_deallocator) + reg_element.set_attr ("deallocator", + alloc_state->m_deallocator->m_name); + } } } // anonymous namespace diff --git a/gcc/analyzer/sm-pattern-test.cc b/gcc/analyzer/sm-pattern-test.cc index f05ffe0..02b32ac 100644 --- a/gcc/analyzer/sm-pattern-test.cc +++ b/gcc/analyzer/sm-pattern-test.cc @@ -122,7 +122,7 @@ pattern_test_state_machine::on_condition (sm_context &sm_ctxt, enum tree_code op, const svalue *rhs) const { - if (stmt == NULL) + if (stmt == nullptr) return; tree rhs_cst = rhs->maybe_get_constant (); diff --git a/gcc/analyzer/sm-sensitive.cc b/gcc/analyzer/sm-sensitive.cc index 7bd5ef6..f8fcded 100644 --- a/gcc/analyzer/sm-sensitive.cc +++ b/gcc/analyzer/sm-sensitive.cc @@ -111,8 +111,8 @@ public: const final override { if (change.m_new_state == m_sm.m_sensitive) - return diagnostic_event::meaning (diagnostic_event::VERB_acquire, - diagnostic_event::NOUN_sensitive); + return diagnostic_event::meaning (diagnostic_event::verb::acquire, + diagnostic_event::noun::sensitive); return diagnostic_event::meaning (); } bool diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc index 83f2808..5a4b384 100644 --- a/gcc/analyzer/sm-signal.cc +++ b/gcc/analyzer/sm-signal.cc @@ -173,7 +173,7 @@ private: if (id_equal ("exit", DECL_NAME (m_unsafe_fndecl))) return "_exit"; - return NULL; + return nullptr; } }; @@ -269,7 +269,7 @@ public: state_entering_handler, src_enode); if (dst_enode) - eg->add_edge (src_enode, dst_enode, NULL, /*state_change (),*/ + eg->add_edge (src_enode, dst_enode, nullptr, /*state_change (),*/ true, /* assume does work */ std::make_unique<signal_delivery_edge_info_t> ()); } diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc index e782081..5c8cc7e 100644 --- a/gcc/analyzer/sm-taint.cc +++ b/gcc/analyzer/sm-taint.cc @@ -214,8 +214,8 @@ public: const final override { if (change.m_new_state == m_sm.m_tainted) - return diagnostic_event::meaning (diagnostic_event::VERB_acquire, - diagnostic_event::NOUN_taint); + return diagnostic_event::meaning (diagnostic_event::verb::acquire, + diagnostic_event::noun::taint); return diagnostic_event::meaning (); } @@ -934,7 +934,7 @@ public: macro when we're describing them. */ return linemap_resolve_location (line_table, loc, LRK_SPELLING_LOCATION, - NULL); + nullptr); else return pending_diagnostic::fixup_location (loc, primary); } @@ -1060,12 +1060,12 @@ taint_state_machine::alt_get_inherited_state (const sm_state_map &map, case BIT_AND_EXPR: case RSHIFT_EXPR: - return NULL; + return nullptr; } } break; } - return NULL; + return nullptr; } /* Return true iff FNDECL should be considered to be an assertion failure @@ -1175,7 +1175,7 @@ taint_state_machine::check_control_flow_arg_for_taint (sm_context &sm_ctxt, tree expr) const { const region_model *old_model = sm_ctxt.get_old_region_model (); - const svalue *sval = old_model->get_rvalue (expr, NULL); + const svalue *sval = old_model->get_rvalue (expr, nullptr); state_t state = sm_ctxt.get_state (stmt, sval); enum bounds b; if (get_taint (state, TREE_TYPE (expr), &b)) @@ -1194,7 +1194,7 @@ taint_state_machine::on_condition (sm_context &sm_ctxt, enum tree_code op, const svalue *rhs) const { - if (stmt == NULL) + if (stmt == nullptr) return; if (lhs->get_kind () == SK_UNKNOWN @@ -1492,7 +1492,7 @@ taint_state_machine::check_for_tainted_divisor (sm_context &sm_ctxt, if (!INTEGRAL_TYPE_P (TREE_TYPE (divisor_expr))) return; - const svalue *divisor_sval = old_model->get_rvalue (divisor_expr, NULL); + const svalue *divisor_sval = old_model->get_rvalue (divisor_expr, nullptr); state_t state = sm_ctxt.get_state (assign, divisor_sval); enum bounds b; @@ -1793,7 +1793,7 @@ region_model::mark_as_tainted (const svalue *sval, if (!ext_state) return; - smap->set_state (this, sval, taint_sm.m_tainted, NULL, *ext_state); + smap->set_state (this, sval, taint_sm.m_tainted, nullptr, *ext_state); } /* Return true if SVAL could possibly be attacker-controlled. */ diff --git a/gcc/analyzer/sm.cc b/gcc/analyzer/sm.cc index 0abbdd6..840806a 100644 --- a/gcc/analyzer/sm.cc +++ b/gcc/analyzer/sm.cc @@ -116,9 +116,11 @@ state_machine::get_state_by_name (const char *name) const /* Base implementation of state_machine::on_leak. */ std::unique_ptr<pending_diagnostic> -state_machine::on_leak (tree var ATTRIBUTE_UNUSED) const +state_machine::on_leak (tree var ATTRIBUTE_UNUSED, + const program_state *old_state ATTRIBUTE_UNUSED, + const program_state *new_state ATTRIBUTE_UNUSED) const { - return NULL; + return nullptr; } /* Dump a multiline representation of this state machine to PP. */ @@ -158,6 +160,21 @@ state_machine::to_json () const return sm_obj; } +void +state_machine::add_state_to_xml (xml_state &out_xml, + const svalue &sval, + state_machine::state_t state) const +{ + // no-op +} + +void +state_machine::add_global_state_to_xml (xml_state &out_xml, + state_machine::state_t state) const +{ + // no-op +} + /* class sm_context. */ const region_model * @@ -166,7 +183,7 @@ sm_context::get_old_region_model () const if (const program_state *old_state = get_old_program_state ()) return old_state->m_region_model; else - return NULL; + return nullptr; } /* Create instances of the various state machines, each using LOGGER, diff --git a/gcc/analyzer/sm.h b/gcc/analyzer/sm.h index a932765..6298fb6 100644 --- a/gcc/analyzer/sm.h +++ b/gcc/analyzer/sm.h @@ -28,6 +28,7 @@ namespace ana { class state_machine; class sm_context; class pending_diagnostic; +class xml_state; extern bool any_pointer_p (tree expr); extern bool any_pointer_p (const svalue *sval); @@ -75,7 +76,7 @@ public: const svalue *, const extrinsic_state &) const { - return NULL; + return nullptr; } virtual bool @@ -136,7 +137,9 @@ public: /* Called when VAR leaks (and !can_purge_p). */ virtual std::unique_ptr<pending_diagnostic> - on_leak (tree var ATTRIBUTE_UNUSED) const; + on_leak (tree var ATTRIBUTE_UNUSED, + const program_state *old_state, + const program_state *new_state) const; /* Return true if S should be reset to "start" for values passed (or reachable from) calls to unknown functions. IS_MUTABLE is true for pointers as @@ -152,7 +155,7 @@ public: } /* Attempt to get a state for the merger of STATE_A and STATE_B, - or return NULL if merging shouldn't occur, so that differences + or return nullptr if merging shouldn't occur, so that differences between sm-state will lead to separate exploded nodes. Most state machines will only merge equal states, but can @@ -173,7 +176,7 @@ public: state_t state_b ATTRIBUTE_UNUSED) const { /* By default, non-equal sm states should inhibit merger of enodes. */ - return NULL; + return nullptr; } void validate (state_t s) const; @@ -184,6 +187,15 @@ public: state_t get_start_state () const { return m_start; } + virtual void + add_state_to_xml (xml_state &out_xml, + const svalue &sval, + state_machine::state_t state) const; + + virtual void + add_global_state_to_xml (xml_state &out_xml, + state_machine::state_t state) const; + protected: state_t add_state (const char *name); state_t add_custom_state (state *s) @@ -318,7 +330,7 @@ public: virtual path_context *get_path_context () const { - return NULL; + return nullptr; } /* Are we handling an external function with unknown side effects? */ diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc index 7a93cee..1371db9 100644 --- a/gcc/analyzer/state-purge.cc +++ b/gcc/analyzer/state-purge.cc @@ -659,7 +659,7 @@ state_purge_per_ssa_name::process_point (const function_point &point, if (snode->entry_p ()) { add_to_worklist - (function_point::before_supernode (snode, NULL), + (function_point::before_supernode (snode, nullptr), worklist, logger); } } @@ -841,8 +841,8 @@ fully_overwrites_p (const gimple *stmt, tree decl, We can't just check for equality; consider the case of "s.field = EXPR;" where the stmt writes to the only field of "s", and there's no padding. */ - const region *lhs_reg = model.get_lvalue (lhs, NULL); - const region *decl_reg = model.get_lvalue (decl, NULL); + const region *lhs_reg = model.get_lvalue (lhs, nullptr); + const region *decl_reg = model.get_lvalue (decl, nullptr); if (same_binding_p (lhs_reg, decl_reg, model.get_manager ()->get_store_manager ())) return true; @@ -1074,7 +1074,7 @@ state_purge_annotator::add_node_annotations (graphviz_out *gv, const supernode &n, bool within_table) const { - if (m_map == NULL) + if (m_map == nullptr) return false; if (within_table) @@ -1091,7 +1091,7 @@ state_purge_annotator::add_node_annotations (graphviz_out *gv, Determine which points to dump. */ auto_vec<function_point> points; if (n.entry_p () || n.m_returning_call) - points.safe_push (function_point::before_supernode (&n, NULL)); + points.safe_push (function_point::before_supernode (&n, nullptr)); else for (auto inedge : n.m_preds) points.safe_push (function_point::before_supernode (&n, inedge)); @@ -1153,7 +1153,7 @@ state_purge_annotator::add_stmt_annotations (graphviz_out *gv, if (within_row) return; - if (m_map == NULL) + if (m_map == nullptr) return; if (stmt->code == GIMPLE_PHI) diff --git a/gcc/analyzer/state-purge.h b/gcc/analyzer/state-purge.h index bbe78a5..2bac564 100644 --- a/gcc/analyzer/state-purge.h +++ b/gcc/analyzer/state-purge.h @@ -109,7 +109,7 @@ public: = const_cast <decl_map_t&> (m_decl_map).get (decl)) return *slot; else - return NULL; + return nullptr; } state_purge_per_decl & diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc index e6723c7..942c945 100644 --- a/gcc/analyzer/store.cc +++ b/gcc/analyzer/store.cc @@ -658,7 +658,7 @@ binding_map::operator== (const binding_map &other) const const svalue *sval = (*iter).second; const svalue **other_slot = const_cast <map_t &> (other.m_map).get (key); - if (other_slot == NULL) + if (other_slot == nullptr) return false; if (sval != *other_slot) return false; @@ -922,7 +922,7 @@ get_svalue_for_ctor_val (tree val, region_model_manager *mgr) { /* Reuse the get_rvalue logic from region_model. */ region_model m (mgr); - return m.get_rvalue (path_var (val, 0), NULL); + return m.get_rvalue (path_var (val, 0), nullptr); } /* Bind values from CONSTRUCTOR to this map, relative to @@ -1564,7 +1564,7 @@ binding_cluster::bind_compound_sval (store_manager *mgr, void binding_cluster::clobber_region (store_manager *mgr, const region *reg) { - remove_overlapping_bindings (mgr, reg, NULL, NULL); + remove_overlapping_bindings (mgr, reg, nullptr, nullptr); } /* Remove any bindings for REG within this cluster. */ @@ -1684,7 +1684,7 @@ binding_cluster::get_binding (store_manager *mgr, const region *reg) const { if (reg->empty_p ()) - return NULL; + return nullptr; const binding_key *reg_binding = binding_key::make (mgr, reg); const svalue *sval = m_map.get (reg_binding); if (sval) @@ -1752,7 +1752,7 @@ binding_cluster::get_binding_recursive (store_manager *mgr, return rmm_mgr->get_or_create_sub_svalue (reg->get_type (), parent_sval, reg); } - return NULL; + return nullptr; } /* Get any value bound for REG within this cluster. */ @@ -1800,7 +1800,7 @@ binding_cluster::get_any_binding (store_manager *mgr, return compound_sval; /* Otherwise, the initial value, or uninitialized. */ - return NULL; + return nullptr; } /* Attempt to get a compound_svalue for the bindings within the cluster @@ -1812,7 +1812,7 @@ binding_cluster::get_any_binding (store_manager *mgr, For example, REG could be one element within an array of structs. - Return the resulting compound_svalue, or NULL if there's a problem. */ + Return the resulting compound_svalue, or nullptr if there's a problem. */ const svalue * binding_cluster::maybe_get_compound_binding (store_manager *mgr, @@ -1821,13 +1821,13 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr, region_offset cluster_offset = m_base_region->get_offset (mgr->get_svalue_manager ()); if (cluster_offset.symbolic_p ()) - return NULL; + return nullptr; region_offset reg_offset = reg->get_offset (mgr->get_svalue_manager ()); if (reg_offset.symbolic_p ()) - return NULL; + return nullptr; if (reg->empty_p ()) - return NULL; + return nullptr; region_model_manager *sval_mgr = mgr->get_svalue_manager (); @@ -1880,7 +1880,7 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr, bit_size_t reg_bit_size; if (!reg->get_bit_size (®_bit_size)) - return NULL; + return nullptr; bit_range reg_range (reg_offset.get_bit_offset (), reg_bit_size); @@ -1909,7 +1909,7 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr, it overlaps with offset_concrete_key. */ default_map.remove_overlapping_bindings (mgr, offset_concrete_key, - NULL, NULL, false); + nullptr, nullptr, false); } else if (bound_range.contains_p (reg_range, &subrange)) { @@ -1943,16 +1943,16 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr, it overlaps with overlap_concrete_key. */ default_map.remove_overlapping_bindings (mgr, overlap_concrete_key, - NULL, NULL, false); + nullptr, nullptr, false); } } else /* Can't handle symbolic bindings. */ - return NULL; + return nullptr; } if (result_map.elements () == 0) - return NULL; + return nullptr; /* Merge any bindings from default_map into result_map. */ for (auto iter : default_map) @@ -2030,23 +2030,23 @@ binding_cluster::can_merge_p (const binding_cluster *cluster_a, /* At least one of CLUSTER_A and CLUSTER_B are non-NULL, but either could be NULL. Handle these cases. */ - if (cluster_a == NULL) + if (cluster_a == nullptr) { - gcc_assert (cluster_b != NULL); + gcc_assert (cluster_b != nullptr); gcc_assert (cluster_b->m_base_region == out_cluster->m_base_region); out_cluster->make_unknown_relative_to (cluster_b, out_store, mgr); return true; } - if (cluster_b == NULL) + if (cluster_b == nullptr) { - gcc_assert (cluster_a != NULL); + gcc_assert (cluster_a != nullptr); gcc_assert (cluster_a->m_base_region == out_cluster->m_base_region); out_cluster->make_unknown_relative_to (cluster_a, out_store, mgr); return true; } /* The "both inputs are non-NULL" case. */ - gcc_assert (cluster_a != NULL && cluster_b != NULL); + gcc_assert (cluster_a != nullptr && cluster_b != nullptr); gcc_assert (cluster_a->m_base_region == out_cluster->m_base_region); gcc_assert (cluster_b->m_base_region == out_cluster->m_base_region); @@ -2319,7 +2319,7 @@ binding_cluster::get_representative_path_vars (const region_model *model, } } -/* Get any svalue bound to KEY, or NULL. */ +/* Get any svalue bound to KEY, or nullptr. */ const svalue * binding_cluster::get_any_value (const binding_key *key) const @@ -2334,16 +2334,16 @@ binding_cluster::get_any_value (const binding_key *key) const const svalue * binding_cluster::maybe_get_simple_value (store_manager *mgr) const { - /* Fail gracefully if MGR is NULL to make it easier to dump store + /* Fail gracefully if MGR is nullptr to make it easier to dump store instances in the debugger. */ - if (mgr == NULL) - return NULL; + if (mgr == nullptr) + return nullptr; if (m_map.elements () != 1) - return NULL; + return nullptr; if (m_base_region->empty_p ()) - return NULL; + return nullptr; const binding_key *key = binding_key::make (mgr, m_base_region); return get_any_value (key); @@ -2467,7 +2467,7 @@ store::operator== (const store &other) const binding_cluster *c = (*iter).second; binding_cluster **other_slot = const_cast <cluster_map_t &> (other.m_cluster_map).get (reg); - if (other_slot == NULL) + if (other_slot == nullptr) return false; if (*c != **other_slot) return false; @@ -2520,7 +2520,7 @@ get_sorted_parent_regions (auto_vec<const region *> *out, /* Dump a representation of this store to PP, using SIMPLE to control how svalues and regions are printed. - MGR is used for simplifying dumps if non-NULL, but can also be NULL + MGR is used for simplifying dumps if non-NULL, but can also be nullptr (to make it easier to use from the debugger). */ void @@ -2629,7 +2629,7 @@ DEBUG_FUNCTION void store::dump (bool simple) const { tree_dump_pretty_printer pp (stderr); - dump_to_pp (&pp, simple, true, NULL); + dump_to_pp (&pp, simple, true, nullptr); pp_newline (&pp); } @@ -2761,7 +2761,7 @@ store::make_dump_widget (const text_art::dump_widget_info &dwi, return store_widget; } -/* Get any svalue bound to REG, or NULL. */ +/* Get any svalue bound to REG, or nullptr. */ const svalue * store::get_any_binding (store_manager *mgr, const region *reg) const @@ -2770,7 +2770,7 @@ store::get_any_binding (store_manager *mgr, const region *reg) const binding_cluster **cluster_slot = const_cast <cluster_map_t &> (m_cluster_map).get (base_reg); if (!cluster_slot) - return NULL; + return nullptr; return (*cluster_slot)->get_any_binding (mgr, reg); } @@ -2796,7 +2796,7 @@ store::set_value (store_manager *mgr, const region *lhs_reg, { /* Reject attempting to bind values into a symbolic region for an unknown ptr; merely invalidate values below. */ - lhs_cluster = NULL; + lhs_cluster = nullptr; /* The LHS of the write is *UNKNOWN. If the RHS is a pointer, then treat the region being pointed to as having escaped. */ @@ -2818,7 +2818,7 @@ store::set_value (store_manager *mgr, const region *lhs_reg, { /* Reject attempting to bind values into an untracked region; merely invalidate values below. */ - lhs_cluster = NULL; + lhs_cluster = nullptr; } /* Bindings to a cluster can affect other clusters if a symbolic @@ -2838,7 +2838,7 @@ store::set_value (store_manager *mgr, const region *lhs_reg, const region *iter_base_reg = (*iter).first; binding_cluster *iter_cluster = (*iter).second; if (iter_base_reg != lhs_base_reg - && (lhs_cluster == NULL + && (lhs_cluster == nullptr || lhs_cluster->symbolic_p () || iter_cluster->symbolic_p ())) { @@ -3097,7 +3097,7 @@ store::purge_state_involving (const svalue *sval, purge_cluster (iter); } -/* Get the cluster for BASE_REG, or NULL (const version). */ +/* Get the cluster for BASE_REG, or nullptr (const version). */ const binding_cluster * store::get_cluster (const region *base_reg) const @@ -3108,10 +3108,10 @@ store::get_cluster (const region *base_reg) const = const_cast <cluster_map_t &> (m_cluster_map).get (base_reg)) return *slot; else - return NULL; + return nullptr; } -/* Get the cluster for BASE_REG, or NULL (non-const version). */ +/* Get the cluster for BASE_REG, or nullptr (non-const version). */ binding_cluster * store::get_cluster (const region *base_reg) @@ -3121,7 +3121,7 @@ store::get_cluster (const region *base_reg) if (binding_cluster **slot = m_cluster_map.get (base_reg)) return *slot; else - return NULL; + return nullptr; } /* Get the cluster for BASE_REG, creating it if doesn't already exist. */ @@ -3321,9 +3321,9 @@ store::remove_overlapping_bindings (store_manager *mgr, const region *reg, delete cluster; return; } - /* Pass NULL for the maybe_live_values here, as we don't want to + /* Pass nullptr for the maybe_live_values here, as we don't want to record the old svalues as being maybe-bound. */ - cluster->remove_overlapping_bindings (mgr, reg, uncertainty, NULL); + cluster->remove_overlapping_bindings (mgr, reg, uncertainty, nullptr); } } @@ -3566,7 +3566,7 @@ store::replay_call_summary_cluster (call_summary_replay &r, caller_sval = reg_mgr->get_or_create_unknown_svalue (summary_sval->get_type ()); set_value (mgr, caller_dest_reg, - caller_sval, NULL /* uncertainty_t * */); + caller_sval, nullptr /* uncertainty_t * */); } break; @@ -3591,7 +3591,7 @@ store::replay_call_summary_cluster (call_summary_replay &r, caller_sval = reg_mgr->get_or_create_unknown_svalue (summary_sval->get_type ()); set_value (mgr, caller_dest_reg, - caller_sval, NULL /* uncertainty_t * */); + caller_sval, nullptr /* uncertainty_t * */); } break; @@ -3786,7 +3786,7 @@ assert_disjoint (const location &loc, static void test_binding_key_overlap () { - store_manager mgr (NULL); + store_manager mgr (nullptr); /* Various 8-bit bindings. */ const concrete_binding *cb_0_7 = mgr.get_concrete_binding (0, 8); diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h index 171324c..95d38e3 100644 --- a/gcc/analyzer/store.h +++ b/gcc/analyzer/store.h @@ -222,9 +222,9 @@ public: static int cmp (const binding_key *, const binding_key *); virtual const concrete_binding *dyn_cast_concrete_binding () const - { return NULL; } + { return nullptr; } virtual const symbolic_binding *dyn_cast_symbolic_binding () const - { return NULL; } + { return nullptr; } }; /* A concrete range of bits. */ @@ -299,6 +299,16 @@ struct bit_range bool as_byte_range (byte_range *out) const; + bool + operator< (const bit_range &other) const + { + if (m_start_bit_offset < other.m_start_bit_offset) + return true; + if (m_start_bit_offset > other.m_start_bit_offset) + return false; + return (m_size_in_bits < other.m_size_in_bits); + } + bit_offset_t m_start_bit_offset; bit_size_t m_size_in_bits; }; @@ -482,10 +492,10 @@ public: static int cmp_ptr_ptr (const void *, const void *); void mark_deleted () { m_region = reinterpret_cast<const region *> (1); } - void mark_empty () { m_region = NULL; } + void mark_empty () { m_region = nullptr; } bool is_deleted () const { return m_region == reinterpret_cast<const region *> (1); } - bool is_empty () const { return m_region == NULL; } + bool is_empty () const { return m_region == nullptr; } private: const region *m_region; @@ -528,7 +538,7 @@ public: if (slot) return *slot; else - return NULL; + return nullptr; } bool put (const binding_key *k, const svalue *v) { diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc index de2c330..8592db7 100644 --- a/gcc/analyzer/supergraph.cc +++ b/gcc/analyzer/supergraph.cc @@ -48,7 +48,7 @@ get_ultimate_function_for_cgraph_edge (cgraph_edge *edge) { cgraph_node *ultimate_node = edge->callee->ultimate_alias_target (); if (!ultimate_node) - return NULL; + return nullptr; return ultimate_node->get_fun (); } @@ -59,15 +59,15 @@ supergraph_call_edge (function *fun, const gimple *stmt) { const gcall *call = dyn_cast<const gcall *> (stmt); if (!call) - return NULL; + return nullptr; cgraph_edge *edge = cgraph_node::get (fun->decl)->get_edge (const_cast <gimple *> (stmt)); if (!edge) - return NULL; + return nullptr; if (!edge->callee) - return NULL; /* e.g. for a function pointer. */ + return nullptr; /* e.g. for a function pointer. */ if (!get_ultimate_function_for_cgraph_edge (edge)) - return NULL; + return nullptr; return edge; } @@ -146,7 +146,8 @@ supergraph::supergraph (logger *logger) FOR_ALL_BB_FN (bb, fun) { /* The initial supernode for the BB gets the phi nodes (if any). */ - supernode *node_for_stmts = add_node (fun, bb, NULL, phi_nodes (bb)); + supernode *node_for_stmts + = add_node (fun, bb, nullptr, phi_nodes (bb)); m_bb_to_initial_node.put (bb, node_for_stmts); for (gphi_iterator gpi = gsi_start_phis (bb); !gsi_end_p (gpi); gsi_next (&gpi)) @@ -171,12 +172,12 @@ supergraph::supergraph (logger *logger) m_stmt_to_node_t.put (stmt, node_for_stmts); m_stmt_uids.make_uid_unique (stmt); if (cgraph_edge *edge = supergraph_call_edge (fun, stmt)) - { - m_cgraph_edge_to_caller_prev_node.put(edge, node_for_stmts); - node_for_stmts = add_node (fun, bb, as_a <gcall *> (stmt), - NULL); - m_cgraph_edge_to_caller_next_node.put (edge, node_for_stmts); - } + { + m_cgraph_edge_to_caller_prev_node.put(edge, node_for_stmts); + node_for_stmts = add_node (fun, bb, as_a <gcall *> (stmt), + nullptr); + m_cgraph_edge_to_caller_next_node.put (edge, node_for_stmts); + } else { // maybe call is via a function pointer @@ -187,13 +188,13 @@ supergraph::supergraph (logger *logger) if (!edge || !edge->callee) { supernode *old_node_for_stmts = node_for_stmts; - node_for_stmts = add_node (fun, bb, call, NULL); + node_for_stmts = add_node (fun, bb, call, nullptr); superedge *sedge = new callgraph_superedge (old_node_for_stmts, node_for_stmts, SUPEREDGE_INTRAPROCEDURAL_CALL, - NULL); + nullptr); add_edge (sedge); } } @@ -984,25 +985,25 @@ superedge::to_json () const } /* If this is an intraprocedural superedge, return the associated - CFG edge. Otherwise, return NULL. */ + CFG edge. Otherwise, return nullptr. */ ::edge superedge::get_any_cfg_edge () const { if (const cfg_superedge *sub = dyn_cast_cfg_superedge ()) return sub->get_cfg_edge (); - return NULL; + return nullptr; } /* If this is an interprocedural superedge, return the associated - cgraph_edge *. Otherwise, return NULL. */ + cgraph_edge *. Otherwise, return nullptr. */ cgraph_edge * superedge::get_any_callgraph_edge () const { if (const callgraph_superedge *sub = dyn_cast_callgraph_superedge ()) return sub->m_cedge; - return NULL; + return nullptr; } /* Build a description of this superedge (e.g. "true" for the true diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h index 8796ab7..f64a2f4 100644 --- a/gcc/analyzer/supergraph.h +++ b/gcc/analyzer/supergraph.h @@ -274,7 +274,7 @@ class supernode : public dnode<supergraph_traits> i.ptr = gimple_seq_first (*pseq); i.seq = pseq; - i.bb = i.ptr ? gimple_bb (i.ptr) : NULL; + i.bb = i.ptr ? gimple_bb (i.ptr) : nullptr; return i; } @@ -287,15 +287,15 @@ class supernode : public dnode<supergraph_traits> gimple *get_last_stmt () const { if (m_stmts.length () == 0) - return NULL; + return nullptr; return m_stmts[m_stmts.length () - 1]; } gcall *get_final_call () const { gimple *stmt = get_last_stmt (); - if (stmt == NULL) - return NULL; + if (stmt == nullptr) + return nullptr; return dyn_cast<gcall *> (stmt); } @@ -331,18 +331,18 @@ class superedge : public dedge<supergraph_traits> enum edge_kind get_kind () const { return m_kind; } - virtual cfg_superedge *dyn_cast_cfg_superedge () { return NULL; } - virtual const cfg_superedge *dyn_cast_cfg_superedge () const { return NULL; } - virtual const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const { return NULL; } + virtual cfg_superedge *dyn_cast_cfg_superedge () { return nullptr; } + virtual const cfg_superedge *dyn_cast_cfg_superedge () const { return nullptr; } + virtual const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const { return nullptr; } virtual const eh_dispatch_cfg_superedge *dyn_cast_eh_dispatch_cfg_superedge () const { return nullptr; } virtual const eh_dispatch_try_cfg_superedge *dyn_cast_eh_dispatch_try_cfg_superedge () const { return nullptr; } virtual const eh_dispatch_allowed_cfg_superedge *dyn_cast_eh_dispatch_allowed_cfg_superedge () const { return nullptr; } - virtual callgraph_superedge *dyn_cast_callgraph_superedge () { return NULL; } - virtual const callgraph_superedge *dyn_cast_callgraph_superedge () const { return NULL; } - virtual call_superedge *dyn_cast_call_superedge () { return NULL; } - virtual const call_superedge *dyn_cast_call_superedge () const { return NULL; } - virtual return_superedge *dyn_cast_return_superedge () { return NULL; } - virtual const return_superedge *dyn_cast_return_superedge () const { return NULL; } + virtual callgraph_superedge *dyn_cast_callgraph_superedge () { return nullptr; } + virtual const callgraph_superedge *dyn_cast_callgraph_superedge () const { return nullptr; } + virtual call_superedge *dyn_cast_call_superedge () { return nullptr; } + virtual const call_superedge *dyn_cast_call_superedge () const { return nullptr; } + virtual return_superedge *dyn_cast_return_superedge () { return nullptr; } + virtual const return_superedge *dyn_cast_return_superedge () const { return nullptr; } ::edge get_any_cfg_edge () const; cgraph_edge *get_any_callgraph_edge () const; @@ -594,7 +594,7 @@ template <> inline bool is_a_helper <const switch_cfg_superedge *>::test (const superedge *sedge) { - return sedge->dyn_cast_switch_cfg_superedge () != NULL; + return sedge->dyn_cast_switch_cfg_superedge () != nullptr; } namespace ana { @@ -653,7 +653,7 @@ template <> inline bool is_a_helper <const eh_dispatch_cfg_superedge *>::test (const superedge *sedge) { - return sedge->dyn_cast_eh_dispatch_cfg_superedge () != NULL; + return sedge->dyn_cast_eh_dispatch_cfg_superedge () != nullptr; } namespace ana { @@ -703,7 +703,7 @@ template <> inline bool is_a_helper <const eh_dispatch_try_cfg_superedge *>::test (const superedge *sedge) { - return sedge->dyn_cast_eh_dispatch_try_cfg_superedge () != NULL; + return sedge->dyn_cast_eh_dispatch_try_cfg_superedge () != nullptr; } namespace ana { @@ -753,7 +753,7 @@ template <> inline bool is_a_helper <const eh_dispatch_allowed_cfg_superedge *>::test (const superedge *sedge) { - return sedge->dyn_cast_eh_dispatch_allowed_cfg_superedge () != NULL; + return sedge->dyn_cast_eh_dispatch_allowed_cfg_superedge () != nullptr; } namespace ana { diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc index f3f80d1..fbbd1d2 100644 --- a/gcc/analyzer/svalue.cc +++ b/gcc/analyzer/svalue.cc @@ -247,7 +247,7 @@ svalue::maybe_get_constant () const } /* If this svalue is a region_svalue, return the region it points to. - Otherwise return NULL. */ + Otherwise return nullptr. */ const region * svalue::maybe_get_region () const @@ -255,12 +255,12 @@ svalue::maybe_get_region () const if (const region_svalue *region_sval = dyn_cast_region_svalue ()) return region_sval->get_pointee (); else - return NULL; + return nullptr; } /* If this svalue is a cast (i.e a unaryop NOP_EXPR or VIEW_CONVERT_EXPR), return the underlying svalue. - Otherwise return NULL. */ + Otherwise return nullptr. */ const svalue * svalue::maybe_undo_cast () const @@ -271,7 +271,7 @@ svalue::maybe_undo_cast () const if (op == NOP_EXPR || op == VIEW_CONVERT_EXPR) return unaryop_sval->get_arg (); } - return NULL; + return nullptr; } /* If this svalue is an unmergeable decorator around another svalue, return @@ -287,7 +287,7 @@ svalue::unwrap_any_unmergeable () const } /* Attempt to merge THIS with OTHER, returning the merged svalue. - Return NULL if not mergeable. */ + Return nullptr if not mergeable. */ const svalue * svalue::can_merge_p (const svalue *other, @@ -295,22 +295,22 @@ svalue::can_merge_p (const svalue *other, model_merger *merger) const { if (!(get_type () && other->get_type ())) - return NULL; + return nullptr; if (!types_compatible_p (get_type (), other->get_type ())) - return NULL; + return nullptr; /* Reject attempts to merge unmergeable svalues. */ if ((get_kind () == SK_UNMERGEABLE) || (other->get_kind () == SK_UNMERGEABLE)) - return NULL; + return nullptr; /* Reject attempts to merge poisoned svalues with other svalues (either non-poisoned, or other kinds of poison), so that e.g. we identify paths in which a variable is conditionally uninitialized. */ if (get_kind () == SK_POISONED || other->get_kind () == SK_POISONED) - return NULL; + return nullptr; /* Reject attempts to merge NULL pointers with not-NULL-pointers. */ if (POINTER_TYPE_P (get_type ())) @@ -324,16 +324,16 @@ svalue::can_merge_p (const svalue *other, if (zerop (cst1)) null1 = true; if (null0 != null1) - return NULL; + return nullptr; } /* Reject merging svalues that have non-purgable sm-state, to avoid falsely reporting memory leaks by merging them with something else. */ if (!merger->mergeable_svalue_p (this)) - return NULL; + return nullptr; if (!merger->mergeable_svalue_p (other)) - return NULL; + return nullptr; /* Widening. */ /* Merge: (new_cst, existing_cst) -> widen (existing, new). */ @@ -410,7 +410,7 @@ svalue::can_merge_p (const svalue *other, /* Determine if this svalue is either within LIVE_SVALUES, or is implicitly live with respect to LIVE_SVALUES and MODEL. - LIVE_SVALUES can be NULL, in which case determine if this svalue is + LIVE_SVALUES can be nullptr, in which case determine if this svalue is intrinsically live. */ bool @@ -806,7 +806,7 @@ svalue::maybe_fold_bits_within (tree, region_model_manager *) const { /* By default, don't fold. */ - return NULL; + return nullptr; } /* Base implementation of svalue::all_zeroes_p. @@ -819,7 +819,7 @@ svalue::all_zeroes_p () const } /* If this svalue is a pointer, attempt to determine the base region it points - to. Return NULL on any problems. */ + to. Return nullptr on any problems. */ const region * svalue::maybe_get_deref_base_region () const @@ -830,7 +830,7 @@ svalue::maybe_get_deref_base_region () const switch (iter->get_kind ()) { default: - return NULL; + return nullptr; case SK_REGION: { @@ -852,9 +852,9 @@ svalue::maybe_get_deref_base_region () const continue; default: - return NULL; + return nullptr; } - return NULL; + return nullptr; } } } @@ -1147,7 +1147,7 @@ constant_svalue::maybe_fold_bits_within (tree type, } /* Otherwise, don't fold. */ - return NULL; + return nullptr; } /* Implementation of svalue::all_zeroes_p for constant_svalue. */ @@ -1374,7 +1374,7 @@ initial_svalue::implicitly_live_p (const svalue_set *, a popped stack frame. */ if (model->region_exists_p (m_reg)) { - const svalue *reg_sval = model->get_store_value (m_reg, NULL); + const svalue *reg_sval = model->get_store_value (m_reg, nullptr); if (reg_sval == this) return true; } @@ -1384,7 +1384,7 @@ initial_svalue::implicitly_live_p (const svalue_set *, live in the external caller. */ if (initial_value_of_param_p ()) if (const frame_region *frame_reg = m_reg->maybe_get_frame_region ()) - if (frame_reg->get_calling_frame () == NULL) + if (frame_reg->get_calling_frame () == nullptr) return true; return false; @@ -1508,7 +1508,7 @@ unaryop_svalue::maybe_fold_bits_within (tree type, break; } /* Otherwise, don't fold. */ - return NULL; + return nullptr; } /* class binop_svalue : public svalue. */ @@ -1837,7 +1837,7 @@ repeated_svalue::maybe_fold_bits_within (tree type, } } - return NULL; + return nullptr; } /* class bits_within_svalue : public svalue. */ @@ -2393,7 +2393,7 @@ compound_svalue::maybe_fold_bits_within (tree type, } else /* If we have any symbolic keys we can't get it as bits. */ - return NULL; + return nullptr; } return mgr->get_or_create_compound_svalue (type, result_map); } diff --git a/gcc/analyzer/svalue.h b/gcc/analyzer/svalue.h index 7a27cb6..0ccb5ce 100644 --- a/gcc/analyzer/svalue.h +++ b/gcc/analyzer/svalue.h @@ -112,37 +112,37 @@ public: const char *prefix = nullptr) const; virtual const region_svalue * - dyn_cast_region_svalue () const { return NULL; } + dyn_cast_region_svalue () const { return nullptr; } virtual const constant_svalue * - dyn_cast_constant_svalue () const { return NULL; } + dyn_cast_constant_svalue () const { return nullptr; } virtual const poisoned_svalue * - dyn_cast_poisoned_svalue () const { return NULL; } + dyn_cast_poisoned_svalue () const { return nullptr; } virtual const setjmp_svalue * - dyn_cast_setjmp_svalue () const { return NULL; } + dyn_cast_setjmp_svalue () const { return nullptr; } virtual const initial_svalue * - dyn_cast_initial_svalue () const { return NULL; } + dyn_cast_initial_svalue () const { return nullptr; } virtual const unaryop_svalue * - dyn_cast_unaryop_svalue () const { return NULL; } + dyn_cast_unaryop_svalue () const { return nullptr; } virtual const binop_svalue * - dyn_cast_binop_svalue () const { return NULL; } + dyn_cast_binop_svalue () const { return nullptr; } virtual const sub_svalue * - dyn_cast_sub_svalue () const { return NULL; } + dyn_cast_sub_svalue () const { return nullptr; } virtual const repeated_svalue * - dyn_cast_repeated_svalue () const { return NULL; } + dyn_cast_repeated_svalue () const { return nullptr; } virtual const bits_within_svalue * - dyn_cast_bits_within_svalue () const { return NULL; } + dyn_cast_bits_within_svalue () const { return nullptr; } virtual const unmergeable_svalue * - dyn_cast_unmergeable_svalue () const { return NULL; } + dyn_cast_unmergeable_svalue () const { return nullptr; } virtual const widening_svalue * - dyn_cast_widening_svalue () const { return NULL; } + dyn_cast_widening_svalue () const { return nullptr; } virtual const compound_svalue * - dyn_cast_compound_svalue () const { return NULL; } + dyn_cast_compound_svalue () const { return nullptr; } virtual const conjured_svalue * - dyn_cast_conjured_svalue () const { return NULL; } + dyn_cast_conjured_svalue () const { return nullptr; } virtual const asm_output_svalue * - dyn_cast_asm_output_svalue () const { return NULL; } + dyn_cast_asm_output_svalue () const { return nullptr; } virtual const const_fn_result_svalue * - dyn_cast_const_fn_result_svalue () const { return NULL; } + dyn_cast_const_fn_result_svalue () const { return nullptr; } tree maybe_get_constant () const; const region *maybe_get_region () const; @@ -246,7 +246,7 @@ public: : svalue (complexity (reg), id, type), m_reg (reg) { - gcc_assert (m_reg != NULL); + gcc_assert (m_reg != nullptr); } enum svalue_kind get_kind () const final override { return SK_REGION; } @@ -650,7 +650,7 @@ public: initial_svalue (symbol::id_t id, tree type, const region *reg) : svalue (complexity (reg), id, type), m_reg (reg) { - gcc_assert (m_reg != NULL); + gcc_assert (m_reg != nullptr); } enum svalue_kind get_kind () const final override { return SK_INITIAL; } @@ -1547,15 +1547,15 @@ public: && m_idx == other.m_idx); } - /* Use m_stmt to mark empty/deleted, as m_type can be NULL for + /* Use m_stmt to mark empty/deleted, as m_type can be NULL_TREE for legitimate instances. */ void mark_deleted () { m_stmt = reinterpret_cast<const gimple *> (1); } - void mark_empty () { m_stmt = NULL; } + void mark_empty () { m_stmt = nullptr; } bool is_deleted () const { return m_stmt == reinterpret_cast<const gimple *> (1); } - bool is_empty () const { return m_stmt == NULL; } + bool is_empty () const { return m_stmt == nullptr; } tree m_type; const gimple *m_stmt; @@ -1568,7 +1568,7 @@ public: : svalue (complexity (id_reg), id, type), m_stmt (stmt), m_id_reg (id_reg), m_idx (idx) { - gcc_assert (m_stmt != NULL); + gcc_assert (m_stmt != nullptr); } enum svalue_kind get_kind () const final override { return SK_CONJURED; } @@ -1668,15 +1668,15 @@ public: return true; } - /* Use m_asm_string to mark empty/deleted, as m_type can be NULL for + /* Use m_asm_string to mark empty/deleted, as m_type can be NULL_TREE for legitimate instances. */ void mark_deleted () { m_asm_string = reinterpret_cast<const char *> (1); } - void mark_empty () { m_asm_string = NULL; } + void mark_empty () { m_asm_string = nullptr; } bool is_deleted () const { return m_asm_string == reinterpret_cast<const char *> (1); } - bool is_empty () const { return m_asm_string == NULL; } + bool is_empty () const { return m_asm_string == nullptr; } tree m_type; const char *m_asm_string; @@ -1813,12 +1813,12 @@ public: /* Use m_fndecl to mark empty/deleted. */ void mark_deleted () { m_fndecl = reinterpret_cast<tree> (1); } - void mark_empty () { m_fndecl = NULL; } + void mark_empty () { m_fndecl = NULL_TREE; } bool is_deleted () const { return m_fndecl == reinterpret_cast<tree> (1); } - bool is_empty () const { return m_fndecl == NULL; } + bool is_empty () const { return m_fndecl == NULL_TREE; } tree m_type; tree m_fndecl; diff --git a/gcc/analyzer/varargs.cc b/gcc/analyzer/varargs.cc index 6ea0d29..4947271 100644 --- a/gcc/analyzer/varargs.cc +++ b/gcc/analyzer/varargs.cc @@ -205,7 +205,11 @@ public: { return s != m_started; } - std::unique_ptr<pending_diagnostic> on_leak (tree var) const final override; + + std::unique_ptr<pending_diagnostic> + on_leak (tree var, + const program_state *old_state, + const program_state *new_state) const final override; /* State for a va_list that is the result of a va_start or va_copy. */ state_t m_started; @@ -294,15 +298,15 @@ get_stateful_arg (sm_context &sm_ctxt, const gcall &call, unsigned arg_idx) if (const program_state *new_state = sm_ctxt.get_new_program_state ()) { const region_model *new_model = new_state->m_region_model; - const svalue *ptr_sval = new_model->get_rvalue (ap, NULL); - const region *reg = new_model->deref_rvalue (ptr_sval, ap, NULL); - const svalue *impl_sval = new_model->get_store_value (reg, NULL); + const svalue *ptr_sval = new_model->get_rvalue (ap, nullptr); + const region *reg = new_model->deref_rvalue (ptr_sval, ap, nullptr); + const svalue *impl_sval = new_model->get_store_value (reg, nullptr); if (const svalue *cast = impl_sval->maybe_undo_cast ()) impl_sval = cast; return impl_sval; } } - return NULL; + return nullptr; } /* Abstract class for diagnostics relating to va_list_state_machine. */ @@ -335,11 +339,11 @@ public: const final override { if (change.m_new_state == m_sm.m_started) - return diagnostic_event::meaning (diagnostic_event::VERB_acquire, - diagnostic_event::NOUN_resource); + return diagnostic_event::meaning (diagnostic_event::verb::acquire, + diagnostic_event::noun::resource); if (change.m_new_state == m_sm.m_ended) - return diagnostic_event::meaning (diagnostic_event::VERB_release, - diagnostic_event::NOUN_resource); + return diagnostic_event::meaning (diagnostic_event::verb::release, + diagnostic_event::noun::resource); return diagnostic_event::meaning (); } @@ -366,7 +370,7 @@ protected: return "va_end"; } } - return NULL; + return nullptr; } const va_list_state_machine &m_sm; @@ -460,10 +464,14 @@ class va_list_leak : public va_list_sm_diagnostic { public: va_list_leak (const va_list_state_machine &sm, - const svalue *ap_sval, tree ap_tree) + const svalue *ap_sval, tree ap_tree, + const program_state *final_state) : va_list_sm_diagnostic (sm, ap_sval, ap_tree), - m_start_event_fnname (NULL) + m_start_event_fnname (nullptr), + m_final_state () { + if (final_state) + m_final_state = std::make_unique<program_state> (*final_state); } int get_controlling_option () const final override @@ -524,9 +532,16 @@ public: return true; } + const program_state * + get_final_state () const final override + { + return m_final_state.get (); + } + private: diagnostic_event_id_t m_start_event; const char *m_start_event_fnname; + std::unique_ptr<program_state> m_final_state; }; /* Update state machine for a "va_start" call. */ @@ -562,7 +577,7 @@ va_list_state_machine::check_for_ended_va_list (sm_context &sm_ctxt, /* Get the svalue with associated va_list_state_machine state for ARG_IDX of CALL to va_copy, if SM_CTXT supports this, - or NULL otherwise. */ + or nullptr otherwise. */ static const svalue * get_stateful_va_copy_arg (sm_context &sm_ctxt, @@ -572,10 +587,10 @@ get_stateful_va_copy_arg (sm_context &sm_ctxt, if (const program_state *new_state = sm_ctxt.get_new_program_state ()) { const region_model *new_model = new_state->m_region_model; - const svalue *arg = get_va_copy_arg (new_model, NULL, call, arg_idx); + const svalue *arg = get_va_copy_arg (new_model, nullptr, call, arg_idx); return arg; } - return NULL; + return nullptr; } /* Update state machine for a "va_copy" call. */ @@ -633,9 +648,11 @@ va_list_state_machine::on_va_end (sm_context &sm_ctxt, (for complaining about leaks of values in state 'started'). */ std::unique_ptr<pending_diagnostic> -va_list_state_machine::on_leak (tree var) const +va_list_state_machine::on_leak (tree var, + const program_state *, + const program_state *new_state) const { - return std::make_unique<va_list_leak> (*this, nullptr, var); + return std::make_unique<va_list_leak> (*this, nullptr, var, new_state); } } // anonymous namespace @@ -723,7 +740,7 @@ kf_va_copy::impl_call_pre (const call_details &cd) const in_va_list = model->check_for_poison (in_va_list, get_va_list_diag_arg (cd.get_arg_tree (1)), - NULL, + nullptr, cd.get_ctxt ()); const region *out_dst_reg @@ -1003,14 +1020,14 @@ va_arg_compatible_types_p (tree lhs_type, tree arg_type, const svalue &arg_sval) } /* If AP_SVAL is a pointer to a var_arg_region, return that var_arg_region. - Otherwise return NULL. */ + Otherwise return nullptr. */ static const var_arg_region * maybe_get_var_arg_region (const svalue *ap_sval) { if (const region *reg = ap_sval->maybe_get_region ()) return reg->dyn_cast_var_arg_region (); - return NULL; + return nullptr; } /* Handler for "__builtin_va_arg". */ |