aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/analyzer')
-rw-r--r--gcc/analyzer/ChangeLog845
-rw-r--r--gcc/analyzer/access-diagram.cc93
-rw-r--r--gcc/analyzer/access-diagram.h4
-rw-r--r--gcc/analyzer/ana-state-to-diagnostic-state.cc689
-rw-r--r--gcc/analyzer/ana-state-to-diagnostic-state.h106
-rw-r--r--gcc/analyzer/analysis-plan.cc20
-rw-r--r--gcc/analyzer/analyzer-language.cc12
-rw-r--r--gcc/analyzer/analyzer-language.h2
-rw-r--r--gcc/analyzer/analyzer-logging.h19
-rw-r--r--gcc/analyzer/analyzer-pass.cc27
-rw-r--r--gcc/analyzer/analyzer-selftests.cc8
-rw-r--r--gcc/analyzer/analyzer.cc78
-rw-r--r--gcc/analyzer/analyzer.opt4
-rw-r--r--gcc/analyzer/analyzer.opt.urls3
-rw-r--r--gcc/analyzer/bounds-checking.cc151
-rw-r--r--gcc/analyzer/call-details.cc143
-rw-r--r--gcc/analyzer/call-details.h14
-rw-r--r--gcc/analyzer/call-info.cc40
-rw-r--r--gcc/analyzer/call-info.h8
-rw-r--r--gcc/analyzer/call-string.cc33
-rw-r--r--gcc/analyzer/call-string.h8
-rw-r--r--gcc/analyzer/call-summary.cc96
-rw-r--r--gcc/analyzer/call-summary.h6
-rw-r--r--gcc/analyzer/checker-event.cc361
-rw-r--r--gcc/analyzer/checker-event.h320
-rw-r--r--gcc/analyzer/checker-path.cc70
-rw-r--r--gcc/analyzer/checker-path.h37
-rw-r--r--gcc/analyzer/common.h (renamed from gcc/analyzer/analyzer.h)69
-rw-r--r--gcc/analyzer/complexity.cc28
-rw-r--r--gcc/analyzer/constraint-manager.cc125
-rw-r--r--gcc/analyzer/constraint-manager.h10
-rw-r--r--gcc/analyzer/diagnostic-manager.cc414
-rw-r--r--gcc/analyzer/diagnostic-manager.h7
-rw-r--r--gcc/analyzer/engine.cc956
-rw-r--r--gcc/analyzer/exploded-graph.h98
-rw-r--r--gcc/analyzer/feasible-graph.cc28
-rw-r--r--gcc/analyzer/function-set.cc2
-rw-r--r--gcc/analyzer/infinite-loop.cc106
-rw-r--r--gcc/analyzer/infinite-recursion.cc83
-rw-r--r--gcc/analyzer/inlining-iterator.h4
-rw-r--r--gcc/analyzer/kf-analyzer.cc66
-rw-r--r--gcc/analyzer/kf-lang-cp.cc198
-rw-r--r--gcc/analyzer/kf.cc403
-rw-r--r--gcc/analyzer/known-function-manager.cc29
-rw-r--r--gcc/analyzer/pending-diagnostic.cc83
-rw-r--r--gcc/analyzer/pending-diagnostic.h40
-rw-r--r--gcc/analyzer/program-point.cc73
-rw-r--r--gcc/analyzer/program-point.h10
-rw-r--r--gcc/analyzer/program-state.cc240
-rw-r--r--gcc/analyzer/program-state.h42
-rw-r--r--gcc/analyzer/ranges.cc34
-rw-r--r--gcc/analyzer/record-layout.cc18
-rw-r--r--gcc/analyzer/record-layout.h9
-rw-r--r--gcc/analyzer/region-model-asm.cc29
-rw-r--r--gcc/analyzer/region-model-manager.cc84
-rw-r--r--gcc/analyzer/region-model-manager.h2
-rw-r--r--gcc/analyzer/region-model-reachability.cc37
-rw-r--r--gcc/analyzer/region-model.cc1310
-rw-r--r--gcc/analyzer/region-model.h181
-rw-r--r--gcc/analyzer/region.cc105
-rw-r--r--gcc/analyzer/region.h56
-rw-r--r--gcc/analyzer/sm-fd.cc464
-rw-r--r--gcc/analyzer/sm-file.cc144
-rw-r--r--gcc/analyzer/sm-malloc.cc316
-rw-r--r--gcc/analyzer/sm-pattern-test.cc24
-rw-r--r--gcc/analyzer/sm-sensitive.cc42
-rw-r--r--gcc/analyzer/sm-signal.cc73
-rw-r--r--gcc/analyzer/sm-taint.cc103
-rw-r--r--gcc/analyzer/sm.cc91
-rw-r--r--gcc/analyzer/sm.h46
-rw-r--r--gcc/analyzer/state-purge.cc37
-rw-r--r--gcc/analyzer/state-purge.h2
-rw-r--r--gcc/analyzer/store.cc141
-rw-r--r--gcc/analyzer/store.h24
-rw-r--r--gcc/analyzer/supergraph.cc326
-rw-r--r--gcc/analyzer/supergraph.h197
-rw-r--r--gcc/analyzer/svalue.cc108
-rw-r--r--gcc/analyzer/svalue.h73
-rw-r--r--gcc/analyzer/symbol.cc7
-rw-r--r--gcc/analyzer/trimmed-graph.cc17
-rw-r--r--gcc/analyzer/varargs.cc164
81 files changed, 7077 insertions, 3498 deletions
diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog
index 443dc6d..aca8186 100644
--- a/gcc/analyzer/ChangeLog
+++ b/gcc/analyzer/ChangeLog
@@ -1,3 +1,848 @@
+2025-08-29 David Malcolm <dmalcolm@redhat.com>
+
+ * pending-diagnostic.cc: Include "diagnostics/logging.h".
+ (diagnostic_emission_context::warn): Add logging.
+ (diagnostic_emission_context::inform): Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * program-point.cc: Make diagnostics::context::m_source_printing
+ private.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * pending-diagnostic.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+ * program-point.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * program-point.cc: : Update for diagnostic_context becoming
+ diagnostics::context, and for diagnostic_source_print_policy
+ becoming diagnostics::source_print_policy.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * ana-state-to-diagnostic-state.cc: Update for move of
+ diagnostics output formats into namespace "diagnostics" as
+ "sinks".
+ * bounds-checking.cc: Likewise.
+ * call-details.cc: Likewise.
+ * checker-event.cc: Likewise.
+ * checker-event.h: Likewise.
+ * diagnostic-manager.cc: Likewise.
+ * diagnostic-manager.h: Likewise.
+ * infinite-loop.cc: Likewise.
+ * infinite-recursion.cc: Likewise.
+ * pending-diagnostic.h: Likewise.
+ * region-model.cc: Likewise.
+ * sm-taint.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * access-diagram.cc: Update for changes to diagnostic paths:
+ "diagnostic-path.h" moving to "diagnostics/paths.h",
+ "diagnostic-event-id.h" moving to "diagnostics/event-id.h",
+ diagnostic_event_id_t to diagnostics::paths::event_id_t,
+ diagnostic_path to diagnostics::paths::path, and
+ diagnostic_event to diagnostics::paths::event.
+ * access-diagram.h: Likewise.
+ * analyzer.cc: Likewise.
+ * bounds-checking.cc: Likewise.
+ * call-info.cc: Likewise.
+ * checker-event.cc: Likewise.
+ * checker-event.h: Likewise.
+ * checker-path.cc: Likewise.
+ * checker-path.h: Likewise.
+ * common.h: Likewise.
+ * diagnostic-manager.cc: Likewise.
+ * pending-diagnostic.cc: Likewise.
+ * pending-diagnostic.h: Likewise.
+ * program-point.cc: Likewise.
+ * program-state.cc: Likewise.
+ * region-model.cc: Likewise.
+ * sm-fd.cc: Likewise.
+ * sm-file.cc: Likewise.
+ * sm-malloc.cc: Likewise.
+ * sm-pattern-test.cc: Likewise.
+ * sm-sensitive.cc: Likewise.
+ * sm-signal.cc: Likewise.
+ * sm-taint.cc: Likewise.
+ * varargs.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * bounds-checking.cc: Update #include for move of
+ "diagnostic-diagram.h" to "diagnostics/diagram.h". Update for
+ move of diagnostic_diagram to diagnostics::diagram.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic-manager.cc: Update for move of diagnostic_metadata to
+ diagnostics::metadata.
+ * kf.cc: Likewise.
+ * pending-diagnostic.h: Likewise; also, update #include for move
+ of "diagnostic-metadata.h" to "diagnostics/metadata.h".
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * checker-event.h (checker_event::get_logical_location): Update
+ for conversion of logical_location to
+ diagnostics::logical_locations::key.
+ (checker_event::m_logical_loc): Likewise.
+ * diagnostic-manager.cc
+ (diagnostic_manager::get_logical_location_manager): Likewise.
+ * diagnostic-manager.h
+ (diagnostic_manager::get_logical_location_manager): Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * ana-state-to-diagnostic-state.cc: Update #include for move of
+ "diagnostic-state-graphs.h" to "diagnostics/state-graphs.h".
+ * ana-state-to-diagnostic-state.h: Likewise.
+ * checker-event.cc: Likewise.
+ * checker-event.h: Update #include for move of
+ "diagnostic-digraphs.h" to "diagnostics/digraphs.h".
+ * program-state.cc: : Update #include for move of
+ "diagnostic-state-graphs.h" to "diagnostics/state-graphs.h".
+
+2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ * region-model-asm.cc (region_model::on_asm_stmt): Pass null
+ pointer to parse_{input,output}_constraint().
+
+2025-07-11 David Malcolm <dmalcolm@redhat.com>
+
+ * ana-state-to-diagnostic-state.cc: Reimplement, replacing
+ XML-based implementation with one based on state graphs.
+ * ana-state-to-diagnostic-state.h: Likewise.
+ * checker-event.cc: Replace include of "xml.h" with include of
+ "diagnostic-state-graphs.h".
+ (checker_event::maybe_make_xml_state): Replace with...
+ (checker_event::maybe_make_diagnostic_state_graph): ...this.
+ * checker-event.h: Add include of "diagnostic-digraphs.h".
+ (checker_event::maybe_make_xml_state): Replace decl with...
+ (checker_event::maybe_make_diagnostic_state_graph): ...this.
+ * engine.cc (exploded_node::on_stmt_pre): Replace
+ "_analyzer_dump_xml" with "__analyzer_dump_sarif".
+ * program-state.cc: Replace include of "diagnostic-state.h" with
+ "diagnostic-state-graphs.h".
+ (program_state::dump_dot): Port from XML to state graphs.
+ * program-state.h: Drop reduntant forward decl of xml::document.
+ (program_state::make_xml): Replace decl with...
+ (program_state::make_diagnostic_state_graph): ...this.
+ (program_state::dump_xml_to_pp): Drop decl.
+ (program_state::dump_xml_to_file): Drop decl.
+ (program_state::dump_xml): Drop decl.
+ (program_state::dump_dump_sarif): New decl.
+ * sm-malloc.cc (get_dynalloc_state_for_state): New.
+ (malloc_state_machine::add_state_to_xml): Replace with...
+ (malloc_state_machine::add_state_to_state_graph): ...this.
+ * sm.cc (state_machine::add_state_to_xml): Replace with...
+ (state_machine::add_state_to_state_graph): ...this.
+ (state_machine::add_global_state_to_xml): Replace with...
+ (state_machine::add_global_state_to_state_graph): ...this.
+ * sm.h (class xml_state): Drop forward decl.
+ (class analyzer_state_graph): New forward decl.
+ (state_machine::add_state_to_xml): Replace decl with...
+ (state_machine::add_state_to_state_graph): ...this.
+ (state_machine::add_global_state_to_xml): Replace decl with...
+ (state_machine::add_global_state_to_state_graph): ...this.
+
+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
+ initialization of m_logical_loc.
+ (checker_event::maybe_add_sarif_properties): Add "builder" param.
+ Replace call to make_sarif_logical_location_object with call to
+ sarif_property_bag::set_logical_location.
+ (superedge_event::maybe_add_sarif_properties): Add "builder"
+ param.
+ * checker-event.h (checker_event::get_logical_location):
+ Reimplement.
+ (checker_event::maybe_add_sarif_properties): Add "builder" param.
+ (checker_event::maybe_add_sarif_properties): Add "builder" param.
+ (checker_event::m_logical_loc): Convert from tree_logical_location
+ to logical_location.
+ (superedge_event::maybe_add_sarif_properties): Add sarif_builder
+ param.
+ * checker-path.h (checker_path::checker_path): Add logical_loc_mgr
+ param.
+ * diagnostic-manager.cc
+ (diagnostic_manager::emit_saved_diagnostic): Pass logical location
+ manager to emission_path ctor.
+ (diagnostic_manager::get_logical_location_manager): New.
+ * diagnostic-manager.h
+ (diagnostic_manager::get_logical_location_manager): New decl.
+
+2025-04-30 David Malcolm <dmalcolm@redhat.com>
+
+ * sm-malloc.cc (malloc_diagnostic::describe_state_change): Tweak
+ the "EXPR is NULL" message for the case where EXPR is a null
+ pointer.
+
+2025-04-29 Marc Poulhiès <dkm@kataplop.net>
+
+ * exploded-graph.h (set_status): Rename parameter.
+ * constraint-manager.cc (bound::ensure_closed): Likewise.
+ (range::add_bound): Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/111536
+ * engine.cc (maybe_update_for_edge): Update for new call_stmt
+ param to region_model::push_frame.
+ * program-state.cc (program_state::push_frame): Likewise.
+ * region-model.cc (region_model::update_for_gcall): Likewise.
+ (region_model::push_frame): Add "call_stmt" param.
+ Handle DECL_RESULT with DECL_BY_REFERENCE set on it by stashing
+ the region of the lhs of the call_stmt in the caller frame,
+ and writing a reference to it within the "result" in the callee
+ frame.
+ (region_model::pop_frame): Don't write back to the LHS for
+ DECL_BY_REFERENCE results.
+ (selftest::test_stack_frames): Update for new call_stmt param to
+ region_model::push_frame.
+ (selftest::test_get_representative_path_var): Likewise.
+ (selftest::test_state_merging): Likewise.
+ (selftest::test_alloca): Likewise.
+ * region-model.h (region_model::push_frame): Add "call_stmt"
+ param.
+ * region.cc: Include "tree-ssa.h".
+ (region::can_have_initial_svalue_p): Use ssa_defined_default_def_p
+ for ssa names, rather than special-casing it for just parameters.
+ This should now also cover DECL_RESULT with DECL_BY_REFERENCE and
+ hard registers.
+ * sm-signal.cc (update_model_for_signal_handler): Update for new
+ call_stmt param to region_model::push_frame.
+ * state-purge.cc (state_purge_per_decl::process_worklists):
+ Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/109366
+ * region-model-manager.cc
+ (region_model_manager::maybe_fold_sub_svalue): Sub-values of zero
+ constants are zero.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/97111
+ * analyzer.cc (is_cxa_throw_p): New.
+ (is_cxa_rethrow_p): New.
+ * analyzer.opt (Wanalyzer-throw-of-unexpected-type): New.
+ * analyzer.opt.urls: Regenerate.
+ * call-info.cc (custom_edge_info::create_enode): New.
+ * call-info.h (call_info::print): Drop "final".
+ (call_info::add_events_to_path): Likewise.
+ * checker-event.cc (event_kind_to_string): Add cases for
+ event_kind::catch_, event_kind::throw_, and event_kind::unwind.
+ (explicit_throw_event::print_desc): New.
+ (throw_from_call_to_external_fn_event::print_desc): New.
+ (unwind_event::print_desc): New.
+ * checker-event.h (enum class event_kind): Add catch_, throw_,
+ and unwind.
+ (class catch_cfg_edge_event): New.
+ (class throw_event): New.
+ (class explicit_throw_event): New.
+ (class throw_from_call_to_external_fn_event): New.
+ (class unwind_event): New.
+ * common.h (class eh_dispatch_cfg_superedge): New forward decl.
+ (class eh_dispatch_try_cfg_superedge): New forward decl.
+ (class eh_dispatch_allowed_cfg_superedge): New forward decl.
+ (custom_edge_info::create_enode): New vfunc decl.
+ (is_cxa_throw_p): New decl.
+ (is_cxa_rethrow_p): New decl.
+ * diagnostic-manager.cc
+ (diagnostic_manager::add_events_for_superedge): Special-case edges
+ for eh_dispach_try.
+ (diagnostic_manager::prune_path): Call consolidate_unwind_events.
+ (diagnostic_manager::prune_for_sm_diagnostic): Don't filter the new
+ event_kinds.
+ (diagnostic_manager::consolidate_unwind_events): New.
+ * diagnostic-manager.h
+ (diagnostic_manager::consolidate_unwind_events): New decl.
+ * engine.cc (exploded_node::on_stmt_pre): Handle "__cxa_throw",
+ "__cxa_rethrow", and resx statements.
+ (class throw_custom_edge): New.
+ (class unwind_custom_edge): New.
+ (get_eh_outedge): New.
+ (exploded_graph::unwind_from_exception): New.
+ (exploded_node::on_throw): New.
+ (exploded_node::on_resx): New.
+ (exploded_graph::get_or_create_node): Add "add_to_worklist" param
+ and use it.
+ (exploded_graph::process_node): Use edge_info's create_enode vfunc
+ to create enodes, rather than calling get_or_create_node directly.
+ Ignore CFG edges in the sgraph flagged with EH whilst we're
+ exploring the egraph.
+ (exploded_graph_annotator::print_enode): Handle case
+ exploded_node::status::special.
+ * exploded-graph.h (exploded_node::status): Add value "special".
+ (exploded_node::on_throw): New decl.
+ (exploded_node::on_resx): New decl.
+ (exploded_graph::get_or_create_node): Add optional
+ "add_to_worklist" param.
+ (exploded_graph::unwind_from_exception): New decl.
+ * kf-lang-cp.cc (class kf_cxa_allocate_exception): New.
+ (class kf_cxa_begin_catch): New.
+ (class kf_cxa_end_catch): New.
+ (class throw_of_unexpected_type): New.
+ (class kf_cxa_call_unexpected): New.
+ (register_known_functions_lang_cp): Register known functions
+ "__cxa_allocate_exception", "__cxa_begin_catch",
+ "__cxa_end_catch", and "__cxa_call_unexpected".
+ * kf.cc (class kf_eh_pointer): New.
+ (register_known_functions): Register it for BUILT_IN_EH_POINTER.
+ * region-model.cc: Include "analyzer/function-set.h".
+ (exception_node::operator==): New.
+ (exception_node::dump_to_pp): New.
+ (exception_node::dump): New.
+ (exception_node::to_json): New.
+ (exception_node::make_dump_widget): New.
+ (exception_node::maybe_get_type): New.
+ (exception_node::add_to_reachable_regions): New.
+ (region_model::region_model): Initialize
+ m_thrown_exceptions_stack and m_caught_exceptions_stack.
+ (region_model::operator=): Likewise.
+ (region_model::operator==): Compare them.
+ (region_model::dump_to_pp): Dump exception stacks.
+ (region_model::to_json): Add exception stacks.
+ (region_model::make_dump_widget): Likewise.
+ (class exception_thrown_from_unrecognized_call): New.
+ (get_fns_assumed_not_to_throw): New.
+ (can_throw_p): New.
+ (region_model::check_for_throw_inside_call): New.
+ (region_model::on_call_pre): Call check_for_throw_inside_call
+ on unknown fns or those we don't have a body for.
+ (region_model::maybe_update_for_edge): Handle eh_dispatch_stmt
+ statements. Drop old code that called
+ apply_constraints_for_exception on EDGE_EH edges.
+ (class rejected_eh_dispatch): New.
+ (exception_matches_type_p): New.
+ (matches_any_exception_type_p): New.
+ (region_model::apply_constraints_for_eh_dispatch): New.
+ (region_model::apply_constraints_for_eh_dispatch_try): New.
+ (region_model::apply_constraints_for_eh_dispatch_allowed): New.
+ (region_model::apply_constraints_for_exception): Delete.
+ (region_model::can_merge_with_p): Don't merge models with
+ non-equal exception stacks.
+ (region_model::get_referenced_base_regions): Add regions from
+ exception stacks.
+ * region-model.h (struct exception_node): New.
+ (region_model::push_thrown_exception): New.
+ (region_model::get_current_thrown_exception): New.
+ (region_model::pop_thrown_exception): New.
+ (region_model::push_caught_exception): New.
+ (region_model::get_current_caught_exception): New.
+ (region_model::pop_caught_exception): New.
+ (region_model::apply_constraints_for_eh_dispatch_try): New decl.
+ (region_model::apply_constraints_for_eh_dispatch_allowed) New decl.
+ (region_model::apply_constraints_for_exception): Delete.
+ (region_model::apply_constraints_for_eh_dispatch): New decl.
+ (region_model::check_for_throw_inside_call): New decl.
+ (region_model::m_thrown_exceptions_stack): New field.
+ (region_model::m_caught_exceptions_stack): New field.
+ * supergraph.cc: Include "except.h" and "analyzer/region-model.h".
+ (supergraph::add_cfg_edge): Special-case eh_dispatch edges.
+ (superedge::get_description): Use default_tree_printer.
+ (get_catch): New.
+ (eh_dispatch_cfg_superedge::make): New.
+ (eh_dispatch_cfg_superedge::eh_dispatch_cfg_superedge): New.
+ (eh_dispatch_cfg_superedge::get_eh_status): New.
+ (eh_dispatch_try_cfg_superedge::dump_label_to_pp): New.
+ (eh_dispatch_try_cfg_superedge::apply_constraints): New.
+ (eh_dispatch_allowed_cfg_superedge::eh_dispatch_allowed_cfg_superedge):
+ New.
+ (eh_dispatch_allowed_cfg_superedge::dump_label_to_pp): New.
+ (eh_dispatch_allowed_cfg_superedge::apply_constraints): New.
+ * supergraph.h: Include "except.h".
+ (superedge::dyn_cast_eh_dispatch_cfg_superedge): New vfunc.
+ (superedge::dyn_cast_eh_dispatch_try_cfg_superedge): New vfunc.
+ (superedge::dyn_cast_eh_dispatch_allowed_cfg_superedge): New
+ vfunc.
+ (class eh_dispatch_cfg_superedge): New.
+ (is_a_helper <const eh_dispatch_cfg_superedge *>::test): New.
+ (class eh_dispatch_try_cfg_superedge): New.
+ (is_a_helper <const eh_dispatch_try_cfg_superedge *>::test): New.
+ (class eh_dispatch_allowed_cfg_superedge): New.
+ (is_a_helper <const eh_dispatch_allowed_cfg_superedge *>::test):
+ New.
+ * svalue.cc (svalue::maybe_get_type_from_typeinfo): New.
+ * svalue.h (svalue::maybe_get_type_from_typeinfo): New decl.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * access-diagram.cc: Replace uses of ::make_unique with
+ std::make_unique.
+ * analyzer.cc: Likewise.
+ * bounds-checking.cc: Likewise.
+ * call-details.cc: Likewise.
+ * call-info.cc: Likewise.
+ * call-string.cc: Likewise.
+ * checker-path.cc: Likewise.
+ * common.h: Drop include of "make-unique.h".
+ * constraint-manager.cc: Replace uses of ::make_unique with
+ std::make_unique.
+ * diagnostic-manager.cc: Likewise.
+ * engine.cc: Likewise.
+ * infinite-loop.cc: Likewise.
+ * infinite-recursion.cc: Likewise.
+ * kf-analyzer.cc: Likewise.
+ * kf-lang-cp.cc: Likewise.
+ * kf.cc: Likewise.
+ * pending-diagnostic.cc: Likewise.
+ * program-point.cc: Likewise; drop #include.
+ * program-state.cc: Likewise.
+ * ranges.cc: Likewise.
+ * region-model.cc: Likewise.
+ * region.cc: Likewise; drop #include.
+ * sm-fd.cc: Likewise.
+ * sm-file.cc: Likewise.
+ * sm-malloc.cc: Likewise.
+ * sm-pattern-test.cc: Likewise.
+ * sm-sensitive.cc: Likewise.
+ * sm-signal.cc: Likewise.
+ * sm-taint.cc: Likewise.
+ * sm.cc: Likewise.
+ * store.cc: Likewise.
+ * supergraph.cc: Likewise.
+ * svalue.cc: Likewise; drop #include.
+ * varargs.cc: Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * engine.cc (class plugin_analyzer_init_impl): Convert
+ "m_checkers" to use std::vector of std::unique_ptr. Convert
+ "m_known_fn_mgr" to a reference.
+ (impl_run_checkers): Convert "checkers" to use std::vector of
+ std::unique_ptr and move it into the extrinsic_state.
+ * program-state.cc (extrinsic_state::dump_to_pp): Update for
+ changes to m_checkers.
+ (extrinsic_state::to_json): Likewise.
+ (extrinsic_state::get_sm_idx_by_name): Likewise.
+ (selftest::test_sm_state_map): Update to use std::unique_ptr
+ for state machines.
+ (selftest::test_program_state_1): Likewise.
+ (selftest::test_program_state_2): Likewise.
+ (selftest::test_program_state_merging): Likewise.
+ (selftest::test_program_state_merging_2): Likewise.
+ * program-state.h (class extrinsic_state): Convert "m_checkers" to
+ use std::vector of std::unique_ptr and to be owned by this object,
+ rather than a reference. Add ctor for use in selftests.
+ * sm-fd.cc (make_fd_state_machine): Update to use std::unique_ptr.
+ * sm-file.cc (make_fileptr_state_machine): Likewise.
+ * sm-malloc.cc (make_malloc_state_machine): Likewise.
+ * sm-pattern-test.cc (make_pattern_test_state_machine): Likewise.
+ * sm-sensitive.cc (make_sensitive_state_machine): Likewise.
+ * sm-signal.cc (make_signal_state_machine): Likewise.
+ * sm-taint.cc (make_taint_state_machine): Likewise.
+ * sm.cc: Define INCLUDE_LIST.
+ (make_checkers): Return the vector directly, rather than pass it
+ in by reference. Update to use std::unique_ptr throughout. Use
+ an intermediate list, and use that to filter with
+ flag_analyzer_checker, fixing memory leak for this case.
+ * sm.h: (make_checkers): Return the vector directly, rather than
+ pass it in by reference, and use std::vector of std::unique_ptr.
+ (make_malloc_state_machine): Convert return type to use std::unique_ptr.
+ (make_fileptr_state_machine): Likewise.
+ (make_taint_state_machine): Likewise.
+ (make_sensitive_state_machine): Likewise.
+ (make_signal_state_machine): Likewise.
+ (make_pattern_test_state_machine): Likewise.
+ (make_va_list_state_machine): Likewise.
+ (make_fd_state_machine): Likewise.
+ * varargs.cc (make_va_list_state_machine): Update to use
+ std::unique_ptr.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * call-summary.cc (call_summary_replay::call_summary_replay):
+ Convert "summary" from call_summary * to call_summary &.
+ (call_summary_replay::dump_to_pp): Likewise for m_summary.
+ * call-summary.h (call_summary_replay::call_summary_replay):
+ Likewise for "summary".
+ (call_summary_replay::m_summary): Likewise.
+ * engine.cc (call_summary_edge_info::call_summary_edge_info):
+ Likewise.
+ (call_summary_edge_info::update_state): Likewise.
+ (call_summary_edge_info::update_model): Likewise.
+ (call_summary_edge_info::print_desc): Likewise for m_summary.
+ (call_summary_edge_info::m_summary): Likewise.
+ (exploded_node::replay_call_summaries): Update for change to
+ replay_call_summary.
+ (exploded_node::replay_call_summary): Convert "summary" from
+ call_summary * to call_summary &.
+ * exploded-graph.h (exploded_node::replay_call_summary): Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * analyzer.cc: Convert gcall * to gcall & where we know the
+ pointer must be non-null.
+ * call-details.cc: Likewise.
+ * call-details.h: Likewise.
+ * call-info.cc: Likewise.
+ * call-info.h: Likewise.
+ * call-summary.h: Likewise.
+ * checker-event.cc: Likewise.
+ * checker-event.h: Likewise.
+ * common.h: Likewise.
+ * diagnostic-manager.cc: Likewise.
+ * engine.cc: Likewise.
+ * exploded-graph.h: Likewise.
+ * kf-analyzer.cc: Likewise.
+ * kf-lang-cp.cc: Likewise.
+ * kf.cc: Likewise.
+ * known-function-manager.cc: Likewise.
+ * program-state.cc: Likewise.
+ * program-state.h: Likewise.
+ * region-model.cc: Likewise.
+ * region-model.h: Likewise.
+ * sm-fd.cc: Likewise.
+ * sm-file.cc: Likewise.
+ * sm-malloc.cc: Likewise.
+ * sm-sensitive.cc: Likewise.
+ * sm-signal.cc: Likewise.
+ * sm-taint.cc: Likewise.
+ * sm.h: Likewise.
+ * store.cc: Likewise.
+ * store.h: Likewise.
+ * supergraph.cc: Likewise.
+ * supergraph.h: Likewise.
+ * svalue.h: Likewise.
+ * varargs.cc: Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * access-diagram.cc: Convert enum access_direction to
+ "enum class".
+ * bounds-checking.cc: Likewise.
+ * checker-event.cc: Convert enum event_kind to "enum class".
+ * checker-event.h: Likewise.
+ * checker-path.cc: Likewise.
+ * common.h: Convert enum access_direction to "enum class".
+ * constraint-manager.cc: Convert enum bound_kind to "enum class".
+ * constraint-manager.h: Likewise.
+ * diagnostic-manager.cc: Convert enum event_kind to "enum class".
+ * engine.cc: Convert enum status to "enum class".
+ * exploded-graph.h: Likewise.
+ * infinite-loop.cc: Likewise.
+ * kf-lang-cp.cc: Convert enum poison_kind to "enum class".
+ * kf.cc: Likewise.
+ * region-model-manager.cc: Likewise.
+ * region-model.cc: Likewise; also for enum access_direction.
+ * svalue.cc: Likewise.
+ * svalue.h: Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * analyzer.h: Rename to...
+ * common.h: ...this. Add define of INCLUDE_VECTOR, includes of
+ "config.h", "system.h", "coretypes.h", "make-unique.h", "tree.h",
+ "function.h", "basic-block.h", "gimple.h", "options.h",
+ "bitmap.h", "diagnostic-core.h", and "diagnostic-path.h".
+ * access-diagram.h: Don't include "analyzer/analyzer.h".
+ * access-diagram.cc: Reorganize includes to #include
+ "analyzer/common.h" first, then group by subsystem, dropping
+ redundant headers.
+ * analysis-plan.cc: Likewise.
+ * analyzer-language.cc: Likewise.
+ * analyzer-pass.cc: Likewise.
+ * analyzer-selftests.cc: Likewise.
+ * analyzer.cc: Likewise.
+ * bounds-checking.cc: Likewise.
+ * call-details.cc: Likewise.
+ * call-info.cc: Likewise.
+ * call-string.cc: Likewise.
+ * call-summary.cc: Likewise.
+ * checker-event.cc: Likewise.
+ * checker-path.cc: Likewise.
+ * complexity.cc: Likewise.
+ * constraint-manager.cc: Likewise.
+ * diagnostic-manager.cc: Likewise.
+ * engine.cc: Likewise.
+ * feasible-graph.cc: Likewise.
+ * infinite-loop.cc: Likewise.
+ * infinite-recursion.cc: Likewise.
+ * kf-analyzer.cc: Likewise.
+ * kf-lang-cp.cc: Likewise.
+ * kf.cc: Likewise.
+ * known-function-manager.cc: Likewise.
+ * pending-diagnostic.cc: Likewise.
+ * program-point.cc: Likewise.
+ * program-state.cc: Likewise.
+ * ranges.cc: Likewise.
+ * record-layout.cc: Likewise.
+ * region-model-asm.cc: Likewise.
+ * region-model-manager.cc: Likewise.
+ * region-model-reachability.cc: Likewise.
+ * region-model.cc: Likewise.
+ * region.cc: Likewise.
+ * sm-fd.cc: Likewise.
+ * sm-file.cc: Likewise.
+ * sm-malloc.cc: Likewise.
+ * sm-pattern-test.cc: Likewise.
+ * sm-sensitive.cc: Likewise.
+ * sm-signal.cc: Likewise.
+ * sm-taint.cc: Likewise.
+ * sm.cc: Likewise.
+ * state-purge.cc: Likewise.
+ * store.cc: Likewise.
+ * supergraph.cc: Likewise.
+ * svalue.cc: Likewise.
+ * symbol.cc: Likewise.
+ * trimmed-graph.cc: Likewise.
+ * varargs.cc: Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * region-model.cc (region_model::on_stmt_pre): Use internal_error
+ if we see an unexpected gimple stmt code.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * call-details.cc (call_details::dump): New overload.
+ (call_details::make_dump_widget): New.
+ * call-details.h (call_details::dump): Declare new overload.
+ (call_details::make_dump_widget): New decl.
+
2025-03-14 Jakub Jelinek <jakub@redhat.com>
PR analyzer/119278
diff --git a/gcc/analyzer/access-diagram.cc b/gcc/analyzer/access-diagram.cc
index e1596bb..166be08 100644
--- a/gcc/analyzer/access-diagram.cc
+++ b/gcc/analyzer/access-diagram.cc
@@ -17,28 +17,18 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
#define INCLUDE_ALGORITHM
#define INCLUDE_MAP
#define INCLUDE_SET
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "diagnostic.h"
+#include "analyzer/common.h"
+
+#include "fold-const.h"
#include "intl.h"
-#include "make-unique.h"
-#include "tree-diagnostic.h" /* for default_tree_printer. */
-#include "analyzer/analyzer.h"
+
+#include "text-art/ruler.h"
+
#include "analyzer/region-model.h"
#include "analyzer/access-diagram.h"
-#include "text-art/ruler.h"
-#include "fold-const.h"
#include "analyzer/analyzer-selftests.h"
#if ENABLE_ANALYZER
@@ -245,7 +235,7 @@ get_access_size_str (style_manager &sm,
pp_format_decoder (&pp) = default_tree_printer;
if (num_bits.maybe_print_for_user (&pp, op.m_model))
{
- if (op.m_dir == DIR_READ)
+ if (op.m_dir == access_direction::read)
return fmt_styled_string (sm,
_("read of %qT (%s)"),
type,
@@ -257,7 +247,7 @@ get_access_size_str (style_manager &sm,
pp_formatted_text (&pp));
}
}
- if (op.m_dir == DIR_READ)
+ if (op.m_dir == access_direction::read)
{
if (auto p
= num_bits.maybe_get_formatted_str (sm, op.m_model,
@@ -284,13 +274,13 @@ get_access_size_str (style_manager &sm,
if (type)
{
- if (op.m_dir == DIR_READ)
+ if (op.m_dir == access_direction::read)
return fmt_styled_string (sm, _("read of %qT"), type);
else
return fmt_styled_string (sm, _("write of %qT"), type);
}
- if (op.m_dir == DIR_READ)
+ if (op.m_dir == access_direction::read)
return styled_string (sm, _("read"));
else
return styled_string (sm, _("write"));
@@ -375,11 +365,11 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm,
if (!wi::fits_uhwi_p (concrete_num_bytes))
return nullptr;
if (concrete_num_bytes == 1)
- return ::make_unique <text_art::styled_string>
+ return std::make_unique <text_art::styled_string>
(fmt_styled_string (sm, concrete_single_byte_fmt,
concrete_num_bytes.to_uhwi ()));
else
- return ::make_unique <text_art::styled_string>
+ return std::make_unique <text_art::styled_string>
(fmt_styled_string (sm, concrete_plural_bytes_fmt,
concrete_num_bytes.to_uhwi ()));
}
@@ -389,7 +379,7 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm,
pp_format_decoder (&pp) = default_tree_printer;
if (!num_bytes->maybe_print_for_user (&pp, model))
return nullptr;
- return ::make_unique <text_art::styled_string>
+ return std::make_unique <text_art::styled_string>
(fmt_styled_string (sm, symbolic_bytes_fmt,
pp_formatted_text (&pp)));
}
@@ -400,11 +390,11 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm,
if (!wi::fits_uhwi_p (concrete_num_bits))
return nullptr;
if (concrete_num_bits == 1)
- return ::make_unique <text_art::styled_string>
+ return std::make_unique <text_art::styled_string>
(fmt_styled_string (sm, concrete_single_bit_fmt,
concrete_num_bits.to_uhwi ()));
else
- return ::make_unique <text_art::styled_string>
+ return std::make_unique <text_art::styled_string>
(fmt_styled_string (sm, concrete_plural_bits_fmt,
concrete_num_bits.to_uhwi ()));
}
@@ -414,7 +404,7 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm,
pp_format_decoder (&pp) = default_tree_printer;
if (!m_num_bits.maybe_print_for_user (&pp, model))
return nullptr;
- return ::make_unique <text_art::styled_string>
+ return std::make_unique <text_art::styled_string>
(fmt_styled_string (sm, symbolic_bits_fmt,
pp_formatted_text (&pp)));
}
@@ -1126,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: ");
@@ -1310,7 +1300,7 @@ class valid_region_spatial_item : public spatial_item
{
public:
valid_region_spatial_item (const access_operation &op,
- diagnostic_event_id_t region_creation_event_id,
+ diagnostics::paths::event_id_t region_creation_event_id,
const theme &theme)
: m_op (op),
m_region_creation_event_id (region_creation_event_id),
@@ -1533,7 +1523,7 @@ public:
private:
const access_operation &m_op;
- diagnostic_event_id_t m_region_creation_event_id;
+ diagnostics::paths::event_id_t m_region_creation_event_id;
mutable const boundaries *m_boundaries;
const svalue *m_existing_sval;
std::unique_ptr<spatial_item> m_existing_sval_spatial_item;
@@ -1975,11 +1965,11 @@ make_written_svalue_spatial_item (const access_operation &op,
if (const initial_svalue *initial_sval = sval.dyn_cast_initial_svalue ())
if (const string_region *string_reg
= initial_sval->get_region ()->dyn_cast_string_region ())
- return make_unique <string_literal_spatial_item>
+ return std::make_unique <string_literal_spatial_item>
(sval, actual_bits,
*string_reg, theme,
svalue_spatial_item::kind::WRITTEN);
- return make_unique <written_svalue_spatial_item> (op, sval, actual_bits);
+ return std::make_unique <written_svalue_spatial_item> (op, sval, actual_bits);
}
static std::unique_ptr<spatial_item>
@@ -2000,7 +1990,7 @@ make_existing_svalue_spatial_item (const svalue *sval,
const initial_svalue *initial_sval = (const initial_svalue *)sval;
if (const string_region *string_reg
= initial_sval->get_region ()->dyn_cast_string_region ())
- return make_unique <string_literal_spatial_item>
+ return std::make_unique <string_literal_spatial_item>
(*sval, bits,
*string_reg, theme,
svalue_spatial_item::kind::EXISTING);
@@ -2008,7 +1998,7 @@ make_existing_svalue_spatial_item (const svalue *sval,
}
case SK_COMPOUND:
- return make_unique<compound_svalue_spatial_item>
+ return std::make_unique<compound_svalue_spatial_item>
(*((const compound_svalue *)sval),
bits,
svalue_spatial_item::kind::EXISTING,
@@ -2022,7 +2012,7 @@ class access_diagram_impl : public vbox_widget
{
public:
access_diagram_impl (const access_operation &op,
- diagnostic_event_id_t region_creation_event_id,
+ diagnostics::paths::event_id_t region_creation_event_id,
style_manager &sm,
const theme &theme,
logger *logger)
@@ -2116,7 +2106,7 @@ public:
}
m_col_widths
- = make_unique <table_dimension_sizes> (m_btm.get_num_columns ());
+ = std::make_unique <table_dimension_sizes> (m_btm.get_num_columns ());
/* Now create child widgets. */
@@ -2211,8 +2201,8 @@ private:
std::unique_ptr<boundaries>
find_boundaries () const
{
- std::unique_ptr<boundaries> result
- = make_unique<boundaries> (*m_op.m_base_region, m_logger);
+ auto result
+ = std::make_unique<boundaries> (*m_op.m_base_region, m_logger);
m_valid_region_spatial_item.add_boundaries (*result, m_logger);
m_accessed_region_spatial_item.add_boundaries (*result, m_logger);
@@ -2254,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))
{
@@ -2271,7 +2261,7 @@ private:
void add_direction_widget ()
{
- add_child (::make_unique<direction_widget> (*this, m_btm));
+ add_child (std::make_unique<direction_widget> (*this, m_btm));
}
void add_invalid_accesses_to_region_table (table &t_region)
@@ -2382,7 +2372,7 @@ private:
bit_size_expr num_before_bits
(invalid_before_bits.get_size (m_op.get_manager ()));
std::unique_ptr<styled_string> label;
- if (m_op.m_dir == DIR_READ)
+ if (m_op.m_dir == access_direction::read)
label = num_before_bits.maybe_get_formatted_str
(m_sm, m_op.m_model,
_("under-read of %wi bit"),
@@ -2423,7 +2413,7 @@ private:
maybe_add_gap (w, invalid_before_bits, valid_bits);
std::unique_ptr<styled_string> label;
- if (m_op.m_dir == DIR_READ)
+ if (m_op.m_dir == access_direction::read)
label = num_valid_bits.maybe_get_formatted_str (m_sm,
m_op.m_model,
_("size: %wi bit"),
@@ -2459,7 +2449,7 @@ private:
bit_size_expr num_after_bits
(invalid_after_bits.get_size (m_op.get_manager ()));
std::unique_ptr<styled_string> label;
- if (m_op.m_dir == DIR_READ)
+ if (m_op.m_dir == access_direction::read)
label = num_after_bits.maybe_get_formatted_str
(m_sm, m_op.m_model,
_("over-read of %wi bit"),
@@ -2505,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))
{
@@ -2574,7 +2564,7 @@ private:
}
const access_operation &m_op;
- diagnostic_event_id_t m_region_creation_event_id;
+ diagnostics::paths::event_id_t m_region_creation_event_id;
style_manager &m_sm;
const theme &m_theme;
logger *m_logger;
@@ -2658,7 +2648,7 @@ direction_widget::paint_to_canvas (canvas &canvas)
(canvas,
canvas_x,
canvas::range_t (get_y_range ()),
- (m_dia_impl.get_op ().m_dir == DIR_READ
+ (m_dia_impl.get_op ().m_dir == access_direction::read
? theme::y_arrow_dir::UP
: theme::y_arrow_dir::DOWN),
style_id);
@@ -2672,15 +2662,16 @@ direction_widget::paint_to_canvas (canvas &canvas)
an access_diagram_impl. */
access_diagram::access_diagram (const access_operation &op,
- diagnostic_event_id_t region_creation_event_id,
+ diagnostics::paths::event_id_t region_creation_event_id,
style_manager &sm,
const theme &theme,
logger *logger)
-: wrapper_widget (make_unique <access_diagram_impl> (op,
- region_creation_event_id,
- sm,
- theme,
- logger))
+: wrapper_widget
+ (std::make_unique <access_diagram_impl> (op,
+ region_creation_event_id,
+ sm,
+ theme,
+ logger))
{
}
diff --git a/gcc/analyzer/access-diagram.h b/gcc/analyzer/access-diagram.h
index ba4649a..d558f53 100644
--- a/gcc/analyzer/access-diagram.h
+++ b/gcc/analyzer/access-diagram.h
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "text-art/canvas.h"
#include "text-art/theme.h"
#include "text-art/widget.h"
-#include "analyzer/analyzer.h"
+
#include "analyzer/store.h"
namespace ana {
@@ -152,7 +152,7 @@ class access_diagram : public text_art::wrapper_widget
{
public:
access_diagram (const access_operation &op,
- diagnostic_event_id_t region_creation_event_id,
+ diagnostics::paths::event_id_t region_creation_event_id,
text_art::style_manager &sm,
const text_art::theme &theme,
logger *logger);
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..996538c
--- /dev/null
+++ b/gcc/analyzer/ana-state-to-diagnostic-state.cc
@@ -0,0 +1,689 @@
+/* Creating diagnostic state graphs from ana::program_state.
+ 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 "diagnostics/state-graphs.h"
+#include "diagnostics/sarif-sink.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 {
+
+using namespace ::diagnostics::state_graphs;
+
+static void
+set_wi_attr (state_node_ref state_node,
+ const char *attr_name,
+ const wide_int_ref &w,
+ signop sgn)
+{
+ pretty_printer pp;
+ pp_wide_int (&pp, w, sgn);
+ state_node.set_attr (attr_name, pp_formatted_text (&pp));
+}
+
+static void
+set_type_attr (state_node_ref state_node, const_tree type)
+{
+ gcc_assert (type);
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_printf (&pp, "%T", type);
+ state_node.set_type (pp_formatted_text (&pp));
+}
+
+static void
+set_bits_attr (state_node_ref state_node,
+ bit_range bits)
+{
+ pretty_printer pp;
+ bits.dump_to_pp (&pp);
+ state_node.set_attr ("bits", pp_formatted_text (&pp));
+}
+
+// class analyzer_state_graph : public diagnostics::digraphs::digraph
+
+analyzer_state_graph::analyzer_state_graph (const program_state &state,
+ const extrinsic_state &ext_state)
+: m_state (state),
+ m_ext_state (ext_state),
+ m_mgr (*ext_state.get_engine ()->get_model_manager ()),
+ m_next_id (0)
+{
+ /* 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_state_node (*reg);
+ }
+
+ /* Create bound memory. */
+ for (auto iter : *state.m_region_model->get_store ())
+ {
+ const bool create_all = false; // "true" for verbose, for debugging
+ create_state_nodes_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_state_graph (*this, *iter.first, iter.second.m_state);
+ if (auto s = smap->get_global_state ())
+ sm.add_global_state_to_state_graph (*this, s);
+ }
+ }
+
+ /* Process pending edges. */
+ while (m_pending_edges.size () > 0)
+ {
+ pending_edge item = m_pending_edges.back ();
+ m_pending_edges.pop_back ();
+
+ /* Ensure we have a node for the dst region. This
+ could lead to additional pending edges. */
+ auto dst_node = get_or_create_state_node (item.m_dst_reg);
+ add_edge (nullptr, item.m_src_node.m_node, dst_node.m_node);
+ }
+}
+
+state_node_ref
+analyzer_state_graph::get_or_create_state_node (const region &reg)
+{
+ auto existing = m_region_to_state_node_map.find (&reg);
+ if (existing != m_region_to_state_node_map.end ())
+ return *existing->second;
+
+ auto ref = create_and_add_state_node (reg);
+ m_region_to_state_node_map[&reg] = &ref.m_node;
+ return ref;
+}
+
+state_node_ref
+analyzer_state_graph::create_and_add_state_node (const region &reg)
+{
+ auto node = create_state_node (reg);
+
+ state_node_ref result = *node;
+ if (auto parent_reg = reg.get_parent_region ())
+ if (parent_reg->get_kind () != RK_ROOT)
+ {
+ auto parent_state_node = get_or_create_state_node (*parent_reg);
+ parent_state_node.m_node.add_child (std::move (node));
+ return result;
+ }
+ add_node (std::move (node));
+ return result;
+}
+
+std::string
+analyzer_state_graph::make_node_id (const char *prefix)
+{
+ return std::string (prefix) + "-" + std::to_string (m_next_id++);
+}
+
+std::string
+analyzer_state_graph::make_node_id (const region &reg)
+{
+ const char *prefix = nullptr;
+ switch (reg.get_kind ())
+ {
+ case RK_ROOT:
+ default:
+ gcc_unreachable ();
+ break;
+
+ case RK_GLOBALS:
+ return "globals";
+ case RK_CODE:
+ return "code";
+ case RK_STACK:
+ return "stack";
+ case RK_HEAP:
+ return "heap";
+
+ case RK_FRAME:
+ prefix = "frame-region";
+ break;
+ case RK_FUNCTION:
+ prefix = "function-region";
+ break;
+ case RK_LABEL:
+ prefix = "label-region";
+ break;
+ case RK_THREAD_LOCAL:
+ prefix = "thread-local-region";
+ break;
+ case RK_SYMBOLIC:
+ prefix = "symbolic-region";
+ break;
+ case RK_DECL:
+ prefix = "decl-region";
+ break;
+ case RK_FIELD:
+ prefix = "field-region";
+ break;
+ case RK_ELEMENT:
+ prefix = "element-region";
+ break;
+ case RK_OFFSET:
+ prefix = "offset-region";
+ break;
+ case RK_SIZED:
+ prefix = "sized-region";
+ break;
+ case RK_CAST:
+ prefix = "cast-region";
+ break;
+ case RK_HEAP_ALLOCATED:
+ prefix = "heap-allocated-region";
+ break;
+ case RK_ALLOCA:
+ prefix = "alloca-region";
+ break;
+ case RK_STRING:
+ prefix = "string-region";
+ break;
+ case RK_BIT_RANGE:
+ prefix = "bit-range-region";
+ break;
+ case RK_VAR_ARG:
+ prefix = "var-arg-region";
+ break;
+ case RK_ERRNO:
+ prefix = "errno-region";
+ break;
+ case RK_PRIVATE:
+ prefix = "private-region";
+ break;
+ case RK_UNKNOWN:
+ prefix = "unknown-region";
+ break;
+ }
+ return std::string (prefix) + "-" + std::to_string (reg.get_id ());
+}
+
+std::unique_ptr<diagnostics::digraphs::node>
+analyzer_state_graph::
+make_state_node (diagnostics::state_graphs::node_kind kind,
+ std::string id)
+{
+ auto node = std::make_unique<diagnostics::digraphs::node> (*this, std::move (id));
+ state_node_ref node_ref (*node);
+ node_ref.set_node_kind (kind);
+ return node;
+}
+
+std::unique_ptr<diagnostics::digraphs::node>
+analyzer_state_graph::
+make_memspace_state_node (const region &reg,
+ diagnostics::state_graphs::node_kind kind)
+{
+ return make_state_node (kind, make_node_id (reg));
+}
+
+std::unique_ptr<diagnostics::digraphs::node>
+analyzer_state_graph::create_state_node (const region &reg)
+{
+ std::unique_ptr<diagnostics::digraphs::node> node;
+
+ switch (reg.get_kind ())
+ {
+ default:
+ gcc_unreachable ();
+
+ case RK_FRAME:
+ {
+ const frame_region &frame_reg
+ = static_cast<const frame_region &> (reg);
+
+ node = make_state_node (diagnostics::state_graphs::node_kind::stack_frame,
+ make_node_id (reg));
+ node->set_logical_loc
+ (m_logical_loc_mgr.key_from_tree (frame_reg.get_fndecl ()));
+ {
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_printf (&pp, "%E", frame_reg.get_fndecl ());
+ node->set_attr (STATE_NODE_PREFIX, "function",
+ pp_formatted_text (&pp));
+ }
+ }
+ break;
+
+ case RK_GLOBALS:
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::globals);
+ break;
+ case RK_CODE:
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::code);
+ break;
+ case RK_FUNCTION:
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::function);
+ // TODO
+ break;
+
+ case RK_STACK:
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::stack);
+ break;
+ case RK_HEAP:
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::heap_);
+ break;
+ case RK_THREAD_LOCAL:
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::thread_local_);
+ break;
+ case RK_ROOT:
+ gcc_unreachable ();
+ break;
+ case RK_SYMBOLIC:
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::other);
+ break;
+
+ case RK_DECL:
+ {
+ node = make_state_node (diagnostics::state_graphs::node_kind::variable,
+ make_node_id (reg));
+ const decl_region &decl_reg
+ = static_cast<const decl_region &> (reg);
+ state_node_ref node_ref (*node);
+ {
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_printf (&pp, "%E", decl_reg.get_decl ());
+ node_ref.set_name (pp_formatted_text (&pp));
+ }
+ set_type_attr (*node, TREE_TYPE (decl_reg.get_decl ()));
+ }
+ break;
+
+ case RK_FIELD:
+ case RK_ELEMENT:
+ /* These should be handled in populate_state_node_for_typed_region. */
+ gcc_unreachable ();
+ break;
+
+ case RK_LABEL:
+ case RK_OFFSET:
+ case RK_SIZED:
+ case RK_CAST:
+ case RK_STRING:
+ case RK_BIT_RANGE:
+ case RK_VAR_ARG:
+ case RK_ERRNO:
+ case RK_PRIVATE:
+ case RK_UNKNOWN:
+ node = make_state_node (diagnostics::state_graphs::node_kind::other,
+ make_node_id (reg));
+ break;
+
+ case RK_HEAP_ALLOCATED:
+ case RK_ALLOCA:
+ node = make_memspace_state_node (reg,
+ diagnostics::state_graphs::node_kind::dynalloc_buffer);
+ set_attr_for_dynamic_extents (reg, *node);
+ break;
+ }
+ gcc_assert (node);
+
+ if (reg.get_base_region () == &reg)
+ if (!reg.get_type ())
+ {
+ auto search
+ = m_types_for_untyped_regions.find (&reg);
+ if (search != m_types_for_untyped_regions.end ())
+ {
+ tree type_to_use = search->second;
+ set_type_attr (*node, type_to_use);
+ }
+ }
+
+ return node;
+}
+
+void
+analyzer_state_graph::
+create_state_nodes_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_state_node (*reg);
+ }
+
+ auto ref = get_or_create_state_node (*cluster.get_base_region ());
+
+ ref.m_node.add_child (create_state_node_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_state_node_for_typed_region (ref,
+ *typed_reg,
+ conc_bindings,
+ create_all);
+ else
+ {
+ // TODO
+ }
+}
+
+std::unique_ptr<diagnostics::digraphs::node>
+analyzer_state_graph::create_state_node_for_conc_bindings (const concrete_bindings_t &conc_bindings)
+{
+ auto node = make_state_node (diagnostics::state_graphs::node_kind::other,
+ make_node_id ("concrete-bindings"));
+ for (auto iter : conc_bindings)
+ {
+ const bit_range bits = iter.first;
+ const svalue *sval = iter.second;
+ auto binding_state_node
+ = make_state_node (diagnostics::state_graphs::node_kind::other,
+ make_node_id ("binding"));
+ set_bits_attr (*binding_state_node, bits);
+ {
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ sval->dump_to_pp (&pp, true);
+ binding_state_node->set_attr (STATE_NODE_PREFIX, "value",
+ pp_formatted_text (&pp));
+ }
+ node->add_child (std::move (binding_state_node));
+ }
+ return node;
+}
+
+// Try to get the bit_range of REG within its base region
+bool
+analyzer_state_graph::get_bit_range_within_base_region (const region &reg,
+ 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
+analyzer_state_graph::
+populate_state_node_for_typed_region (state_node_ref node,
+ const region &reg,
+ const concrete_bindings_t &conc_bindings,
+ bool create_all)
+{
+ const_tree reg_type = reg.get_type ();
+ gcc_assert (reg_type);
+ set_type_attr (node, reg_type);
+
+ bit_range bits (0, 0);
+ if (get_bit_range_within_base_region (reg, bits))
+ {
+ set_bits_attr (node, bits);
+
+ auto search = conc_bindings.find (bits);
+ if (search != conc_bindings.end ())
+ {
+ const svalue *bound_sval = search->second;
+ node.set_json_attr ("value", bound_sval->to_json ());
+ if (const region *dst_reg = bound_sval->maybe_get_region ())
+ m_pending_edges.push_back ({node, *dst_reg});
+ }
+ }
+
+ 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 (&reg,
+ const_cast<tree> (element_type),
+ sval_index);
+ if (show_child_state_node_for_child_region_p (*child_reg,
+ conc_bindings,
+ create_all))
+ {
+ auto child_state_node
+ = make_state_node
+ (diagnostics::state_graphs::node_kind::element,
+ make_node_id (*child_reg));
+ set_wi_attr (*child_state_node, "index", idx, UNSIGNED);
+
+ // Recurse:
+ gcc_assert (element_type);
+ populate_state_node_for_typed_region (*child_state_node,
+ *child_reg,
+ conc_bindings,
+ create_all);
+ node.m_node.add_child (std::move (child_state_node));
+ }
+ }
+ }
+ 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 (&reg, NULL_TREE, bits);
+ if (show_child_state_node_for_child_region_p (*child_reg,
+ conc_bindings,
+ create_all))
+ {
+ auto child_state_node
+ = make_state_node
+ (diagnostics::state_graphs::node_kind::padding,
+ make_node_id (*child_reg));
+ set_wi_attr (*child_state_node, "num_bits",
+ item.m_bit_range.m_size_in_bits, SIGNED);
+ node.m_node.add_child (std::move (child_state_node));
+ }
+ }
+ else
+ {
+ const region *child_reg
+ = m_mgr.get_field_region (&reg,
+ const_cast<tree> (item.m_field));
+ if (show_child_state_node_for_child_region_p (*child_reg,
+ conc_bindings,
+ create_all))
+ {
+ auto child_state_node
+ = make_state_node
+ (diagnostics::state_graphs::node_kind::field,
+ make_node_id (*child_reg));
+ {
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_printf (&pp, "%D", item.m_field);
+ child_state_node->set_attr (STATE_NODE_PREFIX, "name",
+ pp_formatted_text (&pp));
+ }
+
+ // Recurse:
+ populate_state_node_for_typed_region (*child_state_node,
+ *child_reg,
+ conc_bindings,
+ create_all);
+ node.m_node.add_child (std::move (child_state_node));
+ }
+ }
+ }
+ }
+ break;
+ }
+}
+
+void
+analyzer_state_graph::set_attr_for_dynamic_extents (const region &reg,
+ state_node_ref node_ref)
+{
+ const svalue *sval = m_state.m_region_model->get_dynamic_extents (&reg);
+ 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);
+ node_ref.set_attr ("dynamic-extents", pp_formatted_text (&pp));
+ }
+}
+
+bool
+analyzer_state_graph::
+show_child_state_node_for_child_region_p (const region &reg,
+ 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<diagnostics::digraphs::digraph>
+program_state::
+make_diagnostic_state_graph (const extrinsic_state &ext_state) const
+{
+ return std::make_unique<analyzer_state_graph> (*this, ext_state);
+}
+
+void
+program_state::dump_sarif (const extrinsic_state &ext_state) const
+{
+ auto g = make_diagnostic_state_graph (ext_state);
+ g->dump ();
+}
+
+} // 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..3a5ccc1
--- /dev/null
+++ b/gcc/analyzer/ana-state-to-diagnostic-state.h
@@ -0,0 +1,106 @@
+/* Creating diagnostic state graphs from ana::program_state.
+ 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_DIAGNOSTIC_STATE_H
+#define GCC_ANALYZER_ANA_STATE_TO_DIAGNOSTIC_STATE_H
+
+#include "diagnostics/state-graphs.h"
+#include "tree-logical-location.h"
+
+namespace ana {
+
+class analyzer_state_graph : public diagnostics::digraphs::digraph
+{
+public:
+ analyzer_state_graph (const program_state &state,
+ const extrinsic_state &ext_state);
+ diagnostics::state_graphs::state_node_ref
+ get_or_create_state_node (const region &reg);
+
+private:
+ struct pending_edge
+ {
+ diagnostics::state_graphs::state_node_ref m_src_node;
+ const region &m_dst_reg;
+ };
+
+ diagnostics::state_graphs::state_node_ref
+ create_and_add_state_node (const region &reg);
+
+ std::unique_ptr<diagnostics::digraphs::node>
+ make_state_node (diagnostics::state_graphs::node_kind kind,
+ std::string id);
+
+ std::unique_ptr<diagnostics::digraphs::node>
+ make_memspace_state_node (const region &reg,
+ enum diagnostics::state_graphs::node_kind kind);
+
+ std::unique_ptr<diagnostics::digraphs::node>
+ create_state_node (const region &reg);
+
+ /* Spatially sorted concrete bindings. */
+ typedef std::map<bit_range, const svalue *> concrete_bindings_t;
+
+ void
+ create_state_nodes_for_binding_cluster (const binding_cluster &cluster,
+ bool create_all);
+
+ std::unique_ptr<diagnostics::digraphs::node>
+ create_state_node_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 &reg,
+ bit_range &out);
+
+ void
+ populate_state_node_for_typed_region (diagnostics::state_graphs::state_node_ref,
+ const region &reg,
+ const concrete_bindings_t &conc_bindings,
+ bool create_all);
+
+ void
+ set_attr_for_dynamic_extents (const region &reg,
+ diagnostics::state_graphs::state_node_ref);
+
+ bool
+ show_child_state_node_for_child_region_p (const region &reg,
+ const concrete_bindings_t &conc_bindings,
+ bool create_all);
+
+ std::unique_ptr<diagnostics::digraphs::node>
+ create_state_node_for_svalue (const svalue *sval);
+
+ std::string make_node_id (const region &reg);
+ std::string make_node_id (const char *prefix);
+
+ tree_logical_location_manager m_logical_loc_mgr;
+ const program_state &m_state;
+ const extrinsic_state &m_ext_state;
+ region_model_manager &m_mgr;
+ std::map<const region *, diagnostics::digraphs::node *> m_region_to_state_node_map;
+ std::map<const region *, tree> m_types_for_untyped_regions;
+ unsigned m_next_id;
+ std::vector<pending_edge> m_pending_edges;
+};
+
+} // namespace ana
+
+#endif /* GCC_ANALYZER_ANA_STATE_TO_DIAGNOSTIC_STATE_H */
diff --git a/gcc/analyzer/analysis-plan.cc b/gcc/analyzer/analysis-plan.cc
index 7ae01c0..c563554 100644
--- a/gcc/analyzer/analysis-plan.cc
+++ b/gcc/analyzer/analysis-plan.cc
@@ -18,27 +18,19 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "options.h"
-#include "cgraph.h"
+#include "analyzer/common.h"
+
#include "timevar.h"
-#include "ipa-utils.h"
-#include "function.h"
-#include "analyzer/analyzer.h"
-#include "diagnostic-core.h"
-#include "analyzer/analyzer-logging.h"
-#include "analyzer/analysis-plan.h"
#include "ordered-hash-map.h"
#include "options.h"
#include "cgraph.h"
#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
#include "gimple-iterator.h"
#include "digraph.h"
+#include "ipa-utils.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/analysis-plan.h"
#include "analyzer/supergraph.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/analyzer-language.cc b/gcc/analyzer/analyzer-language.cc
index a0fa9f5..d4169f7 100644
--- a/gcc/analyzer/analyzer-language.cc
+++ b/gcc/analyzer/analyzer-language.cc
@@ -18,15 +18,13 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
+#include "analyzer/common.h"
+
+#include "diagnostic.h"
#include "stringpool.h"
-#include "analyzer/analyzer.h"
+
#include "analyzer/analyzer-language.h"
#include "analyzer/analyzer-logging.h"
-#include "diagnostic.h"
/* Map from identifier to INTEGER_CST. */
static GTY (()) hash_map <tree, tree> *analyzer_stashed_constants;
@@ -116,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 ab41de4..559fb94 100644
--- a/gcc/analyzer/analyzer-pass.cc
+++ b/gcc/analyzer/analyzer-pass.cc
@@ -18,15 +18,10 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "context.h"
+#include "analyzer/common.h"
+
#include "tree-pass.h"
-#include "diagnostic.h"
-#include "options.h"
-#include "tree.h"
-#include "analyzer/analyzer.h"
+
#include "analyzer/engine.h"
namespace {
@@ -53,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-selftests.cc b/gcc/analyzer/analyzer-selftests.cc
index 0f131f0..334c355 100644
--- a/gcc/analyzer/analyzer-selftests.cc
+++ b/gcc/analyzer/analyzer-selftests.cc
@@ -18,12 +18,10 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
+#include "analyzer/common.h"
+
#include "stringpool.h"
-#include "analyzer/analyzer.h"
+
#include "analyzer/analyzer-selftests.h"
#if CHECKING_P
diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
index da7491b..9f6f7b4 100644
--- a/gcc/analyzer/analyzer.cc
+++ b/gcc/analyzer/analyzer.cc
@@ -18,20 +18,12 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic.h"
-#include "intl.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "tree-pretty-print.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
#include "tree-dfa.h"
-#include "make-unique.h"
+#include "intl.h"
#if ENABLE_ANALYZER
@@ -227,11 +219,11 @@ std::unique_ptr<json::value>
tree_to_json (tree node)
{
if (!node)
- return ::make_unique<json::literal> (json::JSON_NULL);
+ return std::make_unique<json::literal> (json::JSON_NULL);
pretty_printer pp;
dump_generic_node (&pp, node, 0, TDF_VOPS|TDF_MEMSYMS, false);
- return ::make_unique<json::string> (pp_formatted_text (&pp));
+ return std::make_unique<json::string> (pp_formatted_text (&pp));
}
/* Generate a JSON value for EVENT_ID.
@@ -240,16 +232,16 @@ tree_to_json (tree node)
for unknown). */
std::unique_ptr<json::value>
-diagnostic_event_id_to_json (const diagnostic_event_id_t &event_id)
+diagnostic_event_id_to_json (const diagnostics::paths::event_id_t &event_id)
{
if (event_id.known_p ())
{
pretty_printer pp;
pp_printf (&pp, "%@", &event_id);
- return ::make_unique<json::string> (pp_formatted_text (&pp));
+ return std::make_unique<json::string> (pp_formatted_text (&pp));
}
else
- return ::make_unique<json::literal> (json::JSON_NULL);
+ return std::make_unique<json::literal> (json::JSON_NULL);
}
/* Generate a JSON value for OFFSET.
@@ -261,7 +253,7 @@ bit_offset_to_json (const bit_offset_t &offset)
{
pretty_printer pp;
pp_wide_int_large (&pp, offset, SIGNED);
- return ::make_unique<json::string> (pp_formatted_text (&pp));
+ return std::make_unique<json::string> (pp_formatted_text (&pp));
}
/* Generate a JSON value for OFFSET.
@@ -273,7 +265,7 @@ byte_offset_to_json (const byte_offset_t &offset)
{
pretty_printer pp;
pp_wide_int_large (&pp, offset, SIGNED);
- return ::make_unique<json::string> (pp_formatted_text (&pp));
+ return std::make_unique<json::string> (pp_formatted_text (&pp));
}
/* Workaround for lack of const-correctness of ssa_default_def. */
@@ -298,12 +290,12 @@ get_ssa_default_def (const function &fun, tree var)
If LOOK_IN_STD is true, then also look for within std:: for the name. */
bool
-is_special_named_call_p (const gcall *call, const char *funcname,
+is_special_named_call_p (const gcall &call, const char *funcname,
unsigned int num_args, bool look_in_std)
{
gcc_assert (funcname);
- tree fndecl = gimple_call_fndecl (call);
+ tree fndecl = gimple_call_fndecl (&call);
if (!fndecl)
return false;
@@ -396,7 +388,7 @@ is_std_named_call_p (const_tree fndecl, const char *funcname)
bool
is_named_call_p (const_tree fndecl, const char *funcname,
- const gcall *call, unsigned int num_args)
+ const gcall &call, unsigned int num_args)
{
gcc_assert (fndecl);
gcc_assert (funcname);
@@ -404,7 +396,7 @@ is_named_call_p (const_tree fndecl, const char *funcname,
if (!is_named_call_p (fndecl, funcname))
return false;
- if (gimple_call_num_args (call) != num_args)
+ if (gimple_call_num_args (&call) != num_args)
return false;
return true;
@@ -414,7 +406,7 @@ is_named_call_p (const_tree fndecl, const char *funcname,
bool
is_std_named_call_p (const_tree fndecl, const char *funcname,
- const gcall *call, unsigned int num_args)
+ const gcall &call, unsigned int num_args)
{
gcc_assert (fndecl);
gcc_assert (funcname);
@@ -422,7 +414,7 @@ is_std_named_call_p (const_tree fndecl, const char *funcname,
if (!is_std_named_call_p (fndecl, funcname))
return false;
- if (gimple_call_num_args (call) != num_args)
+ if (gimple_call_num_args (&call) != num_args)
return false;
return true;
@@ -431,12 +423,12 @@ is_std_named_call_p (const_tree fndecl, const char *funcname,
/* Return true if stmt is a setjmp or sigsetjmp call. */
bool
-is_setjmp_call_p (const gcall *call)
+is_setjmp_call_p (const gcall &call)
{
if (is_special_named_call_p (call, "setjmp", 1)
|| is_special_named_call_p (call, "sigsetjmp", 2))
/* region_model::on_setjmp requires a pointer. */
- if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
+ if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (&call, 0))))
return true;
return false;
@@ -445,26 +437,46 @@ is_setjmp_call_p (const gcall *call)
/* Return true if stmt is a longjmp or siglongjmp call. */
bool
-is_longjmp_call_p (const gcall *call)
+is_longjmp_call_p (const gcall &call)
{
if (is_special_named_call_p (call, "longjmp", 2)
|| is_special_named_call_p (call, "siglongjmp", 2))
/* exploded_node::on_longjmp requires a pointer for the initial
argument. */
- if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
+ if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (&call, 0))))
return true;
return false;
}
+bool
+is_cxa_throw_p (const gcall &call)
+{
+ tree fndecl = gimple_call_fndecl (&call);
+ if (!fndecl)
+ return false;
+
+ return is_named_call_p (fndecl, "__cxa_throw");
+}
+
+bool
+is_cxa_rethrow_p (const gcall &call)
+{
+ tree fndecl = gimple_call_fndecl (&call);
+ if (!fndecl)
+ return false;
+
+ return is_named_call_p (fndecl, "__cxa_rethrow");
+}
+
/* For a CALL that matched is_special_named_call_p or is_named_call_p for
some name, return a name for the called function suitable for use in
diagnostics (stripping the leading underscores). */
const char *
-get_user_facing_name (const gcall *call)
+get_user_facing_name (const gcall &call)
{
- tree fndecl = gimple_call_fndecl (call);
+ tree fndecl = gimple_call_fndecl (&call);
gcc_assert (fndecl);
tree identifier = DECL_NAME (fndecl);
@@ -506,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 ());
@@ -537,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/analyzer.opt b/gcc/analyzer/analyzer.opt
index d5f82c6..2ca9058 100644
--- a/gcc/analyzer/analyzer.opt
+++ b/gcc/analyzer/analyzer.opt
@@ -222,6 +222,10 @@ Wanalyzer-tainted-size
Common Var(warn_analyzer_tainted_size) Init(1) Warning
Warn about code paths in which an unsanitized value is used as a size.
+Wanalyzer-throw-of-unexpected-type
+Common Var(warn_analyzer_throw_of_unexpected_type) Init(1) Warning
+Warn about code paths in which an exception of unexpected type is thrown.
+
Wanalyzer-undefined-behavior-ptrdiff
Common Var(warn_analyzer_undefined_behavior_ptrdiff) Init(1) Warning
Warn about code paths in which pointer subtraction involves undefined behavior.
diff --git a/gcc/analyzer/analyzer.opt.urls b/gcc/analyzer/analyzer.opt.urls
index 18a0d69..e76e6e5 100644
--- a/gcc/analyzer/analyzer.opt.urls
+++ b/gcc/analyzer/analyzer.opt.urls
@@ -114,6 +114,9 @@ UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-tainted-offset)
Wanalyzer-tainted-size
UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-tainted-size)
+Wanalyzer-throw-of-unexpected-type
+UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-throw-of-unexpected-type)
+
Wanalyzer-undefined-behavior-ptrdiff
UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-undefined-behavior-ptrdiff)
diff --git a/gcc/analyzer/bounds-checking.cc b/gcc/analyzer/bounds-checking.cc
index c83b419..921ad16 100644
--- a/gcc/analyzer/bounds-checking.cc
+++ b/gcc/analyzer/bounds-checking.cc
@@ -17,21 +17,12 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
+#include "analyzer/common.h"
+
#include "intl.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "diagnostic-diagram.h"
-#include "diagnostic-format-sarif.h"
-#include "analyzer/analyzer.h"
+#include "diagnostics/diagram.h"
+#include "diagnostics/sarif-sink.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/region-model.h"
#include "analyzer/checker-event.h"
@@ -60,7 +51,7 @@ public:
}
void prepare_for_emission (checker_path *path,
pending_diagnostic *pd,
- diagnostic_event_id_t emission_id) override
+ diagnostics::paths::event_id_t emission_id) override
{
region_creation_event_capacity::prepare_for_emission (path,
pd,
@@ -105,18 +96,19 @@ public:
so we don't need an event for that. */
if (byte_capacity)
emission_path.add_event
- (make_unique<oob_region_creation_event_capacity> (byte_capacity,
- loc_info,
- *this));
+ (std::make_unique<oob_region_creation_event_capacity> (byte_capacity,
+ loc_info,
+ *this));
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/out_of_bounds/"
props.set_string (PROPERTY_PREFIX "dir",
- get_dir () == DIR_READ ? "read" : "write");
+ get_dir () == access_direction::read ? "read" : "write");
props.set (PROPERTY_PREFIX "model", m_model.to_json ());
props.set (PROPERTY_PREFIX "region", m_reg->to_json ());
props.set (PROPERTY_PREFIX "diag_arg", tree_to_json (m_diag_arg));
@@ -190,7 +182,7 @@ protected:
a problem. Give up if that's happened. */
return;
}
- diagnostic_diagram diagram
+ diagnostics::diagram diagram
(canvas,
/* Alt text. */
_("Diagram visualizing the predicted out-of-bounds access"));
@@ -212,7 +204,7 @@ protected:
const region *m_reg;
tree m_diag_arg;
const svalue *m_sval_hint;
- diagnostic_event_id_t m_region_creation_event_id;
+ diagnostics::paths::event_id_t m_region_creation_event_id;
};
/* Abstract base class for all out-of-bounds warnings where the
@@ -237,11 +229,11 @@ public:
&& m_out_of_bounds_bits == other.m_out_of_bounds_bits);
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const override
{
out_of_bounds::maybe_add_sarif_properties (result_obj);
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/concrete_out_of_bounds/"
props.set (PROPERTY_PREFIX "out_of_bounds_bits",
m_out_of_bounds_bits.to_json ());
@@ -298,16 +290,16 @@ public:
{
if (m_byte_bound && TREE_CODE (m_byte_bound) == INTEGER_CST)
emission_path.add_event
- (make_unique<oob_region_creation_event_capacity> (m_byte_bound,
- loc_info,
- *this));
+ (std::make_unique<oob_region_creation_event_capacity> (m_byte_bound,
+ loc_info,
+ *this));
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
concrete_out_of_bounds::maybe_add_sarif_properties (result_obj);
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/concrete_past_the_end/"
props.set (PROPERTY_PREFIX "bit_bound",
tree_to_json (m_bit_bound));
@@ -505,7 +497,7 @@ public:
}
}
- enum access_direction get_dir () const final override { return DIR_WRITE; }
+ enum access_direction get_dir () const final override { return access_direction::write; }
};
/* Concrete subclass to complain about buffer over-reads. */
@@ -516,7 +508,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
@@ -689,7 +681,7 @@ public:
}
}
- enum access_direction get_dir () const final override { return DIR_READ; }
+ enum access_direction get_dir () const final override { return access_direction::read; }
};
/* Concrete subclass to complain about buffer underwrites. */
@@ -817,7 +809,7 @@ public:
}
}
- enum access_direction get_dir () const final override { return DIR_WRITE; }
+ enum access_direction get_dir () const final override { return access_direction::write; }
};
/* Concrete subclass to complain about buffer under-reads. */
@@ -828,7 +820,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
@@ -945,7 +937,7 @@ public:
}
}
- enum access_direction get_dir () const final override { return DIR_READ; }
+ enum access_direction get_dir () const final override { return access_direction::read; }
};
/* Abstract class to complain about out-of-bounds read/writes where
@@ -975,11 +967,12 @@ public:
&& pending_diagnostic::same_tree_p (m_capacity, other.m_capacity));
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
out_of_bounds::maybe_add_sarif_properties (result_obj);
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/symbolic_past_the_end/"
props.set (PROPERTY_PREFIX "offset", tree_to_json (m_offset));
props.set (PROPERTY_PREFIX "num_bytes", tree_to_json (m_num_bytes));
@@ -1116,7 +1109,7 @@ public:
return true;
}
- enum access_direction get_dir () const final override { return DIR_WRITE; }
+ enum access_direction get_dir () const final override { return access_direction::write; }
};
/* Concrete subclass to complain about over-reads with symbolic values. */
@@ -1128,7 +1121,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)
{
}
@@ -1243,7 +1236,7 @@ public:
return true;
}
- enum access_direction get_dir () const final override { return DIR_READ; }
+ enum access_direction get_dir () const final override { return access_direction::read; }
};
const svalue *
@@ -1427,24 +1420,26 @@ region_model::check_symbolic_bounds (const region *base_reg,
default:
gcc_unreachable ();
break;
- case DIR_READ:
+ case access_direction::read:
gcc_assert (sval_hint == nullptr);
- ctxt->warn (make_unique<symbolic_buffer_over_read> (*this,
- sized_offset_reg,
- diag_arg,
- offset_tree,
- num_bytes_tree,
- capacity_tree));
+ ctxt->warn
+ (std::make_unique<symbolic_buffer_over_read> (*this,
+ sized_offset_reg,
+ diag_arg,
+ offset_tree,
+ num_bytes_tree,
+ capacity_tree));
return false;
break;
- case DIR_WRITE:
- ctxt->warn (make_unique<symbolic_buffer_overflow> (*this,
- sized_offset_reg,
- diag_arg,
- offset_tree,
- num_bytes_tree,
- capacity_tree,
- sval_hint));
+ case access_direction::write:
+ ctxt->warn
+ (std::make_unique<symbolic_buffer_overflow> (*this,
+ sized_offset_reg,
+ diag_arg,
+ offset_tree,
+ num_bytes_tree,
+ capacity_tree,
+ sval_hint));
return false;
break;
}
@@ -1535,18 +1530,20 @@ region_model::check_region_bounds (const region *reg,
default:
gcc_unreachable ();
break;
- case DIR_READ:
+ case access_direction::read:
gcc_assert (sval_hint == nullptr);
- ctxt->warn (make_unique<concrete_buffer_under_read> (*this, reg,
- diag_arg,
- bits_outside));
+ ctxt->warn
+ (std::make_unique<concrete_buffer_under_read> (*this, reg,
+ diag_arg,
+ bits_outside));
oob_safe = false;
break;
- case DIR_WRITE:
- ctxt->warn (make_unique<concrete_buffer_underwrite> (*this,
- reg, diag_arg,
- bits_outside,
- sval_hint));
+ case access_direction::write:
+ ctxt->warn
+ (std::make_unique<concrete_buffer_underwrite> (*this,
+ reg, diag_arg,
+ bits_outside,
+ sval_hint));
oob_safe = false;
break;
}
@@ -1571,20 +1568,22 @@ region_model::check_region_bounds (const region *reg,
default:
gcc_unreachable ();
break;
- case DIR_READ:
+ case access_direction::read:
gcc_assert (sval_hint == nullptr);
- ctxt->warn (make_unique<concrete_buffer_over_read> (*this,
- reg, diag_arg,
- bits_outside,
- bit_bound));
+ ctxt->warn
+ (std::make_unique<concrete_buffer_over_read> (*this,
+ reg, diag_arg,
+ bits_outside,
+ bit_bound));
oob_safe = false;
break;
- case DIR_WRITE:
- ctxt->warn (make_unique<concrete_buffer_overflow> (*this,
- reg, diag_arg,
- bits_outside,
- bit_bound,
- sval_hint));
+ case access_direction::write:
+ ctxt->warn
+ (std::make_unique<concrete_buffer_overflow> (*this,
+ reg, diag_arg,
+ bits_outside,
+ bit_bound,
+ sval_hint));
oob_safe = false;
break;
}
diff --git a/gcc/analyzer/call-details.cc b/gcc/analyzer/call-details.cc
index 4122f84..ede1229 100644
--- a/gcc/analyzer/call-details.cc
+++ b/gcc/analyzer/call-details.cc
@@ -18,27 +18,19 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "diagnostic.h"
#include "tree-diagnostic.h" /* for default_tree_printer. */
#include "gimple-pretty-print.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "diagnostics/sarif-sink.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/region-model.h"
#include "analyzer/call-details.h"
#include "analyzer/ranges.h"
-#include "stringpool.h"
-#include "attribs.h"
-#include "make-unique.h"
-#include "diagnostic-format-sarif.h"
#if ENABLE_ANALYZER
@@ -48,13 +40,13 @@ namespace ana {
/* call_details's ctor. */
-call_details::call_details (const gcall *call, region_model *model,
+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))
+ if (tree lhs = gimple_call_lhs (&call))
{
m_lhs_region = model->get_lvalue (lhs, ctxt);
m_lhs_type = TREE_TYPE (lhs);
@@ -66,9 +58,11 @@ call_details::call_details (const gcall *call, region_model *model,
call_details::call_details (const call_details &cd,
region_model_context *ctxt)
+: m_call (cd.m_call), m_model (cd.m_model),
+ m_ctxt (ctxt),
+ m_lhs_type (cd.m_lhs_type),
+ m_lhs_region (cd.m_lhs_region)
{
- *this = cd;
- m_ctxt = ctxt;
}
/* Get the manager from m_model. */
@@ -87,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. */
@@ -98,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
@@ -133,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);
}
@@ -228,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
@@ -252,7 +246,7 @@ call_details::set_any_lhs_with_defaults () const
unsigned
call_details::num_args () const
{
- return gimple_call_num_args (m_call);
+ return gimple_call_num_args (&m_call);
}
/* Return true if argument IDX is a size_t (or compatible with it). */
@@ -268,7 +262,7 @@ call_details::arg_is_size_p (unsigned idx) const
location_t
call_details::get_location () const
{
- return m_call->location;
+ return m_call.location;
}
/* Get argument IDX at the callsite as a tree. */
@@ -276,7 +270,7 @@ call_details::get_location () const
tree
call_details::get_arg_tree (unsigned idx) const
{
- return gimple_call_arg (m_call, idx);
+ return gimple_call_arg (&m_call, idx);
}
/* Get the type of argument IDX. */
@@ -284,7 +278,7 @@ call_details::get_arg_tree (unsigned idx) const
tree
call_details::get_arg_type (unsigned idx) const
{
- return TREE_TYPE (gimple_call_arg (m_call, idx));
+ return TREE_TYPE (gimple_call_arg (&m_call, idx));
}
/* Get argument IDX at the callsite as an svalue. */
@@ -298,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
@@ -307,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. */
@@ -322,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
@@ -340,7 +334,7 @@ void
call_details::dump_to_pp (pretty_printer *pp, bool simple) const
{
pp_string (pp, "gcall: ");
- pp_gimple_stmt_1 (pp, m_call, 0 /* spc */, TDF_NONE /* flags */);
+ pp_gimple_stmt_1 (pp, &m_call, 0 /* spc */, TDF_NONE /* flags */);
pp_newline (pp);
pp_string (pp, "return region: ");
if (m_lhs_region)
@@ -348,7 +342,7 @@ call_details::dump_to_pp (pretty_printer *pp, bool simple) const
else
pp_string (pp, "NULL");
pp_newline (pp);
- for (unsigned i = 0; i < gimple_call_num_args (m_call); i++)
+ for (unsigned i = 0; i < gimple_call_num_args (&m_call); i++)
{
const svalue *arg_sval = get_arg_svalue (i);
pp_printf (pp, "arg %i: ", i);
@@ -366,6 +360,65 @@ call_details::dump (bool simple) const
dump_to_pp (&pp, simple);
}
+/* Dump a tree-like representation of this call to stderr. */
+
+DEBUG_FUNCTION void
+call_details::dump () const
+{
+ text_art::dump (*this);
+}
+
+std::unique_ptr<text_art::tree_widget>
+call_details::make_dump_widget (const text_art::dump_widget_info &dwi) const
+{
+ using text_art::tree_widget;
+ std::unique_ptr<tree_widget> cd_widget
+ (tree_widget::from_fmt (dwi, nullptr, "Call Details"));
+
+ {
+ pretty_printer the_pp;
+ pretty_printer * const pp = &the_pp;
+ pp_format_decoder (pp) = default_tree_printer;
+ pp_string (pp, "gcall: ");
+ pp_gimple_stmt_1 (pp, &m_call, 0 /* spc */, TDF_NONE /* flags */);
+ cd_widget->add_child (tree_widget::make (dwi, pp));
+ }
+ {
+ pretty_printer the_pp;
+ pretty_printer * const pp = &the_pp;
+ pp_format_decoder (pp) = default_tree_printer;
+ pp_string (pp, "return region: ");
+ if (m_lhs_region)
+ m_lhs_region->dump_to_pp (pp, true);
+ else
+ pp_string (pp, "NULL");
+ auto w = tree_widget::make (dwi, pp);
+ if (m_lhs_region)
+ w->add_child (m_lhs_region->make_dump_widget (dwi));
+ cd_widget->add_child (std::move (w));
+ }
+ if (gimple_call_num_args (&m_call) > 0)
+ {
+ std::unique_ptr<tree_widget> args_widget
+ (tree_widget::from_fmt (dwi, nullptr, "Arguments"));
+ for (unsigned i = 0; i < gimple_call_num_args (&m_call); i++)
+ {
+ pretty_printer the_pp;
+ pretty_printer * const pp = &the_pp;
+ pp_format_decoder (pp) = default_tree_printer;
+ const svalue *arg_sval = get_arg_svalue (i);
+ pp_printf (pp, "%i: ", i);
+ arg_sval->dump_to_pp (pp, true);
+ auto w = tree_widget::make (dwi, pp);
+ w->add_child (arg_sval->make_dump_widget (dwi));
+ args_widget->add_child (std::move (w));
+ }
+ cd_widget->add_child (std::move (args_widget));
+ }
+
+ return cd_widget;
+}
+
/* Get a conjured_svalue for this call for REG,
and purge any state already relating to that conjured_svalue. */
@@ -373,7 +426,7 @@ const svalue *
call_details::get_or_create_conjured_svalue (const region *reg) const
{
region_model_manager *mgr = m_model->get_manager ();
- return mgr->get_or_create_conjured_svalue (reg->get_type (), m_call, reg,
+ return mgr->get_or_create_conjured_svalue (reg->get_type (), &m_call, reg,
conjured_purge (m_model, m_ctxt));
}
@@ -388,7 +441,7 @@ call_details::lookup_function_attribute (const char *attr_name) const
if (tree fndecl = get_fndecl_for_call ())
allocfntype = TREE_TYPE (fndecl);
else
- allocfntype = gimple_call_fntype (m_call);
+ allocfntype = gimple_call_fntype (&m_call);
if (!allocfntype)
return NULL_TREE;
@@ -475,10 +528,10 @@ public:
return true;
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/overlapping_buffers/"
props.set (PROPERTY_PREFIX "bytes_range_a",
m_byte_range_a.to_json ());
@@ -540,10 +593,10 @@ call_details::complain_about_overlap (unsigned arg_idx_a,
if (!byte_range_a.intersection (byte_range_b, *model).is_true ())
return;
- ctxt->warn (make_unique<overlapping_buffers> (get_fndecl_for_call (),
- byte_range_a,
- byte_range_b,
- num_bytes_read_sval));
+ ctxt->warn (std::make_unique<overlapping_buffers> (get_fndecl_for_call (),
+ byte_range_a,
+ byte_range_b,
+ num_bytes_read_sval));
}
} // namespace ana
diff --git a/gcc/analyzer/call-details.h b/gcc/analyzer/call-details.h
index fee7ad4..c0a9118 100644
--- a/gcc/analyzer/call-details.h
+++ b/gcc/analyzer/call-details.h
@@ -28,7 +28,7 @@ namespace ana {
class call_details
{
public:
- call_details (const gcall *call, region_model *model,
+ call_details (const gcall &call, region_model *model,
region_model_context *ctxt);
call_details (const call_details &cd, region_model_context *ctxt);
@@ -55,7 +55,7 @@ public:
return INTEGRAL_TYPE_P (get_arg_type (idx));
}
- const gcall *get_call_stmt () const { return m_call; }
+ const gcall &get_call_stmt () const { return m_call; }
location_t get_location () const;
tree get_arg_tree (unsigned idx) const;
@@ -68,6 +68,10 @@ public:
void dump_to_pp (pretty_printer *pp, bool simple) const;
void dump (bool simple) const;
+ void dump () const;
+
+ std::unique_ptr<text_art::tree_widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi) const;
const svalue *get_or_create_conjured_svalue (const region *) const;
@@ -86,7 +90,7 @@ public:
const svalue *num_bytes_read_sval) const;
private:
- const gcall *m_call;
+ const gcall &m_call;
region_model *m_model;
region_model_context *m_ctxt;
tree m_lhs_type;
@@ -110,13 +114,13 @@ public:
bool operator== (const call_arg_details &other) const
{
- return (m_call == other.m_call
+ return (&m_call == &other.m_call
&& m_called_fndecl == other.m_called_fndecl
&& m_arg_idx == other.m_arg_idx
&& pending_diagnostic::same_tree_p (m_arg_expr, other.m_arg_expr));
}
- const gcall *m_call;
+ const gcall &m_call;
tree m_called_fndecl;
unsigned m_arg_idx; // 0-based
tree m_arg_expr;
diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc
index 1adbf64..f431143 100644
--- a/gcc/analyzer/call-info.cc
+++ b/gcc/analyzer/call-info.cc
@@ -18,45 +18,31 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-pretty-print.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "ordered-hash-map.h"
#include "cfg.h"
#include "digraph.h"
-#include "analyzer/supergraph.h"
#include "sbitmap.h"
+#include "diagnostics/event-id.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/supergraph.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/constraint-manager.h"
-#include "diagnostic-event-id.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/region-model-reachability.h"
#include "analyzer/analyzer-selftests.h"
#include "analyzer/program-state.h"
-#include "diagnostic-path.h"
#include "analyzer/checker-path.h"
#include "analyzer/diagnostic-manager.h"
#include "analyzer/exploded-graph.h"
#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -72,6 +58,18 @@ custom_edge_info::update_state (program_state *state,
return update_model (state->m_region_model, eedge, ctxt);
}
+/* Base implementation of custom_edge_info::create_enode vfunc. */
+
+exploded_node *
+custom_edge_info::create_enode (exploded_graph &eg,
+ const program_point &point,
+ program_state &&state,
+ exploded_node *enode_for_diag,
+ region_model_context *) const
+{
+ return eg.get_or_create_node (point, state, enode_for_diag);
+}
+
/* class call_info : public custom_edge_info. */
/* Implementation of custom_edge_info::print vfunc for call_info. */
@@ -115,7 +113,7 @@ call_info::add_events_to_path (checker_path *emission_path,
const int stack_depth = src_point.get_stack_depth ();
emission_path->add_event
- (make_unique<call_event> (event_loc_info (get_call_stmt ()->location,
+ (std::make_unique<call_event> (event_loc_info (get_call_stmt ().location,
caller_fndecl,
stack_depth),
this));
diff --git a/gcc/analyzer/call-info.h b/gcc/analyzer/call-info.h
index ec304d8..6548d86 100644
--- a/gcc/analyzer/call-info.h
+++ b/gcc/analyzer/call-info.h
@@ -30,11 +30,11 @@ namespace ana {
class call_info : public custom_edge_info
{
public:
- void print (pretty_printer *pp) const final override;
+ void print (pretty_printer *pp) const override;
void add_events_to_path (checker_path *emission_path,
- const exploded_edge &eedge) const final override;
+ const exploded_edge &eedge) const override;
- const gcall *get_call_stmt () const { return m_call_stmt; }
+ const gcall &get_call_stmt () const { return m_call_stmt; }
tree get_fndecl () const { return m_fndecl; }
virtual void print_desc (pretty_printer &pp) const = 0;
@@ -47,7 +47,7 @@ protected:
call_info (const call_details &cd, const function &called_fn);
private:
- const gcall *m_call_stmt;
+ const gcall &m_call_stmt;
tree m_fndecl;
};
diff --git a/gcc/analyzer/call-string.cc b/gcc/analyzer/call-string.cc
index 5099986..0bac8b4 100644
--- a/gcc/analyzer/call-string.cc
+++ b/gcc/analyzer/call-string.cc
@@ -18,26 +18,11 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "pretty-print.h"
-#include "tree.h"
-#include "options.h"
-#include "ordered-hash-map.h"
-#include "options.h"
-#include "cgraph.h"
-#include "function.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "digraph.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/supergraph.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -106,11 +91,11 @@ call_string::print (pretty_printer *pp) const
std::unique_ptr<json::value>
call_string::to_json () const
{
- auto arr = ::make_unique<json::array> ();
+ auto arr = std::make_unique<json::array> ();
for (const call_string::element_t &e : m_elements)
{
- auto e_obj = ::make_unique<json::object> ();
+ auto e_obj = std::make_unique<json::object> ();
e_obj->set_integer ("src_snode_idx", e.m_callee->m_index);
e_obj->set_integer ("dst_snode_idx", e.m_caller->m_index);
e_obj->set_string ("funcname", function_name (e.m_caller->m_fun));
@@ -238,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;
}
@@ -281,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 27fb575..a094cba 100644
--- a/gcc/analyzer/call-summary.cc
+++ b/gcc/analyzer/call-summary.cc
@@ -17,16 +17,8 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "tree-dfa.h"
-#include "diagnostic-core.h"
-#include "diagnostic.h"
-#include "tree-diagnostic.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "analyzer/region-model.h"
#include "analyzer/call-summary.h"
#include "analyzer/exploded-graph.h"
@@ -79,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:
@@ -165,7 +157,7 @@ call_summary::dump (const extrinsic_state &ext_state, bool simple) const
call_summary_replay::call_summary_replay (const call_details &cd,
const function &called_fn,
- call_summary *summary,
+ call_summary &summary,
const extrinsic_state &ext_state)
: m_cd (cd),
m_summary (summary),
@@ -180,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;
@@ -218,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)
@@ -260,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 (),
@@ -276,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:
{
@@ -290,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;
@@ -303,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 (),
@@ -317,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 (),
@@ -336,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);
@@ -354,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,
@@ -377,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,
@@ -392,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);
}
@@ -408,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 (),
@@ -499,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 ();
@@ -524,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 ();
@@ -540,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)
@@ -604,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,
@@ -627,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. */
@@ -636,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;
@@ -653,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);
}
@@ -666,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);
@@ -685,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);
@@ -705,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);
@@ -723,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 ());
}
@@ -739,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
@@ -748,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 (),
@@ -756,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)
@@ -775,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);
@@ -788,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);
}
@@ -799,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);
}
@@ -816,7 +808,7 @@ call_summary_replay::dump_to_pp (pretty_printer *pp, bool simple) const
pp_newline (pp);
pp_string (pp, "CALLEE SUMMARY:");
pp_newline (pp);
- m_summary->dump_to_pp (m_ext_state, pp, simple);
+ m_summary.dump_to_pp (m_ext_state, pp, simple);
/* Current state of caller (could be in mid-update). */
pp_newline (pp);
diff --git a/gcc/analyzer/call-summary.h b/gcc/analyzer/call-summary.h
index 220dd083..7280cca 100644
--- a/gcc/analyzer/call-summary.h
+++ b/gcc/analyzer/call-summary.h
@@ -69,11 +69,11 @@ class call_summary_replay
public:
call_summary_replay (const call_details &cd,
const function &called_fn,
- call_summary *m_summary,
+ call_summary &summary,
const extrinsic_state &ext_state);
const call_details &get_call_details () const { return m_cd; }
- const gcall *get_call_stmt () const { return m_cd.get_call_stmt (); }
+ const gcall &get_call_stmt () const { return m_cd.get_call_stmt (); }
region_model_manager *get_manager () const { return m_cd.get_manager (); }
store_manager *get_store_manager () const
{
@@ -102,7 +102,7 @@ private:
const region *convert_region_from_summary_1 (const region *);
const call_details &m_cd;
- call_summary *m_summary;
+ call_summary &m_summary;
const extrinsic_state &m_ext_state;
// Mapping from svalues in summary to svalues for callsite:
diff --git a/gcc/analyzer/checker-event.cc b/gcc/analyzer/checker-event.cc
index 5d7647c..4eac945 100644
--- a/gcc/analyzer/checker-event.cc
+++ b/gcc/analyzer/checker-event.cc
@@ -1,4 +1,4 @@
-/* Subclasses of diagnostic_event for analyzer diagnostics.
+/* Subclasses of diagnostics::paths::event for analyzer diagnostics.
Copyright (C) 2019-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -18,45 +18,32 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
+#include "analyzer/common.h"
+
#include "gimple-pretty-print.h"
+#include "sbitmap.h"
+#include "ordered-hash-map.h"
#include "fold-const.h"
-#include "diagnostic-path.h"
-#include "options.h"
-#include "cgraph.h"
-#include "cfg.h"
-#include "digraph.h"
-#include "diagnostic-event-id.h"
-#include "analyzer/analyzer.h"
+#include "gimple-iterator.h"
+#include "inlining-iterator.h"
+#include "tree-logical-location.h"
+#include "diagnostics/sarif-sink.h"
+#include "diagnostics/state-graphs.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
-#include "sbitmap.h"
-#include "bitmap.h"
-#include "ordered-hash-map.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/program-state.h"
#include "analyzer/checker-path.h"
-#include "gimple-iterator.h"
-#include "inlining-iterator.h"
#include "analyzer/supergraph.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
#include "analyzer/constraint-manager.h"
#include "analyzer/checker-event.h"
#include "analyzer/exploded-graph.h"
-#include "diagnostic-format-sarif.h"
-#include "tree-logical-location.h"
#if ENABLE_ANALYZER
@@ -71,56 +58,64 @@ event_kind_to_string (enum event_kind ek)
{
default:
gcc_unreachable ();
- case EK_DEBUG:
- return "EK_DEBUG";
- case EK_CUSTOM:
- return "EK_CUSTOM";
- case EK_STMT:
- return "EK_STMT";
- case EK_REGION_CREATION:
- return "EK_REGION_CREATION";
- case EK_FUNCTION_ENTRY:
- return "EK_FUNCTION_ENTRY";
- case EK_STATE_CHANGE:
- return "EK_STATE_CHANGE";
- case EK_START_CFG_EDGE:
- return "EK_START_CFG_EDGE";
- case EK_END_CFG_EDGE:
- return "EK_END_CFG_EDGE";
- case EK_CALL_EDGE:
- return "EK_CALL_EDGE";
- case EK_RETURN_EDGE:
- return "EK_RETURN_EDGE";
- case EK_START_CONSOLIDATED_CFG_EDGES:
- return "EK_START_CONSOLIDATED_CFG_EDGES";
- case EK_END_CONSOLIDATED_CFG_EDGES:
- return "EK_END_CONSOLIDATED_CFG_EDGES";
- case EK_INLINED_CALL:
- return "EK_INLINED_CALL";
- case EK_SETJMP:
- return "EK_SETJMP";
- case EK_REWIND_FROM_LONGJMP:
- return "EK_REWIND_FROM_LONGJMP";
- case EK_REWIND_TO_SETJMP:
- return "EK_REWIND_TO_SETJMP";
- case EK_WARNING:
- return "EK_WARNING";
+ case event_kind::debug:
+ return "debug";
+ case event_kind::custom:
+ return "custom";
+ case event_kind::stmt:
+ return "stmt";
+ case event_kind::region_creation:
+ return "region_creation";
+ case event_kind::function_entry:
+ return "function_entry";
+ case event_kind::state_change:
+ return "state_change";
+ case event_kind::start_cfg_edge:
+ return "start_cfg_edge";
+ case event_kind::end_cfg_edge:
+ return "end_cfg_edge";
+ case event_kind::catch_:
+ return "catch";
+ case event_kind::call_edge:
+ return "call_edge";
+ case event_kind::return_edge:
+ return "return_edge";
+ case event_kind::start_consolidated_cfg_edges:
+ return "start_consolidated_cfg_edges";
+ case event_kind::end_consolidated_cfg_edges:
+ return "end_consolidated_cfg_edges";
+ case event_kind::inlined_call:
+ return "inlined_call";
+ case event_kind::setjmp_:
+ return "setjmp";
+ case event_kind::rewind_from_longjmp:
+ return "rewind_from_longjmp";
+ case event_kind::rewind_to_setjmp:
+ return "rewind_to_setjmp";
+ case event_kind::throw_:
+ return "throw";
+ case event_kind::unwind:
+ return "unwind";
+ case event_kind::warning:
+ return "warning";
}
}
-/* class checker_event : public diagnostic_event. */
+/* class checker_event : public diagnostics::paths::event. */
/* checker_event's ctor. */
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_logical_loc (loc_info.m_fndecl)
+ m_pending_diagnostic (nullptr), m_emission_id (),
+ m_logical_loc
+ (tree_logical_location_manager::key_from_tree (loc_info.m_fndecl))
{
/* Update effective fndecl and depth if inlining has been recorded. */
if (flag_analyzer_undo_inlining)
@@ -130,40 +125,41 @@ checker_event::checker_event (enum event_kind kind,
{
m_effective_fndecl = info.get_inner_fndecl ();
m_effective_depth += info.get_extra_frames ();
- m_logical_loc = tree_logical_location (m_effective_fndecl);
+ m_logical_loc
+ = tree_logical_location_manager::key_from_tree (m_effective_fndecl);
}
}
}
-/* No-op implementation of diagnostic_event::get_meaning vfunc for
+/* No-op implementation of diagnostics::paths::event::get_meaning vfunc for
checker_event: checker events have no meaning by default. */
-diagnostic_event::meaning
+diagnostics::paths::event::meaning
checker_event::get_meaning () const
{
- return meaning ();
+ return diagnostics::paths::event::meaning ();
}
-/* Implementation of diagnostic_event::maybe_add_sarif_properties
+/* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
for checker_event. */
void
checker_event::
-maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj) const
+maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
+ diagnostics::sarif_object &thread_flow_loc_obj) const
{
- sarif_property_bag &props = thread_flow_loc_obj.get_or_create_properties ();
+ auto &props = thread_flow_loc_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/checker_event/"
props.set (PROPERTY_PREFIX "emission_id",
diagnostic_event_id_to_json (m_emission_id));
props.set_string (PROPERTY_PREFIX "kind", event_kind_to_string (m_kind));
if (m_original_fndecl != m_effective_fndecl)
- {
- tree_logical_location logical_loc (m_original_fndecl);
- props.set<sarif_logical_location>
- (PROPERTY_PREFIX "original_fndecl",
- make_sarif_logical_location_object (logical_loc));
- }
+ props.set_logical_location
+ (PROPERTY_PREFIX "original_fndecl",
+ builder,
+ tree_logical_location_manager::key_from_tree (m_original_fndecl));
+
if (m_original_depth != m_effective_depth)
props.set_integer (PROPERTY_PREFIX "original_depth", m_original_depth);
#undef PROPERTY_PREFIX
@@ -217,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)
+ diagnostics::paths::event_id_t emission_id)
{
+ m_path = path;
m_pending_diagnostic = pd;
m_emission_id = emission_id;
@@ -228,9 +225,34 @@ checker_event::prepare_for_emission (checker_path *,
print_desc (*pp.get ());
}
+std::unique_ptr<diagnostics::digraphs::digraph>
+checker_event::maybe_make_diagnostic_state_graph (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_diagnostic_state_graph (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->set_attr (STATE_GRAPH_PREFIX,
+ "analyzer/program_state/",
+ pp_formatted_text (&pp));
+ }
+
+ return result;
+}
+
/* class debug_event : public checker_event. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
debug_event.
Use the saved string as the event's description. */
@@ -242,7 +264,7 @@ debug_event::print_desc (pretty_printer &pp) const
/* class precanned_custom_event : public custom_event. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
precanned_custom_event.
Use the saved string as the event's description. */
@@ -258,14 +280,14 @@ precanned_custom_event::print_desc (pretty_printer &pp) const
statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
const program_state &dst_state)
-: checker_event (EK_STMT,
+: checker_event (event_kind::stmt,
event_loc_info (gimple_location (stmt), fndecl, depth)),
m_stmt (stmt),
m_dst_state (dst_state)
{
}
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
statement_event.
Use the statement's dump form as the event's description. */
@@ -279,7 +301,7 @@ statement_event::print_desc (pretty_printer &pp) const
/* class region_creation_event : public checker_event. */
region_creation_event::region_creation_event (const event_loc_info &loc_info)
-: checker_event (EK_REGION_CREATION, loc_info)
+: checker_event (event_kind::region_creation, loc_info)
{
}
@@ -350,16 +372,18 @@ 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)
-: checker_event (EK_FUNCTION_ENTRY,
+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)
{
}
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
function_entry_event.
Use a string such as "entry to 'foo'" as the event's description. */
@@ -370,13 +394,13 @@ function_entry_event::print_desc (pretty_printer &pp) const
pp_printf (&pp, "entry to %qE", m_effective_fndecl);
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
function entry. */
-diagnostic_event::meaning
+diagnostics::paths::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. */
@@ -393,7 +417,7 @@ state_change_event::state_change_event (const supernode *node,
const svalue *origin,
const program_state &dst_state,
const exploded_node *enode)
-: checker_event (EK_STATE_CHANGE,
+: checker_event (event_kind::state_change,
event_loc_info (stmt->location,
node->m_fun->decl,
stack_depth)),
@@ -405,7 +429,7 @@ state_change_event::state_change_event (const supernode *node,
{
}
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
state_change_event.
Attempt to generate a nicer human-readable description.
@@ -447,7 +471,7 @@ state_change_event::print_desc (pretty_printer &pp) const
pp_string (&pp, "NULL origin");
/* Get any "meaning" of event. */
- diagnostic_event::meaning meaning = get_meaning ();
+ diagnostics::paths::event::meaning meaning = get_meaning ();
pp_string (&pp, ", meaning: ");
meaning.dump_to_pp (&pp);
pp_string (&pp, ")");
@@ -476,7 +500,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 (),
@@ -484,11 +508,11 @@ state_change_event::print_desc (pretty_printer &pp) const
}
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
state change events: delegate to the pending_diagnostic to
get any meaning. */
-diagnostic_event::meaning
+diagnostics::paths::event::meaning
state_change_event::get_meaning () const
{
if (m_pending_diagnostic)
@@ -506,15 +530,17 @@ state_change_event::get_meaning () const
/* class superedge_event : public checker_event. */
-/* Implementation of diagnostic_event::maybe_add_sarif_properties
+/* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
for superedge_event. */
void
-superedge_event::maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj)
+superedge_event::
+maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
+ diagnostics::sarif_object &thread_flow_loc_obj)
const
{
- checker_event::maybe_add_sarif_properties (thread_flow_loc_obj);
- sarif_property_bag &props = thread_flow_loc_obj.get_or_create_properties ();
+ checker_event::maybe_add_sarif_properties (builder, thread_flow_loc_obj);
+ auto &props = thread_flow_loc_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
if (m_sedge)
props.set (PROPERTY_PREFIX "superedge", m_sedge->to_json ());
@@ -562,6 +588,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,
@@ -595,24 +627,24 @@ cfg_edge_event::cfg_edge_event (enum event_kind kind,
gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
CFG edge events. */
-diagnostic_event::meaning
+diagnostics::paths::event::meaning
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 ();
}
/* class start_cfg_edge_event : public cfg_edge_event. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
start_cfg_edge_event.
If -fanalyzer-verbose-edges, then generate low-level descriptions, such
@@ -715,7 +747,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.
@@ -741,7 +773,7 @@ start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
&& zerop (rhs))
{
if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
- if (is_special_named_call_p (call, "strcmp", 2))
+ if (is_special_named_call_p (*call, "strcmp", 2))
{
if (op == EQ_EXPR)
return label_text::borrow ("when the strings are equal");
@@ -752,9 +784,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))
@@ -804,7 +836,7 @@ start_cfg_edge_event::should_print_expr_p (tree expr)
call_event::call_event (const exploded_edge &eedge,
const event_loc_info &loc_info)
-: superedge_event (EK_CALL_EDGE, eedge, loc_info)
+: superedge_event (event_kind::call_edge, eedge, loc_info)
{
if (eedge.m_sedge)
gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
@@ -813,7 +845,7 @@ call_event::call_event (const exploded_edge &eedge,
m_dest_snode = eedge.m_dest->get_supernode ();
}
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
call_event.
If this call event passes critical state for an sm-based warning,
@@ -845,13 +877,13 @@ call_event::print_desc (pretty_printer &pp) const
get_caller_fndecl ());
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
function call events. */
-diagnostic_event::meaning
+diagnostics::paths::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. */
@@ -874,13 +906,21 @@ 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. */
return_event::return_event (const exploded_edge &eedge,
const event_loc_info &loc_info)
-: superedge_event (EK_RETURN_EDGE, eedge, loc_info)
+: superedge_event (event_kind::return_edge, eedge, loc_info)
{
if (eedge.m_sedge)
gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
@@ -889,7 +929,7 @@ return_event::return_event (const exploded_edge &eedge,
m_dest_snode = eedge.m_dest->get_supernode ();
}
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
return_event.
If this return event returns critical state for an sm-based warning,
@@ -921,13 +961,13 @@ return_event::print_desc (pretty_printer &pp) const
m_src_snode->m_fun->decl);
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
function return events. */
-diagnostic_event::meaning
+diagnostics::paths::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. */
@@ -948,14 +988,14 @@ start_consolidated_cfg_edges_event::print_desc (pretty_printer &pp) const
m_edge_sense ? "true" : "false");
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
start_consolidated_cfg_edges_event. */
-diagnostic_event::meaning
+diagnostics::paths::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. */
@@ -969,18 +1009,18 @@ inlined_call_event::print_desc (pretty_printer &pp) const
m_apparent_caller_fndecl);
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
reconstructed inlined function calls. */
-diagnostic_event::meaning
+diagnostics::paths::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. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
setjmp_event. */
void
@@ -999,7 +1039,7 @@ setjmp_event::print_desc (pretty_printer &pp) const
void
setjmp_event::prepare_for_emission (checker_path *path,
pending_diagnostic *pd,
- diagnostic_event_id_t emission_id)
+ diagnostics::paths::event_id_t emission_id)
{
checker_event::prepare_for_emission (path, pd, emission_id);
path->record_setjmp_event (m_enode, emission_id);
@@ -1038,7 +1078,7 @@ rewind_event::rewind_event (const exploded_edge *eedge,
/* class rewind_from_longjmp_event : public rewind_event. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
rewind_from_longjmp_event. */
void
@@ -1062,7 +1102,7 @@ rewind_from_longjmp_event::print_desc (pretty_printer &pp) const
/* class rewind_to_setjmp_event : public rewind_event. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
rewind_to_setjmp_event. */
void
@@ -1111,16 +1151,60 @@ rewind_to_setjmp_event::print_desc (pretty_printer &pp) const
void
rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
pending_diagnostic *pd,
- diagnostic_event_id_t emission_id)
+ diagnostics::paths::event_id_t emission_id)
{
checker_event::prepare_for_emission (path, pd, emission_id);
path->get_setjmp_event (m_rewind_info->get_enode_origin (),
&m_original_setjmp_event_id);
}
+/* class throw_event : public checker_event. */
+
+/* class explicit_throw_event : public throw_event. */
+void
+explicit_throw_event::print_desc (pretty_printer &pp) const
+{
+ if (m_is_rethrow)
+ {
+ if (m_type)
+ pp_printf (&pp, "rethrowing exception of type %qT here...", m_type);
+ else
+ pp_printf (&pp, "rethrowing exception here...");
+ }
+ else
+ {
+ if (m_type)
+ pp_printf (&pp, "throwing exception of type %qT here...", m_type);
+ else
+ pp_printf (&pp, "throwing exception here...");
+ }
+}
+
+/* class throw_from_call_to_external_fn_event : public throw_event. */
+
+void
+throw_from_call_to_external_fn_event::print_desc (pretty_printer &pp) const
+{
+ if (m_fndecl)
+ pp_printf (&pp, "if %qD throws an exception...", m_fndecl);
+ else
+ pp_printf (&pp, "if the called function throws an exception...");
+}
+
+// class unwind_event : public checker_event
+
+void
+unwind_event::print_desc (pretty_printer &pp) const
+{
+ if (m_num_frames > 1)
+ pp_printf (&pp, "unwinding %i stack frames", m_num_frames);
+ else
+ pp_printf (&pp, "unwinding stack frame");
+}
+
/* class warning_event : public checker_event. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
warning_event.
If the pending diagnostic implements describe_final_event, use it,
@@ -1165,13 +1249,22 @@ warning_event::print_desc (pretty_printer &pp) const
pp_string (&pp, "here");
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
warning_event. */
-diagnostic_event::meaning
+diagnostics::paths::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 f92f514..909e388 100644
--- a/gcc/analyzer/checker-event.h
+++ b/gcc/analyzer/checker-event.h
@@ -1,4 +1,4 @@
-/* Subclasses of diagnostic_event for analyzer diagnostics.
+/* Subclasses of diagnostics::paths::event for analyzer diagnostics.
Copyright (C) 2019-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -24,31 +24,35 @@ along with GCC; see the file COPYING3. If not see
#include "tree-logical-location.h"
#include "analyzer/program-state.h"
#include "analyzer/event-loc-info.h"
+#include "diagnostics/digraphs.h"
namespace ana {
/* An enum for discriminating between the concrete subclasses of
checker_event. */
-enum event_kind
-{
- EK_DEBUG,
- EK_CUSTOM,
- EK_STMT,
- EK_REGION_CREATION,
- EK_FUNCTION_ENTRY,
- EK_STATE_CHANGE,
- EK_START_CFG_EDGE,
- EK_END_CFG_EDGE,
- EK_CALL_EDGE,
- EK_RETURN_EDGE,
- EK_START_CONSOLIDATED_CFG_EDGES,
- EK_END_CONSOLIDATED_CFG_EDGES,
- EK_INLINED_CALL,
- EK_SETJMP,
- EK_REWIND_FROM_LONGJMP,
- EK_REWIND_TO_SETJMP,
- EK_WARNING
+enum class event_kind
+{
+ debug,
+ custom,
+ stmt,
+ region_creation,
+ function_entry,
+ state_change,
+ start_cfg_edge,
+ end_cfg_edge,
+ catch_,
+ call_edge,
+ return_edge,
+ start_consolidated_cfg_edges,
+ end_consolidated_cfg_edges,
+ inlined_call,
+ setjmp_,
+ rewind_from_longjmp,
+ rewind_to_setjmp,
+ throw_,
+ unwind,
+ warning
};
extern const char *event_kind_to_string (enum event_kind ek);
@@ -58,71 +62,83 @@ extern const char *event_kind_to_string (enum event_kind ek);
The class hierarchy looks like this (using indentation to show
inheritance, and with event_kinds shown for the concrete subclasses):
- diagnostic_event
+ diagnostics::paths::event
checker_event
- debug_event (EK_DEBUG)
- custom_event (EK_CUSTOM)
+ debug_event (event_kind::debug)
+ custom_event (event_kind::custom)
precanned_custom_event
- statement_event (EK_STMT)
- region_creation_event (EK_REGION_CREATION)
- function_entry_event (EK_FUNCTION_ENTRY)
- state_change_event (EK_STATE_CHANGE)
+ statement_event (event_kind::stmt)
+ region_creation_event (event_kind::region_creation)
+ function_entry_event (event_kind::function_entry)
+ state_change_event (event_kind::state_change)
superedge_event
cfg_edge_event
- start_cfg_edge_event (EK_START_CFG_EDGE)
- end_cfg_edge_event (EK_END_CFG_EDGE)
- call_event (EK_CALL_EDGE)
- return_edge (EK_RETURN_EDGE)
- start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES)
- end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES)
- inlined_call_event (EK_INLINED_CALL)
- setjmp_event (EK_SETJMP)
+ start_cfg_edge_event (event_kind::start_cfg_edge)
+ end_cfg_edge_event (event_kind::end_cfg_edge)
+ catch_cfg_edge_event (event_kind::catch_cfg_edge)
+ call_event (event_kind::call_edge)
+ return_edge (event_kind::return_edge)
+ start_consolidated_cfg_edges_event (event_kind::start_consolidated_cfg_edges)
+ end_consolidated_cfg_edges_event (event_kind::end_consolidated_cfg_edges)
+ inlined_call_event (event_kind::inlined_call)
+ setjmp_event (event_kind::setjmp_)
rewind_event
- rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
- rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
- warning_event (EK_WARNING). */
-
-/* Abstract subclass of diagnostic_event; the base class for use in
- checker_path (the analyzer's diagnostic_path subclass). */
-
-class checker_event : public diagnostic_event
+ rewind_from_longjmp_event (event_kind::rewind_from_longjmp)
+ rewind_to_setjmp_event (event_kind::rewind_to_setjmp)
+ throw_event (event_kind:throw_)
+ explicit_throw_event
+ throw_from_call_to_external_fn_event
+ unwind_event (event_kind::unwind)
+ warning_event (event_kind::warning). */
+
+/* Abstract subclass of diagnostics::paths::event; the base class for use in
+ checker_path (the analyzer's diagnostics::paths::path subclass). */
+
+class checker_event : public diagnostics::paths::event
{
public:
- /* Implementation of diagnostic_event. */
+ /* Implementation of diagnostics::paths::event. */
location_t get_location () const final override { return m_loc; }
int get_stack_depth () const final override { return m_effective_depth; }
- const logical_location *get_logical_location () const final override
+ diagnostics::logical_locations::key
+ get_logical_location () const final override
{
- if (m_effective_fndecl)
- return &m_logical_loc;
- else
- return NULL;
+ return m_logical_loc;
}
meaning get_meaning () const override;
bool connect_to_next_event_p () const override { return false; }
- diagnostic_thread_id_t get_thread_id () const final override
+ diagnostics::paths::thread_id_t get_thread_id () const final override
{
return 0;
}
void
- maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj) const override;
+ maybe_add_sarif_properties (diagnostics::sarif_builder &,
+ diagnostics::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; }
virtual void prepare_for_emission (checker_path *,
pending_diagnostic *pd,
- diagnostic_event_id_t emission_id);
+ diagnostics::paths::event_id_t emission_id);
virtual bool is_call_p () const { return false; }
virtual bool is_function_entry_p () const { return false; }
virtual bool is_return_p () const { return false; }
+ std::unique_ptr<diagnostics::digraphs::digraph>
+ maybe_make_diagnostic_state_graph (bool debug) const final override;
+
+ virtual const program_state *
+ get_program_state () const { return nullptr; }
+
/* For use with %@. */
- const diagnostic_event_id_t *get_id_ptr () const
+ const diagnostics::paths::event_id_t *get_id_ptr () const
{
return &m_emission_id;
}
@@ -136,7 +152,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;
@@ -145,8 +162,8 @@ protected:
int m_original_depth;
int m_effective_depth;
pending_diagnostic *m_pending_diagnostic;
- diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
- tree_logical_location m_logical_loc;
+ diagnostics::paths::event_id_t m_emission_id; // only set once all pruning has occurred
+ diagnostics::logical_locations::key m_logical_loc;
};
/* A concrete event subclass for a purely textual event, for use in
@@ -158,7 +175,7 @@ public:
debug_event (const event_loc_info &loc_info,
const char *desc)
- : checker_event (EK_DEBUG, loc_info),
+ : checker_event (event_kind::debug, loc_info),
m_desc (xstrdup (desc))
{
}
@@ -180,7 +197,7 @@ class custom_event : public checker_event
{
protected:
custom_event (const event_loc_info &loc_info)
- : checker_event (EK_CUSTOM, loc_info)
+ : checker_event (event_kind::custom, loc_info)
{
}
};
@@ -218,6 +235,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;
};
@@ -328,17 +351,29 @@ private:
class function_entry_event : public checker_event
{
public:
- function_entry_event (const event_loc_info &loc_info)
- : checker_event (EK_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. */
@@ -359,6 +394,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 ();
@@ -383,7 +424,9 @@ public:
class superedge_event : public checker_event
{
public:
- void maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_builder &,
+ diagnostics::sarif_object &thread_flow_loc_obj)
const override;
/* Mark this edge event as being either an interprocedural call or
@@ -400,6 +443,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);
@@ -435,7 +481,7 @@ class start_cfg_edge_event : public cfg_edge_event
public:
start_cfg_edge_event (const exploded_edge &eedge,
const event_loc_info &loc_info)
- : cfg_edge_event (EK_START_CFG_EDGE, eedge, loc_info)
+ : cfg_edge_event (event_kind::start_cfg_edge, eedge, loc_info)
{
}
@@ -461,7 +507,7 @@ class end_cfg_edge_event : public cfg_edge_event
public:
end_cfg_edge_event (const exploded_edge &eedge,
const event_loc_info &loc_info)
- : cfg_edge_event (EK_END_CFG_EDGE, eedge, loc_info)
+ : cfg_edge_event (event_kind::end_cfg_edge, eedge, loc_info)
{
}
@@ -471,6 +517,32 @@ public:
}
};
+/* A concrete event subclass for catching an exception
+ e.g. "...catching 'struct io_error' here". */
+
+class catch_cfg_edge_event : public cfg_edge_event
+{
+public:
+ catch_cfg_edge_event (const exploded_edge &eedge,
+ const event_loc_info &loc_info,
+ tree type)
+ : cfg_edge_event (event_kind::catch_, eedge, loc_info),
+ m_type (type)
+ {
+ }
+
+ void print_desc (pretty_printer &pp) const final override
+ {
+ if (m_type)
+ pp_printf (&pp, "...catching exception of type %qT here", m_type);
+ else
+ pp_string (&pp, "...catching exception here");
+ }
+
+private:
+ tree m_type;
+};
+
/* A concrete event subclass for an interprocedural call. */
class call_event : public superedge_event
@@ -484,6 +556,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;
@@ -517,7 +592,7 @@ class start_consolidated_cfg_edges_event : public checker_event
public:
start_consolidated_cfg_edges_event (const event_loc_info &loc_info,
bool edge_sense)
- : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc_info),
+ : checker_event (event_kind::start_consolidated_cfg_edges, loc_info),
m_edge_sense (edge_sense)
{
}
@@ -537,7 +612,7 @@ class end_consolidated_cfg_edges_event : public checker_event
{
public:
end_consolidated_cfg_edges_event (const event_loc_info &loc_info)
- : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc_info)
+ : checker_event (event_kind::end_consolidated_cfg_edges, loc_info)
{
}
@@ -558,7 +633,7 @@ public:
tree apparent_caller_fndecl,
int actual_depth,
int stack_depth_adjustment)
- : checker_event (EK_INLINED_CALL,
+ : checker_event (event_kind::inlined_call,
event_loc_info (loc,
apparent_caller_fndecl,
actual_depth + stack_depth_adjustment)),
@@ -583,8 +658,8 @@ class setjmp_event : public checker_event
public:
setjmp_event (const event_loc_info &loc_info,
const exploded_node *enode,
- const gcall *setjmp_call)
- : checker_event (EK_SETJMP, loc_info),
+ const gcall &setjmp_call)
+ : checker_event (event_kind::setjmp_, loc_info),
m_enode (enode), m_setjmp_call (setjmp_call)
{
}
@@ -593,11 +668,11 @@ public:
void prepare_for_emission (checker_path *path,
pending_diagnostic *pd,
- diagnostic_event_id_t emission_id) final override;
+ diagnostics::paths::event_id_t emission_id) final override;
private:
const exploded_node *m_enode;
- const gcall *m_setjmp_call;
+ const gcall &m_setjmp_call;
};
/* An abstract event subclass for rewinding from a longjmp to a setjmp
@@ -633,7 +708,7 @@ public:
rewind_from_longjmp_event (const exploded_edge *eedge,
const event_loc_info &loc_info,
const rewind_info_t *rewind_info)
- : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc_info,
+ : rewind_event (eedge, event_kind::rewind_from_longjmp, loc_info,
rewind_info)
{
}
@@ -650,7 +725,7 @@ public:
rewind_to_setjmp_event (const exploded_edge *eedge,
const event_loc_info &loc_info,
const rewind_info_t *rewind_info)
- : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc_info,
+ : rewind_event (eedge, event_kind::rewind_to_setjmp, loc_info,
rewind_info)
{
}
@@ -659,10 +734,92 @@ public:
void prepare_for_emission (checker_path *path,
pending_diagnostic *pd,
- diagnostic_event_id_t emission_id) final override;
+ diagnostics::paths::event_id_t emission_id) final override;
private:
- diagnostic_event_id_t m_original_setjmp_event_id;
+ diagnostics::paths::event_id_t m_original_setjmp_event_id;
+};
+
+/* An abstract subclass for throwing/rethrowing an exception. */
+
+class throw_event : public checker_event
+{
+public:
+ throw_event (const event_loc_info &loc_info,
+ const exploded_node *enode,
+ const gcall &throw_call)
+ : checker_event (event_kind::throw_, loc_info),
+ m_enode (enode),
+ m_throw_call (throw_call)
+ {
+ }
+
+protected:
+ const exploded_node *m_enode;
+ const gcall &m_throw_call;
+};
+
+/* A concrete event subclass for an explicit "throw EXC;"
+ or "throw;" (actually, a call to __cxa_throw or __cxa_rethrow). */
+
+class explicit_throw_event : public throw_event
+{
+public:
+ explicit_throw_event (const event_loc_info &loc_info,
+ const exploded_node *enode,
+ const gcall &throw_call,
+ tree type,
+ bool is_rethrow)
+ : throw_event (loc_info, enode, throw_call),
+ m_type (type),
+ m_is_rethrow (is_rethrow)
+ {
+ }
+
+ void print_desc (pretty_printer &pp) const final override;
+
+private:
+ tree m_type;
+ bool m_is_rethrow;
+};
+
+/* A concrete event subclass for an exception being thrown
+ from within a call to a function we don't have the body of,
+ or where we don't know what function was called. */
+
+class throw_from_call_to_external_fn_event : public throw_event
+{
+public:
+ throw_from_call_to_external_fn_event (const event_loc_info &loc_info,
+ const exploded_node *enode,
+ const gcall &throw_call,
+ tree fndecl)
+ : throw_event (loc_info, enode, throw_call),
+ m_fndecl (fndecl)
+ {
+ }
+
+ void print_desc (pretty_printer &pp) const final override;
+
+private:
+ tree m_fndecl;
+};
+
+/* A concrete event subclass for unwinding a stack frame when
+ processing an exception. */
+
+class unwind_event : public checker_event
+{
+public:
+ unwind_event (const event_loc_info &loc_info)
+ : checker_event (event_kind::unwind, loc_info),
+ m_num_frames (1)
+ {
+ }
+
+ void print_desc (pretty_printer &pp) const final override;
+
+ int m_num_frames;
};
/* Concrete subclass of checker_event for use at the end of a path:
@@ -676,16 +833,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)
- : checker_event (EK_WARNING, loc_info),
+ 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:
@@ -693,6 +856,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 d97378e..646d72c 100644
--- a/gcc/analyzer/checker-path.cc
+++ b/gcc/analyzer/checker-path.cc
@@ -1,4 +1,4 @@
-/* Subclass of diagnostic_path for analyzer diagnostics.
+/* Subclass of diagnostics::paths::path for analyzer diagnostics.
Copyright (C) 2019-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -18,37 +18,22 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "gimple-pretty-print.h"
-#include "fold-const.h"
-#include "diagnostic-path.h"
-#include "options.h"
-#include "cgraph.h"
-#include "cfg.h"
-#include "digraph.h"
-#include "diagnostic-event-id.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
-#include "analyzer/sm.h"
+#include "analyzer/common.h"
+
+#include "tree-pretty-print.h"
#include "sbitmap.h"
-#include "bitmap.h"
#include "ordered-hash-map.h"
+#include "gimple-iterator.h"
+#include "inlining-iterator.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/sm.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/program-state.h"
#include "analyzer/checker-path.h"
-#include "gimple-iterator.h"
-#include "inlining-iterator.h"
#include "analyzer/supergraph.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
@@ -56,7 +41,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/diagnostic-manager.h"
#include "analyzer/checker-path.h"
#include "analyzer/exploded-graph.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -105,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 ();
}
@@ -119,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 ();
}
@@ -139,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 ());
}
}
@@ -164,8 +148,8 @@ checker_path::add_region_creation_events (pending_diagnostic *pd,
pd->add_region_creation_events (reg, capacity, loc_info, *this);
if (debug)
- add_event (make_unique<region_creation_event_debug> (reg, capacity,
- loc_info));
+ add_event (std::make_unique<region_creation_event_debug> (reg, capacity,
+ loc_info));
}
void
@@ -183,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 == EK_START_CFG_EDGE
- && m_events[idx + 1]->m_kind == EK_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",
@@ -202,38 +186,38 @@ checker_path::cfg_edge_pair_at_p (unsigned idx) const
(for gcc.dg/analyzer/inlining-4.c):
before[0]:
- EK_FUNCTION_ENTRY "entry to ‘outer’"
+ event_kind::function_entry "entry to ‘outer’"
(depth 1, fndecl ‘outer’, m_loc=511c4)
before[1]:
- EK_START_CFG_EDGE "following ‘true’ branch (when ‘flag != 0’)..."
+ event_kind::start_cfg_edge "following ‘true’ branch (when ‘flag != 0’)..."
(depth 3 corrected from 1,
fndecl ‘inner’ corrected from ‘outer’, m_loc=8000000f)
before[2]:
- EK_END_CFG_EDGE "...to here"
+ event_kind::end_cfg_edge "...to here"
(depth 1, fndecl ‘outer’, m_loc=0)
before[3]:
- EK_WARNING "here (‘<unknown>’ is in state ‘null’)"
+ event_kind::warning "here (‘<unknown>’ is in state ‘null’)"
(depth 1, fndecl ‘outer’, m_loc=80000004)
We want to add inlined_call_events showing the calls, so that
the above becomes:
after[0]:
- EK_FUNCTION_ENTRY "entry to ‘outer’"
+ event_kind::function_entry "entry to ‘outer’"
(depth 1, fndecl ‘outer’, m_loc=511c4)
after[1]:
- EK_INLINED_CALL "inlined call to ‘middle’ from ‘outer’"
+ event_kind::inlined_call "inlined call to ‘middle’ from ‘outer’"
(depth 1, fndecl ‘outer’, m_loc=53300)
after[2]:
- EK_INLINED_CALL "inlined call to ‘inner’ from ‘middle’"
+ event_kind::inlined_call "inlined call to ‘inner’ from ‘middle’"
(depth 2, fndecl ‘middle’, m_loc=4d2e0)
after[3]:
- EK_START_CFG_EDGE "following ‘true’ branch (when ‘flag != 0’)..."
+ event_kind::start_cfg_edge "following ‘true’ branch (when ‘flag != 0’)..."
(depth 3 corrected from 1,
fndecl ‘inner’ corrected from ‘outer’, m_loc=8000000f)
- after[4]: EK_END_CFG_EDGE "...to here"
+ after[4]: event_kind::end_cfg_edge "...to here"
(depth 1, fndecl ‘outer’, m_loc=0)
- after[5]: EK_WARNING "here (‘<unknown>’ is in state ‘null’)"
+ after[5]: event_kind::warning "here (‘<unknown>’ is in state ‘null’)"
(depth 1, fndecl ‘outer’, m_loc=80000004)
where we've added events between before[0] and before[1] to show
@@ -270,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 dfc782d..490d21b 100644
--- a/gcc/analyzer/checker-path.h
+++ b/gcc/analyzer/checker-path.h
@@ -1,4 +1,4 @@
-/* Subclass of diagnostic_path for analyzer diagnostics.
+/* Subclass of diagnostics::paths::path for analyzer diagnostics.
Copyright (C) 2019-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -26,25 +26,29 @@ along with GCC; see the file COPYING3. If not see
namespace ana {
-/* Subclass of diagnostic_path for analyzer diagnostics. */
+/* Subclass of diagnostic path for analyzer diagnostics. */
-class checker_path : public diagnostic_path
+class checker_path : public diagnostics::paths::path
{
public:
- checker_path (logger *logger)
- : diagnostic_path (),
+ checker_path (const diagnostics::logical_locations::manager &logical_loc_mgr,
+ const extrinsic_state &ext_state,
+ logger *logger)
+ : diagnostics::paths::path (logical_loc_mgr),
+ m_ext_state (ext_state),
m_thread ("main"),
m_logger (logger)
{}
- /* Implementation of diagnostic_path vfuncs. */
+ /* Implementation of diagnostics::paths::path vfuncs. */
unsigned num_events () const final override
{
return m_events.length ();
}
- const diagnostic_event & get_event (int idx) const final override
+ const diagnostics::paths::event &
+ get_event (int idx) const final override
{
return *m_events[idx];
}
@@ -52,12 +56,14 @@ public:
{
return 1;
}
- const diagnostic_thread &
- get_thread (diagnostic_thread_id_t) const final override
+ const diagnostics::paths::thread &
+ get_thread (diagnostics::paths::thread_id_t) const final override
{
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];
@@ -110,21 +116,22 @@ public:
checker_event *e;
int i;
FOR_EACH_VEC_ELT (m_events, i, e)
- e->prepare_for_emission (this, pd, diagnostic_event_id_t (i));
+ e->prepare_for_emission (this, pd, diagnostics::paths::event_id_t (i));
}
void fixup_locations (pending_diagnostic *pd);
void record_setjmp_event (const exploded_node *enode,
- diagnostic_event_id_t setjmp_emission_id)
+ diagnostics::paths::event_id_t setjmp_emission_id)
{
m_setjmp_event_ids.put (enode, setjmp_emission_id);
}
bool get_setjmp_event (const exploded_node *enode,
- diagnostic_event_id_t *out_emission_id)
+ diagnostics::paths::event_id_t *out_emission_id)
{
- if (diagnostic_event_id_t *emission_id = m_setjmp_event_ids.get (enode))
+ if (diagnostics::paths::event_id_t *emission_id
+ = m_setjmp_event_ids.get (enode))
{
*out_emission_id = *emission_id;
return true;
@@ -139,6 +146,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. */
@@ -147,7 +156,7 @@ private:
/* During prepare_for_emission (and after), the setjmp_event for each
exploded_node *, so that rewind events can refer to them in their
descriptions. */
- hash_map <const exploded_node *, diagnostic_event_id_t> m_setjmp_event_ids;
+ hash_map <const exploded_node *, diagnostics::paths::event_id_t> m_setjmp_event_ids;
logger *m_logger;
};
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/common.h
index 4843d99..ac3048c 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/common.h
@@ -1,4 +1,4 @@
-/* Utility functions for the analyzer.
+/* Base header for the analyzer, plus utility functions.
Copyright (C) 2019-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -18,9 +18,23 @@ 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_ANALYZER_H
-#define GCC_ANALYZER_ANALYZER_H
+#ifndef GCC_ANALYZER_COMMON_H
+#define GCC_ANALYZER_COMMON_H
+#include "config.h"
+#define INCLUDE_MAP
+#define INCLUDE_STRING
+#define INCLUDE_VECTOR
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "options.h"
+#include "bitmap.h"
+#include "diagnostic-core.h"
+#include "diagnostics/paths.h"
#include "rich-location.h"
#include "function.h"
#include "json.h"
@@ -37,6 +51,9 @@ class supernode;
class superedge;
class cfg_superedge;
class switch_cfg_superedge;
+ class eh_dispatch_cfg_superedge;
+ class eh_dispatch_try_cfg_superedge;
+ class eh_dispatch_allowed_cfg_superedge;
class callgraph_superedge;
class call_superedge;
class return_superedge;
@@ -192,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)
@@ -211,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
{
@@ -289,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. */
@@ -350,10 +367,10 @@ public:
/* An enum for describing the direction of an access to memory. */
-enum access_direction
+enum class access_direction
{
- DIR_READ,
- DIR_WRITE
+ read,
+ write
};
/* Abstract base class for associating custom data with an
@@ -384,6 +401,12 @@ public:
virtual void add_events_to_path (checker_path *emission_path,
const exploded_edge &eedge) const = 0;
+
+ virtual exploded_node *create_enode (exploded_graph &eg,
+ const program_point &point,
+ program_state &&state,
+ exploded_node *enode_for_diag,
+ region_model_context *ctxt) const;
};
/* Abstract base class for splitting state.
@@ -420,7 +443,7 @@ extern std::unique_ptr<json::value>
tree_to_json (tree node);
extern std::unique_ptr<json::value>
-diagnostic_event_id_to_json (const diagnostic_event_id_t &);
+diagnostic_event_id_to_json (const diagnostics::paths::event_id_t &);
extern std::unique_ptr<json::value>
bit_offset_to_json (const bit_offset_t &offset);
@@ -447,21 +470,23 @@ extern tree remove_ssa_names (tree expr);
} // namespace ana
-extern bool is_special_named_call_p (const gcall *call, const char *funcname,
+extern bool is_special_named_call_p (const gcall &call, const char *funcname,
unsigned int num_args,
bool look_in_std = false);
extern bool is_named_call_p (const_tree fndecl, const char *funcname);
extern bool is_named_call_p (const_tree fndecl, const char *funcname,
- const gcall *call, unsigned int num_args);
+ const gcall &call, unsigned int num_args);
extern bool is_std_function_p (const_tree fndecl);
extern bool is_std_named_call_p (const_tree fndecl, const char *funcname);
extern bool is_std_named_call_p (const_tree fndecl, const char *funcname,
- const gcall *call, unsigned int num_args);
-extern bool is_setjmp_call_p (const gcall *call);
-extern bool is_longjmp_call_p (const gcall *call);
-extern bool is_placement_new_p (const gcall *call);
+ const gcall &call, unsigned int num_args);
+extern bool is_setjmp_call_p (const gcall &call);
+extern bool is_longjmp_call_p (const gcall &call);
+extern bool is_placement_new_p (const gcall &call);
+extern bool is_cxa_throw_p (const gcall &call);
+extern bool is_cxa_rethrow_p (const gcall &call);
-extern const char *get_user_facing_name (const gcall *call);
+extern const char *get_user_facing_name (const gcall &call);
extern void register_analyzer_pass ();
@@ -542,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. */
@@ -577,4 +602,4 @@ private:
extern void sorry_no_analyzer ();
#endif /* #if !ENABLE_ANALYZER */
-#endif /* GCC_ANALYZER_ANALYZER_H */
+#endif /* GCC_ANALYZER_COMMON_H */
diff --git a/gcc/analyzer/complexity.cc b/gcc/analyzer/complexity.cc
index cb88f60..4a0a156 100644
--- a/gcc/analyzer/complexity.cc
+++ b/gcc/analyzer/complexity.cc
@@ -18,34 +18,14 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "diagnostic-core.h"
-#include "gimple-pretty-print.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
-#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "options.h"
#include "cgraph.h"
#include "cfg.h"
#include "digraph.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
diff --git a/gcc/analyzer/constraint-manager.cc b/gcc/analyzer/constraint-manager.cc
index 55d8996..58c60fe 100644
--- a/gcc/analyzer/constraint-manager.cc
+++ b/gcc/analyzer/constraint-manager.cc
@@ -18,28 +18,17 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
+#include "analyzer/common.h"
+
#include "fold-const.h"
-#include "selftest.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "analyzer/analyzer.h"
#include "ordered-hash-map.h"
-#include "options.h"
#include "cgraph.h"
#include "cfg.h"
#include "digraph.h"
-#include "analyzer/supergraph.h"
#include "sbitmap.h"
-#include "bitmap.h"
+#include "tree-pretty-print.h"
+
+#include "analyzer/supergraph.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
@@ -48,8 +37,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/constraint-manager.h"
#include "analyzer/call-summary.h"
#include "analyzer/analyzer-selftests.h"
-#include "tree-pretty-print.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -117,7 +104,7 @@ minus_one (tree cst)
closed one. */
void
-bound::ensure_closed (enum bound_kind bound_kind)
+bound::ensure_closed (enum bound_kind bnd_kind)
{
if (!m_closed)
{
@@ -126,7 +113,7 @@ bound::ensure_closed (enum bound_kind bound_kind)
and convert x < 5 into x <= 4. */
gcc_assert (CONSTANT_CLASS_P (m_constant));
gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (m_constant)));
- m_constant = fold_build2 (bound_kind == BK_UPPER ? MINUS_EXPR : PLUS_EXPR,
+ m_constant = fold_build2 (bnd_kind == bound_kind::upper ? MINUS_EXPR : PLUS_EXPR,
TREE_TYPE (m_constant),
m_constant, integer_one_node);
gcc_assert (CONSTANT_CLASS_P (m_constant));
@@ -203,8 +190,8 @@ range::constrained_to_single_element ()
return NULL_TREE;
/* Convert any open bounds to closed bounds. */
- m_lower_bound.ensure_closed (BK_LOWER);
- m_upper_bound.ensure_closed (BK_UPPER);
+ m_lower_bound.ensure_closed (bound_kind::lower);
+ m_upper_bound.ensure_closed (bound_kind::upper);
// Are they equal?
tree comparison = fold_binary (EQ_EXPR, boolean_type_node,
@@ -303,30 +290,30 @@ range::above_upper_bound (tree rhs_const) const
Return true if feasible; false if infeasible. */
bool
-range::add_bound (bound b, enum bound_kind bound_kind)
+range::add_bound (bound b, enum bound_kind bnd_kind)
{
/* Bail out on floating point constants. */
if (!INTEGRAL_TYPE_P (TREE_TYPE (b.m_constant)))
return true;
- b.ensure_closed (bound_kind);
+ b.ensure_closed (bnd_kind);
- switch (bound_kind)
+ switch (bnd_kind)
{
default:
gcc_unreachable ();
- case BK_LOWER:
+ case bound_kind::lower:
/* Discard redundant bounds. */
if (m_lower_bound.m_constant)
{
- m_lower_bound.ensure_closed (BK_LOWER);
+ m_lower_bound.ensure_closed (bound_kind::lower);
if (tree_int_cst_le (b.m_constant,
m_lower_bound.m_constant))
return true;
}
if (m_upper_bound.m_constant)
{
- m_upper_bound.ensure_closed (BK_UPPER);
+ m_upper_bound.ensure_closed (bound_kind::upper);
/* Reject B <= V <= UPPER when B > UPPER. */
if (!tree_int_cst_le (b.m_constant,
m_upper_bound.m_constant))
@@ -335,18 +322,18 @@ range::add_bound (bound b, enum bound_kind bound_kind)
m_lower_bound = b;
break;
- case BK_UPPER:
+ case bound_kind::upper:
/* Discard redundant bounds. */
if (m_upper_bound.m_constant)
{
- m_upper_bound.ensure_closed (BK_UPPER);
+ m_upper_bound.ensure_closed (bound_kind::upper);
if (!tree_int_cst_lt (b.m_constant,
m_upper_bound.m_constant))
return true;
}
if (m_lower_bound.m_constant)
{
- m_lower_bound.ensure_closed (BK_LOWER);
+ m_lower_bound.ensure_closed (bound_kind::lower);
/* Reject LOWER <= V <= B when LOWER > B. */
if (!tree_int_cst_le (m_lower_bound.m_constant,
b.m_constant))
@@ -371,16 +358,16 @@ range::add_bound (enum tree_code op, tree rhs_const)
return true;
case LT_EXPR:
/* "V < RHS_CONST" */
- return add_bound (bound (rhs_const, false), BK_UPPER);
+ return add_bound (bound (rhs_const, false), bound_kind::upper);
case LE_EXPR:
/* "V <= RHS_CONST" */
- return add_bound (bound (rhs_const, true), BK_UPPER);
+ return add_bound (bound (rhs_const, true), bound_kind::upper);
case GE_EXPR:
/* "V >= RHS_CONST" */
- return add_bound (bound (rhs_const, true), BK_LOWER);
+ return add_bound (bound (rhs_const, true), bound_kind::lower);
case GT_EXPR:
/* "V > RHS_CONST" */
- return add_bound (bound (rhs_const, false), BK_LOWER);
+ return add_bound (bound (rhs_const, false), bound_kind::lower);
}
}
@@ -449,7 +436,7 @@ bounded_range::dump (bool show_types) const
std::unique_ptr<json::object>
bounded_range::to_json () const
{
- auto range_obj = ::make_unique<json::object> ();
+ auto range_obj = std::make_unique<json::object> ();
set_json_attr (*range_obj, "lower", m_lower);
set_json_attr (*range_obj, "upper", m_upper);
return range_obj;
@@ -622,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)))
@@ -718,7 +705,7 @@ bounded_ranges::dump (bool show_types) const
std::unique_ptr<json::value>
bounded_ranges::to_json () const
{
- auto arr_obj = ::make_unique<json::array> ();
+ auto arr_obj = std::make_unique<json::array> ();
for (unsigned i = 0; i < m_ranges.length (); ++i)
arr_obj->append (m_ranges[i].to_json ());
@@ -1071,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 ()
{
}
@@ -1116,9 +1103,9 @@ equiv_class::print (pretty_printer *pp) const
std::unique_ptr<json::object>
equiv_class::to_json () const
{
- auto ec_obj = ::make_unique<json::object> ();
+ auto ec_obj = std::make_unique<json::object> ();
- auto sval_arr = ::make_unique<json::array> ();
+ auto sval_arr = std::make_unique<json::array> ();
for (const svalue *sval : m_vars)
sval_arr->append (sval->to_json ());
ec_obj->set ("svals", std::move (sval_arr));
@@ -1383,7 +1370,7 @@ constraint::print (pretty_printer *pp, const constraint_manager &cm) const
std::unique_ptr<json::object>
constraint::to_json () const
{
- auto con_obj = ::make_unique<json::object> ();
+ auto con_obj = std::make_unique<json::object> ();
con_obj->set_integer ("lhs", m_lhs.as_int ());
con_obj->set_string ("op", constraint_op_code (m_op));
@@ -1471,7 +1458,7 @@ bounded_ranges_constraint::print (pretty_printer *pp,
std::unique_ptr<json::object>
bounded_ranges_constraint::to_json () const
{
- auto con_obj = ::make_unique<json::object> ();
+ auto con_obj = std::make_unique<json::object> ();
con_obj->set_integer ("ec", m_ec_id.as_int ());
con_obj->set ("ranges", m_ranges->to_json ());
@@ -1784,11 +1771,11 @@ debug (const constraint_manager &cm)
std::unique_ptr<json::object>
constraint_manager::to_json () const
{
- auto cm_obj = ::make_unique<json::object> ();
+ auto cm_obj = std::make_unique<json::object> ();
/* Equivalence classes. */
{
- auto ec_arr = ::make_unique<json::array> ();
+ auto ec_arr = std::make_unique<json::array> ();
for (const equiv_class *ec : m_equiv_classes)
ec_arr->append (ec->to_json ());
cm_obj->set ("ecs", std::move (ec_arr));
@@ -1796,7 +1783,7 @@ constraint_manager::to_json () const
/* Constraints. */
{
- auto con_arr = ::make_unique<json::array> ();
+ auto con_arr = std::make_unique<json::array> ();
for (const constraint &c : m_constraints)
con_arr->append (c.to_json ());
cm_obj->set ("constraints", std::move (con_arr));
@@ -1804,7 +1791,7 @@ constraint_manager::to_json () const
/* m_bounded_ranges_constraints. */
{
- auto con_arr = ::make_unique<json::array> ();
+ auto con_arr = std::make_unique<json::array> ();
for (const auto &c : m_bounded_ranges_constraints)
con_arr->append (c.to_json ());
cm_obj->set ("bounded_ranges_constraints", std::move (con_arr));
@@ -2578,12 +2565,12 @@ constraint_manager::get_ec_bounds (equiv_class_id ec_id) const
case CONSTRAINT_LT:
/* We have "EC_ID < OTHER_CST". */
- result.add_bound (bound (other_cst, false), BK_UPPER);
+ result.add_bound (bound (other_cst, false), bound_kind::upper);
break;
case CONSTRAINT_LE:
/* We have "EC_ID <= OTHER_CST". */
- result.add_bound (bound (other_cst, true), BK_UPPER);
+ result.add_bound (bound (other_cst, true), bound_kind::upper);
break;
}
}
@@ -2600,13 +2587,13 @@ constraint_manager::get_ec_bounds (equiv_class_id ec_id) const
case CONSTRAINT_LT:
/* We have "OTHER_CST < EC_ID"
i.e. "EC_ID > OTHER_CST". */
- result.add_bound (bound (other_cst, false), BK_LOWER);
+ result.add_bound (bound (other_cst, false), bound_kind::lower);
break;
case CONSTRAINT_LE:
/* We have "OTHER_CST <= EC_ID"
i.e. "EC_ID >= OTHER_CST". */
- result.add_bound (bound (other_cst, true), BK_LOWER);
+ result.add_bound (bound (other_cst, true), bound_kind::lower);
break;
}
}
@@ -3037,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
@@ -3060,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.
@@ -3204,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);
@@ -3528,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);
@@ -4317,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);
@@ -4335,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);
@@ -4354,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);
@@ -4372,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);
@@ -4390,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);
@@ -4409,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);
@@ -4472,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 c22b99e..4339ea6 100644
--- a/gcc/analyzer/constraint-manager.h
+++ b/gcc/analyzer/constraint-manager.h
@@ -25,10 +25,10 @@ namespace ana {
class constraint_manager;
-enum bound_kind
+enum class bound_kind
{
- BK_LOWER,
- BK_UPPER
+ lower,
+ upper
};
/* One of the end-points of a range. */
@@ -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 4bf1dce..88f72d1 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -18,22 +18,19 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "input.h"
-#include "diagnostic-core.h"
-#include "pretty-print.h"
-#include "gcc-rich-location.h"
+#include "analyzer/common.h"
+
+#include "cfg.h"
+#include "basic-block.h"
+#include "gimple.h"
#include "gimple-pretty-print.h"
-#include "function.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-path.h"
-#include "bitmap.h"
-#include "ordered-hash-map.h"
-#include "analyzer/analyzer.h"
+#include "gimple-iterator.h"
+#include "inlining-iterator.h"
+#include "cgraph.h"
+#include "digraph.h"
+#include "gcc-rich-location.h"
+#include "diagnostics/sarif-sink.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
@@ -43,13 +40,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/constraint-manager.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "inlining-iterator.h"
-#include "cgraph.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
@@ -57,8 +47,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/feasible-graph.h"
#include "analyzer/checker-path.h"
#include "analyzer/reachability.h"
-#include "make-unique.h"
-#include "diagnostic-format-sarif.h"
#if ENABLE_ANALYZER
@@ -75,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. */
@@ -137,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
@@ -189,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
@@ -203,7 +191,7 @@ epath_finder::get_best_epath (const exploded_node *enode,
logger->log ("trying to find shortest path ignoring feasibility");
gcc_assert (m_sep);
std::unique_ptr<exploded_path> epath
- = make_unique<exploded_path> (m_sep->get_shortest_path (enode));
+ = std::make_unique<exploded_path> (m_sep->get_shortest_path (enode));
if (epath->feasible_p (logger, out_problem, m_eg.get_engine (), &m_eg))
{
if (logger)
@@ -233,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)
{
}
@@ -428,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);
@@ -520,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,
@@ -624,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);
}
@@ -642,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);
}
@@ -699,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
@@ -742,7 +735,7 @@ saved_diagnostic::add_event (std::unique_ptr<checker_event> event)
std::unique_ptr<json::object>
saved_diagnostic::to_json () const
{
- auto sd_obj = ::make_unique<json::object> ();
+ auto sd_obj = std::make_unique<json::object> ();
if (m_sm)
sd_obj->set_string ("sm", m_sm->get_name ());
@@ -834,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. */
@@ -843,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);
@@ -1024,9 +1017,10 @@ saved_diagnostic::emit_any_notes () const
This extra data is intended for use when debugging the analyzer. */
void
-saved_diagnostic::maybe_add_sarif_properties (sarif_object &result_obj) const
+saved_diagnostic::
+maybe_add_sarif_properties (diagnostics::sarif_object &result_obj) const
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/saved_diagnostic/"
if (m_sm)
props.set_string (PROPERTY_PREFIX "sm", m_sm->get_name ());
@@ -1048,10 +1042,10 @@ saved_diagnostic::maybe_add_sarif_properties (sarif_object &result_obj) const
props.set_integer (PROPERTY_PREFIX "idx", m_idx);
if (m_duplicates.length () > 0)
{
- auto duplicates_arr = ::make_unique<json::array> ();
+ auto duplicates_arr = std::make_unique<json::array> ();
for (auto iter : m_duplicates)
{
- auto sd_obj = ::make_unique<sarif_object> ();
+ auto sd_obj = std::make_unique<diagnostics::sarif_object> ();
iter->maybe_add_sarif_properties (*sd_obj);
duplicates_arr->append (std::move (sd_obj));
}
@@ -1205,7 +1199,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. */
@@ -1242,10 +1236,10 @@ diagnostic_manager::add_event (std::unique_ptr<checker_event> event)
std::unique_ptr<json::object>
diagnostic_manager::to_json () const
{
- auto dm_obj = ::make_unique<json::object> ();
+ auto dm_obj = std::make_unique<json::object> ();
{
- auto sd_arr = ::make_unique<json::array> ();
+ auto sd_arr = std::make_unique<json::array> ();
int i;
saved_diagnostic *sd;
FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
@@ -1350,7 +1344,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)
@@ -1360,7 +1354,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;
};
@@ -1548,12 +1542,12 @@ diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg)
best_candidates.emit_best (this, eg);
}
-/* Custom subclass of diagnostic_metadata which, for SARIF output,
+/* Custom subclass of diagnostics::metadata which, for SARIF output,
populates the property bag of the diagnostic's "result" object
with information from the saved_diagnostic and the
pending_diagnostic. */
-class pending_diagnostic_metadata : public diagnostic_metadata
+class pending_diagnostic_metadata : public diagnostics::metadata
{
public:
pending_diagnostic_metadata (const saved_diagnostic &sd)
@@ -1562,7 +1556,8 @@ public:
}
void
- maybe_add_sarif_properties (sarif_object &result_obj) const override
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
+ const override
{
m_sd.maybe_add_sarif_properties (result_obj);
}
@@ -1590,9 +1585,11 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
/* Precompute all enodes from which the diagnostic is reachable. */
path_builder pb (eg, *epath, sd.get_feasibility_problem (), sd);
- /* This is the diagnostic_path subclass that will be built for
+ /* This is the diagnostics::paths::path subclass that will be built for
the diagnostic. */
- checker_path emission_path (get_logger ());
+ checker_path emission_path (get_logical_location_manager (),
+ eg.get_ext_state (),
+ get_logger ());
/* Populate emission_path with a full description of EPATH. */
build_emission_path (pb, *epath, &emission_path);
@@ -1625,7 +1622,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 ());
@@ -1668,6 +1665,15 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
}
}
+const diagnostics::logical_locations::manager &
+diagnostic_manager::get_logical_location_manager () const
+{
+ gcc_assert (global_dc);
+ auto mgr = global_dc->get_logical_location_manager ();
+ gcc_assert (mgr);
+ return *mgr;
+}
+
/* Emit a "path" of events to EMISSION_PATH describing the exploded path
EPATH within EG. */
@@ -1700,7 +1706,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),
@@ -1759,7 +1765,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:
@@ -1816,16 +1822,16 @@ public:
int stack_depth = src_stack_depth;
m_emission_path->add_event
- (make_unique<state_change_event> (supernode,
- stmt,
- stack_depth,
- sm,
- nullptr,
- src_sm_val,
- dst_sm_val,
- nullptr,
- dst_state,
- src_node));
+ (std::make_unique<state_change_event> (supernode,
+ stmt,
+ stack_depth,
+ sm,
+ nullptr,
+ src_sm_val,
+ dst_sm_val,
+ nullptr,
+ dst_state,
+ src_node));
return false;
}
@@ -1861,16 +1867,16 @@ public:
return false;
m_emission_path->add_event
- (make_unique<state_change_event> (supernode,
- stmt,
- stack_depth,
- sm,
- sval,
- src_sm_val,
- dst_sm_val,
- dst_origin_sval,
- dst_state,
- src_node));
+ (std::make_unique<state_change_event> (supernode,
+ stmt,
+ stack_depth,
+ sm,
+ sval,
+ src_sm_val,
+ dst_sm_val,
+ dst_origin_sval,
+ dst_state,
+ src_node));
return false;
}
@@ -1963,7 +1969,7 @@ struct null_assignment_sm_context : public sm_context
{
}
- tree get_fndecl_for_call (const gcall */*call*/) final override
+ tree get_fndecl_for_call (const gcall &/*call*/) final override
{
return NULL_TREE;
}
@@ -1972,7 +1978,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
@@ -2001,21 +2007,21 @@ 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 ();
m_emission_path->add_event
- (make_unique<state_change_event> (supernode,
- m_stmt,
- stack_depth,
- m_sm,
- var_new_sval,
- from, to,
- nullptr,
- *m_new_state,
- nullptr));
+ (std::make_unique<state_change_event> (supernode,
+ m_stmt,
+ stack_depth,
+ m_sm,
+ var_new_sval,
+ from, to,
+ nullptr,
+ *m_new_state,
+ nullptr));
}
void set_next_state (const gimple *stmt,
@@ -2033,15 +2039,15 @@ struct null_assignment_sm_context : public sm_context
int stack_depth = m_point->get_stack_depth ();
m_emission_path->add_event
- (make_unique<state_change_event> (supernode,
- m_stmt,
- stack_depth,
- m_sm,
- sval,
- from, to,
- nullptr,
- *m_new_state,
- nullptr));
+ (std::make_unique<state_change_event> (supernode,
+ m_stmt,
+ stack_depth,
+ m_sm,
+ sval,
+ from, to,
+ nullptr,
+ *m_new_state,
+ nullptr));
}
void warn (const supernode *, const gimple *,
@@ -2088,7 +2094,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);
@@ -2220,18 +2226,19 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb,
{
const gimple *stmt = dst_point.get_stmt ();
const gcall *call = dyn_cast <const gcall *> (stmt);
- if (call && is_setjmp_call_p (call))
+ if (call && is_setjmp_call_p (*call))
emission_path->add_event
- (make_unique<setjmp_event> (event_loc_info (stmt->location,
- dst_point.get_fndecl (),
- dst_stack_depth),
- dst_node,
- call));
+ (std::make_unique<setjmp_event>
+ (event_loc_info (stmt->location,
+ dst_point.get_fndecl (),
+ dst_stack_depth),
+ dst_node,
+ *call));
else
emission_path->add_event
- (make_unique<statement_event> (stmt,
- dst_point.get_fndecl (),
- dst_stack_depth, dst_state));
+ (std::make_unique<statement_event> (stmt,
+ dst_point.get_fndecl (),
+ dst_stack_depth, dst_state));
/* Create state change events for assignment to NULL.
Iterate through the stmts in dst_enode, adding state change
@@ -2248,7 +2255,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);
@@ -2294,7 +2301,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:
@@ -2324,11 +2331,11 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb,
" at this edge: ");
pb.get_feasibility_problem ()->dump_to_pp (&pp);
emission_path->add_event
- (make_unique<precanned_custom_event>
- (event_loc_info (dst_point.get_location (),
- dst_point.get_fndecl (),
- dst_stack_depth),
- pp_formatted_text (&pp)));
+ (std::make_unique<precanned_custom_event>
+ (event_loc_info (dst_point.get_location (),
+ dst_point.get_fndecl (),
+ dst_stack_depth),
+ pp_formatted_text (&pp)));
}
}
@@ -2438,18 +2445,48 @@ diagnostic_manager::add_events_for_superedge (const path_builder &pb,
{
case SUPEREDGE_CFG_EDGE:
{
+ if (auto eh_dispatch_try_sedge
+ = eedge.m_sedge->dyn_cast_eh_dispatch_try_cfg_superedge ())
+ {
+ if (eh_dispatch_try_sedge->get_eh_catch ())
+ {
+ const region_model *model = src_node->get_state ().m_region_model;
+ auto curr_thrown_exception_node
+ = model->get_current_thrown_exception ();
+ gcc_assert (curr_thrown_exception_node);
+ tree type = curr_thrown_exception_node->maybe_get_type ();
+ emission_path->add_event
+ (std::make_unique<catch_cfg_edge_event>
+ (eedge,
+ event_loc_info (dst_point.get_supernode ()->get_start_location (),
+ dst_point.get_fndecl (),
+ dst_stack_depth),
+ type));
+ return;
+ }
+ else
+ {
+ /* We have the "uncaught exception" sedge, from eh_dispatch
+ to a block containing resx.
+ Don't add any events for this, so that we can consolidate
+ adjacent stack unwinding events. */
+ return;
+ }
+ }
+
emission_path->add_event
- (make_unique<start_cfg_edge_event>
- (eedge,
- event_loc_info (last_stmt ? last_stmt->location : UNKNOWN_LOCATION,
- src_point.get_fndecl (),
- src_stack_depth)));
+ (std::make_unique<start_cfg_edge_event>
+ (eedge,
+ event_loc_info
+ (last_stmt ? last_stmt->location : UNKNOWN_LOCATION,
+ src_point.get_fndecl (),
+ src_stack_depth)));
emission_path->add_event
- (make_unique<end_cfg_edge_event>
- (eedge,
- event_loc_info (dst_point.get_supernode ()->get_start_location (),
- dst_point.get_fndecl (),
- dst_stack_depth)));
+ (std::make_unique<end_cfg_edge_event>
+ (eedge,
+ event_loc_info (dst_point.get_supernode ()->get_start_location (),
+ dst_point.get_fndecl (),
+ dst_stack_depth)));
}
break;
@@ -2462,12 +2499,13 @@ diagnostic_manager::add_events_for_superedge (const path_builder &pb,
/* TODO: add a subclass for this, or generate events for the
summary. */
emission_path->add_event
- (make_unique<debug_event> (event_loc_info (last_stmt
- ? last_stmt->location
- : UNKNOWN_LOCATION,
- src_point.get_fndecl (),
- src_stack_depth),
- "call summary"));
+ (std::make_unique<debug_event>
+ (event_loc_info (last_stmt
+ ? last_stmt->location
+ : UNKNOWN_LOCATION,
+ src_point.get_fndecl (),
+ src_stack_depth),
+ "call summary"));
}
break;
@@ -2476,14 +2514,13 @@ diagnostic_manager::add_events_for_superedge (const path_builder &pb,
const return_superedge *return_edge
= as_a <const return_superedge *> (eedge.m_sedge);
- const gcall *call_stmt = return_edge->get_call_stmt ();
+ const gcall &call_stmt = return_edge->get_call_stmt ();
emission_path->add_event
- (make_unique<return_event> (eedge,
- event_loc_info (call_stmt
- ? call_stmt->location
- : UNKNOWN_LOCATION,
- dst_point.get_fndecl (),
- dst_stack_depth)));
+ (std::make_unique<return_event>
+ (eedge,
+ event_loc_info (call_stmt.location,
+ dst_point.get_fndecl (),
+ dst_stack_depth)));
}
break;
}
@@ -2512,6 +2549,7 @@ diagnostic_manager::prune_path (checker_path *path,
if (! flag_analyzer_show_events_in_system_headers)
prune_system_headers (path);
consolidate_conditions (path);
+ consolidate_unwind_events (path);
finish_pruning (path);
path->maybe_log (get_logger (), "pruned");
}
@@ -2569,24 +2607,24 @@ 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 ();
- case EK_DEBUG:
+ case event_kind::debug:
if (m_verbosity < 4)
{
log ("filtering event %i: debug event", idx);
@@ -2594,11 +2632,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
}
break;
- case EK_CUSTOM:
+ case event_kind::custom:
/* Don't filter custom events. */
break;
- case EK_STMT:
+ case event_kind::stmt:
{
if (m_verbosity < 4)
{
@@ -2608,11 +2646,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
}
break;
- case EK_REGION_CREATION:
+ case event_kind::region_creation:
/* Don't filter these. */
break;
- case EK_FUNCTION_ENTRY:
+ case event_kind::function_entry:
if (m_verbosity < 1)
{
log ("filtering event %i: function entry", idx);
@@ -2620,7 +2658,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
}
break;
- case EK_STATE_CHANGE:
+ case event_kind::state_change:
{
state_change_event *state_change = (state_change_event *)base_event;
gcc_assert (state_change->m_dst_state.m_region_model);
@@ -2674,7 +2712,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
}
break;
- case EK_START_CFG_EDGE:
+ case event_kind::start_cfg_edge:
{
cfg_edge_event *event = (cfg_edge_event *)base_event;
@@ -2687,20 +2725,26 @@ 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 EK_END_CFG_EDGE. */
- gcc_assert (path->get_checker_event (idx)->m_kind
- == EK_END_CFG_EDGE);
+ /* Also delete the corresponding event_kind::end_cfg_edge. */
+ gcc_assert (path->get_checker_event (idx)->get_kind ()
+ == event_kind::end_cfg_edge);
path->delete_event (idx);
}
}
break;
- case EK_END_CFG_EDGE:
- /* These come in pairs with EK_START_CFG_EDGE events and are
+ case event_kind::end_cfg_edge:
+ /* These come in pairs with event_kind::start_cfg_edge events and are
filtered when their start event is filtered. */
break;
- case EK_CALL_EDGE:
+ case event_kind::catch_:
+ case event_kind::throw_:
+ case event_kind::unwind:
+ /* Don't filter these. */
+ break;
+
+ case event_kind::call_edge:
{
call_event *event = (call_event *)base_event;
const region_model *callee_model
@@ -2741,7 +2785,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
}
break;
- case EK_RETURN_EDGE:
+ case event_kind::return_edge:
{
if (sval)
{
@@ -2785,19 +2829,19 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
}
break;
- case EK_INLINED_CALL:
+ case event_kind::inlined_call:
/* We don't expect to see these yet, as they're added later.
We'd want to keep them around. */
break;
- case EK_SETJMP:
+ case event_kind::setjmp_:
/* TODO: only show setjmp_events that matter i.e. those for which
there is a later rewind event using them. */
- case EK_REWIND_FROM_LONGJMP:
- case EK_REWIND_TO_SETJMP:
+ case event_kind::rewind_from_longjmp:
+ case event_kind::rewind_to_setjmp:
break;
- case EK_WARNING:
+ case event_kind::warning:
/* Always show the final "warning" event in the path. */
break;
}
@@ -3002,7 +3046,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;
@@ -3067,13 +3111,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 == EK_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
@@ -3096,7 +3140,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 == EK_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
@@ -3140,6 +3184,50 @@ diagnostic_manager::consolidate_conditions (checker_path *path) const
}
}
+/* Consolidate runs of consecutive unwind_event. */
+
+void
+diagnostic_manager::consolidate_unwind_events (checker_path *path) const
+{
+ /* Don't simplify edges if we're debugging them. */
+ if (flag_analyzer_verbose_edges)
+ return;
+
+ for (int start_idx = 0;
+ start_idx < (signed)path->num_events () - 1;
+ start_idx++)
+ {
+ /* Find a run of consecutive unwind_event instances. */
+ 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)->get_kind ()
+ == event_kind::unwind)
+ ++iter_idx;
+ else
+ break;
+
+ /* iter_idx should now be one after the last unwind_event in the run. */
+ const int last_idx = iter_idx - 1;
+ if (last_idx == start_idx)
+ continue;
+
+ gcc_assert (last_idx > start_idx);
+
+ log ("consolidating unwind events %i-%i into %i",
+ start_idx, last_idx, start_idx);
+
+ unwind_event *first_event
+ = (unwind_event *)path->get_checker_event (start_idx);
+ const unwind_event *last_event
+ = (const unwind_event *)path->get_checker_event (last_idx);
+ first_event->m_num_frames += last_event->m_num_frames;
+ path->delete_events (start_idx + 1, last_idx - start_idx);
+ }
+}
+
/* Final pass of diagnostic_manager::prune_path.
If all we're left with is in one function, then filter function entry
@@ -3154,7 +3242,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 == EK_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/diagnostic-manager.h b/gcc/analyzer/diagnostic-manager.h
index 06a8233..d9cf109 100644
--- a/gcc/analyzer/diagnostic-manager.h
+++ b/gcc/analyzer/diagnostic-manager.h
@@ -67,7 +67,8 @@ public:
void emit_any_notes () const;
- void maybe_add_sarif_properties (sarif_object &result_obj) const;
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj) const;
//private:
const state_machine *m_sm;
@@ -191,6 +192,9 @@ public:
}
private:
+ const diagnostics::logical_locations::manager &
+ get_logical_location_manager () const;
+
void build_emission_path (const path_builder &pb,
const exploded_path &epath,
checker_path *emission_path) const;
@@ -229,6 +233,7 @@ private:
void prune_interproc_events (checker_path *path) const;
void prune_system_headers (checker_path *path) const;
void consolidate_conditions (checker_path *path) const;
+ void consolidate_unwind_events (checker_path *path) const;
void finish_pruning (checker_path *path) const;
engine *m_eng;
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 71d7ed7..745ef7e 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -18,23 +18,27 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "fold-const.h"
+#include "analyzer/common.h"
+
+#include <zlib.h>
+
+#include "cfg.h"
+#include "basic-block.h"
#include "gcc-rich-location.h"
-#include "diagnostic-core.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-path.h"
-#include "function.h"
-#include "pretty-print.h"
-#include "sbitmap.h"
-#include "bitmap.h"
-#include "ordered-hash-map.h"
-#include "analyzer/analyzer.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "gimple-pretty-print.h"
+#include "cgraph.h"
+#include "fold-const.h"
+#include "digraph.h"
+#include "plugin.h"
+#include "target.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "tree-dfa.h"
+
+#include "text-art/dump.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
@@ -44,13 +48,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "gimple-pretty-print.h"
-#include "cgraph.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
@@ -59,16 +56,8 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/state-purge.h"
#include "analyzer/bar-chart.h"
#include "analyzer/call-info.h"
-#include <zlib.h>
-#include "plugin.h"
-#include "target.h"
-#include <memory>
-#include "stringpool.h"
-#include "attribs.h"
-#include "tree-dfa.h"
#include "analyzer/known-function-manager.h"
#include "analyzer/call-summary.h"
-#include "text-art/dump.h"
/* For an overview, see gcc/doc/analyzer.texi. */
@@ -106,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)
{
}
@@ -124,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");
@@ -307,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 ()),
@@ -322,11 +311,11 @@ public:
logger *get_logger () const { return m_logger.get_logger (); }
- tree get_fndecl_for_call (const gcall *call) final override
+ 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);
}
@@ -336,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 ());
@@ -364,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
@@ -389,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 ());
@@ -419,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 ())
@@ -472,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;
@@ -513,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))
@@ -583,17 +572,17 @@ get_state_map_by_name (const char *name,
{
const sm_state_map *old_smap = m_old_state->m_checker_states[sm_idx];
*out_sm_context
- = make_unique<impl_sm_context> (*m_eg,
- sm_idx,
- *sm,
- m_enode_for_diag,
- m_old_state,
- m_new_state,
- old_smap,
- new_smap,
- m_path_ctxt,
- m_stmt_finder,
- false);
+ = std::make_unique<impl_sm_context> (*m_eg,
+ sm_idx,
+ *sm,
+ m_enode_for_diag,
+ m_old_state,
+ m_new_state,
+ old_smap,
+ new_smap,
+ m_path_ctxt,
+ m_stmt_finder,
+ false);
}
return true;
}
@@ -609,7 +598,7 @@ public:
std::unique_ptr<stmt_finder> clone () const final override
{
- return make_unique<leak_stmt_finder> (m_eg, m_var);
+ return std::make_unique<leak_stmt_finder> (m_eg, m_var);
}
const gimple *find_stmt (const exploded_path &epath)
@@ -677,7 +666,7 @@ public:
}
gcc_unreachable ();
- return NULL;
+ return nullptr;
}
void update_event_loc_info (event_loc_info &) final override
@@ -936,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,
@@ -971,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);
}
@@ -998,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);
}
}
@@ -1207,10 +1198,10 @@ exploded_node::status_to_str (enum status s)
switch (s)
{
default: gcc_unreachable ();
- case STATUS_WORKLIST: return "WORKLIST";
- case STATUS_PROCESSED: return "PROCESSED";
- case STATUS_MERGER: return "MERGER";
- case STATUS_BULK_MERGED: return "BULK_MERGED";
+ case status::worklist: return "worklist";
+ case status::processed: return "processed";
+ case status::merger: return "merger";
+ case status::bulk_merged: return "bulk_merged";
}
}
@@ -1218,7 +1209,7 @@ exploded_node::status_to_str (enum status s)
exploded_node::exploded_node (const point_and_state &ps,
int index)
-: m_ps (ps), m_status (STATUS_WORKLIST), m_index (index),
+: m_ps (ps), m_status (status::worklist), m_index (index),
m_num_processed_stmts (0)
{
gcc_checking_assert (ps.get_state ().m_region_model->canonicalized_p ());
@@ -1296,9 +1287,9 @@ exploded_node::dump_dot (graphviz_out *gv, const dump_args_t &args) const
pp_write_text_to_stream (pp);
pp_printf (pp, "EN: %i", m_index);
- if (m_status == STATUS_MERGER)
+ if (m_status == status::merger)
pp_string (pp, " (merger)");
- else if (m_status == STATUS_BULK_MERGED)
+ else if (m_status == status::bulk_merged)
pp_string (pp, " (bulk merged)");
pp_newline (pp);
@@ -1440,7 +1431,7 @@ exploded_node::dump (const extrinsic_state &ext_state) const
std::unique_ptr<json::object>
exploded_node::to_json (const extrinsic_state &ext_state) const
{
- auto enode_obj = ::make_unique<json::object> ();
+ auto enode_obj = std::make_unique<json::object> ();
enode_obj->set ("point", get_point ().to_json ());
enode_obj->set ("state", get_state ().to_json (ext_state));
@@ -1522,7 +1513,7 @@ exploded_node::on_stmt (exploded_graph &eg,
gcc_assert (called_fn);
return replay_call_summaries (eg,
snode,
- as_a <const gcall *> (stmt),
+ *as_a <const gcall *> (stmt),
state,
path_ctxt,
*called_fn,
@@ -1549,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. */
@@ -1579,8 +1570,9 @@ exploded_node::on_stmt_pre (exploded_graph &eg,
region_model_context *ctxt)
{
/* Handle special-case calls that require the full program_state. */
- if (const gcall *call = dyn_cast <const gcall *> (stmt))
+ if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt))
{
+ const gcall &call = *call_stmt;
if (is_special_named_call_p (call, "__analyzer_dump", 0))
{
/* Handle the builtin "__analyzer_dump" by dumping state
@@ -1588,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_sarif", 0))
+ {
+ state->dump_sarif (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 (),
@@ -1609,6 +1611,24 @@ exploded_node::on_stmt_pre (exploded_graph &eg,
ctxt->maybe_did_work ();
return;
}
+ else if (is_cxa_throw_p (call))
+ {
+ on_throw (eg, call, state, false, ctxt);
+ *out_terminate_path = true;
+ return;
+ }
+ else if (is_cxa_rethrow_p (call))
+ {
+ on_throw (eg, call, state, true, ctxt);
+ *out_terminate_path = true;
+ return;
+ }
+ }
+ else if (const gresx *resx = dyn_cast <const gresx *> (stmt))
+ {
+ on_resx (eg, *resx, state, ctxt);
+ *out_terminate_path = true;
+ return;
}
/* Otherwise, defer to m_region_model. */
@@ -1626,7 +1646,7 @@ exploded_node::on_stmt_post (const gimple *stmt,
region_model_context *ctxt)
{
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- state->m_region_model->on_call_post (call, unknown_side_effects, ctxt);
+ state->m_region_model->on_call_post (*call, unknown_side_effects, ctxt);
}
/* A concrete call_info subclass representing a replay of a call summary. */
@@ -1636,7 +1656,7 @@ class call_summary_edge_info : public call_info
public:
call_summary_edge_info (const call_details &cd,
const function &called_fn,
- call_summary *summary,
+ call_summary &summary,
const extrinsic_state &ext_state)
: call_info (cd, called_fn),
m_called_fn (called_fn),
@@ -1651,7 +1671,7 @@ public:
/* Update STATE based on summary_end_state. */
call_details cd (get_call_details (state->m_region_model, ctxt));
call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
- const program_state &summary_end_state = m_summary->get_state ();
+ const program_state &summary_end_state = m_summary.get_state ();
return state->replay_call_summary (r, summary_end_state);
}
@@ -1662,19 +1682,19 @@ public:
/* Update STATE based on summary_end_state. */
call_details cd (get_call_details (model, ctxt));
call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
- const program_state &summary_end_state = m_summary->get_state ();
+ const program_state &summary_end_state = m_summary.get_state ();
model->replay_call_summary (r, *summary_end_state.m_region_model);
return true;
}
void print_desc (pretty_printer &pp) const final override
{
- pp_string (&pp, m_summary->get_desc ().get ());
+ pp_string (&pp, m_summary.get_desc ().get ());
}
private:
const function &m_called_fn;
- call_summary *m_summary;
+ call_summary &m_summary;
const extrinsic_state &m_ext_state;
};
@@ -1684,7 +1704,7 @@ private:
exploded_node::on_stmt_flags
exploded_node::replay_call_summaries (exploded_graph &eg,
const supernode *snode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
program_state *state,
path_context *path_ctxt,
const function &called_fn,
@@ -1696,8 +1716,11 @@ exploded_node::replay_call_summaries (exploded_graph &eg,
/* Each summary will call bifurcate on the PATH_CTXT. */
for (auto summary : called_fn_data.m_summaries)
- replay_call_summary (eg, snode, call_stmt, state,
- path_ctxt, called_fn, summary, ctxt);
+ {
+ gcc_assert (summary);
+ replay_call_summary (eg, snode, call_stmt, state,
+ path_ctxt, called_fn, *summary, ctxt);
+ }
path_ctxt->terminate_path ();
return on_stmt_flags ();
@@ -1710,27 +1733,25 @@ exploded_node::replay_call_summaries (exploded_graph &eg,
void
exploded_node::replay_call_summary (exploded_graph &eg,
const supernode *snode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
program_state *old_state,
path_context *path_ctxt,
const function &called_fn,
- call_summary *summary,
+ call_summary &summary,
region_model_context *ctxt)
{
logger *logger = eg.get_logger ();
LOG_SCOPE (logger);
gcc_assert (snode);
- gcc_assert (call_stmt);
gcc_assert (old_state);
- gcc_assert (summary);
if (logger)
logger->log ("using %s as summary for call to %qE from %qE",
- summary->get_desc ().get (),
+ summary.get_desc ().get (),
called_fn.decl,
snode->get_function ()->decl);
const extrinsic_state &ext_state = eg.get_ext_state ();
- const program_state &summary_end_state = summary->get_state ();
+ const program_state &summary_end_state = summary.get_state ();
if (logger)
{
pretty_printer *pp = logger->get_printer ();
@@ -1752,10 +1773,11 @@ exploded_node::replay_call_summary (exploded_graph &eg,
call_summary_replay r (cd, called_fn, summary, ext_state);
if (path_ctxt)
- path_ctxt->bifurcate (make_unique<call_summary_edge_info> (cd,
- called_fn,
- summary,
- ext_state));
+ path_ctxt->bifurcate
+ (std::make_unique<call_summary_edge_info> (cd,
+ called_fn,
+ summary,
+ ext_state));
}
@@ -1826,10 +1848,10 @@ valid_longjmp_stack_p (const program_point &longjmp_point,
class stale_jmp_buf : public pending_diagnostic_subclass<stale_jmp_buf>
{
public:
- stale_jmp_buf (const gcall *setjmp_call, const gcall *longjmp_call,
+ 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
@@ -1849,8 +1871,8 @@ public:
bool operator== (const stale_jmp_buf &other) const
{
- return (m_setjmp_call == other.m_setjmp_call
- && m_longjmp_call == other.m_longjmp_call);
+ return (&m_setjmp_call == &other.m_setjmp_call
+ && &m_longjmp_call == &other.m_longjmp_call);
}
bool
@@ -1903,8 +1925,8 @@ public:
private:
- const gcall *m_setjmp_call;
- const gcall *m_longjmp_call;
+ const gcall &m_setjmp_call;
+ const gcall &m_longjmp_call;
program_point m_setjmp_point;
custom_event *m_stack_pop_event;
};
@@ -1917,11 +1939,11 @@ private:
void
exploded_node::on_longjmp (exploded_graph &eg,
- const gcall *longjmp_call,
+ const gcall &longjmp_call,
program_state *new_state,
region_model_context *ctxt)
{
- tree buf_ptr = gimple_call_arg (longjmp_call, 0);
+ tree buf_ptr = gimple_call_arg (&longjmp_call, 0);
gcc_assert (POINTER_TYPE_P (TREE_TYPE (buf_ptr)));
region_model *new_region_model = new_state->m_region_model;
@@ -1942,7 +1964,7 @@ exploded_node::on_longjmp (exploded_graph &eg,
call back to the setjmp/sigsetjmp. */
rewind_info_t rewind_info (tmp_setjmp_record, longjmp_call);
- const gcall *setjmp_call = rewind_info.get_setjmp_call ();
+ const gcall &setjmp_call = rewind_info.get_setjmp_call ();
const program_point &setjmp_point = rewind_info.get_setjmp_point ();
const program_point &longjmp_point = get_point ();
@@ -1950,9 +1972,9 @@ exploded_node::on_longjmp (exploded_graph &eg,
/* Verify that the setjmp's call_stack hasn't been popped. */
if (!valid_longjmp_stack_p (longjmp_point, setjmp_point))
{
- ctxt->warn (make_unique<stale_jmp_buf> (setjmp_call,
- longjmp_call,
- setjmp_point));
+ ctxt->warn (std::make_unique<stale_jmp_buf> (setjmp_call,
+ longjmp_call,
+ setjmp_point));
return;
}
@@ -1971,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
@@ -1985,9 +2007,9 @@ exploded_node::on_longjmp (exploded_graph &eg,
if (next)
{
exploded_edge *eedge
- = eg.add_edge (const_cast<exploded_node *> (this), next, NULL, true,
- make_unique<rewind_info_t> (tmp_setjmp_record,
- longjmp_call));
+ = eg.add_edge (const_cast<exploded_node *> (this), next, nullptr, true,
+ std::make_unique<rewind_info_t> (tmp_setjmp_record,
+ longjmp_call));
/* For any diagnostics that were queued here (such as leaks) we want
the checker_path to show the rewinding events after the "final event"
@@ -2025,6 +2047,332 @@ exploded_node::on_longjmp (exploded_graph &eg,
}
}
+/* Subclass of call_info for exploded edges that express
+ a throw or rethrow of an exception (actually a call
+ to __cxa_throw or __cxa_rethrow). */
+
+class throw_custom_edge : public call_info
+{
+public:
+ throw_custom_edge (const call_details &cd,
+ tree type,
+ bool is_rethrow)
+ : call_info (cd),
+ m_type (type),
+ m_is_rethrow (is_rethrow)
+ {
+ }
+
+ void print (pretty_printer *pp) const final override
+ {
+ if (m_is_rethrow)
+ {
+ if (m_type)
+ pp_printf (pp, "rethrowing %qT", m_type);
+ else
+ pp_printf (pp, "rethrowing");
+ }
+ else
+ {
+ if (m_type)
+ pp_printf (pp, "throwing %qT", m_type);
+ else
+ pp_printf (pp, "throwing");
+ }
+ }
+
+ void print_desc (pretty_printer &pp) const final override
+ {
+ print (&pp);
+ }
+
+ bool update_model (region_model *model,
+ const exploded_edge *,
+ region_model_context *ctxt) const final override
+ {
+ if (m_is_rethrow)
+ {
+ auto eh_node = model->get_current_caught_exception ();
+ gcc_assert (eh_node);
+ model->push_thrown_exception (*eh_node);
+ }
+ else
+ {
+ call_details cd (get_call_details (model, ctxt));
+
+ const svalue *exception_sval = cd.get_arg_svalue (0);
+ const svalue *tinfo_sval = cd.get_arg_svalue (1);
+ const svalue *destructor_sval = cd.get_arg_svalue (2);
+
+ /* Push a new exception_node on the model's m_exception_stack. */
+ exception_node eh_node (exception_sval, tinfo_sval, destructor_sval);
+ model->push_thrown_exception (eh_node);
+ }
+
+ return true;
+ }
+
+ void add_events_to_path (checker_path *emission_path,
+ const exploded_edge &eedge) const final override
+ {
+ const exploded_node *dst_node = eedge.m_dest;
+ const program_point &dst_point = dst_node->get_point ();
+ const int dst_stack_depth = dst_point.get_stack_depth ();
+
+ const gcall &call = get_call_stmt ();
+
+ emission_path->add_event
+ (std::make_unique<explicit_throw_event>
+ (event_loc_info (call.location,
+ dst_point.get_fndecl (),
+ dst_stack_depth),
+ dst_node,
+ call,
+ m_type,
+ m_is_rethrow));
+ }
+
+private:
+ tree m_type;
+ bool m_is_rethrow;
+};
+
+/* Subclass of custom_edge_info for an exploded edge that expresses
+ unwinding one stack frame during exception handling. */
+
+class unwind_custom_edge : public custom_edge_info
+{
+public:
+ unwind_custom_edge (location_t loc)
+ : m_loc (loc)
+ {
+ }
+
+ void print (pretty_printer *pp) const final override
+ {
+ pp_printf (pp, "unwinding frame");
+ }
+
+ bool update_model (region_model *model,
+ const exploded_edge *,
+ region_model_context *ctxt) const final override
+ {
+ model->pop_frame (NULL_TREE, nullptr, ctxt, nullptr, false);
+ return true;
+ }
+
+ void add_events_to_path (checker_path *emission_path,
+ const exploded_edge &eedge) const final override
+ {
+ const exploded_node *src_node = eedge.m_src;
+ const program_point &src_point = src_node->get_point ();
+ const int src_stack_depth = src_point.get_stack_depth ();
+ emission_path->add_event
+ (std::make_unique<unwind_event> (event_loc_info (m_loc,
+ src_point.get_fndecl (),
+ src_stack_depth)));
+ }
+
+private:
+ location_t m_loc;
+};
+
+/* Locate an SNODE that's a CFG edge with the EH flag,
+ or return nullptr. */
+
+static const superedge *
+get_eh_outedge (const supernode &snode)
+{
+ for (auto out_sedge : snode.m_succs)
+ if (::edge cfg_edge = out_sedge->get_any_cfg_edge ())
+ if (cfg_edge->flags & EDGE_EH)
+ return out_sedge;
+
+ // Not found
+ return nullptr;
+}
+
+/* Given THROWN_ENODE, which expreses a throw or rethrow occurring at
+ THROW_STMT, unwind intraprocedurally and interprocedurally to find
+ the next eh_dispatch statement to handle exceptions, if any.
+
+ Add eedges and enodes to this graph expressing the actions taken
+ to reach an enode containing the eh_dispatch stmt, if any.
+ Only the final enode is added to this graph's worklist.
+
+ Use CTXT to warn about problems e.g. memory leaks due to stack frames
+ being unwound. */
+
+void
+exploded_graph::unwind_from_exception (exploded_node &thrown_enode,
+ const gimple *throw_stmt,
+ region_model_context *ctxt)
+{
+ logger * const logger = get_logger ();
+ LOG_FUNC_1 (logger, "thrown EN: %i", thrown_enode.m_index);
+
+ /* Iteratively unwind the stack looking for an out-cfg-edge
+ flagged EH. */
+ exploded_node *iter_enode = &thrown_enode;
+ while (iter_enode)
+ {
+ /* If we have an out-cfg-edge flagged EH, follow that,
+ presumably to a bb with a label and an eh_dispatch stmt.
+ Otherwise assume no out-cfgs-edges, and we are unwinding to the
+ caller. */
+ if (auto sedge = get_eh_outedge (*iter_enode->get_supernode ()))
+ {
+ /* Intraprocedural case.
+ Assume we have an out-edge flagged with EH leading to
+ code for dispatch to catch handlers. */
+ const program_point next_point
+ = program_point::before_supernode (sedge->m_dest,
+ sedge,
+ iter_enode->get_point ().get_call_string ());
+ exploded_node *next_enode
+ = get_or_create_node (next_point,
+ iter_enode->get_state (),
+ iter_enode,
+ /* Add this enode to the worklist. */
+ true);
+ if (!next_enode)
+ return;
+
+ add_edge (iter_enode, next_enode, nullptr, false, nullptr);
+ return;
+ }
+ else
+ {
+ /* Interprocedural case.
+ No out-cfg-edge. Unwind one stack frame. */
+ program_state unwound_state (iter_enode->get_state ());
+ location_t loc = throw_stmt ? throw_stmt->location : UNKNOWN_LOCATION;
+ auto unwind_edge_info
+ = std::make_unique<unwind_custom_edge> (loc);
+ unwind_edge_info->update_model (unwound_state.m_region_model, nullptr,
+ ctxt);
+
+ /* Detect leaks in the new state relative to the old state.
+ Use an alternate ctxt that uses the original enode and the stmt
+ (if any) for the location of any diagnostics. */
+ {
+ uncertainty_t uncertainty;
+ impl_region_model_context ctxt (*this,
+ &thrown_enode,
+ &iter_enode->get_state (),
+ &unwound_state,
+ &uncertainty,
+ nullptr,
+ throw_stmt);
+ program_state::detect_leaks (iter_enode->get_state (),
+ unwound_state,
+ nullptr,
+ get_ext_state (), &ctxt);
+ }
+ const call_string &cs = iter_enode->get_point ().get_call_string ();
+ if (cs.empty_p ())
+ {
+ /* Top-level stack frame in analysis: unwinding
+ to the outside world that called us. */
+ return;
+ }
+ else
+ {
+ /* Nested function in analysis: unwinding to
+ the callsite in the analysis (or beyond). */
+ program_point unwound_point
+ = program_point::after_supernode (cs.get_caller_node (), cs);
+ unwound_point.pop_from_call_stack ();
+
+ exploded_node *after_unwind_enode
+ = get_or_create_node (unwound_point,
+ std::move (unwound_state),
+ iter_enode,
+ /* Don't add this enode to the
+ worklist; we will process it
+ on the next iteration. */
+ false);
+
+ if (!after_unwind_enode)
+ return;
+
+ add_edge (iter_enode, after_unwind_enode, nullptr, true,
+ std::move (unwind_edge_info));
+ iter_enode = after_unwind_enode;
+ }
+ }
+ }
+}
+
+/* Handle THROW_CALL, a call to __cxa_throw or __cxa_rethrow.
+
+ Create an eedge and destination enode for the throw/rethrow, adding
+ them to this egraph. The new enode isn't added to the worklist, but
+ instead exploded_graph::unwind_from_exception is immediately called
+ on it, potentially creating more eedges and enodes leading to an
+ eh_handler stmt. */
+
+void
+exploded_node::on_throw (exploded_graph &eg,
+ const gcall &throw_call,
+ program_state *new_state,
+ bool is_rethrow,
+ region_model_context *ctxt)
+{
+ region_model *model = new_state->m_region_model;
+ call_details cd (throw_call, model, ctxt);
+
+ /* Create an enode and eedge for the "throw". */
+ tree type = NULL_TREE;
+ if (is_rethrow)
+ {
+ const exception_node *eh_node = model->get_current_caught_exception ();
+ gcc_assert (eh_node);
+ type = eh_node->maybe_get_type ();
+ }
+ else
+ {
+ const svalue *tinfo_sval = cd.get_arg_svalue (1);
+ type = tinfo_sval->maybe_get_type_from_typeinfo ();
+ }
+ auto throw_edge_info
+ = std::make_unique<throw_custom_edge> (cd, type, is_rethrow);
+ throw_edge_info->update_model (model, nullptr, ctxt);
+
+ program_point after_throw_point = get_point ().get_next ();
+
+ exploded_node *after_throw_enode
+ = eg.get_or_create_node (after_throw_point, *new_state, this,
+ /* Don't add to worklist; we process
+ this immediately below. */
+ false);
+
+ if (!after_throw_enode)
+ return;
+
+ /* Create custom exploded_edge for a throw. */
+ eg.add_edge (this, after_throw_enode, nullptr, true,
+ std::move (throw_edge_info));
+
+ eg.unwind_from_exception (*after_throw_enode, &throw_call, ctxt);
+}
+
+/* Handle a gimple "resx" statement by adding eedges and enode.
+ that unwind to the next eh_dispatch statement, if any. Only
+ the final enode is added to the worklist. */
+
+void
+exploded_node::on_resx (exploded_graph &eg,
+ const gresx &/*resx*/,
+ program_state */*new_state*/,
+ region_model_context *ctxt)
+{
+ eg.unwind_from_exception (*this,
+ nullptr,
+ ctxt);
+}
+
+
/* Subroutine of exploded_graph::process_node for finding the successors
of the supernode for a function exit basic block.
@@ -2056,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);
}
@@ -2131,20 +2479,16 @@ dynamic_call_info_t::add_events_to_path (checker_path *emission_path,
if (m_is_returning_call)
emission_path->add_event
- (make_unique<return_event> (eedge,
- event_loc_info (m_dynamic_call
- ? m_dynamic_call->location
- : UNKNOWN_LOCATION,
- dest_point.get_fndecl (),
- dest_stack_depth)));
+ (std::make_unique<return_event> (eedge,
+ event_loc_info (m_dynamic_call.location,
+ dest_point.get_fndecl (),
+ dest_stack_depth)));
else
emission_path->add_event
- (make_unique<call_event> (eedge,
- event_loc_info (m_dynamic_call
- ? m_dynamic_call->location
- : UNKNOWN_LOCATION,
- src_point.get_fndecl (),
- src_stack_depth)));
+ (std::make_unique<call_event> (eedge,
+ event_loc_info (m_dynamic_call.location,
+ src_point.get_fndecl (),
+ src_stack_depth)));
}
/* class rewind_info_t : public custom_edge_info. */
@@ -2170,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;
}
@@ -2189,19 +2533,19 @@ rewind_info_t::add_events_to_path (checker_path *emission_path,
const int dst_stack_depth = dst_point.get_stack_depth ();
emission_path->add_event
- (make_unique<rewind_from_longjmp_event>
- (&eedge,
- event_loc_info (get_longjmp_call ()->location,
- src_point.get_fndecl (),
- src_stack_depth),
- this));
+ (std::make_unique<rewind_from_longjmp_event>
+ (&eedge,
+ event_loc_info (get_longjmp_call ().location,
+ src_point.get_fndecl (),
+ src_stack_depth),
+ this));
emission_path->add_event
- (make_unique<rewind_to_setjmp_event>
- (&eedge,
- event_loc_info (get_setjmp_call ()->location,
- dst_point.get_fndecl (),
- dst_stack_depth),
- this));
+ (std::make_unique<rewind_to_setjmp_event>
+ (&eedge,
+ event_loc_info (get_setjmp_call ().location,
+ dst_point.get_fndecl (),
+ dst_stack_depth),
+ this));
}
/* class exploded_edge : public dedge<eg_traits>. */
@@ -2294,7 +2638,7 @@ exploded_edge::dump_dot_label (pretty_printer *pp) const
std::unique_ptr<json::object>
exploded_edge::to_json () const
{
- auto eedge_obj = ::make_unique<json::object> ();
+ auto eedge_obj = std::make_unique<json::object> ();
eedge_obj->set_integer ("src_idx", m_src->m_index);
eedge_obj->set_integer ("dst_idx", m_dest->m_index);
if (m_sedge)
@@ -2420,9 +2764,9 @@ strongly_connected_components::dump () const
std::unique_ptr<json::array>
strongly_connected_components::to_json () const
{
- auto scc_arr = ::make_unique<json::array> ();
+ auto scc_arr = std::make_unique<json::array> ();
for (int i = 0; i < m_sg.num_nodes (); i++)
- scc_arr->append (::make_unique<json::integer_number> (get_scc_id (i)));
+ scc_arr->append (std::make_unique<json::integer_number> (get_scc_id (i)));
return scc_arr;
}
@@ -2485,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))
{
}
@@ -2518,7 +2862,7 @@ worklist::peek_next ()
void
worklist::add_node (exploded_node *enode)
{
- gcc_assert (enode->get_status () == exploded_node::STATUS_WORKLIST);
+ gcc_assert (enode->get_status () == exploded_node::status::worklist);
m_queue.insert (key_t (*this, enode), enode);
}
@@ -2547,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 (),
@@ -2584,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;
@@ -2641,7 +2985,7 @@ worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb)
std::unique_ptr<json::object>
worklist::to_json () const
{
- auto worklist_obj = ::make_unique<json::object> ();
+ auto worklist_obj = std::make_unique<json::object> ();
worklist_obj->set ("scc", m_scc.to_json ());
@@ -2670,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);
}
@@ -2722,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);
@@ -2733,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);
}
}
@@ -2791,8 +3135,8 @@ public:
const exploded_edge &) const final override
{
emission_path->add_event
- (make_unique<tainted_args_function_custom_event>
- (event_loc_info (DECL_SOURCE_LOCATION (m_fndecl), m_fndecl, 0)));
+ (std::make_unique<tainted_args_function_custom_event>
+ (event_loc_info (DECL_SOURCE_LOCATION (m_fndecl), m_fndecl, 0)));
}
private:
@@ -2819,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
@@ -2828,22 +3172,22 @@ 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)))
{
if (mark_params_as_tainted (&state, fun.decl, m_ext_state))
- edge_info = make_unique<tainted_args_function_info> (fun.decl);
+ edge_info = std::make_unique<tainted_args_function_info> (fun.decl);
}
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);
@@ -2851,7 +3195,8 @@ exploded_graph::add_function_entry (const function &fun)
}
/* Get or create an exploded_node for (POINT, STATE).
- If a new node is created, it is added to the worklist.
+ If a new node is created and ADD_TO_WORKLIST is true,
+ it is added to the worklist.
Use ENODE_FOR_DIAG, a pre-existing enode, for any diagnostics
that need to be emitted (e.g. when purging state *before* we have
@@ -2860,7 +3205,8 @@ exploded_graph::add_function_entry (const function &fun)
exploded_node *
exploded_graph::get_or_create_node (const program_point &point,
const program_state &state,
- exploded_node *enode_for_diag)
+ exploded_node *enode_for_diag,
+ bool add_to_worklist)
{
logger * const logger = get_logger ();
LOG_FUNC (logger);
@@ -2884,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 ());
@@ -2998,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);
@@ -3035,7 +3381,10 @@ exploded_graph::get_or_create_node (const program_point &point,
}
/* Add the new node to the worlist. */
- m_worklist.add_node (node);
+ if (add_to_worklist)
+ m_worklist.add_node (node);
+ else
+ node->set_status (exploded_node::status::special);
return node;
}
@@ -3075,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
@@ -3084,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;
@@ -3117,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
@@ -3126,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
@@ -3238,16 +3587,16 @@ public:
/* Show the field in the struct declaration, e.g.
"(1) field 'store' is marked with '__attribute__((tainted_args))'" */
emission_path->add_event
- (make_unique<tainted_args_field_custom_event> (m_field));
+ (std::make_unique<tainted_args_field_custom_event> (m_field));
/* Show the callback in the initializer
e.g.
"(2) function 'gadget_dev_desc_UDC_store' used as initializer
for field 'store' marked with '__attribute__((tainted_args))'". */
emission_path->add_event
- (make_unique<tainted_args_callback_custom_event>
- (event_loc_info (m_loc, m_fndecl, 0),
- m_field));
+ (std::make_unique<tainted_args_callback_custom_event>
+ (event_loc_info (m_loc, m_fndecl, 0),
+ m_field));
}
private:
@@ -3289,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)
@@ -3303,8 +3652,8 @@ add_tainted_args_callback (exploded_graph *eg, tree field, tree fndecl,
}
}
- eg->add_edge (eg->get_origin (), enode, NULL, false,
- make_unique<tainted_args_call_info> (field, fndecl, loc));
+ eg->add_edge (eg->get_origin (), enode, nullptr, false,
+ std::make_unique<tainted_args_call_info> (field, fndecl, loc));
}
/* Callback for walk_tree for finding callbacks within initializers;
@@ -3377,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);
}
}
@@ -3397,7 +3746,7 @@ exploded_graph::process_worklist ()
while (m_worklist.length () > 0)
{
exploded_node *node = m_worklist.take_next ();
- gcc_assert (node->get_status () == exploded_node::STATUS_WORKLIST);
+ gcc_assert (node->get_status () == exploded_node::status::worklist);
gcc_assert (node->m_succs.length () == 0
|| node == m_origin);
@@ -3417,7 +3766,7 @@ exploded_graph::process_worklist ()
if (exploded_node *node_2 = m_worklist.peek_next ())
{
gcc_assert (node_2->get_status ()
- == exploded_node::STATUS_WORKLIST);
+ == exploded_node::status::worklist);
gcc_assert (node->m_succs.length () == 0);
gcc_assert (node_2->m_succs.length () == 0);
@@ -3458,11 +3807,11 @@ 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 ();
- node_2->set_status (exploded_node::STATUS_MERGER);
+ node_2->set_status (exploded_node::status::merger);
/* Continue processing "node" below. */
}
@@ -3471,8 +3820,8 @@ 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);
- node->set_status (exploded_node::STATUS_MERGER);
+ add_edge (node, node_2, nullptr, false);
+ node->set_status (exploded_node::status::merger);
continue;
}
else
@@ -3488,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)
@@ -3516,16 +3865,16 @@ exploded_graph::process_worklist ()
m_worklist.add_node (merged_enode);
else
{
- add_edge (node, merged_enode, NULL, false);
- node->set_status (exploded_node::STATUS_MERGER);
+ add_edge (node, merged_enode, nullptr, false);
+ node->set_status (exploded_node::status::merger);
}
if (merged_enode == node_2)
m_worklist.add_node (merged_enode);
else
{
- add_edge (node_2, merged_enode, NULL, false);
- node_2->set_status (exploded_node::STATUS_MERGER);
+ add_edge (node_2, merged_enode, nullptr, false);
+ node_2->set_status (exploded_node::status::merger);
}
continue;
@@ -3575,7 +3924,7 @@ exploded_graph::process_worklist ()
If ENODE's point is of the form (before-supernode, SNODE) and the next
nodes in the worklist are a consecutive run of enodes of the same form,
for the same supernode as ENODE (but potentially from different in-edges),
- process them all together, setting their status to STATUS_BULK_MERGED,
+ process them all together, setting their status to status::bulk_merged,
and return true.
Otherwise, return false, in which case ENODE must be processed in the
normal way.
@@ -3614,7 +3963,7 @@ maybe_process_run_of_before_supernode_enodes (exploded_node *enode)
int m_merger_idx;
};
- gcc_assert (enode->get_status () == exploded_node::STATUS_WORKLIST);
+ gcc_assert (enode->get_status () == exploded_node::status::worklist);
gcc_assert (enode->m_succs.length () == 0);
const program_point &point = enode->get_point ();
@@ -3634,7 +3983,7 @@ maybe_process_run_of_before_supernode_enodes (exploded_node *enode)
while (exploded_node *enode_2 = m_worklist.peek_next ())
{
gcc_assert (enode_2->get_status ()
- == exploded_node::STATUS_WORKLIST);
+ == exploded_node::status::worklist);
gcc_assert (enode_2->m_succs.length () == 0);
const program_point &point_2 = enode_2->get_point ();
@@ -3679,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)
@@ -3742,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)
{
@@ -3759,9 +4108,9 @@ 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);
+ it->m_input_enode->set_status (exploded_node::status::bulk_merged);
}
if (logger)
@@ -3779,8 +4128,9 @@ static bool
stmt_requires_new_enode_p (const gimple *stmt,
const gimple *prev_stmt)
{
- if (const gcall *call = dyn_cast <const gcall *> (stmt))
+ if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt))
{
+ const gcall &call = *call_stmt;
/* Stop consolidating at calls to
"__analyzer_dump_exploded_nodes", so they always appear at the
start of an exploded_node. */
@@ -3849,7 +4199,7 @@ state_change_requires_new_enode_p (const program_state &old_state,
functions or calls that happen via function pointer. */
bool
-exploded_graph::maybe_create_dynamic_call (const gcall *call,
+exploded_graph::maybe_create_dynamic_call (const gcall &call,
tree fn_decl,
exploded_node *node,
program_state next_state,
@@ -3869,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,
@@ -3902,9 +4252,9 @@ 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. */
- make_unique<dynamic_call_info_t> (call));
+ std::make_unique<dynamic_call_info_t> (call));
return true;
}
}
@@ -3992,7 +4342,7 @@ private:
class jump_through_null : public pending_diagnostic_subclass<jump_through_null>
{
public:
- jump_through_null (const gcall *call)
+ jump_through_null (const gcall &call)
: m_call (call)
{}
@@ -4003,7 +4353,7 @@ public:
bool operator== (const jump_through_null &other) const
{
- return m_call == other.m_call;
+ return &m_call == &other.m_call;
}
int get_controlling_option () const final override
@@ -4024,7 +4374,7 @@ public:
}
private:
- const gcall *m_call;
+ const gcall &m_call;
};
/* The core of exploded_graph::process_worklist (the main analysis loop),
@@ -4041,7 +4391,7 @@ exploded_graph::process_node (exploded_node *node)
logger * const logger = get_logger ();
LOG_FUNC_1 (logger, "EN: %i", node->m_index);
- node->set_status (exploded_node::STATUS_PROCESSED);
+ node->set_status (exploded_node::status::processed);
const program_point &point = node->get_point ();
@@ -4082,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)
@@ -4090,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;
@@ -4130,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++)
@@ -4162,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);
}
@@ -4207,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
@@ -4234,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
@@ -4262,19 +4612,25 @@ 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))
{
- exploded_node *next2
- = get_or_create_node (next_point, bifurcated_new_state, node);
- if (next2)
- add_edge (node, next2, NULL,
- true /* assume that work could be done */,
- std::move (edge_info));
+ if (exploded_node *next2
+ = edge_info->create_enode
+ (*this,
+ next_point,
+ std::move (bifurcated_new_state),
+ node,
+ &bifurcation_ctxt))
+ {
+ add_edge (node, next2, nullptr,
+ true /* assume that work could be done */,
+ std::move (edge_info));
+ }
}
else
{
@@ -4344,15 +4700,15 @@ exploded_graph::process_node (exploded_node *node)
if (succ->m_kind == SUPEREDGE_INTRAPROCEDURAL_CALL
&& !(succ->get_any_callgraph_edge ()))
{
- const gcall *call
- = point.get_supernode ()->get_final_call ();
+ const gcall &call
+ = *point.get_supernode ()->get_final_call ();
impl_region_model_context ctxt (*this,
node,
&state,
&next_state,
&uncertainty,
- NULL,
+ nullptr,
point.get_stmt());
region_model *model = state.m_region_model;
@@ -4368,13 +4724,14 @@ exploded_graph::process_node (exploded_node *node)
logger);
if (!call_discovered)
{
- /* Check for jump through NULL. */
- if (tree fn_ptr = gimple_call_fn (call))
+ /* Check for jump through nullptr. */
+ if (tree fn_ptr = gimple_call_fn (&call))
{
const svalue *fn_ptr_sval
= model->get_rvalue (fn_ptr, &ctxt);
if (fn_ptr_sval->all_zeroes_p ())
- ctxt.warn (make_unique<jump_through_null> (call));
+ ctxt.warn
+ (std::make_unique<jump_through_null> (call));
}
/* An unknown function or a special function was called
@@ -4394,6 +4751,18 @@ exploded_graph::process_node (exploded_node *node)
}
}
+ /* Ignore CFG edges in the sgraph flagged with EH whilst
+ we're exploring the egraph.
+ We only use these sedges in special-case logic for
+ dealing with exception-handling. */
+ if (auto cfg_sedge = succ->dyn_cast_cfg_superedge ())
+ if (cfg_sedge->get_flags () & EDGE_EH)
+ {
+ if (logger)
+ logger->log ("rejecting EH edge");
+ continue;
+ }
+
if (!node->on_edge (*this, succ, &next_point, &next_state,
&uncertainty))
{
@@ -4422,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;
@@ -4431,7 +4800,7 @@ exploded_graph::process_node (exploded_node *node)
= next_point.get_supernode ()->get_returning_call ();
if (call)
- next_state.returning_call (*this, node, call, &uncertainty);
+ next_state.returning_call (*this, node, *call, &uncertainty);
if (next_state.m_valid)
{
@@ -4440,8 +4809,8 @@ exploded_graph::process_node (exploded_node *node)
next_state,
node);
if (enode)
- add_edge (node, enode, NULL, false,
- make_unique<dynamic_call_info_t> (call, true));
+ add_edge (node, enode, nullptr, false,
+ std::make_unique<dynamic_call_info_t> (*call, true));
}
}
}
@@ -4450,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 *
@@ -4660,11 +5029,11 @@ exploded_graph::dump_states_for_supernode (FILE *out,
std::unique_ptr<json::object>
exploded_graph::to_json () const
{
- auto egraph_obj = ::make_unique<json::object> ();
+ auto egraph_obj = std::make_unique<json::object> ();
/* Nodes. */
{
- auto nodes_arr = ::make_unique<json::array> ();
+ auto nodes_arr = std::make_unique<json::array> ();
unsigned i;
exploded_node *n;
FOR_EACH_VEC_ELT (m_nodes, i, n)
@@ -4674,7 +5043,7 @@ exploded_graph::to_json () const
/* Edges. */
{
- auto edges_arr = ::make_unique<json::array> ();
+ auto edges_arr = std::make_unique<json::array> ();
unsigned i;
exploded_edge *n;
FOR_EACH_VEC_ELT (m_edges, i, n)
@@ -4780,9 +5149,9 @@ exploded_path::feasible_p (logger *logger,
const program_point &src_point = src_enode.get_point ();
const gimple *last_stmt
= src_point.get_supernode ()->get_last_stmt ();
- *out = ::make_unique<feasibility_problem> (edge_idx, *eedge,
- last_stmt,
- std::move (rc));
+ *out = std::make_unique<feasibility_problem> (edge_idx, *eedge,
+ last_stmt,
+ std::move (rc));
}
return false;
}
@@ -4986,7 +5355,7 @@ maybe_update_for_edge (logger *logger,
== PK_BEFORE_SUPERNODE);
function *fun = eedge->m_dest->get_function ();
gcc_assert (fun);
- m_model.push_frame (*fun, NULL, ctxt);
+ m_model.push_frame (*fun, nullptr, nullptr, ctxt);
if (logger)
logger->log (" pushing frame for %qD", fun->decl);
}
@@ -5032,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. */
@@ -5256,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
@@ -5268,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 {
@@ -5424,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);
@@ -5499,7 +5868,7 @@ exploded_graph::dump_exploded_nodes () const
if (const gimple *stmt = enode->get_stmt ())
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (is_special_named_call_p (call, "__analyzer_dump_exploded_nodes",
+ if (is_special_named_call_p (*call, "__analyzer_dump_exploded_nodes",
1))
{
if (seen.contains (stmt))
@@ -5520,13 +5889,13 @@ exploded_graph::dump_exploded_nodes () const
{
default:
gcc_unreachable ();
- case exploded_node::STATUS_WORKLIST:
+ case exploded_node::status::worklist:
worklist_enodes.safe_push (other_enode);
break;
- case exploded_node::STATUS_PROCESSED:
+ case exploded_node::status::processed:
processed_enodes.safe_push (other_enode);
break;
- case exploded_node::STATUS_MERGER:
+ case exploded_node::status::merger:
merger_enodes.safe_push (other_enode);
break;
}
@@ -5851,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);
}
@@ -5862,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);
}
@@ -6007,15 +6376,18 @@ private:
{
default:
gcc_unreachable ();
- case exploded_node::STATUS_WORKLIST:
+ case exploded_node::status::worklist:
pp_string (pp, "(W)");
break;
- case exploded_node::STATUS_PROCESSED:
+ case exploded_node::status::processed:
+ break;
+ case exploded_node::status::special:
+ pp_string (pp, "(S)");
break;
- case exploded_node::STATUS_MERGER:
+ case exploded_node::status::merger:
pp_string (pp, "(M)");
break;
- case exploded_node::STATUS_BULK_MERGED:
+ case exploded_node::status::bulk_merged:
pp_string (pp, "(BM)");
break;
}
@@ -6085,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)
{
@@ -6094,7 +6466,7 @@ dump_analyzer_json (const supergraph &sg,
return;
}
- auto toplev_obj = ::make_unique<json::object> ();
+ auto toplev_obj = std::make_unique<json::object> ();
toplev_obj->set ("sgraph", sg.to_json ());
toplev_obj->set ("egraph", eg.to_json ());
@@ -6115,8 +6487,8 @@ dump_analyzer_json (const supergraph &sg,
class plugin_analyzer_init_impl : public plugin_analyzer_init_iface
{
public:
- plugin_analyzer_init_impl (auto_delete_vec <state_machine> *checkers,
- known_function_manager *known_fn_mgr,
+ plugin_analyzer_init_impl (std::vector<std::unique_ptr<state_machine>> &checkers,
+ known_function_manager &known_fn_mgr,
logger *logger)
: m_checkers (checkers),
m_known_fn_mgr (known_fn_mgr),
@@ -6126,14 +6498,14 @@ public:
void register_state_machine (std::unique_ptr<state_machine> sm) final override
{
LOG_SCOPE (m_logger);
- m_checkers->safe_push (sm.release ());
+ m_checkers.push_back (std::move (sm));
}
void register_known_function (const char *name,
std::unique_ptr<known_function> kf) final override
{
LOG_SCOPE (m_logger);
- m_known_fn_mgr->add (name, std::move (kf));
+ m_known_fn_mgr.add (name, std::move (kf));
}
logger *get_logger () const final override
@@ -6142,8 +6514,8 @@ public:
}
private:
- auto_delete_vec <state_machine> *m_checkers;
- known_function_manager *m_known_fn_mgr;
+ std::vector<std::unique_ptr<state_machine>> &m_checkers;
+ known_function_manager &m_known_fn_mgr;
logger *m_logger;
};
@@ -6172,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);
@@ -6181,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);
}
@@ -6191,33 +6563,31 @@ 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);
}
- auto_delete_vec <state_machine> checkers;
- make_checkers (checkers, logger);
+ auto checkers = make_checkers (logger);
register_known_functions (*eng.get_known_function_manager (),
*eng.get_model_manager ());
- plugin_analyzer_init_impl data (&checkers,
- eng.get_known_function_manager (),
+ plugin_analyzer_init_impl data (checkers,
+ *eng.get_known_function_manager (),
logger);
invoke_plugin_callbacks (PLUGIN_ANALYZER_INIT, &data);
if (logger)
{
- int i;
- state_machine *sm;
- FOR_EACH_VEC_ELT (checkers, i, sm)
- logger->log ("checkers[%i]: %s", i, sm->get_name ());
+ int i = 0;
+ for (auto &sm : checkers)
+ logger->log ("checkers[%i]: %s", ++i, sm->get_name ());
}
/* Extrinsic state shared by nodes in the graph. */
- const extrinsic_state ext_state (checkers, &eng, logger);
+ const extrinsic_state ext_state (std::move (checkers), &eng, logger);
const analysis_plan plan (sg, logger);
@@ -6238,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);
@@ -6259,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);
@@ -6283,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;
@@ -6300,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)
@@ -6320,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,
@@ -6337,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 6148ed7..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 {}
@@ -206,20 +208,24 @@ class exploded_node : public dnode<eg_traits>
This allows us to distinguish enodes that were merged during
worklist-handling, and thus never had process_node called on them
(in favor of processing the merged node). */
- enum status
+ enum class status
{
/* Node is in the worklist. */
- STATUS_WORKLIST,
+ worklist,
/* Node has had exploded_graph::process_node called on it. */
- STATUS_PROCESSED,
+ processed,
+
+ /* Node was excluded from worklist on creation.
+ e.g. for handling exception-unwinding. */
+ special,
/* Node was left unprocessed due to merger; it won't have had
exploded_graph::process_node called on it. */
- STATUS_MERGER,
+ merger,
/* Node was processed by maybe_process_run_of_before_supernode_enodes. */
- STATUS_BULK_MERGED
+ bulk_merged
};
static const char * status_to_str (enum status s);
@@ -282,7 +288,7 @@ class exploded_node : public dnode<eg_traits>
on_stmt_flags replay_call_summaries (exploded_graph &eg,
const supernode *snode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
program_state *state,
path_context *path_ctxt,
const function &called_fn,
@@ -290,11 +296,11 @@ class exploded_node : public dnode<eg_traits>
region_model_context *ctxt);
void replay_call_summary (exploded_graph &eg,
const supernode *snode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
program_state *state,
path_context *path_ctxt,
const function &called_fn,
- call_summary *summary,
+ call_summary &summary,
region_model_context *ctxt);
bool on_edge (exploded_graph &eg,
@@ -303,9 +309,18 @@ class exploded_node : public dnode<eg_traits>
program_state *next_state,
uncertainty_t *uncertainty);
void on_longjmp (exploded_graph &eg,
- const gcall *call,
+ const gcall &call,
program_state *new_state,
region_model_context *ctxt);
+ void on_throw (exploded_graph &eg,
+ const gcall &call,
+ program_state *new_state,
+ bool is_rethrow,
+ region_model_context *ctxt);
+ void on_resx (exploded_graph &eg,
+ const gresx &resx,
+ program_state *new_state,
+ region_model_context *ctxt);
void detect_leaks (exploded_graph &eg);
@@ -333,10 +348,10 @@ class exploded_node : public dnode<eg_traits>
void dump_succs_and_preds (FILE *outf) const;
enum status get_status () const { return m_status; }
- void set_status (enum status status)
+ void set_status (enum status s)
{
- gcc_assert (m_status == STATUS_WORKLIST);
- m_status = status;
+ gcc_assert (m_status == status::worklist);
+ m_status = s;
}
void add_diagnostic (const saved_diagnostic *sd)
@@ -392,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;
@@ -424,7 +439,7 @@ private:
class dynamic_call_info_t : public custom_edge_info
{
public:
- dynamic_call_info_t (const gcall *dynamic_call,
+ dynamic_call_info_t (const gcall &dynamic_call,
const bool is_returning_call = false)
: m_dynamic_call (dynamic_call),
m_is_returning_call (is_returning_call)
@@ -445,7 +460,7 @@ public:
void add_events_to_path (checker_path *emission_path,
const exploded_edge &eedge) const final override;
private:
- const gcall *m_dynamic_call;
+ const gcall &m_dynamic_call;
const bool m_is_returning_call;
};
@@ -457,7 +472,7 @@ class rewind_info_t : public custom_edge_info
{
public:
rewind_info_t (const setjmp_record &setjmp_record,
- const gcall *longjmp_call)
+ const gcall &longjmp_call)
: m_setjmp_record (setjmp_record),
m_longjmp_call (longjmp_call)
{}
@@ -486,12 +501,12 @@ public:
return origin_point;
}
- const gcall *get_setjmp_call () const
+ const gcall &get_setjmp_call () const
{
- return m_setjmp_record.m_setjmp_call;
+ return *m_setjmp_record.m_setjmp_call;
}
- const gcall *get_longjmp_call () const
+ const gcall &get_longjmp_call () const
{
return m_longjmp_call;
}
@@ -503,7 +518,7 @@ public:
private:
setjmp_record m_setjmp_record;
- const gcall *m_longjmp_call;
+ const gcall &m_longjmp_call;
};
/* Statistics about aspects of an exploded_graph. */
@@ -533,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)
@@ -562,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)
@@ -572,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;
};
@@ -603,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)
@@ -632,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)
@@ -642,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;
};
@@ -763,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);
}
@@ -817,7 +832,7 @@ public:
bool maybe_process_run_of_before_supernode_enodes (exploded_node *node);
void process_node (exploded_node *node);
- bool maybe_create_dynamic_call (const gcall *call,
+ bool maybe_create_dynamic_call (const gcall &call,
tree fn_decl,
exploded_node *node,
program_state next_state,
@@ -827,10 +842,11 @@ public:
exploded_node *get_or_create_node (const program_point &point,
const program_state &state,
- exploded_node *enode_for_diag);
+ exploded_node *enode_for_diag,
+ 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 &);
@@ -881,6 +897,10 @@ public:
void on_escaped_function (tree fndecl);
+ void unwind_from_exception (exploded_node &enode,
+ const gimple *stmt,
+ region_model_context *ctxt);
+
/* In infinite-loop.cc */
void detect_infinite_loops ();
@@ -959,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;
@@ -1024,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/feasible-graph.cc b/gcc/analyzer/feasible-graph.cc
index f8d28ac..25a97e7 100644
--- a/gcc/analyzer/feasible-graph.cc
+++ b/gcc/analyzer/feasible-graph.cc
@@ -18,21 +18,13 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "pretty-print.h"
-#include "gcc-rich-location.h"
-#include "gimple-pretty-print.h"
-#include "function.h"
-#include "diagnostic-core.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-path.h"
-#include "bitmap.h"
-#include "ordered-hash-map.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "cgraph.h"
+#include "digraph.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
@@ -42,12 +34,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/constraint-manager.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "cgraph.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
diff --git a/gcc/analyzer/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-loop.cc b/gcc/analyzer/infinite-loop.cc
index d6f05d8..a53807c 100644
--- a/gcc/analyzer/infinite-loop.cc
+++ b/gcc/analyzer/infinite-loop.cc
@@ -18,28 +18,15 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "fold-const.h"
-#include "gcc-rich-location.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
-#include "shortest-paths.h"
-#include "diagnostic-core.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-path.h"
-#include "function.h"
-#include "pretty-print.h"
-#include "sbitmap.h"
-#include "bitmap.h"
-#include "tristate.h"
-#include "ordered-hash-map.h"
-#include "selftest.h"
-#include "json.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-pretty-print.h"
+#include "cgraph.h"
+#include "digraph.h"
+#include "diagnostics/sarif-sink.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
@@ -49,20 +36,11 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "gimple-pretty-print.h"
-#include "cgraph.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
#include "analyzer/checker-path.h"
#include "analyzer/feasible-graph.h"
-#include "make-unique.h"
-#include "diagnostic-format-sarif.h"
/* A bundle of data characterizing a particular infinite loop
identified within the exploded graph. */
@@ -108,9 +86,9 @@ struct infinite_loop
std::unique_ptr<json::object>
to_json () const
{
- auto loop_obj = ::make_unique<json::object> ();
+ auto loop_obj = std::make_unique<json::object> ();
loop_obj->set_integer ("enode", m_enode.m_index);
- auto edge_arr = ::make_unique<json::array> ();
+ auto edge_arr = std::make_unique<json::array> ();
for (auto eedge : m_eedge_vec)
edge_arr->append (eedge->to_json ());
loop_obj->set ("eedges", std::move (edge_arr));
@@ -237,7 +215,7 @@ public:
checker_path *emission_path) final override
{
emission_path->add_event
- (make_unique<warning_event>
+ (std::make_unique<warning_event>
(event_loc_info (m_inf_loop->m_loc,
enode->get_function ()->decl,
enode->get_stack_depth ()),
@@ -285,51 +263,55 @@ public:
if (switch_cfg_sedge->implicitly_created_default_p ())
{
emission_path->add_event
- (make_unique<perpetual_start_cfg_edge_event> (*eedge,
- loc_info_from));
+ (std::make_unique<perpetual_start_cfg_edge_event>
+ (*eedge,
+ loc_info_from));
emission_path->add_event
- (make_unique<end_cfg_edge_event>
- (*eedge,
- loc_info_to));
+ (std::make_unique<end_cfg_edge_event>
+ (*eedge,
+ loc_info_to));
}
}
if (cfg_sedge->true_value_p ())
{
emission_path->add_event
- (make_unique<perpetual_start_cfg_edge_event> (*eedge,
- loc_info_from));
+ (std::make_unique<perpetual_start_cfg_edge_event>
+ (*eedge,
+ loc_info_from));
emission_path->add_event
- (make_unique<end_cfg_edge_event>
- (*eedge,
- loc_info_to));
+ (std::make_unique<end_cfg_edge_event>
+ (*eedge,
+ loc_info_to));
}
else if (cfg_sedge->false_value_p ())
{
emission_path->add_event
- (make_unique<perpetual_start_cfg_edge_event> (*eedge,
- loc_info_from));
+ (std::make_unique<perpetual_start_cfg_edge_event>
+ (*eedge,
+ loc_info_from));
emission_path->add_event
- (make_unique<end_cfg_edge_event>
- (*eedge,
- loc_info_to));
+ (std::make_unique<end_cfg_edge_event>
+ (*eedge,
+ loc_info_to));
}
else if (cfg_sedge->back_edge_p ())
{
emission_path->add_event
- (make_unique<looping_back_event> (*eedge, loc_info_from));
+ (std::make_unique<looping_back_event> (*eedge, loc_info_from));
emission_path->add_event
- (make_unique<end_cfg_edge_event>
- (*eedge,
- loc_info_to));
+ (std::make_unique<end_cfg_edge_event>
+ (*eedge,
+ loc_info_to));
}
}
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/infinite_loop_diagnostic/"
props.set (PROPERTY_PREFIX "inf_loop", m_inf_loop->to_json ());
#undef PROPERTY_PREFIX
@@ -415,7 +397,7 @@ starts_infinite_loop_p (const exploded_node &enode,
feasible_node *curr_fnode = nullptr;
if (flag_dump_analyzer_infinite_loop)
- fg = ::make_unique<feasible_graph> ();
+ fg = std::make_unique<feasible_graph> ();
location_t first_loc = UNKNOWN_LOCATION;
const exploded_node *iter = &enode;
@@ -432,7 +414,7 @@ starts_infinite_loop_p (const exploded_node &enode,
if (logger)
logger->log ("iter: EN: %i", iter->m_index);
/* Analysis bailed out before processing this node. */
- if (iter->get_status () == exploded_node::STATUS_WORKLIST)
+ if (iter->get_status () == exploded_node::status::worklist)
{
if (logger)
logger->log ("rejecting: EN: %i is still in worklist",
@@ -460,10 +442,10 @@ starts_infinite_loop_p (const exploded_node &enode,
fg->dump_dot (filename, nullptr, dump_args);
free (filename);
}
- return ::make_unique<infinite_loop> (enode,
- first_loc,
- std::move (eedges),
- logger);
+ return std::make_unique<infinite_loop> (enode,
+ first_loc,
+ std::move (eedges),
+ logger);
}
else
{
@@ -593,7 +575,7 @@ exploded_graph::detect_infinite_loops ()
pending_location ploc (enode, snode, inf_loop->m_loc);
auto d
- = ::make_unique<infinite_loop_diagnostic> (std::move (inf_loop));
+ = std::make_unique<infinite_loop_diagnostic> (std::move (inf_loop));
get_diagnostic_manager ().add_diagnostic (ploc, std::move (d));
}
}
diff --git a/gcc/analyzer/infinite-recursion.cc b/gcc/analyzer/infinite-recursion.cc
index 42f87ed..960b487 100644
--- a/gcc/analyzer/infinite-recursion.cc
+++ b/gcc/analyzer/infinite-recursion.cc
@@ -18,28 +18,15 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "fold-const.h"
-#include "gcc-rich-location.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
-#include "shortest-paths.h"
-#include "diagnostic-core.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-path.h"
-#include "function.h"
-#include "pretty-print.h"
-#include "sbitmap.h"
-#include "bitmap.h"
-#include "tristate.h"
-#include "ordered-hash-map.h"
-#include "selftest.h"
-#include "json.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-pretty-print.h"
+#include "cgraph.h"
+#include "digraph.h"
+#include "diagnostics/sarif-sink.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
@@ -49,20 +36,11 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "gimple-pretty-print.h"
-#include "cgraph.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
-#include "make-unique.h"
#include "analyzer/checker-path.h"
#include "analyzer/feasible-graph.h"
-#include "diagnostic-format-sarif.h"
/* A subclass of pending_diagnostic for complaining about suspected
infinite recursion. */
@@ -77,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
@@ -130,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)
{
@@ -168,16 +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
- = 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
- (make_unique<recursive_function_entry_event> (dst_point, *this, true));
+ (std::make_unique<recursive_function_entry_event>
+ (dst_point, dst_node->get_state (), *this, true));
else
pending_diagnostic::add_function_entry_event (eedge, emission_path);
}
@@ -193,7 +175,7 @@ public:
{
gcc_assert (m_new_entry_enode);
emission_path->add_event
- (make_unique<warning_event>
+ (std::make_unique<warning_event>
(event_loc_info (m_new_entry_enode->get_supernode
()->get_start_location (),
m_callee_fndecl,
@@ -241,10 +223,11 @@ public:
return false;
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/infinite_recursion_diagnostic/"
props.set_integer (PROPERTY_PREFIX "prev_entry_enode",
m_prev_entry_enode->m_index);
@@ -309,7 +292,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;
@@ -369,7 +352,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),
@@ -403,7 +386,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);
}
}
}
@@ -445,7 +428,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
@@ -465,7 +448,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. */
@@ -487,11 +470,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. */
@@ -645,7 +628,7 @@ exploded_graph::detect_infinite_recursion (exploded_node *enode)
nullptr);
get_diagnostic_manager ().add_diagnostic
(ploc,
- make_unique<infinite_recursion_diagnostic> (prev_entry_enode,
- enode,
- fndecl));
+ std::make_unique<infinite_recursion_diagnostic> (prev_entry_enode,
+ enode,
+ fndecl));
}
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 54f85a4..13476de 100644
--- a/gcc/analyzer/kf-analyzer.cc
+++ b/gcc/analyzer/kf-analyzer.cc
@@ -18,24 +18,17 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "diagnostic.h"
#include "tree-diagnostic.h" /* for default_tree_printer. */
+#include "pretty-print-markup.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/region-model.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/call-details.h"
-#include "make-unique.h"
-#include "pretty-print-markup.h"
+#include "analyzer/program-state.h"
#if ENABLE_ANALYZER
@@ -110,7 +103,7 @@ public:
const region *base_reg = reg->get_base_region ();
const svalue *capacity = model->get_capacity (base_reg);
label_text desc = capacity->get_desc (true);
- warning_at (cd.get_call_stmt ()->location, 0,
+ warning_at (cd.get_call_stmt ().location, 0,
"capacity: %qs", desc.get ());
}
};
@@ -268,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;
@@ -288,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
@@ -305,7 +312,8 @@ public:
region_model_context *ctxt = cd.get_ctxt ();
if (!ctxt)
return;
- ctxt->warn (make_unique<dump_path_diagnostic> ());
+ if (const program_state *state = ctxt->get_state ())
+ ctxt->warn (std::make_unique<dump_path_diagnostic> (*state));
}
};
@@ -382,22 +390,28 @@ public:
void
register_known_analyzer_functions (known_function_manager &kfm)
{
- kfm.add ("__analyzer_break", make_unique<kf_analyzer_break> ());
- kfm.add ("__analyzer_describe", make_unique<kf_analyzer_describe> ());
+ kfm.add ("__analyzer_break",
+ std::make_unique<kf_analyzer_break> ());
+ kfm.add ("__analyzer_describe",
+ std::make_unique<kf_analyzer_describe> ());
kfm.add ("__analyzer_dump_capacity",
- make_unique<kf_analyzer_dump_capacity> ());
- kfm.add ("__analyzer_dump_escaped", make_unique<kf_analyzer_dump_escaped> ());
+ std::make_unique<kf_analyzer_dump_capacity> ());
+ kfm.add ("__analyzer_dump_escaped",
+ std::make_unique<kf_analyzer_dump_escaped> ());
kfm.add ("__analyzer_dump_exploded_nodes",
- make_unique<kf_analyzer_dump_exploded_nodes> ());
+ std::make_unique<kf_analyzer_dump_exploded_nodes> ());
kfm.add ("__analyzer_dump_named_constant",
- make_unique<kf_analyzer_dump_named_constant> ());
- kfm.add ("__analyzer_dump_path", make_unique<kf_analyzer_dump_path> ());
+ std::make_unique<kf_analyzer_dump_named_constant> ());
+ kfm.add ("__analyzer_dump_path",
+ std::make_unique<kf_analyzer_dump_path> ());
kfm.add ("__analyzer_dump_region_model",
- make_unique<kf_analyzer_dump_region_model> ());
- kfm.add ("__analyzer_eval", make_unique<kf_analyzer_eval> ());
+ std::make_unique<kf_analyzer_dump_region_model> ());
+ kfm.add ("__analyzer_eval",
+ std::make_unique<kf_analyzer_eval> ());
kfm.add ("__analyzer_get_unknown_ptr",
- make_unique<kf_analyzer_get_unknown_ptr> ());
- kfm.add ("__analyzer_get_strlen", make_kf_strlen ());
+ std::make_unique<kf_analyzer_get_unknown_ptr> ());
+ kfm.add ("__analyzer_get_strlen",
+ make_kf_strlen ());
}
} // namespace ana
diff --git a/gcc/analyzer/kf-lang-cp.cc b/gcc/analyzer/kf-lang-cp.cc
index b2b0c9b..01a98b0 100644
--- a/gcc/analyzer/kf-lang-cp.cc
+++ b/gcc/analyzer/kf-lang-cp.cc
@@ -18,20 +18,13 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "diagnostic.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/region-model.h"
#include "analyzer/call-details.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -43,10 +36,9 @@ along with GCC; see the file COPYING3. If not see
See https://en.cppreference.com/w/cpp/memory/new/operator_new. */
-bool is_placement_new_p (const gcall *call)
+bool is_placement_new_p (const gcall &call)
{
- gcc_assert (call);
- tree fndecl = gimple_call_fndecl (call);
+ tree fndecl = gimple_call_fndecl (&call);
if (!fndecl || TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
/* Give up on overloaded operator new. */
@@ -91,7 +83,7 @@ public:
region_model_manager *mgr = cd.get_manager ();
const svalue *size_sval = cd.get_arg_svalue (0);
region_model_context *ctxt = cd.get_ctxt ();
- const gcall *call = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
/* If the call was actually a placement new, check that accessing
the buffer lhs is placed into does not result in out-of-bounds. */
@@ -169,10 +161,165 @@ public:
/* If the ptr points to an underlying heap region, delete it,
poisoning pointers. */
model->unbind_region_and_descendents (freed_reg,
- POISON_KIND_DELETED);
+ poison_kind::deleted);
+ }
+ }
+
+};
+
+class kf_cxa_allocate_exception : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 1 && cd.arg_is_size_p (0);
+ }
+
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model *model = cd.get_model ();
+ region_model_manager *mgr = cd.get_manager ();
+ const svalue *size_sval = cd.get_arg_svalue (0);
+ region_model_context *ctxt = cd.get_ctxt ();
+
+ /* Create a heap allocated region. */
+ const region *new_reg
+ = model->get_or_create_region_for_heap_alloc (size_sval, ctxt);
+ if (cd.get_lhs_type ())
+ {
+ const svalue *ptr_sval
+ = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
+ cd.maybe_set_lhs (ptr_sval);
+ }
+ }
+};
+
+class kf_cxa_begin_catch : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return (cd.num_args () == 1
+ && POINTER_TYPE_P (cd.get_arg_type (0)));
+ }
+
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model *model = cd.get_model ();
+
+ auto node = model->pop_thrown_exception ();
+ model->push_caught_exception (node);
+ cd.maybe_set_lhs (node.m_exception_sval);
+ }
+};
+
+class kf_cxa_end_catch : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 0;
+ }
+
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model *model = cd.get_model ();
+ model->pop_caught_exception ();
+ }
+};
+
+/* A subclass of pending_diagnostic for complaining about an exception
+ of an unexpected type being thrown (due to a call to
+ __cxa_call_unexpected).
+ See https://en.cppreference.com/w/cpp/language/except_spec */
+
+class throw_of_unexpected_type
+: public pending_diagnostic_subclass<throw_of_unexpected_type>
+{
+public:
+ throw_of_unexpected_type (tree exception_type,
+ tree thrown_from_fndecl)
+ : m_exception_type (exception_type),
+ m_thrown_from_fndecl (thrown_from_fndecl)
+ {
+ gcc_assert (m_exception_type);
+ gcc_assert (m_thrown_from_fndecl);
+ }
+
+ const char *get_kind () const final override
+ {
+ return "throw_of_unexpected_type";
+ }
+
+ bool operator== (const throw_of_unexpected_type &other) const
+ {
+ return (m_exception_type == other.m_exception_type
+ && m_thrown_from_fndecl == other.m_thrown_from_fndecl);
+ }
+
+ int get_controlling_option () const final override
+ {
+ return OPT_Wanalyzer_throw_of_unexpected_type;
+ }
+
+ bool emit (diagnostic_emission_context &ctxt) final override
+ {
+ auto_diagnostic_group d;
+
+ bool warned
+ = ctxt.warn ("throwing exception of unexpected type %qT from %qE",
+ m_exception_type, m_thrown_from_fndecl);
+ if (warned)
+ {
+ inform (DECL_SOURCE_LOCATION (m_thrown_from_fndecl),
+ "%qE declared here", m_thrown_from_fndecl);
+ // TODO: show specified types?
}
+ return warned;
+ }
+
+ bool
+ describe_final_event (pretty_printer &pp,
+ const evdesc::final_event &) final override
+ {
+ pp_printf (&pp,
+ "exception of unexpected type %qT thrown from %qE",
+ m_exception_type, m_thrown_from_fndecl);
+ return true;
+ }
+
+private:
+ tree m_exception_type;
+ tree m_thrown_from_fndecl;
+};
+
+/* See https://en.cppreference.com/w/cpp/language/except_spec */
+
+class kf_cxa_call_unexpected : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return (cd.num_args () == 1
+ && POINTER_TYPE_P (cd.get_arg_type (0)));
}
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ if (region_model_context *ctxt = cd.get_ctxt ())
+ {
+ region_model *model = cd.get_model ();
+ tree thrown_from_fndecl = model->get_current_function ()->decl;
+ /* We must have a thrown exception. */
+ auto eh_node = model->get_current_thrown_exception ();
+ gcc_assert (eh_node);
+ tree exception_type = eh_node->maybe_get_type ();
+ ctxt->warn
+ (std::make_unique<throw_of_unexpected_type> (exception_type,
+ thrown_from_fndecl));
+ ctxt->terminate_path ();
+ }
+ }
};
/* Populate KFM with instances of known functions relating to C++. */
@@ -180,10 +327,21 @@ public:
void
register_known_functions_lang_cp (known_function_manager &kfm)
{
- kfm.add ("operator new", make_unique<kf_operator_new> ());
- kfm.add ("operator new []", make_unique<kf_operator_new> ());
- kfm.add ("operator delete", make_unique<kf_operator_delete> ());
- kfm.add ("operator delete []", make_unique<kf_operator_delete> ());
+ kfm.add ("operator new", std::make_unique<kf_operator_new> ());
+ kfm.add ("operator new []", std::make_unique<kf_operator_new> ());
+ kfm.add ("operator delete", std::make_unique<kf_operator_delete> ());
+ kfm.add ("operator delete []", std::make_unique<kf_operator_delete> ());
+
+ /* Functions mentioned in "Itanium C++ ABI: Exception Handling"'s
+ "Level II: C++ ABI"
+ https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-abi */
+ kfm.add ("__cxa_allocate_exception",
+ std::make_unique<kf_cxa_allocate_exception> ());
+ // We treat __cxa_throw and __cxa_rethrow as special cases
+ kfm.add ("__cxa_begin_catch", std::make_unique<kf_cxa_begin_catch> ());
+ kfm.add ("__cxa_end_catch", std::make_unique<kf_cxa_end_catch> ());
+ kfm.add ("__cxa_call_unexpected",
+ std::make_unique<kf_cxa_call_unexpected> ());
}
} // namespace ana
diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc
index dceedd4..2a7c357 100644
--- a/gcc/analyzer/kf.cc
+++ b/gcc/analyzer/kf.cc
@@ -18,23 +18,14 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "diagnostic-metadata.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "diagnostic.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/region-model.h"
#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -50,7 +41,6 @@ public:
: m_call_stmt (cd.get_call_stmt ()),
m_callee_fndecl (cd.get_fndecl_for_call ())
{
- gcc_assert (m_call_stmt);
gcc_assert (m_callee_fndecl);
}
@@ -61,7 +51,7 @@ public:
bool operator== (const undefined_function_behavior &other) const
{
- return (m_call_stmt == other.m_call_stmt
+ return (&m_call_stmt == &other.m_call_stmt
&& m_callee_fndecl == other.m_callee_fndecl);
}
@@ -70,7 +60,7 @@ public:
tree get_callee_fndecl () const { return m_callee_fndecl; }
private:
- const gimple *m_call_stmt;
+ const gimple &m_call_stmt;
tree m_callee_fndecl;
};
@@ -596,7 +586,7 @@ kf_free::impl_call_post (const call_details &cd) const
/* If the ptr points to an underlying heap region, delete it,
poisoning pointers. */
region_model *model = cd.get_model ();
- model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
+ model->unbind_region_and_descendents (freed_reg, poison_kind::freed);
model->unset_dynamic_extents (freed_reg);
}
}
@@ -793,7 +783,7 @@ public:
/* SEI CERT C Coding Standard: "POS34-C. Do not call putenv() with a
pointer to an automatic variable as the argument". */
- diagnostic_metadata::precanned_rule
+ diagnostics::metadata::precanned_rule
rule ("POS34-C", "https://wiki.sei.cmu.edu/confluence/x/6NYxBQ");
ctxt.add_rule (rule);
@@ -881,7 +871,7 @@ public:
break;
case MEMSPACE_STACK:
if (ctxt)
- ctxt->warn (make_unique<putenv_of_auto_var> (fndecl, reg));
+ ctxt->warn (std::make_unique<putenv_of_auto_var> (fndecl, reg));
break;
}
cd.set_any_lhs_with_defaults ();
@@ -1063,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 ());
}
@@ -1084,7 +1074,7 @@ kf_realloc::impl_call_post (const call_details &cd) const
/* If the ptr points to an underlying heap region, delete it,
poisoning pointers. */
- model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
+ model->unbind_region_and_descendents (freed_reg, poison_kind::freed);
model->unset_dynamic_extents (freed_reg);
}
@@ -1129,9 +1119,9 @@ kf_realloc::impl_call_post (const call_details &cd) const
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
- cd.get_ctxt ()->bifurcate (make_unique<success_no_move> (cd));
- cd.get_ctxt ()->bifurcate (make_unique<success_with_move> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<failure> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<success_no_move> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<success_with_move> (cd));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -1200,7 +1190,7 @@ kf_strchr::impl_call_post (const call_details &cd) const
using the str_reg as the id of the conjured_svalue. */
const svalue *offset
= mgr->get_or_create_conjured_svalue (size_type_node,
- cd.get_call_stmt (),
+ &cd.get_call_stmt (),
str_reg,
conjured_purge (model,
ctxt));
@@ -1220,8 +1210,8 @@ kf_strchr::impl_call_post (const call_details &cd) const
/* Body of kf_strchr::impl_call_post. */
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, true));
+ cd.get_ctxt ()->bifurcate (std::make_unique<strchr_call_info> (cd, false));
+ cd.get_ctxt ()->bifurcate (std::make_unique<strchr_call_info> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -1286,6 +1276,27 @@ public:
/* Currently a no-op. */
};
+/* Handler for "__builtin_eh_pointer". */
+
+class kf_eh_pointer : public builtin_known_function
+{
+public:
+ bool matches_call_types_p (const call_details &) const final override
+ {
+ return true;
+ }
+
+ enum built_in_function builtin_code () const final override
+ {
+ return BUILT_IN_EH_POINTER;
+ }
+
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ cd.set_any_lhs_with_defaults ();
+ }
+};
+
/* Handler for "strcat" and "__builtin_strcat_chk". */
class kf_strcat : public builtin_known_function
@@ -1476,7 +1487,7 @@ public:
std::unique_ptr<known_function>
make_kf_strlen ()
{
- return make_unique<kf_strlen> ();
+ return std::make_unique<kf_strlen> ();
}
/* Handler for "strncpy" and "__builtin_strncpy".
@@ -1625,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;
@@ -1650,11 +1661,13 @@ kf_strncpy::impl_call_post (const call_details &cd) const
nullptr,
nullptr);
cd.get_ctxt ()->bifurcate
- (make_unique<strncpy_call_info> (cd, num_bytes_with_terminator_sval,
- false));
+ (std::make_unique<strncpy_call_info>
+ (cd, num_bytes_with_terminator_sval,
+ false));
cd.get_ctxt ()->bifurcate
- (make_unique<strncpy_call_info> (cd, num_bytes_with_terminator_sval,
- true));
+ (std::make_unique<strncpy_call_info>
+ (cd, num_bytes_with_terminator_sval,
+ true));
cd.get_ctxt ()->terminate_path ();
}
};
@@ -1678,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
@@ -1757,7 +1770,7 @@ kf_strstr::impl_call_post (const call_details &cd) const
using the str_reg as the id of the conjured_svalue. */
const svalue *offset
= mgr->get_or_create_conjured_svalue (size_type_node,
- cd.get_call_stmt (),
+ &cd.get_call_stmt (),
str_reg,
conjured_purge (model,
ctxt));
@@ -1777,8 +1790,8 @@ kf_strstr::impl_call_post (const call_details &cd) const
/* Body of kf_strstr::impl_call_post. */
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<strstr_call_info> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<strstr_call_info> (cd, true));
+ cd.get_ctxt ()->bifurcate (std::make_unique<strstr_call_info> (cd, false));
+ cd.get_ctxt ()->bifurcate (std::make_unique<strstr_call_info> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -1924,7 +1937,7 @@ public:
if (cd.get_arg_svalue (0)->all_zeroes_p ())
{
if (ctxt)
- ctxt->warn (::make_unique<undefined_behavior> (cd));
+ ctxt->warn (::std::make_unique<undefined_behavior> (cd));
}
/* Assume that "str" was actually non-null; terminate
@@ -1958,14 +1971,14 @@ public:
using the str_reg as the id of the conjured_svalue. */
const svalue *start_offset
= mgr->get_or_create_conjured_svalue (size_type_node,
- cd.get_call_stmt (),
+ &cd.get_call_stmt (),
str_reg,
conjured_purge (model,
ctxt),
0);
const svalue *nul_offset
= mgr->get_or_create_conjured_svalue (size_type_node,
- cd.get_call_stmt (),
+ &cd.get_call_stmt (),
str_reg,
conjured_purge (model,
ctxt),
@@ -2042,13 +2055,13 @@ public:
Typically the str is either null or non-null at a particular site,
so hopefully this will generally just lead to two out-edges. */
cd.get_ctxt ()->bifurcate
- (make_unique<strtok_call_info> (cd, m_private_reg, false, false));
+ (std::make_unique<strtok_call_info> (cd, m_private_reg, false, false));
cd.get_ctxt ()->bifurcate
- (make_unique<strtok_call_info> (cd, m_private_reg, false, true));
+ (std::make_unique<strtok_call_info> (cd, m_private_reg, false, true));
cd.get_ctxt ()->bifurcate
- (make_unique<strtok_call_info> (cd, m_private_reg, true, false));
+ (std::make_unique<strtok_call_info> (cd, m_private_reg, true, false));
cd.get_ctxt ()->bifurcate
- (make_unique<strtok_call_info> (cd, m_private_reg, true, true));
+ (std::make_unique<strtok_call_info> (cd, m_private_reg, true, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2074,127 +2087,127 @@ region_model::impl_deallocation_call (const call_details &cd)
static void
register_atomic_builtins (known_function_manager &kfm)
{
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE, make_unique<kf_atomic_exchange> ());
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE_N, make_unique<kf_atomic_exchange_n> ());
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE_1, make_unique<kf_atomic_exchange_n> ());
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE_2, make_unique<kf_atomic_exchange_n> ());
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE_4, make_unique<kf_atomic_exchange_n> ());
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE_8, make_unique<kf_atomic_exchange_n> ());
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE_16, make_unique<kf_atomic_exchange_n> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD, make_unique<kf_atomic_load> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD_N, make_unique<kf_atomic_load_n> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD_1, make_unique<kf_atomic_load_n> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD_2, make_unique<kf_atomic_load_n> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD_4, make_unique<kf_atomic_load_n> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD_8, make_unique<kf_atomic_load_n> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD_16, make_unique<kf_atomic_load_n> ());
- kfm.add (BUILT_IN_ATOMIC_STORE, make_unique<kf_atomic_store> ());
- kfm.add (BUILT_IN_ATOMIC_STORE_N, make_unique<kf_atomic_store_n> ());
- kfm.add (BUILT_IN_ATOMIC_STORE_1, make_unique<kf_atomic_store_n> ());
- kfm.add (BUILT_IN_ATOMIC_STORE_2, make_unique<kf_atomic_store_n> ());
- kfm.add (BUILT_IN_ATOMIC_STORE_4, make_unique<kf_atomic_store_n> ());
- kfm.add (BUILT_IN_ATOMIC_STORE_8, make_unique<kf_atomic_store_n> ());
- kfm.add (BUILT_IN_ATOMIC_STORE_16, make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE, std::make_unique<kf_atomic_exchange> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_N, std::make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_1, std::make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_2, std::make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_4, std::make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_8, std::make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_16, std::make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD, std::make_unique<kf_atomic_load> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_N, std::make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_1, std::make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_2, std::make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_4, std::make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_8, std::make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_16, std::make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE, std::make_unique<kf_atomic_store> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_N, std::make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_1, std::make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_2, std::make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_4, std::make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_8, std::make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_16, std::make_unique<kf_atomic_store_n> ());
kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_1,
- make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_2,
- make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_4,
- make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_8,
- make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_16,
- make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_1,
- make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_2,
- make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_4,
- make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_8,
- make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_16,
- make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_AND_FETCH_1,
- make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_AND_FETCH_2,
- make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_AND_FETCH_4,
- make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_AND_FETCH_8,
- make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_AND_FETCH_16,
- make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_1,
- make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_2,
- make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_4,
- make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_8,
- make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_16,
- make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_OR_FETCH_1,
- make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_OR_FETCH_2,
- make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_OR_FETCH_4,
- make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_OR_FETCH_8,
- make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_OR_FETCH_16,
- make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_1,
- make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_2,
- make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_4,
- make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_8,
- make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_16,
- make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_1,
- make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_2,
- make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_4,
- make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_8,
- make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_16,
- make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_AND_1,
- make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_AND_2,
- make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_AND_4,
- make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_AND_8,
- make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_AND_16,
- make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_1,
- make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_2,
- make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_4,
- make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_8,
- make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_16,
- make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_OR_1,
- make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_OR_2,
- make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_OR_4,
- make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_OR_8,
- make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_OR_16,
- make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
}
/* Handle calls to the various IFN_UBSAN_* with no return value.
@@ -2224,14 +2237,14 @@ register_sanitizer_builtins (known_function_manager &kfm)
/* Handle calls to the various IFN_UBSAN_* with no return value.
For now, treat these as no-ops. */
kfm.add (IFN_UBSAN_NULL,
- make_unique<kf_ubsan_noop> ());
+ std::make_unique<kf_ubsan_noop> ());
kfm.add (IFN_UBSAN_BOUNDS,
- make_unique<kf_ubsan_noop> ());
+ std::make_unique<kf_ubsan_noop> ());
kfm.add (IFN_UBSAN_PTR,
- make_unique<kf_ubsan_noop> ());
+ std::make_unique<kf_ubsan_noop> ());
kfm.add (BUILT_IN_UBSAN_HANDLE_NONNULL_ARG,
- make_unique<kf_ubsan_handler> ());
+ std::make_unique<kf_ubsan_handler> ());
}
/* Populate KFM with instances of known functions supported by the core of the
@@ -2246,17 +2259,19 @@ register_known_functions (known_function_manager &kfm,
/* Internal fns the analyzer has known_functions for. */
{
- kfm.add (IFN_BUILTIN_EXPECT, make_unique<kf_expect> ());
+ kfm.add (IFN_BUILTIN_EXPECT, std::make_unique<kf_expect> ());
}
/* GCC built-ins that do not correspond to a function
in the standard library. */
{
- kfm.add (BUILT_IN_EXPECT, make_unique<kf_expect> ());
- kfm.add (BUILT_IN_EXPECT_WITH_PROBABILITY, make_unique<kf_expect> ());
- kfm.add (BUILT_IN_ALLOCA_WITH_ALIGN, make_unique<kf_alloca> ());
- kfm.add (BUILT_IN_STACK_RESTORE, make_unique<kf_stack_restore> ());
- kfm.add (BUILT_IN_STACK_SAVE, make_unique<kf_stack_save> ());
+ kfm.add (BUILT_IN_EXPECT, std::make_unique<kf_expect> ());
+ kfm.add (BUILT_IN_EXPECT_WITH_PROBABILITY, std::make_unique<kf_expect> ());
+ kfm.add (BUILT_IN_ALLOCA_WITH_ALIGN, std::make_unique<kf_alloca> ());
+ kfm.add (BUILT_IN_STACK_RESTORE, std::make_unique<kf_stack_restore> ());
+ kfm.add (BUILT_IN_STACK_SAVE, std::make_unique<kf_stack_save> ());
+
+ kfm.add (BUILT_IN_EH_POINTER, std::make_unique<kf_eh_pointer> ());
register_atomic_builtins (kfm);
register_sanitizer_builtins (kfm);
@@ -2266,58 +2281,58 @@ register_known_functions (known_function_manager &kfm,
/* Known builtins and C standard library functions
the analyzer has known functions for. */
{
- kfm.add ("alloca", make_unique<kf_alloca> ());
- kfm.add ("__builtin_alloca", make_unique<kf_alloca> ());
- kfm.add ("calloc", make_unique<kf_calloc> ());
- kfm.add ("__builtin_calloc", make_unique<kf_calloc> ());
- kfm.add ("free", make_unique<kf_free> ());
- kfm.add ("__builtin_free", make_unique<kf_free> ());
- kfm.add ("malloc", make_unique<kf_malloc> ());
- kfm.add ("__builtin_malloc", make_unique<kf_malloc> ());
+ kfm.add ("alloca", std::make_unique<kf_alloca> ());
+ kfm.add ("__builtin_alloca", std::make_unique<kf_alloca> ());
+ kfm.add ("calloc", std::make_unique<kf_calloc> ());
+ kfm.add ("__builtin_calloc", std::make_unique<kf_calloc> ());
+ kfm.add ("free", std::make_unique<kf_free> ());
+ kfm.add ("__builtin_free", std::make_unique<kf_free> ());
+ kfm.add ("malloc", std::make_unique<kf_malloc> ());
+ kfm.add ("__builtin_malloc", std::make_unique<kf_malloc> ());
kfm.add ("memcpy",
- make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
+ std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
kfm.add ("__builtin_memcpy",
- make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
- kfm.add ("__memcpy_chk", make_unique<kf_memcpy_memmove>
+ std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
+ kfm.add ("__memcpy_chk", std::make_unique<kf_memcpy_memmove>
(kf_memcpy_memmove::KF_MEMCPY_CHK));
- kfm.add ("__builtin___memcpy_chk", make_unique<kf_memcpy_memmove>
+ kfm.add ("__builtin___memcpy_chk", std::make_unique<kf_memcpy_memmove>
(kf_memcpy_memmove::KF_MEMCPY_CHK));
kfm.add ("memmove",
- make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
+ std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
kfm.add ("__builtin_memmove",
- make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
- kfm.add ("__memmove_chk", make_unique<kf_memcpy_memmove>
+ std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
+ kfm.add ("__memmove_chk", std::make_unique<kf_memcpy_memmove>
(kf_memcpy_memmove::KF_MEMMOVE_CHK));
- kfm.add ("__builtin___memmove_chk", make_unique<kf_memcpy_memmove>
+ kfm.add ("__builtin___memmove_chk", std::make_unique<kf_memcpy_memmove>
(kf_memcpy_memmove::KF_MEMMOVE_CHK));
- kfm.add ("memset", make_unique<kf_memset> (false));
- kfm.add ("__builtin_memset", make_unique<kf_memset> (false));
- kfm.add ("__memset_chk", make_unique<kf_memset> (true));
- kfm.add ("__builtin___memset_chk", make_unique<kf_memset> (true));
- kfm.add ("realloc", make_unique<kf_realloc> ());
- kfm.add ("__builtin_realloc", make_unique<kf_realloc> ());
- kfm.add ("sprintf", make_unique<kf_sprintf> ());
- kfm.add ("__builtin_sprintf", make_unique<kf_sprintf> ());
- kfm.add ("strchr", make_unique<kf_strchr> ());
- kfm.add ("__builtin_strchr", make_unique<kf_strchr> ());
- kfm.add ("strcpy", make_unique<kf_strcpy> (2, false));
- kfm.add ("__builtin_strcpy", make_unique<kf_strcpy> (2, false));
- kfm.add ("__strcpy_chk", make_unique<kf_strcpy> (3, true));
- kfm.add ("__builtin___strcpy_chk", make_unique<kf_strcpy> (3, true));
- kfm.add ("strcat", make_unique<kf_strcat> (2, false));
- kfm.add ("__builtin_strcat", make_unique<kf_strcat> (2, false));
- kfm.add ("__strcat_chk", make_unique<kf_strcat> (3, true));
- kfm.add ("__builtin___strcat_chk", make_unique<kf_strcat> (3, true));
- kfm.add ("strdup", make_unique<kf_strdup> ());
- kfm.add ("__builtin_strdup", make_unique<kf_strdup> ());
- kfm.add ("strncpy", make_unique<kf_strncpy> ());
- kfm.add ("__builtin_strncpy", make_unique<kf_strncpy> ());
- kfm.add ("strndup", make_unique<kf_strndup> ());
- kfm.add ("__builtin_strndup", make_unique<kf_strndup> ());
- kfm.add ("strlen", make_unique<kf_strlen> ());
- kfm.add ("__builtin_strlen", make_unique<kf_strlen> ());
- kfm.add ("strstr", make_unique<kf_strstr> ());
- kfm.add ("__builtin_strstr", make_unique<kf_strstr> ());
+ kfm.add ("memset", std::make_unique<kf_memset> (false));
+ kfm.add ("__builtin_memset", std::make_unique<kf_memset> (false));
+ kfm.add ("__memset_chk", std::make_unique<kf_memset> (true));
+ kfm.add ("__builtin___memset_chk", std::make_unique<kf_memset> (true));
+ kfm.add ("realloc", std::make_unique<kf_realloc> ());
+ kfm.add ("__builtin_realloc", std::make_unique<kf_realloc> ());
+ kfm.add ("sprintf", std::make_unique<kf_sprintf> ());
+ kfm.add ("__builtin_sprintf", std::make_unique<kf_sprintf> ());
+ kfm.add ("strchr", std::make_unique<kf_strchr> ());
+ kfm.add ("__builtin_strchr", std::make_unique<kf_strchr> ());
+ kfm.add ("strcpy", std::make_unique<kf_strcpy> (2, false));
+ kfm.add ("__builtin_strcpy", std::make_unique<kf_strcpy> (2, false));
+ kfm.add ("__strcpy_chk", std::make_unique<kf_strcpy> (3, true));
+ kfm.add ("__builtin___strcpy_chk", std::make_unique<kf_strcpy> (3, true));
+ kfm.add ("strcat", std::make_unique<kf_strcat> (2, false));
+ kfm.add ("__builtin_strcat", std::make_unique<kf_strcat> (2, false));
+ kfm.add ("__strcat_chk", std::make_unique<kf_strcat> (3, true));
+ kfm.add ("__builtin___strcat_chk", std::make_unique<kf_strcat> (3, true));
+ kfm.add ("strdup", std::make_unique<kf_strdup> ());
+ kfm.add ("__builtin_strdup", std::make_unique<kf_strdup> ());
+ kfm.add ("strncpy", std::make_unique<kf_strncpy> ());
+ kfm.add ("__builtin_strncpy", std::make_unique<kf_strncpy> ());
+ kfm.add ("strndup", std::make_unique<kf_strndup> ());
+ kfm.add ("__builtin_strndup", std::make_unique<kf_strndup> ());
+ kfm.add ("strlen", std::make_unique<kf_strlen> ());
+ kfm.add ("__builtin_strlen", std::make_unique<kf_strlen> ());
+ kfm.add ("strstr", std::make_unique<kf_strstr> ());
+ kfm.add ("__builtin_strstr", std::make_unique<kf_strstr> ());
register_atomic_builtins (kfm);
register_varargs_builtins (kfm);
@@ -2325,9 +2340,9 @@ register_known_functions (known_function_manager &kfm,
/* Known POSIX functions, and some non-standard extensions. */
{
- kfm.add ("fopen", make_unique<kf_fopen> ());
- kfm.add ("putenv", make_unique<kf_putenv> ());
- kfm.add ("strtok", make_unique<kf_strtok> (rmm));
+ kfm.add ("fopen", std::make_unique<kf_fopen> ());
+ kfm.add ("putenv", std::make_unique<kf_putenv> ());
+ kfm.add ("strtok", std::make_unique<kf_strtok> (rmm));
register_known_fd_functions (kfm);
register_known_file_functions (kfm);
@@ -2335,13 +2350,13 @@ register_known_functions (known_function_manager &kfm,
/* glibc functions. */
{
- kfm.add ("__errno_location", make_unique<kf_errno_location> ());
- kfm.add ("error", make_unique<kf_error> (3));
- kfm.add ("error_at_line", make_unique<kf_error> (5));
+ kfm.add ("__errno_location", std::make_unique<kf_errno_location> ());
+ kfm.add ("error", std::make_unique<kf_error> (3));
+ kfm.add ("error_at_line", std::make_unique<kf_error> (5));
/* Variants of "error" and "error_at_line" seen by the
analyzer at -O0 (PR analyzer/115724). */
- kfm.add ("__error_alias", make_unique<kf_error> (3));
- kfm.add ("__error_at_line_alias", make_unique<kf_error> (5));
+ kfm.add ("__error_alias", std::make_unique<kf_error> (3));
+ kfm.add ("__error_at_line_alias", std::make_unique<kf_error> (5));
}
/* Other implementations of C standard library. */
@@ -2355,9 +2370,9 @@ register_known_functions (known_function_manager &kfm,
#define errno (*__error())
and similarly __errno for newlib.
Add these as synonyms for "__errno_location". */
- kfm.add ("___errno", make_unique<kf_errno_location> ());
- kfm.add ("__error", make_unique<kf_errno_location> ());
- kfm.add ("__errno", make_unique<kf_errno_location> ());
+ kfm.add ("___errno", std::make_unique<kf_errno_location> ());
+ kfm.add ("__error", std::make_unique<kf_errno_location> ());
+ kfm.add ("__errno", std::make_unique<kf_errno_location> ());
}
/* Language-specific support functions. */
@@ -2367,22 +2382,22 @@ register_known_functions (known_function_manager &kfm,
from <cstdlib> etc for the C spellings of these headers (e.g. <stdlib.h>),
so we must match against these too. */
{
- kfm.add_std_ns ("malloc", make_unique<kf_malloc> ());
- kfm.add_std_ns ("free", make_unique<kf_free> ());
- kfm.add_std_ns ("realloc", make_unique<kf_realloc> ());
- kfm.add_std_ns ("calloc", make_unique<kf_calloc> ());
+ kfm.add_std_ns ("malloc", std::make_unique<kf_malloc> ());
+ kfm.add_std_ns ("free", std::make_unique<kf_free> ());
+ kfm.add_std_ns ("realloc", std::make_unique<kf_realloc> ());
+ kfm.add_std_ns ("calloc", std::make_unique<kf_calloc> ());
kfm.add_std_ns
("memcpy",
- make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
+ std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
kfm.add_std_ns
("memmove",
- make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
- kfm.add_std_ns ("memset", make_unique<kf_memset> (false));
- kfm.add_std_ns ("strcat", make_unique<kf_strcat> (2, false));
- kfm.add_std_ns ("strcpy", make_unique<kf_strcpy> (2, false));
- kfm.add_std_ns ("strlen", make_unique<kf_strlen> ());
- kfm.add_std_ns ("strncpy", make_unique<kf_strncpy> ());
- kfm.add_std_ns ("strtok", make_unique<kf_strtok> (rmm));
+ std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
+ kfm.add_std_ns ("memset", std::make_unique<kf_memset> (false));
+ kfm.add_std_ns ("strcat", std::make_unique<kf_strcat> (2, false));
+ kfm.add_std_ns ("strcpy", std::make_unique<kf_strcpy> (2, false));
+ kfm.add_std_ns ("strlen", std::make_unique<kf_strlen> ());
+ kfm.add_std_ns ("strncpy", std::make_unique<kf_strncpy> ());
+ kfm.add_std_ns ("strtok", std::make_unique<kf_strtok> (rmm));
}
}
diff --git a/gcc/analyzer/known-function-manager.cc b/gcc/analyzer/known-function-manager.cc
index db670b8..3b645a8 100644
--- a/gcc/analyzer/known-function-manager.cc
+++ b/gcc/analyzer/known-function-manager.cc
@@ -18,17 +18,12 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "diagnostic-core.h"
-#include "analyzer/analyzer-logging.h"
#include "stringpool.h"
-#include "basic-block.h"
-#include "gimple.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/known-function-manager.h"
#include "analyzer/region-model.h"
#include "analyzer/call-details.h"
@@ -97,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 *
@@ -108,7 +103,7 @@ known_function_manager::get_match (tree fndecl, const call_details &cd) const
{
if (const known_function *candidate
= get_normal_builtin (DECL_FUNCTION_CODE (fndecl)))
- if (gimple_builtin_call_types_compatible_p (cd.get_call_stmt (),
+ if (gimple_builtin_call_types_compatible_p (&cd.get_call_stmt (),
fndecl))
return candidate;
}
@@ -127,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
@@ -146,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
@@ -165,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
@@ -175,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 0f69d02..14d8f9f 100644
--- a/gcc/analyzer/pending-diagnostic.cc
+++ b/gcc/analyzer/pending-diagnostic.cc
@@ -18,18 +18,19 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "intl.h"
-#include "diagnostic.h"
-#include "analyzer/analyzer.h"
-#include "diagnostic-event-id.h"
+#include "analyzer/common.h"
+
+#include "diagnostics/event-id.h"
+#include "diagnostics/logging.h"
+#include "cpplib.h"
+#include "digraph.h"
+#include "ordered-hash-map.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "cgraph.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
-#include "diagnostic-event-id.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
@@ -37,20 +38,10 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
-#include "cpplib.h"
-#include "digraph.h"
-#include "ordered-hash-map.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "cgraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
-#include "diagnostic-path.h"
#include "analyzer/checker-path.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -98,15 +89,26 @@ diagnostic_emission_context::get_pending_diagnostic () const
bool
diagnostic_emission_context::warn (const char *gmsgid, ...)
{
+ auto dc_logger = global_dc->get_logger ();
+ diagnostics::logging::log_function_params
+ (dc_logger, "ana::diagnostic_emission_context::warn")
+ .log_param_string ("gmsgid", gmsgid);
+ diagnostics::logging::auto_inc_depth depth_sentinel (dc_logger);
+
const pending_diagnostic &pd = get_pending_diagnostic ();
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
- const bool result = emit_diagnostic_valist_meta (DK_WARNING,
+ const bool result = emit_diagnostic_valist_meta (diagnostics::kind::warning,
&m_rich_loc, &m_metadata,
pd.get_controlling_option (),
gmsgid, &ap);
va_end (ap);
+
+ if (dc_logger)
+ dc_logger->log_bool_return ("ana::diagnostic_emission_context::warn",
+ result);
+
return result;
}
@@ -116,11 +118,17 @@ diagnostic_emission_context::warn (const char *gmsgid, ...)
void
diagnostic_emission_context::inform (const char *gmsgid, ...)
{
+ auto dc_logger = global_dc->get_logger ();
+ diagnostics::logging::log_function_params
+ (dc_logger, "ana::diagnostic_emission_context::inform")
+ .log_param_string ("gmsgid", gmsgid);
+ diagnostics::logging::auto_inc_depth depth_sentinel (dc_logger);
+
const pending_diagnostic &pd = get_pending_diagnostic ();
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
- emit_diagnostic_valist_meta (DK_NOTE,
+ emit_diagnostic_valist_meta (diagnostics::kind::note,
&m_rich_loc, &m_metadata,
pd.get_controlling_option (),
gmsgid, &ap);
@@ -181,7 +189,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;
}
@@ -195,7 +203,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 (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.
@@ -210,12 +221,12 @@ pending_diagnostic::add_call_event (const exploded_edge &eedge,
const int src_stack_depth = src_point.get_stack_depth ();
const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
emission_path->add_event
- (make_unique<call_event> (eedge,
- event_loc_info (last_stmt
- ? last_stmt->location
- : UNKNOWN_LOCATION,
- src_point.get_fndecl (),
- src_stack_depth)));
+ (std::make_unique<call_event> (eedge,
+ event_loc_info (last_stmt
+ ? last_stmt->location
+ : UNKNOWN_LOCATION,
+ src_point.get_fndecl (),
+ src_stack_depth)));
}
/* Base implementation of pending_diagnostic::add_region_creation_events.
@@ -228,12 +239,13 @@ pending_diagnostic::add_region_creation_events (const region *reg,
checker_path &emission_path)
{
emission_path.add_event
- (make_unique<region_creation_event_memory_space> (reg->get_memory_space (),
- loc_info));
+ (std::make_unique<region_creation_event_memory_space>
+ (reg->get_memory_space (),
+ loc_info));
if (capacity)
emission_path.add_event
- (make_unique<region_creation_event_capacity> (capacity, loc_info));
+ (std::make_unique<region_creation_event_capacity> (capacity, loc_info));
}
/* Base implementation of pending_diagnostic::add_final_event.
@@ -247,10 +259,11 @@ pending_diagnostic::add_final_event (const state_machine *sm,
checker_path *emission_path)
{
emission_path->add_event
- (make_unique<warning_event>
+ (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..b5d90a2 100644
--- a/gcc/analyzer/pending-diagnostic.h
+++ b/gcc/analyzer/pending-diagnostic.h
@@ -21,8 +21,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ANALYZER_PENDING_DIAGNOSTIC_H
#define GCC_ANALYZER_PENDING_DIAGNOSTIC_H
-#include "diagnostic-metadata.h"
-#include "diagnostic-path.h"
+#include "diagnostics/metadata.h"
#include "analyzer/sm.h"
namespace ana {
@@ -44,7 +43,7 @@ struct interesting_t
};
/* Various bundles of information used for generating more precise
- messages for events within a diagnostic_path, for passing to the
+ messages for events within a diagnostic path, for passing to the
various "describe_*" vfuncs of pending_diagnostic. See those
for more information. */
@@ -58,7 +57,7 @@ struct state_change
tree origin,
state_machine::state_t old_state,
state_machine::state_t new_state,
- diagnostic_event_id_t event_id,
+ diagnostics::paths::event_id_t event_id,
const state_change_event &event)
: m_expr (expr), m_origin (origin),
m_old_state (old_state), m_new_state (new_state),
@@ -71,7 +70,7 @@ struct state_change
tree m_origin;
state_machine::state_t m_old_state;
state_machine::state_t m_new_state;
- diagnostic_event_id_t m_event_id;
+ diagnostics::paths::event_id_t m_event_id;
const state_change_event &m_event;
};
@@ -131,14 +130,14 @@ struct final_event
pending_diagnostic::emit vfunc.
The rich_location will have already been populated with a
- diagnostic_path. */
+ diagnostics::paths::path. */
class diagnostic_emission_context
{
public:
diagnostic_emission_context (const saved_diagnostic &sd,
rich_location &rich_loc,
- diagnostic_metadata &metadata,
+ diagnostics::metadata &metadata,
logger *logger)
: m_sd (sd),
m_rich_loc (rich_loc),
@@ -156,7 +155,7 @@ public:
logger *get_logger () const { return m_logger; }
void add_cwe (int cwe) { m_metadata.add_cwe (cwe); }
- void add_rule (const diagnostic_metadata::rule &r)
+ void add_rule (const diagnostics::metadata::rule &r)
{
m_metadata.add_rule (r);
}
@@ -164,7 +163,7 @@ public:
private:
const saved_diagnostic &m_sd;
rich_location &m_rich_loc;
- diagnostic_metadata &m_metadata;
+ diagnostics::metadata &m_metadata;
logger *m_logger;
};
@@ -182,7 +181,7 @@ private:
As well as emitting a diagnostic, the class has various "precision of
wording" virtual functions, for generating descriptions for events
- within a diagnostic_path. These are optional, but implementing these
+ within a diagnostic path. These are optional, but implementing these
allows for more precise wordings than the more generic
implementation. */
@@ -238,7 +237,7 @@ class pending_diagnostic
virtual location_t fixup_location (location_t loc, bool primary) const;
/* Precision-of-wording vfunc for describing a critical state change
- within the diagnostic_path.
+ within the diagnostic path.
For example, a double-free diagnostic might use the descriptions:
- "first 'free' happens here"
@@ -260,13 +259,13 @@ class pending_diagnostic
return false;
}
- /* Vfunc for implementing diagnostic_event::get_meaning for
+ /* Vfunc for implementing event::get_meaning for
state_change_event. */
- virtual diagnostic_event::meaning
+ virtual diagnostics::paths::event::meaning
get_meaning_for_state_change (const evdesc::state_change &) const
{
/* Default no-op implementation. */
- return diagnostic_event::meaning ();
+ return diagnostics::paths::event::meaning ();
}
/* Precision-of-wording vfunc for describing an interprocedural call
@@ -285,7 +284,7 @@ class pending_diagnostic
}
/* Precision-of-wording vfunc for describing an interprocedural return
- within the diagnostic_path that carries critial state for the
+ within the diagnostic path that carries critial state for the
diagnostic, from callee back to caller.
For example, a deref-of-unchecked-malloc diagnostic might use:
@@ -301,7 +300,7 @@ class pending_diagnostic
}
/* Precision-of-wording vfunc for describing the final event within a
- diagnostic_path.
+ diagnostic path.
For example a double-free diagnostic might use:
- "second 'free' here; first 'free' was at (3)"
@@ -364,6 +363,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. */
@@ -396,7 +401,8 @@ class pending_diagnostic
the opportunity to add diagnostic-specific properties to the SARIF
"result" object for the diagnostic.
This is intended for use when debugging a diagnostic. */
- virtual void maybe_add_sarif_properties (sarif_object &/*result_obj*/) const
+ virtual void
+ maybe_add_sarif_properties (diagnostics::sarif_object &/*result_obj*/) const
{
/* Default no-op implementation. */
}
diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc
index 473c102..9baa007 100644
--- a/gcc/analyzer/program-point.cc
+++ b/gcc/analyzer/program-point.cc
@@ -18,42 +18,28 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "gimple-pretty-print.h"
+#include "analyzer/common.h"
+
+#include "diagnostics/event-id.h"
#include "gcc-rich-location.h"
-#include "ordered-hash-map.h"
-#include "options.h"
-#include "cgraph.h"
-#include "function.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "digraph.h"
-#include "analyzer/analyzer.h"
+#include "gimple-pretty-print.h"
+#include "sbitmap.h"
+#include "selftest.h"
+#include "shortest-paths.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-point.h"
-#include "sbitmap.h"
-#include "bitmap.h"
-#include "selftest.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/sm.h"
#include "analyzer/program-state.h"
-#include "diagnostic-event-id.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
-#include "shortest-paths.h"
#include "analyzer/exploded-graph.h"
#include "analyzer/analysis-plan.h"
#include "analyzer/inlining-iterator.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -185,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. */
@@ -198,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. */
@@ -233,32 +219,33 @@ 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);
}
-/* A subclass of diagnostic_context for use by
+/* A subclass of diagnostics::context for use by
program_point::print_source_line. */
-class debug_diagnostic_context : public diagnostic_context
+class debug_diagnostic_context : public diagnostics::context
{
public:
debug_diagnostic_context ()
{
diagnostic_initialize (this, 0);
- m_source_printing.show_line_numbers_p = true;
- m_source_printing.enabled = true;
+ auto &source_printing_opts = get_source_printing_options ();
+ source_printing_opts.show_line_numbers_p = true;
+ source_printing_opts.enabled = true;
}
~debug_diagnostic_context ()
{
@@ -277,9 +264,9 @@ function_point::print_source_line (pretty_printer *pp) const
// TODO: monospace font
debug_diagnostic_context tmp_dc;
gcc_rich_location richloc (stmt->location);
- diagnostic_source_print_policy source_policy (tmp_dc);
+ diagnostics::source_print_policy source_policy (tmp_dc);
gcc_assert (pp);
- source_policy.print (*pp, richloc, DK_ERROR, nullptr);
+ source_policy.print (*pp, richloc, diagnostics::kind::error, nullptr);
pp_string (pp, pp_formatted_text (tmp_dc.get_reference_printer ()));
}
@@ -316,7 +303,7 @@ program_point::dump () const
std::unique_ptr<json::object>
program_point::to_json () const
{
- auto point_obj = ::make_unique<json::object> ();
+ auto point_obj = std::make_unique<json::object> ();
point_obj->set_string ("kind", point_kind_to_string (get_kind ()));
@@ -687,7 +674,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 ());
}
@@ -780,11 +767,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);
}
@@ -793,12 +780,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));
@@ -830,14 +817,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 ec96900..e16a50f 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -18,44 +18,39 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "diagnostic-core.h"
-#include "diagnostic.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
-#include "analyzer/sm.h"
+#include "analyzer/common.h"
+
#include "sbitmap.h"
-#include "bitmap.h"
#include "ordered-hash-map.h"
#include "selftest.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "cgraph.h"
+#include "digraph.h"
+#include "diagnostics/event-id.h"
+#include "diagnostics/state-graphs.h"
+#include "graphviz.h"
+
+#include "text-art/tree-widget.h"
+#include "text-art/dump.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/sm.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/program-state.h"
#include "analyzer/constraint-manager.h"
-#include "diagnostic-event-id.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "cgraph.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
#include "analyzer/state-purge.h"
#include "analyzer/call-summary.h"
#include "analyzer/analyzer-selftests.h"
-#include "text-art/tree-widget.h"
-#include "text-art/dump.h"
-#include "make-unique.h"
+#include "analyzer/ana-state-to-diagnostic-state.h"
#if ENABLE_ANALYZER
@@ -69,11 +64,10 @@ void
extrinsic_state::dump_to_pp (pretty_printer *pp) const
{
pp_printf (pp, "extrinsic_state: %i checker(s)\n", get_num_checkers ());
- unsigned i;
- state_machine *checker;
- FOR_EACH_VEC_ELT (m_checkers, i, checker)
+ unsigned i = 0;
+ for (auto &checker : m_checkers)
{
- pp_printf (pp, "m_checkers[%i]: %qs\n", i, checker->get_name ());
+ pp_printf (pp, "m_checkers[%i]: %qs\n", ++i, checker->get_name ());
checker->dump_to_pp (pp);
}
}
@@ -101,13 +95,11 @@ extrinsic_state::dump () const
std::unique_ptr<json::object>
extrinsic_state::to_json () const
{
- auto ext_state_obj = ::make_unique<json::object> ();
+ auto ext_state_obj = std::make_unique<json::object> ();
{
- auto checkers_arr = ::make_unique<json::array> ();
- unsigned i;
- state_machine *sm;
- FOR_EACH_VEC_ELT (m_checkers, i, sm)
+ auto checkers_arr = std::make_unique<json::array> ();
+ for (auto &sm : m_checkers)
checkers_arr->append (sm->to_json ());
ext_state_obj->set ("checkers", std::move (checkers_arr));
}
@@ -123,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.
@@ -133,10 +125,8 @@ extrinsic_state::get_model_manager () const
bool
extrinsic_state::get_sm_idx_by_name (const char *name, unsigned *out) const
{
- unsigned i;
- state_machine *sm;
- FOR_EACH_VEC_ELT (m_checkers, i, sm)
- if (0 == strcmp (name, sm->get_name ()))
+ for (size_t i = 0; i < m_checkers.size (); ++i)
+ if (0 == strcmp (name, m_checkers[i]->get_name ()))
{
/* Found NAME. */
*out = i;
@@ -268,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);
}
@@ -279,7 +269,7 @@ sm_state_map::dump (bool simple) const
std::unique_ptr<json::object>
sm_state_map::to_json () const
{
- auto map_obj = ::make_unique<json::object> ();
+ auto map_obj = std::make_unique<json::object> ();
if (m_global_state != m_sm.get_start_state ())
map_obj->set ("global", m_global_state->to_json ());
@@ -430,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;
@@ -511,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
@@ -524,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. */
@@ -781,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.
@@ -812,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. */
@@ -922,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;
}
@@ -936,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)
{
@@ -970,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;
@@ -1019,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;
@@ -1188,7 +1178,7 @@ program_state::dump () const
std::unique_ptr<json::object>
program_state::to_json (const extrinsic_state &ext_state) const
{
- auto state_obj = ::make_unique<json::object> ();
+ auto state_obj = std::make_unique<json::object> ();
state_obj->set ("store", m_region_model->get_store ()->to_json ());
state_obj->set ("constraints",
@@ -1199,7 +1189,7 @@ program_state::to_json (const extrinsic_state &ext_state) const
/* Provide m_checker_states as an object, using names as keys. */
{
- auto checkers_obj = ::make_unique<json::object> ();
+ auto checkers_obj = std::make_unique<json::object> ();
int i;
sm_state_map *smap;
@@ -1237,6 +1227,24 @@ 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 state_graph = make_diagnostic_state_graph (ext_state);
+
+ gcc_assert (global_dc);
+ auto logical_loc_mgr = global_dc->get_logical_location_manager ();
+ gcc_assert (logical_loc_mgr);
+
+ auto graph = diagnostics::state_graphs::make_dot_graph (*state_graph,
+ *logical_loc_mgr);
+
+ 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. */
@@ -1244,7 +1252,7 @@ void
program_state::push_frame (const extrinsic_state &ext_state ATTRIBUTE_UNUSED,
const function &fun)
{
- m_region_model->push_frame (fun, NULL, NULL);
+ m_region_model->push_frame (fun, nullptr, nullptr, nullptr);
}
/* Get the current function of this state. */
@@ -1335,7 +1343,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;
@@ -1348,7 +1356,7 @@ program_state::on_edge (exploded_graph &eg,
void
program_state::push_call (exploded_graph &eg,
exploded_node *enode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
uncertainty_t *uncertainty)
{
/* Update state. */
@@ -1359,7 +1367,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);
}
@@ -1371,7 +1379,7 @@ program_state::push_call (exploded_graph &eg,
void
program_state::returning_call (exploded_graph &eg,
exploded_node *enode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
uncertainty_t *uncertainty)
{
/* Update state. */
@@ -1382,7 +1390,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);
}
@@ -1440,7 +1448,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))
{
@@ -1499,9 +1507,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);
}
}
@@ -1673,7 +1681,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);
@@ -1749,7 +1757,7 @@ program_state::replay_call_summary (call_summary_replay &r,
/* Handle calls to "__analyzer_dump_state". */
void
-program_state::impl_call_analyzer_dump_state (const gcall *call,
+program_state::impl_call_analyzer_dump_state (const gcall &call,
const extrinsic_state &ext_state,
region_model_context *ctxt)
{
@@ -1757,13 +1765,13 @@ program_state::impl_call_analyzer_dump_state (const gcall *call,
const char *sm_name = cd.get_arg_string_literal (0);
if (!sm_name)
{
- error_at (call->location, "cannot determine state machine");
+ error_at (call.location, "cannot determine state machine");
return;
}
unsigned sm_idx;
if (!ext_state.get_sm_idx_by_name (sm_name, &sm_idx))
{
- error_at (call->location, "unrecognized state machine %qs", sm_name);
+ error_at (call.location, "unrecognized state machine %qs", sm_name);
return;
}
const sm_state_map *smap = m_checker_states[sm_idx];
@@ -1775,7 +1783,7 @@ program_state::impl_call_analyzer_dump_state (const gcall *call,
sval = cast;
state_machine::state_t state = smap->get_state (sval, ext_state);
- warning_at (call->location, 0, "state: %qs", state->get_name ());
+ warning_at (call.location, 0, "state: %qs", state->get_name ());
}
#if CHECKING_P
@@ -1791,12 +1799,13 @@ test_sm_state_map ()
tree y = build_global_decl ("y", integer_type_node);
tree z = build_global_decl ("z", integer_type_node);
- state_machine *sm = make_malloc_state_machine (NULL);
- auto_delete_vec <state_machine> checkers;
- checkers.safe_push (sm);
- engine eng;
- extrinsic_state ext_state (checkers, &eng);
+ std::unique_ptr<state_machine> sm = make_malloc_state_machine (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 ();
+ checkers.push_back (std::move (sm));
+ engine eng;
+ extrinsic_state ext_state (std::move (checkers), &eng);
/* Test setting states on svalue_id instances directly. */
{
@@ -1804,11 +1813,11 @@ 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 (*sm);
+ sm_state_map map (borrowed_sm);
ASSERT_TRUE (map.is_empty_p ());
ASSERT_EQ (map.get_state (x_sval, ext_state), start);
@@ -1833,16 +1842,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 (*sm);
+ sm_state_map map (borrowed_sm);
ASSERT_TRUE (map.is_empty_p ());
ASSERT_EQ (map.get_state (x_sval, ext_state), start);
ASSERT_EQ (map.get_state (y_sval, ext_state), start);
- 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. */
@@ -1857,12 +1866,12 @@ 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 (*sm);
- sm_state_map map1 (*sm);
- sm_state_map map2 (*sm);
+ sm_state_map map0 (borrowed_sm);
+ sm_state_map map1 (borrowed_sm);
+ sm_state_map map2 (borrowed_sm);
ASSERT_EQ (map0.hash (), map1.hash ());
ASSERT_EQ (map0, map1);
@@ -1883,26 +1892,26 @@ test_sm_state_map ()
const state_machine::state_t TEST_STATE_2 = &test_state_2;
const state_machine::state test_state_3 ("test state 3", 3);
const state_machine::state_t TEST_STATE_3 = &test_state_3;
- sm_state_map map0 (*sm);
- sm_state_map map1 (*sm);
- sm_state_map map2 (*sm);
+ sm_state_map map0 (borrowed_sm);
+ sm_state_map map1 (borrowed_sm);
+ sm_state_map map2 (borrowed_sm);
ASSERT_EQ (map0.hash (), map1.hash ());
ASSERT_EQ (map0, map1);
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);
@@ -1920,27 +1929,25 @@ test_program_state_1 ()
malloc sm-state, pointing to a region on the heap. */
tree p = build_global_decl ("p", ptr_type_node);
- state_machine *sm = make_malloc_state_machine (NULL);
+ std::unique_ptr<state_machine> sm = make_malloc_state_machine (nullptr);
const state_machine::state_t UNCHECKED_STATE
= sm->get_state_by_name ("unchecked");
- auto_delete_vec <state_machine> checkers;
- checkers.safe_push (sm);
engine eng;
- extrinsic_state ext_state (checkers, &eng);
+ extrinsic_state ext_state (std::move (sm), &eng);
region_model_manager *mgr = eng.get_model_manager ();
program_state s (ext_state);
region_model *model = s.m_region_model;
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);
}
@@ -1955,15 +1962,15 @@ test_program_state_2 ()
tree string_cst_ptr = build_string_literal (4, "foo");
- auto_delete_vec <state_machine> checkers;
+ std::vector<std::unique_ptr<state_machine>> checkers;
engine eng;
- extrinsic_state ext_state (checkers, &eng);
+ extrinsic_state ext_state (std::move (checkers), &eng);
program_state s (ext_state);
region_model *model = s.m_region_model;
- 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,
@@ -1979,9 +1986,8 @@ test_program_state_merging ()
engine eng;
region_model_manager *mgr = eng.get_model_manager ();
program_point point (program_point::origin (*mgr));
- auto_delete_vec <state_machine> checkers;
- checkers.safe_push (make_malloc_state_machine (NULL));
- extrinsic_state ext_state (checkers, &eng);
+ extrinsic_state ext_state (make_malloc_state_machine (nullptr),
+ &eng);
program_state s0 (ext_state);
uncertainty_t uncertainty;
@@ -1991,20 +1997,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. */
@@ -2021,7 +2027,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);
@@ -2030,7 +2036,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);
@@ -2047,9 +2053,7 @@ test_program_state_merging_2 ()
engine eng;
region_model_manager *mgr = eng.get_model_manager ();
program_point point (program_point::origin (*mgr));
- auto_delete_vec <state_machine> checkers;
- checkers.safe_push (make_signal_state_machine (NULL));
- extrinsic_state ext_state (checkers, &eng);
+ extrinsic_state ext_state (make_signal_state_machine (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 e0f4ee8..4278237 100644
--- a/gcc/analyzer/program-state.h
+++ b/gcc/analyzer/program-state.h
@@ -22,6 +22,9 @@ 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 ana {
@@ -30,11 +33,23 @@ namespace ana {
class extrinsic_state
{
public:
- extrinsic_state (auto_delete_vec <state_machine> &checkers,
+ extrinsic_state (std::vector<std::unique_ptr<state_machine>> &&checkers,
+ engine *eng,
+ logger *logger = nullptr)
+ : m_checkers (std::move (checkers)),
+ m_logger (logger),
+ m_engine (eng)
+ {
+ }
+
+ // For use in selftests that use just one state machine
+ extrinsic_state (std::unique_ptr<state_machine> sm,
engine *eng,
- logger *logger = NULL)
- : m_checkers (checkers), m_logger (logger), m_engine (eng)
+ logger *logger = nullptr)
+ : m_logger (logger),
+ m_engine (eng)
{
+ m_checkers.push_back (std::move (sm));
}
const state_machine &get_sm (int idx) const
@@ -47,7 +62,7 @@ public:
return m_checkers[idx]->get_name ();
}
- unsigned get_num_checkers () const { return m_checkers.length (); }
+ unsigned get_num_checkers () const { return m_checkers.size (); }
logger *get_logger () const { return m_logger; }
@@ -64,7 +79,7 @@ public:
private:
/* The state machines. */
- auto_delete_vec <state_machine> &m_checkers;
+ std::vector<std::unique_ptr<state_machine>> m_checkers;
logger *m_logger;
engine *m_engine;
@@ -81,7 +96,7 @@ public:
{
/* Default ctor needed by hash_map::empty. */
entry_t ()
- : m_state (0), m_origin (NULL)
+ : m_state (0), m_origin (nullptr)
{
}
@@ -231,6 +246,15 @@ public:
void dump (const extrinsic_state &ext_state, bool simple) const;
void dump () const;
+ std::unique_ptr<diagnostics::digraphs::digraph>
+ make_diagnostic_state_graph (const extrinsic_state &ext_state) const;
+
+ void
+ dump_sarif (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;
@@ -242,12 +266,12 @@ public:
void push_call (exploded_graph &eg,
exploded_node *enode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
uncertainty_t *uncertainty);
void returning_call (exploded_graph &eg,
exploded_node *enode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
uncertainty_t *uncertainty);
@@ -298,7 +322,7 @@ public:
bool replay_call_summary (call_summary_replay &r,
const program_state &summary);
- void impl_call_analyzer_dump_state (const gcall *call,
+ void impl_call_analyzer_dump_state (const gcall &call,
const extrinsic_state &ext_state,
region_model_context *ctxt);
diff --git a/gcc/analyzer/ranges.cc b/gcc/analyzer/ranges.cc
index 4c63ecc..1a960fa 100644
--- a/gcc/analyzer/ranges.cc
+++ b/gcc/analyzer/ranges.cc
@@ -18,34 +18,13 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "diagnostic-core.h"
-#include "gimple-pretty-print.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
-#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
+#include "sbitmap.h"
#include "ordered-hash-map.h"
-#include "options.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/supergraph.h"
-#include "sbitmap.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
@@ -53,7 +32,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/constraint-manager.h"
#include "analyzer/analyzer-selftests.h"
#include "analyzer/ranges.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -158,7 +136,7 @@ symbolic_byte_range::dump (bool simple, region_model_manager &mgr) const
std::unique_ptr<json::value>
symbolic_byte_range::to_json () const
{
- auto obj = ::make_unique<json::object> ();
+ auto obj = std::make_unique<json::object> ();
obj->set ("start", m_start.to_json ());
obj->set ("size", m_size.to_json ());
return obj;
diff --git a/gcc/analyzer/record-layout.cc b/gcc/analyzer/record-layout.cc
index 2eb3444..3446536 100644
--- a/gcc/analyzer/record-layout.cc
+++ b/gcc/analyzer/record-layout.cc
@@ -18,18 +18,10 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "diagnostic.h"
+#include "analyzer/common.h"
+
#include "tree-diagnostic.h"
-#include "analyzer/analyzer.h"
+
#include "analyzer/record-layout.h"
#if ENABLE_ANALYZER
@@ -38,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);
@@ -94,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 0da5cc5..fe70490 100644
--- a/gcc/analyzer/region-model-asm.cc
+++ b/gcc/analyzer/region-model-asm.cc
@@ -18,26 +18,16 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "pretty-print.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
+#include "stmt.h"
+
#include "analyzer/analyzer-logging.h"
-#include "options.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/region-model-reachability.h"
-#include "stmt.h"
#if ENABLE_ANALYZER
@@ -129,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);
@@ -181,7 +171,8 @@ region_model::on_asm_stmt (const gasm *stmt, region_model_context *ctxt)
no point in going further. */
constraint = constraints[i];
if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
- &allows_mem, &allows_reg, &is_inout))
+ &allows_mem, &allows_reg, &is_inout,
+ nullptr))
{
if (logger)
logger->log ("error parsing constraint for output %i: %qs",
@@ -214,8 +205,8 @@ region_model::on_asm_stmt (const gasm *stmt, region_model_context *ctxt)
const char *constraint = constraints[i + noutputs];
bool allows_reg, allows_mem;
if (! parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
- constraints.address (),
- &allows_mem, &allows_reg))
+ constraints.address (), &allows_mem,
+ &allows_reg, nullptr))
{
if (logger)
logger->log ("error parsing constraint for input %i: %qs",
@@ -226,7 +217,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 dfce420..872b1d6 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -18,34 +18,16 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "diagnostic-core.h"
-#include "gimple-pretty-print.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
+#include "analyzer/common.h"
+
#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
#include "ordered-hash-map.h"
#include "options.h"
#include "analyzer/supergraph.h"
#include "sbitmap.h"
+#include "target.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
@@ -67,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),
@@ -277,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 */
@@ -325,7 +307,7 @@ region_model_manager::get_or_create_initial_value (const region *reg,
bool check_poisoned)
{
if (!reg->can_have_initial_svalue_p () && check_poisoned)
- return get_or_create_poisoned_svalue (POISON_KIND_UNINIT,
+ return get_or_create_poisoned_svalue (poison_kind::uninit,
reg->get_type ());
/* The initial value of a cast is a cast of the initial value. */
@@ -425,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,
@@ -534,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
@@ -612,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::
@@ -624,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);
@@ -632,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)
@@ -642,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. */
@@ -659,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,
@@ -687,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)
{
@@ -916,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
@@ -951,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,
@@ -962,6 +944,12 @@ region_model_manager::maybe_fold_sub_svalue (tree type,
if (!parent_svalue->can_have_associated_state_p ())
return get_or_create_unknown_svalue (type);
+ /* If we have a subvalue of a zero constant, it's zero. */
+ if (tree cst = parent_svalue->maybe_get_constant ())
+ if (TREE_CODE (cst) == INTEGER_CST)
+ if (zerop (cst))
+ return get_or_create_cast (type, parent_svalue);
+
/* If we have a subregion of a zero-fill, it's zero. */
if (const unaryop_svalue *unary
= parent_svalue->dyn_cast_unaryop_svalue ())
@@ -1032,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
@@ -1058,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,
@@ -1092,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
@@ -1286,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,
@@ -1413,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::
@@ -1425,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
@@ -1513,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,
@@ -1545,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,
@@ -1564,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,
@@ -1579,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,
@@ -1813,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 4799ba8..0fe324d 100644
--- a/gcc/analyzer/region-model-reachability.cc
+++ b/gcc/analyzer/region-model-reachability.cc
@@ -18,37 +18,18 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
-#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "ordered-hash-map.h"
-#include "options.h"
+#include "diagnostic.h"
+#include "tree-diagnostic.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/region-model-reachability.h"
-#include "diagnostic.h"
-#include "tree-diagnostic.h"
#if ENABLE_ANALYZER
@@ -87,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 ())
{
@@ -103,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);
}
@@ -150,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 84b81e9..618d96b 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -18,70 +18,53 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
#define INCLUDE_ALGORITHM
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
+#include "analyzer/common.h"
+
+#include "ordered-hash-map.h"
#include "options.h"
#include "cgraph.h"
-#include "tree-dfa.h"
+#include "cfg.h"
+#include "sbitmap.h"
+#include "diagnostics/event-id.h"
+#include "stor-layout.h"
#include "stringpool.h"
-#include "convert.h"
+#include "attribs.h"
+#include "tree-object-size.h"
+#include "gimple-ssa.h"
+#include "tree-phinodes.h"
+#include "tree-ssa-operands.h"
+#include "ssa-iterators.h"
#include "target.h"
-#include "fold-const.h"
+#include "calls.h"
+#include "is-a.h"
+#include "gcc-rich-location.h"
+#include "gcc-urlifier.h"
+#include "diagnostics/sarif-sink.h"
#include "tree-pretty-print.h"
-#include "diagnostic-color.h"
-#include "bitmap.h"
-#include "selftest.h"
+#include "fold-const.h"
#include "selftest-tree.h"
-#include "analyzer/analyzer.h"
+
+#include "text-art/tree-widget.h"
+
#include "analyzer/analyzer-logging.h"
-#include "ordered-hash-map.h"
-#include "options.h"
-#include "cgraph.h"
-#include "cfg.h"
#include "analyzer/supergraph.h"
-#include "sbitmap.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/constraint-manager.h"
-#include "diagnostic-event-id.h"
-#include "analyzer/sm.h"
-#include "diagnostic-event-id.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/region-model-reachability.h"
#include "analyzer/analyzer-selftests.h"
#include "analyzer/program-state.h"
#include "analyzer/call-summary.h"
-#include "stor-layout.h"
-#include "attribs.h"
-#include "tree-object-size.h"
-#include "gimple-ssa.h"
-#include "tree-phinodes.h"
-#include "tree-ssa-operands.h"
-#include "ssa-iterators.h"
-#include "calls.h"
-#include "is-a.h"
-#include "gcc-rich-location.h"
#include "analyzer/checker-event.h"
#include "analyzer/checker-path.h"
#include "analyzer/feasible-graph.h"
#include "analyzer/record-layout.h"
-#include "diagnostic-format-sarif.h"
-#include "text-art/tree-widget.h"
-#include "gcc-urlifier.h"
+#include "analyzer/function-set.h"
#if ENABLE_ANALYZER
@@ -176,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;
@@ -235,7 +218,7 @@ region_to_value_map::dump (bool simple) const
std::unique_ptr<json::object>
region_to_value_map::to_json () const
{
- auto map_obj = ::make_unique<json::object> ();
+ auto map_obj = std::make_unique<json::object> ();
auto_vec<const region *> regs;
for (iterator iter = begin (); iter != end (); ++iter)
@@ -332,12 +315,97 @@ region_to_value_map::purge_state_involving (const svalue *sval)
m_hash_map.remove (iter);
}
+// struct exception_node
+
+bool
+exception_node::operator== (const exception_node &other) const
+{
+ return (m_exception_sval == other.m_exception_sval
+ && m_typeinfo_sval == other.m_typeinfo_sval
+ && m_destructor_sval == other.m_destructor_sval);
+}
+
+void
+exception_node::dump_to_pp (pretty_printer *pp,
+ bool simple) const
+{
+ pp_printf (pp, "{exception: ");
+ m_exception_sval->dump_to_pp (pp, simple);
+ pp_string (pp, ", typeinfo: ");
+ m_typeinfo_sval->dump_to_pp (pp, simple);
+ pp_string (pp, ", destructor: ");
+ m_destructor_sval->dump_to_pp (pp, simple);
+ pp_string (pp, "}");
+}
+
+void
+exception_node::dump (FILE *fp, bool simple) const
+{
+ tree_dump_pretty_printer pp (fp);
+ dump_to_pp (&pp, simple);
+ pp_newline (&pp);
+}
+
+/* Dump a multiline representation of this model to stderr. */
+
+DEBUG_FUNCTION void
+exception_node::dump (bool simple) const
+{
+ dump (stderr, simple);
+}
+
+DEBUG_FUNCTION void
+exception_node::dump () const
+{
+ text_art::dump (*this);
+}
+
+std::unique_ptr<json::object>
+exception_node::to_json () const
+{
+ auto obj = std::make_unique<json::object> ();
+ obj->set ("exception", m_exception_sval->to_json ());
+ obj->set ("typeinfo", m_typeinfo_sval->to_json ());
+ obj->set ("destructor", m_destructor_sval->to_json ());
+ return obj;
+}
+
+std::unique_ptr<text_art::tree_widget>
+exception_node::make_dump_widget (const text_art::dump_widget_info &dwi) const
+{
+ using text_art::tree_widget;
+ std::unique_ptr<tree_widget> w
+ (tree_widget::from_fmt (dwi, nullptr, "Exception Node"));
+
+ w->add_child (m_exception_sval->make_dump_widget (dwi, "exception"));
+ w->add_child (m_typeinfo_sval->make_dump_widget (dwi, "typeinfo"));
+ w->add_child (m_destructor_sval->make_dump_widget (dwi, "destructor"));
+
+ return w;
+}
+
+tree
+exception_node::maybe_get_type () const
+{
+ return m_typeinfo_sval->maybe_get_type_from_typeinfo ();
+}
+
+void
+exception_node::add_to_reachable_regions (reachable_regions &regs) const
+{
+ regs.handle_sval (m_exception_sval);
+ regs.handle_sval (m_typeinfo_sval);
+ regs.handle_sval (m_destructor_sval);
+}
+
/* class region_model. */
/* 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 ()
{
m_constraints = new constraint_manager (mgr);
@@ -349,6 +417,8 @@ region_model::region_model (const region_model &other)
: m_mgr (other.m_mgr), m_store (other.m_store),
m_constraints (new constraint_manager (*other.m_constraints)),
m_current_frame (other.m_current_frame),
+ m_thrown_exceptions_stack (other.m_thrown_exceptions_stack),
+ m_caught_exceptions_stack (other.m_caught_exceptions_stack),
m_dynamic_extents (other.m_dynamic_extents)
{
}
@@ -375,6 +445,9 @@ region_model::operator= (const region_model &other)
m_current_frame = other.m_current_frame;
+ m_thrown_exceptions_stack = other.m_thrown_exceptions_stack;
+ m_caught_exceptions_stack = other.m_caught_exceptions_stack;
+
m_dynamic_extents = other.m_dynamic_extents;
return *this;
@@ -401,6 +474,11 @@ region_model::operator== (const region_model &other) const
if (m_current_frame != other.m_current_frame)
return false;
+ if (m_thrown_exceptions_stack != other.m_thrown_exceptions_stack)
+ return false;
+ if (m_caught_exceptions_stack != other.m_caught_exceptions_stack)
+ return false;
+
if (m_dynamic_extents != other.m_dynamic_extents)
return false;
@@ -427,7 +505,7 @@ void
region_model::dump_to_pp (pretty_printer *pp, bool simple,
bool multiline) const
{
- /* Dump stack. */
+ /* Dump frame stack. */
pp_printf (pp, "stack depth: %i", get_stack_depth ());
if (multiline)
pp_newline (pp);
@@ -448,6 +526,50 @@ region_model::dump_to_pp (pretty_printer *pp, bool simple,
if (!multiline)
pp_string (pp, "}");
+ /* Dump exception stacks. */
+ if (m_thrown_exceptions_stack.size () > 0)
+ {
+ pp_printf (pp, "thrown exceptions: %i", (int)m_thrown_exceptions_stack.size ());
+ if (multiline)
+ pp_newline (pp);
+ else
+ pp_string (pp, " {");
+ for (size_t idx = 0; idx < m_thrown_exceptions_stack.size (); ++idx)
+ {
+ if (multiline)
+ pp_string (pp, " ");
+ else if (idx > 0)
+ pp_string (pp, ", ");
+ pp_printf (pp, "exception (index %i): ", (int)idx);
+ m_thrown_exceptions_stack[idx].dump_to_pp (pp, simple);
+ if (multiline)
+ pp_newline (pp);
+ }
+ if (!multiline)
+ pp_string (pp, "}");
+ }
+ if (m_caught_exceptions_stack.size () > 0)
+ {
+ pp_printf (pp, "caught exceptions: %i", (int)m_caught_exceptions_stack.size ());
+ if (multiline)
+ pp_newline (pp);
+ else
+ pp_string (pp, " {");
+ for (size_t idx = 0; idx < m_caught_exceptions_stack.size (); ++idx)
+ {
+ if (multiline)
+ pp_string (pp, " ");
+ else if (idx > 0)
+ pp_string (pp, ", ");
+ pp_printf (pp, "exception (index %i): ", (int)idx);
+ m_caught_exceptions_stack[idx].dump_to_pp (pp, simple);
+ if (multiline)
+ pp_newline (pp);
+ }
+ if (!multiline)
+ pp_string (pp, "}");
+ }
+
/* Dump store. */
if (!multiline)
pp_string (pp, ", {");
@@ -515,11 +637,22 @@ region_model::debug () const
std::unique_ptr<json::object>
region_model::to_json () const
{
- auto model_obj = ::make_unique<json::object> ();
+ auto model_obj = std::make_unique<json::object> ();
model_obj->set ("store", m_store.to_json ());
model_obj->set ("constraints", m_constraints->to_json ());
if (m_current_frame)
model_obj->set ("current_frame", m_current_frame->to_json ());
+
+ auto thrown_exceptions_arr = std::make_unique<json::array> ();
+ for (auto &node : m_thrown_exceptions_stack)
+ thrown_exceptions_arr->append (node.to_json ());
+ model_obj->set ("thrown_exception_stack", std::move (thrown_exceptions_arr));
+
+ auto caught_exceptions_arr = std::make_unique<json::array> ();
+ for (auto &node : m_caught_exceptions_stack)
+ caught_exceptions_arr->append (node.to_json ());
+ model_obj->set ("caught_exception_stack", std::move (caught_exceptions_arr));
+
model_obj->set ("dynamic_extents", m_dynamic_extents.to_json ());
return model_obj;
}
@@ -543,6 +676,26 @@ region_model::make_dump_widget (const text_art::dump_widget_info &dwi) const
m_current_frame->dump_to_pp (pp, simple);
model_widget->add_child (tree_widget::make (dwi, pp));
}
+
+ if (m_thrown_exceptions_stack.size () > 0)
+ {
+ auto thrown_exceptions_widget
+ = tree_widget::make (dwi, "Thrown Exceptions");
+ for (auto &thrown_exception : m_thrown_exceptions_stack)
+ thrown_exceptions_widget->add_child
+ (thrown_exception.make_dump_widget (dwi));
+ model_widget->add_child (std::move (thrown_exceptions_widget));
+ }
+ if (m_caught_exceptions_stack.size () > 0)
+ {
+ auto caught_exceptions_widget
+ = tree_widget::make (dwi, "Caught Exceptions");
+ for (auto &caught_exception : m_caught_exceptions_stack)
+ caught_exceptions_widget->add_child
+ (caught_exception.make_dump_widget (dwi));
+ model_widget->add_child (std::move (caught_exceptions_widget));
+ }
+
model_widget->add_child
(m_store.make_dump_widget (dwi,
m_mgr->get_store_manager ()));
@@ -606,7 +759,7 @@ public:
bool use_of_uninit_p () const final override
{
- return m_pkind == POISON_KIND_UNINIT;
+ return m_pkind == poison_kind::uninit;
}
bool operator== (const poisoned_value_diagnostic &other) const
@@ -622,12 +775,12 @@ public:
{
default:
gcc_unreachable ();
- case POISON_KIND_UNINIT:
+ case poison_kind::uninit:
return OPT_Wanalyzer_use_of_uninitialized_value;
- case POISON_KIND_FREED:
- case POISON_KIND_DELETED:
+ case poison_kind::freed:
+ case poison_kind::deleted:
return OPT_Wanalyzer_use_after_free;
- case POISON_KIND_POPPED_STACK:
+ case poison_kind::popped_stack:
return OPT_Wanalyzer_use_of_pointer_in_stale_stack_frame;
}
}
@@ -640,28 +793,28 @@ public:
{
default:
gcc_unreachable ();
- case POISON_KIND_UNINIT:
+ case poison_kind::uninit:
{
ctxt.add_cwe (457); /* "CWE-457: Use of Uninitialized Variable". */
return ctxt.warn ("use of uninitialized value %qE",
m_expr);
}
break;
- case POISON_KIND_FREED:
+ case poison_kind::freed:
{
ctxt.add_cwe (416); /* "CWE-416: Use After Free". */
return ctxt.warn ("use after %<free%> of %qE",
m_expr);
}
break;
- case POISON_KIND_DELETED:
+ case poison_kind::deleted:
{
ctxt.add_cwe (416); /* "CWE-416: Use After Free". */
return ctxt.warn ("use after %<delete%> of %qE",
m_expr);
}
break;
- case POISON_KIND_POPPED_STACK:
+ case poison_kind::popped_stack:
{
/* TODO: which CWE? */
return ctxt.warn
@@ -680,28 +833,28 @@ public:
{
default:
gcc_unreachable ();
- case POISON_KIND_UNINIT:
+ case poison_kind::uninit:
{
pp_printf (&pp,
"use of uninitialized value %qE here",
m_expr);
return true;
}
- case POISON_KIND_FREED:
+ case poison_kind::freed:
{
pp_printf (&pp,
"use after %<free%> of %qE here",
m_expr);
return true;
}
- case POISON_KIND_DELETED:
+ case poison_kind::deleted:
{
pp_printf (&pp,
"use after %<delete%> of %qE here",
m_expr);
return true;
}
- case POISON_KIND_POPPED_STACK:
+ case poison_kind::popped_stack:
{
pp_printf (&pp,
"dereferencing pointer %qE to within stale stack frame",
@@ -742,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 ();
@@ -754,9 +907,10 @@ public:
}
void
- maybe_add_sarif_properties (sarif_object &result_obj) const final override
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
+ const final override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/poisoned_value_diagnostic/"
props.set (PROPERTY_PREFIX "expr", tree_to_json (m_expr));
props.set_string (PROPERTY_PREFIX "kind", poison_kind_to_str (m_pkind));
@@ -956,10 +1110,10 @@ public:
{
if (reg == m_base_reg_a)
emission_path.add_event
- (make_unique<ptrdiff_region_creation_event> (loc_info, true));
+ (std::make_unique<ptrdiff_region_creation_event> (loc_info, true));
else if (reg == m_base_reg_b)
emission_path.add_event
- (make_unique<ptrdiff_region_creation_event> (loc_info, false));
+ (std::make_unique<ptrdiff_region_creation_event> (loc_info, false));
}
bool
@@ -1009,17 +1163,18 @@ check_for_invalid_ptrdiff (const gassign *assign,
if (base_reg_b->get_kind () == RK_SYMBOLIC)
return;
- ctxt.warn (make_unique<undefined_ptrdiff_diagnostic> (assign,
- sval_a,
- sval_b,
- base_reg_a,
- base_reg_b));
+ ctxt.warn
+ (std::make_unique<undefined_ptrdiff_diagnostic> (assign,
+ sval_a,
+ sval_b,
+ base_reg_a,
+ base_reg_b));
}
/* 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,
@@ -1042,7 +1197,7 @@ region_model::get_gassign_result (const gassign *assign,
switch (op)
{
default:
- return NULL;
+ return nullptr;
case POINTER_PLUS_EXPR:
{
@@ -1192,13 +1347,13 @@ region_model::get_gassign_result (const gassign *assign,
{
if (tree_int_cst_sgn (rhs2_cst) < 0)
ctxt->warn
- (make_unique<shift_count_negative_diagnostic>
+ (std::make_unique<shift_count_negative_diagnostic>
(assign, rhs2_cst));
else if (compare_tree_int (rhs2_cst,
TYPE_PRECISION (TREE_TYPE (rhs1)))
>= 0)
ctxt->warn
- (make_unique<shift_count_overflow_diagnostic>
+ (std::make_unique<shift_count_overflow_diagnostic>
(assign,
int (TYPE_PRECISION (TREE_TYPE (rhs1))),
rhs2_cst));
@@ -1307,8 +1462,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;
@@ -1375,7 +1530,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,
@@ -1392,12 +1547,12 @@ region_model::check_for_poison (const svalue *sval,
/* Ignore uninitialized uses of empty types; there's nothing
to initialize. */
- if (pkind == POISON_KIND_UNINIT
+ if (pkind == poison_kind::uninit
&& sval->get_type ()
&& is_empty_type (sval->get_type ()))
return sval;
- if (pkind == POISON_KIND_UNINIT)
+ if (pkind == poison_kind::uninit)
if (const gimple *curr_stmt = ctxt->get_stmt ())
if (const gassign *assign_stmt
= dyn_cast <const gassign *> (curr_stmt))
@@ -1418,7 +1573,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"?
@@ -1427,15 +1582,16 @@ 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;
- if (ctxt->warn (make_unique<poisoned_value_diagnostic> (diag_arg,
- pkind,
- src_region,
- check_expr)))
+ check_expr = nullptr;
+ if (ctxt->warn
+ (std::make_unique<poisoned_value_diagnostic> (diag_arg,
+ pkind,
+ src_region,
+ check_expr)))
{
/* We only want to report use of a poisoned value at the first
place it gets used; return an unknown value to avoid generating
@@ -1451,7 +1607,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
@@ -1462,9 +1618,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
@@ -1493,7 +1649,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;
}
@@ -1553,7 +1709,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;
}
@@ -1570,13 +1726,15 @@ region_model::on_stmt_pre (const gimple *stmt,
{
switch (gimple_code (stmt))
{
- default:
- /* No-op for now. */
- break;
-
- case GIMPLE_DEBUG:
- /* We should have stripped these out when building the supergraph. */
- gcc_unreachable ();
+ case GIMPLE_COND:
+ case GIMPLE_EH_DISPATCH:
+ case GIMPLE_GOTO:
+ case GIMPLE_LABEL:
+ case GIMPLE_NOP:
+ case GIMPLE_PREDICT:
+ case GIMPLE_RESX:
+ case GIMPLE_SWITCH:
+ /* No-ops here. */
break;
case GIMPLE_ASSIGN:
@@ -1601,7 +1759,7 @@ region_model::on_stmt_pre (const gimple *stmt,
anything, for which we don't have a function body, or for which we
don't know the fndecl. */
const gcall *call = as_a <const gcall *> (stmt);
- *out_unknown_side_effects = on_call_pre (call, ctxt);
+ *out_unknown_side_effects = on_call_pre (*call, ctxt);
}
break;
@@ -1611,6 +1769,13 @@ region_model::on_stmt_pre (const gimple *stmt,
on_return (return_, ctxt);
}
break;
+
+ /* We don't expect to see any other statement kinds in the analyzer. */
+ case GIMPLE_DEBUG: // should have stripped these out when building the supergraph
+ default:
+ internal_error ("unexpected gimple stmt code: %qs",
+ gimple_code_name[gimple_code (stmt)]);
+ break;
}
}
@@ -1689,7 +1854,7 @@ region_model::check_call_format_attr (const call_details &cd,
};
call_arg_details arg_details (m_cd, m_fmt_param_idx);
- add_note (make_unique<reason_format_attr> (arg_details));
+ add_note (std::make_unique<reason_format_attr> (arg_details));
}
private:
const call_details &m_cd;
@@ -1775,7 +1940,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,
@@ -1793,7 +1958,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
@@ -1804,7 +1969,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,
@@ -1830,7 +1995,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.
@@ -1838,7 +2003,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 *
@@ -1848,7 +2013,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
@@ -1858,12 +2023,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
@@ -1898,19 +2063,183 @@ region_model::get_known_function (enum internal_fn ifn) const
attributes. */
const builtin_known_function *
-region_model::get_builtin_kf (const gcall *call,
- region_model_context *ctxt /* = NULL */) const
+region_model::get_builtin_kf (const gcall &call,
+ 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
+ an exception being thrown from a call we don't have the code for. */
+
+class exception_thrown_from_unrecognized_call : public custom_edge_info
+{
+public:
+ exception_thrown_from_unrecognized_call (const gcall &call,
+ tree fndecl)
+ : m_call (call),
+ m_fndecl (fndecl)
+ {
+ }
+
+ void print (pretty_printer *pp) const final override
+ {
+ if (m_fndecl)
+ pp_printf (pp, "if %qD throws an exception...", m_fndecl);
+ else
+ pp_printf (pp, "if the called function throws an exception...");
+ };
+
+ bool
+ update_model (region_model *model,
+ const exploded_edge *,
+ region_model_context *ctxt) const final override
+ {
+ /* Allocate an exception and set it as the current exception. */
+ const region *exception_reg
+ = model->get_or_create_region_for_heap_alloc
+ (nullptr, /* We don't know the size of the region. */
+ ctxt);
+
+ region_model_manager *mgr = model->get_manager ();
+ conjured_purge p (model, ctxt);
+
+ /* The contents of the region are some conjured svalue. */
+ const svalue *exception_sval
+ = mgr->get_or_create_conjured_svalue (NULL_TREE,
+ &m_call,
+ exception_reg, p, 0);
+ model->set_value (exception_reg, exception_sval, ctxt);
+ const svalue *exception_ptr_sval
+ = mgr->get_ptr_svalue (ptr_type_node, exception_reg);
+ const svalue *tinfo_sval
+ = mgr->get_or_create_conjured_svalue (ptr_type_node,
+ &m_call,
+ exception_reg, p, 1);
+ const svalue *destructor_sval
+ = mgr->get_or_create_conjured_svalue (ptr_type_node,
+ &m_call,
+ exception_reg, p, 2);
+
+ /* Push a new exception_node on the model's thrown exception stack. */
+ exception_node eh_node (exception_ptr_sval, tinfo_sval, destructor_sval);
+ model->push_thrown_exception (eh_node);
+
+ return true;
+ }
+
+ void
+ add_events_to_path (checker_path *emission_path,
+ const exploded_edge &eedge) const final override
+ {
+ const exploded_node *dst_node = eedge.m_dest;
+ const program_point &dst_point = dst_node->get_point ();
+ const int dst_stack_depth = dst_point.get_stack_depth ();
+
+ emission_path->add_event
+ (std::make_unique<throw_from_call_to_external_fn_event>
+ (event_loc_info (m_call.location,
+ dst_point.get_fndecl (),
+ dst_stack_depth),
+ dst_node,
+ m_call,
+ m_fndecl));
+ }
+
+ exploded_node *
+ create_enode (exploded_graph &eg,
+ const program_point &point,
+ program_state &&state,
+ exploded_node *enode_for_diag,
+ region_model_context *ctxt) const final override
+ {
+ exploded_node *thrown_enode
+ = eg.get_or_create_node (point, state, enode_for_diag,
+ /* Don't add to worklist. */
+ false);
+ if (!thrown_enode)
+ return nullptr;
+
+ /* Add successor edges for thrown_enode "by hand" for the exception. */
+ eg.unwind_from_exception (*thrown_enode,
+ &m_call,
+ ctxt);
+ return thrown_enode;
+ }
+
+private:
+ const gcall &m_call;
+ tree m_fndecl; // could be null
+};
+
+/* Get a set of functions that are assumed to not throw exceptions. */
+
+static function_set
+get_fns_assumed_not_to_throw ()
+{
+ // TODO: populate this list more fully
+ static const char * const fn_names[] = {
+ /* This array must be kept sorted. */
+
+ "fclose"
+ };
+ const size_t count = ARRAY_SIZE (fn_names);
+ function_set fs (fn_names, count);
+ return fs;
+}
+
+/* Return true if CALL could throw an exception.
+ FNDECL could be NULL_TREE. */
+
+static bool
+can_throw_p (const gcall &call, tree fndecl)
+{
+ if (!flag_exceptions)
+ return false;
+
+ if (gimple_call_nothrow_p (&call))
+ return false;
+
+ if (fndecl)
+ {
+ const function_set fs = get_fns_assumed_not_to_throw ();
+ if (fs.contains_decl_p (fndecl))
+ return false;
+ }
+
+ return true;
+}
+
+/* Given CALL where we don't know what code is being called
+ (by not having the body of FNDECL, or having NULL_TREE for FNDECL),
+ potentially bifurcate control flow to simulate the call throwing
+ an exception. */
+
+void
+region_model::check_for_throw_inside_call (const gcall &call,
+ tree fndecl,
+ region_model_context *ctxt)
+{
+ if (!ctxt)
+ return;
+
+ /* Could this function throw an exception?
+ If so, add an extra e-edge for that. */
+ if (!can_throw_p (call, fndecl))
+ return;
+
+ auto throws_exception
+ = std::make_unique<exception_thrown_from_unrecognized_call> (call, fndecl);
+ ctxt->bifurcate (std::move (throws_exception));
}
/* Update this model for the CALL stmt, using CTXT to report any
@@ -1925,7 +2254,7 @@ region_model::get_builtin_kf (const gcall *call,
fndecl it is). */
bool
-region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
+region_model::on_call_pre (const gcall &call, region_model_context *ctxt)
{
call_details cd (call, this, ctxt);
@@ -1935,8 +2264,8 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
Handle IFN_DEFERRED_INIT by treating it as no-op: don't touch the
lhs of the call, so that it is still uninitialized from the point of
view of the analyzer. */
- if (gimple_call_internal_p (call)
- && gimple_call_internal_fn (call) == IFN_DEFERRED_INIT)
+ if (gimple_call_internal_p (&call)
+ && gimple_call_internal_fn (&call) == IFN_DEFERRED_INIT)
return false; /* No side effects. */
/* Get svalues for all of the arguments at the callsite, to ensure that we
@@ -1948,9 +2277,9 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
tree callee_fndecl = get_fndecl_for_call (call, ctxt);
- if (gimple_call_internal_p (call))
+ if (gimple_call_internal_p (&call))
if (const known_function *kf
- = get_known_function (gimple_call_internal_fn (call)))
+ = get_known_function (gimple_call_internal_fn (&call)))
{
kf->impl_call_pre (cd);
return false; /* No further side effects. */
@@ -1958,6 +2287,7 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
if (!callee_fndecl)
{
+ check_for_throw_inside_call (call, NULL_TREE, ctxt);
cd.set_any_lhs_with_defaults ();
return true; /* Unknown side effects. */
}
@@ -1978,7 +2308,10 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
return true; /* Unknown side effects. */
if (!fndecl_has_gimple_body_p (callee_fndecl))
- return true; /* Unknown side effects. */
+ {
+ check_for_throw_inside_call (call, callee_fndecl, ctxt);
+ return true; /* Unknown side effects. */
+ }
return false; /* No side effects. */
}
@@ -1994,7 +2327,7 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
to purge state. */
void
-region_model::on_call_post (const gcall *call,
+region_model::on_call_post (const gcall &call,
bool unknown_side_effects,
region_model_context *ctxt)
{
@@ -2102,12 +2435,11 @@ private:
attribute. */
void
-region_model::check_function_attr_access (const gcall *call,
+region_model::check_function_attr_access (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt,
rdwr_map &rdwr_idx) const
{
- gcc_assert (call);
gcc_assert (callee_fndecl);
gcc_assert (ctxt);
@@ -2145,8 +2477,8 @@ region_model::check_function_attr_access (const gcall *call,
}
void add_annotations () final override
{
- add_note (make_unique<reason_attr_access>
- (m_callee_fndecl, m_access));
+ add_note (std::make_unique<reason_attr_access>
+ (m_callee_fndecl, m_access));
}
private:
tree m_callee_fndecl;
@@ -2157,7 +2489,7 @@ region_model::check_function_attr_access (const gcall *call,
note added to them. */
annotating_ctxt my_ctxt (callee_fndecl, *access, ctxt);
- tree ptr_tree = gimple_call_arg (call, access->ptrarg);
+ tree ptr_tree = gimple_call_arg (&call, access->ptrarg);
const svalue *ptr_sval = get_rvalue (ptr_tree, &my_ctxt);
const region *reg = deref_rvalue (ptr_sval, ptr_tree, &my_ctxt);
check_region_for_write (reg, nullptr, &my_ctxt);
@@ -2171,13 +2503,12 @@ region_model::check_function_attr_access (const gcall *call,
void
region_model::
-check_one_function_attr_null_terminated_string_arg (const gcall *call,
+check_one_function_attr_null_terminated_string_arg (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt,
rdwr_map &rdwr_idx,
tree attr)
{
- gcc_assert (call);
gcc_assert (callee_fndecl);
gcc_assert (ctxt);
gcc_assert (attr);
@@ -2245,12 +2576,11 @@ check_one_function_attr_null_terminated_string_arg (const gcall *call,
void
region_model::
-check_function_attr_null_terminated_string_arg (const gcall *call,
+check_function_attr_null_terminated_string_arg (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt,
rdwr_map &rdwr_idx)
{
- gcc_assert (call);
gcc_assert (callee_fndecl);
gcc_assert (ctxt);
@@ -2275,11 +2605,10 @@ check_function_attr_null_terminated_string_arg (const gcall *call,
function attributes, complaining to CTXT about any issues. */
void
-region_model::check_function_attrs (const gcall *call,
+region_model::check_function_attrs (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt)
{
- gcc_assert (call);
gcc_assert (callee_fndecl);
gcc_assert (ctxt);
@@ -2310,7 +2639,7 @@ region_model::check_function_attrs (const gcall *call,
from their values, and from values that point to them. */
void
-region_model::handle_unrecognized_call (const gcall *call,
+region_model::handle_unrecognized_call (const gcall &call,
region_model_context *ctxt)
{
tree fndecl = get_fndecl_for_call (call, ctxt);
@@ -2331,7 +2660,8 @@ region_model::handle_unrecognized_call (const gcall *call,
tree iter_param_types = NULL_TREE;
if (fndecl)
iter_param_types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
- for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++)
+ for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (&call);
+ arg_idx++)
{
/* Track expected param type, where available. */
tree param_type = NULL_TREE;
@@ -2342,13 +2672,13 @@ region_model::handle_unrecognized_call (const gcall *call,
iter_param_types = TREE_CHAIN (iter_param_types);
}
- tree parm = gimple_call_arg (call, arg_idx);
+ tree parm = gimple_call_arg (&call, arg_idx);
const svalue *parm_sval = get_rvalue (parm, ctxt);
reachable_regs.handle_parm (parm_sval, param_type);
}
}
- 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. */
@@ -2466,11 +2796,11 @@ region_model::on_return (const greturn *return_stmt, region_model_context *ctxt)
0), as opposed to any second return due to longjmp/sigsetjmp. */
void
-region_model::on_setjmp (const gcall *call, const exploded_node *enode,
+region_model::on_setjmp (const gcall &call, const exploded_node *enode,
region_model_context *ctxt)
{
- const svalue *buf_ptr = get_rvalue (gimple_call_arg (call, 0), ctxt);
- const region *buf_reg = deref_rvalue (buf_ptr, gimple_call_arg (call, 0),
+ const svalue *buf_ptr = get_rvalue (gimple_call_arg (&call, 0), ctxt);
+ const region *buf_reg = deref_rvalue (buf_ptr, gimple_call_arg (&call, 0),
ctxt);
/* Create a setjmp_svalue for this call and store it in BUF_REG's
@@ -2484,7 +2814,7 @@ region_model::on_setjmp (const gcall *call, const exploded_node *enode,
}
/* Direct calls to setjmp return 0. */
- if (tree lhs = gimple_call_lhs (call))
+ if (tree lhs = gimple_call_lhs (&call))
{
const svalue *new_sval
= m_mgr->get_or_create_int_cst (TREE_TYPE (lhs), 0);
@@ -2499,23 +2829,23 @@ region_model::on_setjmp (const gcall *call, const exploded_node *enode,
done, and should be done by the caller. */
void
-region_model::on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call,
+region_model::on_longjmp (const gcall &longjmp_call, const gcall &setjmp_call,
int setjmp_stack_depth, region_model_context *ctxt)
{
/* Evaluate the val, using the frame of the "longjmp". */
- tree fake_retval = gimple_call_arg (longjmp_call, 1);
+ tree fake_retval = gimple_call_arg (&longjmp_call, 1);
const svalue *fake_retval_sval = get_rvalue (fake_retval, ctxt);
/* Pop any frames until we reach the stack depth of the function where
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);
/* Assign to LHS of "setjmp" in new_state. */
- if (tree lhs = gimple_call_lhs (setjmp_call))
+ if (tree lhs = gimple_call_lhs (&setjmp_call))
{
/* Passing 0 as the val to longjmp leads to setjmp returning 1. */
const svalue *zero_sval
@@ -2711,7 +3041,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));
@@ -2856,13 +3186,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;
}
@@ -3092,7 +3422,7 @@ region_model::deref_rvalue (const svalue *ptr_sval, tree ptr_tree,
const poisoned_svalue *poisoned_sval
= as_a <const poisoned_svalue *> (ptr_sval);
enum poison_kind pkind = poisoned_sval->get_poison_kind ();
- ctxt->warn (::make_unique<poisoned_value_diagnostic>
+ ctxt->warn (std::make_unique<poisoned_value_diagnostic>
(ptr, pkind, nullptr, nullptr));
}
}
@@ -3250,7 +3580,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;
@@ -3263,16 +3593,18 @@ region_model::check_for_writable_region (const region* dest_reg,
{
const function_region *func_reg = as_a <const function_region *> (base_reg);
tree fndecl = func_reg->get_fndecl ();
- ctxt->warn (make_unique<write_to_const_diagnostic>
- (func_reg, fndecl));
+ ctxt->warn
+ (std::make_unique<write_to_const_diagnostic>
+ (func_reg, fndecl));
}
break;
case RK_LABEL:
{
const label_region *label_reg = as_a <const label_region *> (base_reg);
tree label = label_reg->get_label ();
- ctxt->warn (make_unique<write_to_const_diagnostic>
- (label_reg, label));
+ ctxt->warn
+ (std::make_unique<write_to_const_diagnostic>
+ (label_reg, label));
}
break;
case RK_DECL:
@@ -3285,11 +3617,13 @@ region_model::check_for_writable_region (const region* dest_reg,
"this" param is "T* const"). */
if (TREE_READONLY (decl)
&& is_global_var (decl))
- ctxt->warn (make_unique<write_to_const_diagnostic> (dest_reg, decl));
+ ctxt->warn
+ (std::make_unique<write_to_const_diagnostic> (dest_reg, decl));
}
break;
case RK_STRING:
- ctxt->warn (make_unique<write_to_string_literal_diagnostic> (dest_reg));
+ ctxt->warn
+ (std::make_unique<write_to_string_literal_diagnostic> (dest_reg));
break;
}
}
@@ -3311,13 +3645,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;
@@ -3367,10 +3701,10 @@ region_model::check_region_access (const region *reg,
{
default:
gcc_unreachable ();
- case DIR_READ:
+ case access_direction::read:
/* Currently a no-op. */
break;
- case DIR_WRITE:
+ case access_direction::write:
check_for_writable_region (reg, ctxt);
break;
}
@@ -3384,7 +3718,7 @@ region_model::check_region_for_write (const region *dest_reg,
const svalue *sval_hint,
region_model_context *ctxt) const
{
- check_region_access (dest_reg, DIR_WRITE, sval_hint, ctxt);
+ check_region_access (dest_reg, access_direction::write, sval_hint, ctxt);
}
/* If CTXT is non-NULL, use it to warn about any problems reading from REG.
@@ -3394,7 +3728,7 @@ bool
region_model::check_region_for_read (const region *src_reg,
region_model_context *ctxt) const
{
- return check_region_access (src_reg, DIR_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. */
@@ -3491,7 +3825,8 @@ public:
checker_path &emission_path) final override
{
emission_path.add_event
- (make_unique<region_creation_event_allocation_size> (capacity, loc_info));
+ (std::make_unique<region_creation_event_allocation_size>
+ (capacity, loc_info));
m_has_allocation_event = true;
}
@@ -3501,10 +3836,11 @@ public:
interest->add_region_creation (m_rhs);
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/dubious_allocation_size/"
props.set (PROPERTY_PREFIX "lhs", m_lhs->to_json ());
props.set (PROPERTY_PREFIX "rhs", m_rhs->to_json ());
@@ -3781,7 +4117,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 ()))
@@ -3827,9 +4163,10 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval,
if (TREE_CODE (cst_cap) == INTEGER_CST
&& !capacity_compatible_with_type (cst_cap, pointee_size_tree,
is_struct))
- ctxt->warn (make_unique <dubious_allocation_size> (lhs_reg, rhs_reg,
- capacity, cst_cap,
- ctxt->get_stmt ()));
+ ctxt->warn
+ (std::make_unique <dubious_allocation_size> (lhs_reg, rhs_reg,
+ capacity, cst_cap,
+ ctxt->get_stmt ()));
}
break;
default:
@@ -3841,10 +4178,11 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval,
m_constraints))
{
tree expr = get_representative_tree (capacity);
- ctxt->warn (make_unique <dubious_allocation_size> (lhs_reg,
- rhs_reg,
- capacity, expr,
- ctxt->get_stmt ()));
+ ctxt->warn
+ (std::make_unique <dubious_allocation_size> (lhs_reg,
+ rhs_reg,
+ capacity, expr,
+ ctxt->get_stmt ()));
}
}
break;
@@ -3872,7 +4210,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. */
@@ -4509,7 +4847,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
@@ -4537,7 +4875,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
@@ -4546,7 +4884,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.
@@ -4637,9 +4975,11 @@ region_model::check_for_null_terminated_string_arg (const call_details &cd,
m_cd.get_model ()->get_current_function ()->decl,
m_cd.get_model ()->get_stack_depth ());
- add_event (make_unique<null_terminator_check_event> (loc_info,
- arg_details));
- add_note (make_unique <null_terminator_check_decl_note> (arg_details));
+ add_event
+ (std::make_unique<null_terminator_check_event> (loc_info,
+ arg_details));
+ add_note
+ (std::make_unique <null_terminator_check_decl_note> (arg_details));
}
private:
const call_details &m_cd;
@@ -5385,7 +5725,7 @@ region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
{
bool sat = add_constraint (lhs, op, rhs, ctxt);
if (!sat && out)
- *out = make_unique <rejected_op_constraint> (*this, lhs, op, rhs);
+ *out = std::make_unique <rejected_op_constraint> (*this, lhs, op, rhs);
return sat;
}
@@ -5507,7 +5847,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);
@@ -5866,7 +6206,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. */
@@ -5885,17 +6225,22 @@ region_model::maybe_update_for_edge (const superedge &edge,
ctxt, out);
}
+ if (const geh_dispatch *eh_dispatch_stmt
+ = dyn_cast <const geh_dispatch *> (last_stmt))
+ {
+ const eh_dispatch_cfg_superedge *eh_dispatch_cfg_sedge
+ = as_a <const eh_dispatch_cfg_superedge *> (&edge);
+ return apply_constraints_for_eh_dispatch (*eh_dispatch_cfg_sedge,
+ eh_dispatch_stmt,
+ ctxt, out);
+ }
+
if (const ggoto *goto_stmt = dyn_cast <const ggoto *> (last_stmt))
{
const cfg_superedge *cfg_sedge = as_a <const cfg_superedge *> (&edge);
return apply_constraints_for_ggoto (*cfg_sedge, goto_stmt, ctxt);
}
- /* Apply any constraints due to an exception being thrown. */
- if (const cfg_superedge *cfg_sedge = dyn_cast <const cfg_superedge *> (&edge))
- if (cfg_sedge->get_flags () & EDGE_EH)
- return apply_constraints_for_exception (last_stmt, ctxt, out);
-
return true;
}
@@ -5905,29 +6250,29 @@ region_model::maybe_update_for_edge (const superedge &edge,
caller's frame. */
void
-region_model::update_for_gcall (const gcall *call_stmt,
+region_model::update_for_gcall (const gcall &call_stmt,
region_model_context *ctxt,
function *callee)
{
/* Build a vec of argument svalues, using the current top
frame for resolving tree expressions. */
- auto_vec<const svalue *> arg_svals (gimple_call_num_args (call_stmt));
+ auto_vec<const svalue *> arg_svals (gimple_call_num_args (&call_stmt));
- for (unsigned i = 0; i < gimple_call_num_args (call_stmt); i++)
+ for (unsigned i = 0; i < gimple_call_num_args (&call_stmt); i++)
{
- tree arg = gimple_call_arg (call_stmt, i);
+ tree arg = gimple_call_arg (&call_stmt, i);
arg_svals.quick_push (get_rvalue (arg, ctxt));
}
if(!callee)
{
/* Get the function * from the gcall. */
- tree fn_decl = get_fndecl_for_call (call_stmt,ctxt);
+ tree fn_decl = get_fndecl_for_call (call_stmt, ctxt);
callee = DECL_STRUCT_FUNCTION (fn_decl);
}
gcc_assert (callee);
- push_frame (*callee, &arg_svals, ctxt);
+ push_frame (*callee, &call_stmt, &arg_svals, ctxt);
}
/* Pop the top-most frame_region from the stack, and copy the return
@@ -5935,14 +6280,14 @@ region_model::update_for_gcall (const gcall *call_stmt,
the call (if any). */
void
-region_model::update_for_return_gcall (const gcall *call_stmt,
+region_model::update_for_return_gcall (const gcall &call_stmt,
region_model_context *ctxt)
{
/* Get the lvalue for the result of the call, passing it to pop_frame,
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);
+ tree lhs = gimple_call_lhs (&call_stmt);
+ pop_frame (lhs, nullptr, ctxt, &call_stmt);
}
/* Extract calling information from the superedge and update the model for the
@@ -5952,7 +6297,7 @@ void
region_model::update_for_call_superedge (const call_superedge &call_edge,
region_model_context *ctxt)
{
- const gcall *call_stmt = call_edge.get_call_stmt ();
+ const gcall &call_stmt = call_edge.get_call_stmt ();
update_for_gcall (call_stmt, ctxt, call_edge.get_callee_function ());
}
@@ -5963,7 +6308,7 @@ void
region_model::update_for_return_superedge (const return_superedge &return_edge,
region_model_context *ctxt)
{
- const gcall *call_stmt = return_edge.get_call_stmt ();
+ const gcall &call_stmt = return_edge.get_call_stmt ();
update_for_return_gcall (call_stmt, ctxt);
}
@@ -6018,7 +6363,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);
@@ -6036,7 +6381,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;
@@ -6156,7 +6501,7 @@ apply_constraints_for_gswitch (const switch_cfg_superedge &edge,
&& !ctxt->possibly_tainted_p (index_sval))
{
if (out)
- *out = make_unique <rejected_default_case> (*this);
+ *out = std::make_unique <rejected_default_case> (*this);
return false;
}
@@ -6165,12 +6510,180 @@ apply_constraints_for_gswitch (const switch_cfg_superedge &edge,
= ranges_mgr->get_or_create_ranges_for_switch (&edge, switch_stmt);
bool sat = m_constraints->add_bounded_ranges (index_sval, all_cases_ranges);
if (!sat && out)
- *out = make_unique <rejected_ranges_constraint> (*this, index, all_cases_ranges);
+ *out = std::make_unique <rejected_ranges_constraint>
+ (*this, index, all_cases_ranges);
if (sat && ctxt && !all_cases_ranges->empty_p ())
ctxt->on_bounded_ranges (*index_sval, *all_cases_ranges);
return sat;
}
+class rejected_eh_dispatch : public rejected_constraint
+{
+public:
+ rejected_eh_dispatch (const region_model &model)
+ : rejected_constraint (model)
+ {}
+
+ void dump_to_pp (pretty_printer *pp) const final override
+ {
+ pp_printf (pp, "rejected_eh_dispatch");
+ }
+};
+
+static bool
+exception_matches_type_p (tree exception_type,
+ tree catch_type)
+{
+ if (catch_type == exception_type)
+ return true;
+
+ /* TODO (PR analyzer/119697): we should also handle subclasses etc;
+ see the rules in https://en.cppreference.com/w/cpp/language/catch
+
+ It looks like we should be calling (or emulating)
+ can_convert_eh from the C++ FE, but that's specific to the C++ FE. */
+
+ return false;
+}
+
+static bool
+matches_any_exception_type_p (eh_catch ehc, tree exception_type)
+{
+ if (ehc->type_list == NULL_TREE)
+ /* All exceptions are caught here. */
+ return true;
+
+ for (tree iter = ehc->type_list; iter; iter = TREE_CHAIN (iter))
+ if (exception_matches_type_p (TREE_VALUE (iter),
+ exception_type))
+ return true;
+ return false;
+}
+
+bool
+region_model::
+apply_constraints_for_eh_dispatch (const eh_dispatch_cfg_superedge &edge,
+ const geh_dispatch *,
+ region_model_context *ctxt,
+ std::unique_ptr<rejected_constraint> *out)
+{
+ const exception_node *current_node = get_current_thrown_exception ();
+ gcc_assert (current_node);
+ tree curr_exception_type = current_node->maybe_get_type ();
+ if (!curr_exception_type)
+ /* We don't know the specific type. */
+ return true;
+
+ return edge.apply_constraints (this, ctxt, curr_exception_type, out);
+}
+
+bool
+region_model::
+apply_constraints_for_eh_dispatch_try (const eh_dispatch_try_cfg_superedge &edge,
+ region_model_context */*ctxt*/,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out)
+{
+ /* TODO: can we rely on this ordering?
+ or do we need to iterate through prev_catch ? */
+ /* The exception must not match any of the previous edges. */
+ for (auto sibling_sedge : edge.m_src->m_succs)
+ {
+ if (sibling_sedge == &edge)
+ break;
+
+ const eh_dispatch_try_cfg_superedge *sibling_eh_sedge
+ = as_a <const eh_dispatch_try_cfg_superedge *> (sibling_sedge);
+ if (eh_catch ehc = sibling_eh_sedge->get_eh_catch ())
+ if (matches_any_exception_type_p (ehc, exception_type))
+ {
+ /* The earlier sibling matches, so the "unhandled" edge is
+ not taken. */
+ if (out)
+ *out = std::make_unique<rejected_eh_dispatch> (*this);
+ return false;
+ }
+ }
+
+ if (eh_catch ehc = edge.get_eh_catch ())
+ {
+ /* We have an edge that tried to match one or more types. */
+
+ /* The exception must not match any of the previous edges. */
+
+ /* It must match this type. */
+ if (matches_any_exception_type_p (ehc, exception_type))
+ return true;
+ else
+ {
+ /* Exception type doesn't match. */
+ if (out)
+ *out = std::make_unique<rejected_eh_dispatch> (*this);
+ return false;
+ }
+ }
+ else
+ {
+ /* This is the "unhandled exception" edge.
+ If we get here then no sibling edges matched;
+ we will follow this edge. */
+ return true;
+ }
+}
+
+bool
+region_model::
+apply_constraints_for_eh_dispatch_allowed (const eh_dispatch_allowed_cfg_superedge &edge,
+ region_model_context */*ctxt*/,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out)
+{
+ auto curr_thrown_exception_node = get_current_thrown_exception ();
+ gcc_assert (curr_thrown_exception_node);
+ tree curr_exception_type = curr_thrown_exception_node->maybe_get_type ();
+ eh_region eh_reg = edge.get_eh_region ();
+ tree type_list = eh_reg->u.allowed.type_list;
+
+ switch (edge.get_eh_kind ())
+ {
+ default:
+ gcc_unreachable ();
+ case eh_dispatch_allowed_cfg_superedge::eh_kind::expected:
+ if (!curr_exception_type)
+ {
+ /* We don't know the specific type;
+ assume we have one of an expected type. */
+ return true;
+ }
+ for (tree iter = type_list; iter; iter = TREE_CHAIN (iter))
+ if (exception_matches_type_p (TREE_VALUE (iter),
+ exception_type))
+ return true;
+ if (out)
+ *out = std::make_unique<rejected_eh_dispatch> (*this);
+ return false;
+
+ case eh_dispatch_allowed_cfg_superedge::eh_kind::unexpected:
+ if (!curr_exception_type)
+ {
+ /* We don't know the specific type;
+ assume we don't have one of an expected type. */
+ if (out)
+ *out = std::make_unique<rejected_eh_dispatch> (*this);
+ return false;
+ }
+ for (tree iter = type_list; iter; iter = TREE_CHAIN (iter))
+ if (exception_matches_type_p (TREE_VALUE (iter),
+ exception_type))
+ {
+ if (out)
+ *out = std::make_unique<rejected_eh_dispatch> (*this);
+ return false;
+ }
+ return true;
+ }
+}
+
/* Given an edge reached by GOTO_STMT, determine appropriate constraints
for the edge to be taken.
@@ -6202,38 +6715,6 @@ region_model::apply_constraints_for_ggoto (const cfg_superedge &edge,
return true;
}
-/* Apply any constraints due to an exception being thrown at LAST_STMT.
-
- If they are feasible, add the constraints and return true.
-
- Return false if the constraints contradict existing knowledge
- (and so the edge should not be taken).
- When returning false, if OUT is non-NULL, write a new rejected_constraint
- to it. */
-
-bool
-region_model::
-apply_constraints_for_exception (const gimple *last_stmt,
- region_model_context *ctxt,
- std::unique_ptr<rejected_constraint> *out)
-{
- gcc_assert (last_stmt);
- if (const gcall *call = dyn_cast <const gcall *> (last_stmt))
- if (tree callee_fndecl = get_fndecl_for_call (call, ctxt))
- if (is_named_call_p (callee_fndecl, "operator new", call, 1)
- || is_named_call_p (callee_fndecl, "operator new []", call, 1))
- {
- /* We have an exception thrown from operator new.
- Add a constraint that the result was NULL, to avoid a false
- leak report due to the result being lost when following
- the EH edge. */
- if (tree lhs = gimple_call_lhs (call))
- return add_constraint (lhs, EQ_EXPR, null_pointer_node, ctxt, out);
- return true;
- }
- return true;
-}
-
/* For use with push_frame when handling a top-level call within the analysis.
PARAM has a defined but unknown initial value.
Anything it points to has escaped, since the calling context "knows"
@@ -6265,6 +6746,10 @@ region_model::on_top_level_param (tree param,
/* Update this region_model to reflect pushing a frame onto the stack
for a call to FUN.
+ If CALL_STMT is non-NULL, this is for the interprocedural case where
+ we already have an execution path into the caller. It can be NULL for
+ top-level entrypoints into the analysis, or in selftests.
+
If ARG_SVALS is non-NULL, use it to populate the parameters
in the new frame.
Otherwise, the params have their initial_svalues.
@@ -6273,14 +6758,32 @@ region_model::on_top_level_param (tree param,
const region *
region_model::push_frame (const function &fun,
+ const gcall *call_stmt,
const vec<const svalue *> *arg_svals,
region_model_context *ctxt)
{
- m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
+ tree fndecl = fun.decl;
if (arg_svals)
{
+ /* If the result of the callee is DECL_BY_REFERENCE, then
+ we'll need to store a reference to the caller's lhs of
+ CALL_STMT within callee's result.
+ If so, determine the region of CALL_STMT's lhs within
+ the caller's frame before updating m_current_frame. */
+ const region *caller_return_by_reference_reg = nullptr;
+ if (tree result = DECL_RESULT (fndecl))
+ if (DECL_BY_REFERENCE (result))
+ {
+ gcc_assert (call_stmt);
+ tree lhs = gimple_call_lhs (call_stmt);
+ gcc_assert (lhs);
+ caller_return_by_reference_reg = get_lvalue (lhs, ctxt);
+ }
+
+ /* Update m_current_frame. */
+ m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
+
/* Arguments supplied from a caller frame. */
- tree fndecl = fun.decl;
unsigned idx = 0;
for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
iter_parm = DECL_CHAIN (iter_parm), ++idx)
@@ -6308,13 +6811,39 @@ region_model::push_frame (const function &fun,
va_arg_idx);
set_value (var_arg_reg, arg_sval, ctxt);
}
+
+ /* If the result of the callee is DECL_BY_REFERENCE, then above
+ we should have determined the region within the
+ caller's frame that the callee will be writing back to.
+ Use this now to initialize the reference in callee's frame. */
+ if (tree result = DECL_RESULT (fndecl))
+ if (DECL_BY_REFERENCE (result))
+ {
+ /* Get reference to the caller lhs. */
+ gcc_assert (caller_return_by_reference_reg);
+ const svalue *ref_sval
+ = m_mgr->get_ptr_svalue (TREE_TYPE (result),
+ caller_return_by_reference_reg);
+
+ /* Get region for default val of DECL_RESULT within the
+ callee. */
+ tree result_default_ssa = get_ssa_default_def (fun, result);
+ gcc_assert (result_default_ssa);
+ const region *callee_result_reg
+ = get_lvalue (result_default_ssa, ctxt);
+
+ /* Set the callee's reference to refer to the caller's lhs. */
+ set_value (callee_result_reg, ref_sval, ctxt);
+ }
}
else
{
/* Otherwise we have a top-level call within the analysis. The params
have defined but unknown initial values.
Anything they point to has escaped. */
- tree fndecl = fun.decl;
+
+ /* Update m_current_frame. */
+ m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
/* Handle "__attribute__((nonnull))". */
tree fntype = TREE_TYPE (fndecl);
@@ -6382,7 +6911,7 @@ public:
{}
std::unique_ptr<stmt_finder> clone () const override
{
- return ::make_unique<my_finder> (m_call_stmt, m_caller_frame);
+ return std::make_unique<my_finder> (m_call_stmt, m_caller_frame);
}
const gimple *find_stmt (const exploded_path &) override
{
@@ -6433,7 +6962,7 @@ private:
Purge the frame region and all its descendent regions.
Convert any pointers that point into such regions into
- POISON_KIND_POPPED_STACK svalues. */
+ poison_kind::popped_stack svalues. */
void
region_model::pop_frame (tree result_lvalue,
@@ -6454,7 +6983,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)
@@ -6467,7 +6996,11 @@ region_model::pop_frame (tree result_lvalue,
/* Pop the frame. */
m_current_frame = m_current_frame->get_calling_frame ();
- if (result_lvalue && retval)
+ if (result_lvalue
+ && retval
+ /* Don't write back for DECL_BY_REFERENCE; the writes
+ should have happened within the callee already. */
+ && !DECL_BY_REFERENCE (result))
{
gcc_assert (eval_return_svalue);
@@ -6483,7 +7016,7 @@ region_model::pop_frame (tree result_lvalue,
set_value (result_dst_reg, retval, call_stmt ? &caller_ctxt : ctxt);
}
- unbind_region_and_descendents (frame_reg,POISON_KIND_POPPED_STACK);
+ unbind_region_and_descendents (frame_reg,poison_kind::popped_stack);
notify_on_pop_frame (this, &pre_popped_model, retval, ctxt);
}
@@ -6640,6 +7173,14 @@ region_model::can_merge_with_p (const region_model &other_model,
for (auto iter : m.m_svals_changing_meaning)
out_model->m_constraints->purge_state_involving (iter);
+ if (m_thrown_exceptions_stack != other_model.m_thrown_exceptions_stack)
+ return false;
+ out_model->m_thrown_exceptions_stack = m_thrown_exceptions_stack;
+
+ if (m_caught_exceptions_stack != other_model.m_caught_exceptions_stack)
+ return false;
+ out_model->m_caught_exceptions_stack = m_caught_exceptions_stack;
+
return true;
}
@@ -6647,10 +7188,10 @@ region_model::can_merge_with_p (const region_model &other_model,
otherwise. */
tree
-region_model::get_fndecl_for_call (const gcall *call,
+region_model::get_fndecl_for_call (const gcall &call,
region_model_context *ctxt)
{
- tree fn_ptr = gimple_call_fn (call);
+ tree fn_ptr = gimple_call_fn (&call);
if (fn_ptr == NULL_TREE)
return NULL_TREE;
const svalue *fn_ptr_sval = get_rvalue (fn_ptr, ctxt);
@@ -6773,7 +7314,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);
}
@@ -6825,7 +7366,7 @@ region_model::check_dynamic_size_for_floats (const svalue *size_in_bytes,
if (const svalue *float_sval = v.get_svalue_to_report ())
{
tree diag_arg = get_representative_tree (float_sval);
- ctxt->warn (make_unique<float_as_size_arg> (diag_arg));
+ ctxt->warn (std::make_unique<float_as_size_arg> (diag_arg));
}
}
@@ -6894,6 +7435,12 @@ region_model::get_referenced_base_regions (auto_bitmap &out_ids) const
reachable_regs.add (base_reg, false);
}
+ for (auto &eh_node : m_thrown_exceptions_stack)
+ eh_node.add_to_reachable_regions (reachable_regs);
+ for (auto &eh_node : m_caught_exceptions_stack)
+ eh_node.add_to_reachable_regions (reachable_regs);
+
+
bitmap_clear (out_ids);
for (auto iter_reg : reachable_regs)
bitmap_set_bit (out_ids, iter_reg->get_id ());
@@ -6931,7 +7478,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 *
@@ -6939,7 +7486,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. */
@@ -7050,9 +7597,10 @@ public:
}
void
- maybe_add_sarif_properties (sarif_object &result_obj) const final override
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
+ const final override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/-Wanalyzer-exposure-through-uninit-copy/"
props.set (PROPERTY_PREFIX "src_region", m_src_region->to_json ());
props.set (PROPERTY_PREFIX "dest_region", m_dest_region->to_json ());
@@ -7077,7 +7625,7 @@ private:
{
const poisoned_svalue *poisoned_sval
= as_a <const poisoned_svalue *> (m_copied_sval);
- gcc_assert (poisoned_sval->get_poison_kind () == POISON_KIND_UNINIT);
+ gcc_assert (poisoned_sval->get_poison_kind () == poison_kind::uninit);
/* Give up if don't have type information. */
if (m_copied_sval->get_type () == NULL_TREE)
@@ -7102,7 +7650,7 @@ private:
const svalue *sval = iter.second;
if (const poisoned_svalue *psval
= sval->dyn_cast_poisoned_svalue ())
- if (psval->get_poison_kind () == POISON_KIND_UNINIT)
+ if (psval->get_poison_kind () == poison_kind::uninit)
{
const binding_key *key = iter.first;
const concrete_binding *ckey
@@ -7154,7 +7702,7 @@ private:
const svalue *sval = iter.second;
if (const poisoned_svalue *psval
= sval->dyn_cast_poisoned_svalue ())
- if (psval->get_poison_kind () == POISON_KIND_UNINIT)
+ if (psval->get_poison_kind () == poison_kind::uninit)
{
const binding_key *key = iter.first;
const concrete_binding *ckey
@@ -7171,8 +7719,7 @@ private:
tree type = m_copied_sval->get_type ();
if (type && TREE_CODE (type) == RECORD_TYPE)
{
- // (std::make_unique is C++14)
- layout = std::unique_ptr<record_layout> (new record_layout (type));
+ layout = std::make_unique<record_layout> (type);
if (0)
layout->dump ();
@@ -7254,7 +7801,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)
{
@@ -7315,7 +7862,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",
@@ -7358,7 +7905,7 @@ contains_uninit_p (const svalue *sval)
{
const poisoned_svalue *psval
= as_a <const poisoned_svalue *> (sval);
- return psval->get_poison_kind () == POISON_KIND_UNINIT;
+ return psval->get_poison_kind () == poison_kind::uninit;
}
case SK_COMPOUND:
{
@@ -7370,7 +7917,7 @@ contains_uninit_p (const svalue *sval)
const svalue *sval = iter.second;
if (const poisoned_svalue *psval
= sval->dyn_cast_poisoned_svalue ())
- if (psval->get_poison_kind () == POISON_KIND_UNINIT)
+ if (psval->get_poison_kind () == poison_kind::uninit)
return true;
}
@@ -7386,7 +7933,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
@@ -7397,9 +7944,10 @@ region_model::maybe_complain_about_infoleak (const region *dst_reg,
{
/* Check for exposure. */
if (contains_uninit_p (copied_sval))
- ctxt->warn (make_unique<exposure_through_uninit_copy> (src_reg,
- dst_reg,
- copied_sval));
+ ctxt->warn
+ (std::make_unique<exposure_through_uninit_copy> (src_reg,
+ dst_reg,
+ copied_sval));
}
/* Set errno to a positive symbolic int, as if some error has occurred. */
@@ -7411,7 +7959,7 @@ region_model::set_errno (const call_details &cd)
conjured_purge p (this, cd.get_ctxt ());
const svalue *new_errno_sval
= m_mgr->get_or_create_conjured_svalue (integer_type_node,
- cd.get_call_stmt (),
+ &cd.get_call_stmt (),
errno_reg, p);
const svalue *zero
= m_mgr->get_or_create_int_cst (integer_type_node, 0);
@@ -7538,8 +8086,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);
@@ -7559,7 +8107,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);
@@ -7660,7 +8208,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);
}
@@ -7749,7 +8297,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)
@@ -7804,22 +8352,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);
}
}
@@ -7840,7 +8388,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. */
@@ -7854,7 +8402,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);
}
@@ -7863,7 +8411,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]");
}
@@ -7988,12 +8536,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);
}
@@ -8337,9 +8885,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);
}
@@ -8367,16 +8915,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. */
@@ -8432,7 +8980,7 @@ test_stack_frames ()
/* Push stack frame for "parent_fn". */
const region *parent_frame_reg
= model.push_frame (*DECL_STRUCT_FUNCTION (parent_fndecl),
- NULL, &ctxt);
+ nullptr, nullptr, &ctxt);
ASSERT_EQ (model.get_current_frame (), parent_frame_reg);
ASSERT_TRUE (model.region_exists_p (parent_frame_reg));
const region *a_in_parent_reg = model.get_lvalue (a, &ctxt);
@@ -8447,7 +8995,8 @@ test_stack_frames ()
/* Push stack frame for "child_fn". */
const region *child_frame_reg
- = model.push_frame (*DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt);
+ = model.push_frame (*DECL_STRUCT_FUNCTION (child_fndecl),
+ nullptr, nullptr, &ctxt);
ASSERT_EQ (model.get_current_frame (), child_frame_reg);
ASSERT_TRUE (model.region_exists_p (child_frame_reg));
const region *x_in_child_reg = model.get_lvalue (x, &ctxt);
@@ -8465,7 +9014,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);
@@ -8479,16 +9028,16 @@ 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);
+ poison_kind::popped_stack);
/* Verify that q still points to p, in spite of the region
renumbering. */
@@ -8540,7 +9089,8 @@ test_get_representative_path_var ()
for (int depth = 0; depth < 5; depth++)
{
const region *frame_n_reg
- = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl), NULL, &ctxt);
+ = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl),
+ nullptr, nullptr, &ctxt);
const region *parm_n_reg = model.get_lvalue (path_var (n, depth), &ctxt);
parm_regs.safe_push (parm_n_reg);
@@ -8562,7 +9112,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. */
{
@@ -8591,22 +9141,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
@@ -8625,20 +9175,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);
}
@@ -8659,12 +9209,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 ();
@@ -8684,7 +9234,7 @@ test_canonicalization_4 ()
region_model model (&mgr);
for (tree cst : csts)
- model.get_rvalue (cst, NULL);
+ model.get_rvalue (cst, nullptr);
model.canonicalize ();
}
@@ -8693,7 +9243,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
@@ -8786,9 +9336,11 @@ test_state_merging ()
region_model model0 (&mgr);
region_model model1 (&mgr);
ASSERT_EQ (model0.get_stack_depth (), 0);
- model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
+ model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
+ nullptr, nullptr, &ctxt);
ASSERT_EQ (model0.get_stack_depth (), 1);
- model1.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
+ model1.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
+ nullptr, nullptr, &ctxt);
placeholder_svalue test_sval (mgr.alloc_symbol_id (),
integer_type_node, "test sval");
@@ -8880,9 +9432,10 @@ test_state_merging ()
/* Pointers: non-NULL and non-NULL: ptr to a local. */
{
region_model model0 (&mgr);
- model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
- model0.set_value (model0.get_lvalue (p, NULL),
- model0.get_rvalue (addr_of_a, NULL), NULL);
+ model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
+ nullptr, nullptr, nullptr);
+ model0.set_value (model0.get_lvalue (p, nullptr),
+ model0.get_rvalue (addr_of_a, nullptr), nullptr);
region_model model1 (model0);
ASSERT_EQ (model0, model1);
@@ -8906,7 +9459,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. */
@@ -9019,17 +9572,19 @@ test_state_merging ()
frame points to a local in a more recent stack frame. */
{
region_model model0 (&mgr);
- model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
- const region *q_in_first_frame = model0.get_lvalue (q, NULL);
+ model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
+ nullptr, nullptr, nullptr);
+ const region *q_in_first_frame = model0.get_lvalue (q, nullptr);
/* Push a second frame. */
const region *reg_2nd_frame
- = model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
+ = model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
+ nullptr, nullptr, nullptr);
/* 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 ();
@@ -9051,9 +9606,10 @@ test_state_merging ()
/* Verify that we can merge a model in which a local points to a global. */
{
region_model model0 (&mgr);
- model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
- model0.set_value (model0.get_lvalue (q, NULL),
- model0.get_rvalue (addr_of_y, NULL), NULL);
+ model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
+ nullptr, nullptr, nullptr);
+ model0.set_value (model0.get_lvalue (q, nullptr),
+ model0.get_rvalue (addr_of_y, nullptr), nullptr);
region_model model1 (model0);
ASSERT_EQ (model0, model1);
@@ -9085,14 +9641,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). */
@@ -9317,17 +9873,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);
@@ -9349,25 +9905,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". */
{
@@ -9406,38 +9962,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;
@@ -9445,14 +10004,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. */
@@ -9479,12 +10039,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);
}
@@ -9530,8 +10090,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. */
@@ -9583,7 +10143,7 @@ test_alloca ()
/* Push stack frame. */
const region *frame_reg
= model.push_frame (*DECL_STRUCT_FUNCTION (fndecl),
- NULL, &ctxt);
+ nullptr, nullptr, &ctxt);
/* "p = alloca (n * 4);". */
const svalue *size_sval = model.get_rvalue (n_times_4, &ctxt);
const region *reg = model.create_region_for_alloca (size_sval, &ctxt);
@@ -9594,8 +10154,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 d8e508d..6271ea2 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -250,6 +250,41 @@ typedef void (*pop_frame_callback) (const region_model *model,
const svalue *retval,
region_model_context *ctxt);
+/* Roughly equivalent to a struct __cxa_exception, except we store a std::vector
+ rather than a linked list. */
+
+struct exception_node
+{
+ exception_node (const svalue *exception_sval,
+ const svalue *typeinfo_sval,
+ const svalue *destructor_sval)
+ : m_exception_sval (exception_sval),
+ m_typeinfo_sval (typeinfo_sval),
+ m_destructor_sval (destructor_sval)
+ {
+ }
+
+ bool operator== (const exception_node &other) const;
+
+ void dump_to_pp (pretty_printer *pp, bool simple) const;
+ void dump (FILE *fp, bool simple) const;
+ void dump (bool simple) const;
+ void dump () const;
+
+ std::unique_ptr<json::object> to_json () const;
+
+ std::unique_ptr<text_art::tree_widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi) const;
+
+ tree maybe_get_type () const;
+
+ void add_to_reachable_regions (reachable_regions &) const;
+
+ const svalue *m_exception_sval;
+ const svalue *m_typeinfo_sval;
+ const svalue *m_destructor_sval;
+};
+
/* A region_model encapsulates a representation of the state of memory, with
a tree of regions, along with their associated values.
The representation is graph-like because values can be pointers to
@@ -305,8 +340,8 @@ class region_model
const svalue *get_gassign_result (const gassign *assign,
region_model_context *ctxt);
void on_asm_stmt (const gasm *asm_stmt, region_model_context *ctxt);
- bool on_call_pre (const gcall *stmt, region_model_context *ctxt);
- void on_call_post (const gcall *stmt,
+ bool on_call_pre (const gcall &stmt, region_model_context *ctxt);
+ void on_call_post (const gcall &stmt,
bool unknown_side_effects,
region_model_context *ctxt);
@@ -323,16 +358,16 @@ class region_model
bool unmergeable);
void update_for_nonzero_return (const call_details &cd);
- void handle_unrecognized_call (const gcall *call,
+ void handle_unrecognized_call (const gcall &call,
region_model_context *ctxt);
void get_reachable_svalues (svalue_set *out,
const svalue *extra_sval,
const uncertainty_t *uncertainty);
void on_return (const greturn *stmt, region_model_context *ctxt);
- void on_setjmp (const gcall *stmt, const exploded_node *enode,
+ void on_setjmp (const gcall &stmt, const exploded_node *enode,
region_model_context *ctxt);
- void on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call,
+ void on_longjmp (const gcall &longjmp_call, const gcall &setjmp_call,
int setjmp_stack_depth, region_model_context *ctxt);
void update_for_phis (const supernode *snode,
@@ -349,14 +384,16 @@ class region_model
region_model_context *ctxt,
std::unique_ptr<rejected_constraint> *out);
- void update_for_gcall (const gcall *call_stmt,
- region_model_context *ctxt,
- function *callee = NULL);
+ void update_for_gcall (const gcall &call_stmt,
+ region_model_context *ctxt,
+ function *callee = nullptr);
- void update_for_return_gcall (const gcall *call_stmt,
- region_model_context *ctxt);
+ void update_for_return_gcall (const gcall &call_stmt,
+ region_model_context *ctxt);
- const region *push_frame (const function &fun, const vec<const svalue *> *arg_sids,
+ const region *push_frame (const function &fun,
+ const gcall *call_stmt,
+ const vec<const svalue *> *arg_sids,
region_model_context *ctxt);
const frame_region *get_current_frame () const { return m_current_frame; }
const function *get_current_function () const;
@@ -480,11 +517,11 @@ 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,
+ tree get_fndecl_for_call (const gcall &call,
region_model_context *ctxt);
void get_regions_for_current_frame (auto_vec<const decl_region *> *out) const;
@@ -562,8 +599,8 @@ class region_model
const svalue **out_sval) const;
const builtin_known_function *
- get_builtin_kf (const gcall *call,
- region_model_context *ctxt = NULL) const;
+ get_builtin_kf (const gcall &call,
+ region_model_context *ctxt = nullptr) const;
static void
register_pop_frame_callback (const pop_frame_callback &callback)
@@ -583,6 +620,56 @@ class region_model
bool called_from_main_p () const;
+ void push_thrown_exception (const exception_node &node)
+ {
+ m_thrown_exceptions_stack.push_back (node);
+ }
+ const exception_node *get_current_thrown_exception () const
+ {
+ if (m_thrown_exceptions_stack.empty ())
+ return nullptr;
+ return &m_thrown_exceptions_stack.back ();
+ }
+ exception_node pop_thrown_exception ()
+ {
+ gcc_assert (!m_thrown_exceptions_stack.empty ());
+ const exception_node retval = m_thrown_exceptions_stack.back ();
+ m_thrown_exceptions_stack.pop_back ();
+ return retval;
+ }
+
+ void push_caught_exception (const exception_node &node)
+ {
+ m_caught_exceptions_stack.push_back (node);
+ }
+ const exception_node *get_current_caught_exception () const
+ {
+ if (m_caught_exceptions_stack.empty ())
+ return nullptr;
+ return &m_caught_exceptions_stack.back ();
+ }
+ exception_node pop_caught_exception ()
+ {
+ gcc_assert (!m_caught_exceptions_stack.empty ());
+ const exception_node retval = m_caught_exceptions_stack.back ();
+ m_caught_exceptions_stack.pop_back ();
+ return retval;
+ }
+
+ bool
+ apply_constraints_for_eh_dispatch_try
+ (const eh_dispatch_try_cfg_superedge &edge,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out);
+
+ bool
+ apply_constraints_for_eh_dispatch_allowed
+ (const eh_dispatch_allowed_cfg_superedge &edge,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out);
+
private:
const region *get_lvalue_1 (path_var pv, region_model_context *ctxt) const;
const svalue *get_rvalue_1 (path_var pv, region_model_context *ctxt) const;
@@ -621,9 +708,12 @@ private:
bool apply_constraints_for_ggoto (const cfg_superedge &edge,
const ggoto *goto_stmt,
region_model_context *ctxt);
- bool apply_constraints_for_exception (const gimple *last_stmt,
- region_model_context *ctxt,
- std::unique_ptr<rejected_constraint> *out);
+
+ bool
+ apply_constraints_for_eh_dispatch (const eh_dispatch_cfg_superedge &edge,
+ const geh_dispatch *eh_dispatch_stmt,
+ region_model_context *ctxt,
+ std::unique_ptr<rejected_constraint> *out);
int poison_any_pointers_to_descendents (const region *reg,
enum poison_kind pkind);
@@ -672,23 +762,27 @@ private:
void check_call_args (const call_details &cd) const;
void check_call_format_attr (const call_details &cd,
tree format_attr) const;
- void check_function_attr_access (const gcall *call,
+ void check_function_attr_access (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt,
rdwr_map &rdwr_idx) const;
- void check_function_attr_null_terminated_string_arg (const gcall *call,
+ void check_function_attr_null_terminated_string_arg (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt,
rdwr_map &rdwr_idx);
- void check_one_function_attr_null_terminated_string_arg (const gcall *call,
+ void check_one_function_attr_null_terminated_string_arg (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt,
rdwr_map &rdwr_idx,
tree attr);
- void check_function_attrs (const gcall *call,
+ void check_function_attrs (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt);
+ void check_for_throw_inside_call (const gcall &call,
+ tree fndecl,
+ region_model_context *ctxt);
+
static auto_vec<pop_frame_callback> pop_frame_callbacks;
/* Storing this here to avoid passing it around everywhere. */
region_model_manager *const m_mgr;
@@ -699,6 +793,9 @@ private:
const frame_region *m_current_frame;
+ std::vector<exception_node> m_thrown_exceptions_stack;
+ std::vector<exception_node> m_caught_exceptions_stack;
+
/* Map from base region to size in bytes, for tracking the sizes of
dynamically-allocated regions.
This is part of the region_model rather than the region to allow for
@@ -721,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. */
@@ -815,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);
@@ -831,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;
@@ -849,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
@@ -872,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 **,
@@ -890,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 {}
@@ -1070,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)
@@ -1240,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 ()
@@ -1299,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
@@ -1308,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 d464153..e27fc6e 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -18,38 +18,19 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "diagnostic-core.h"
-#include "gimple-pretty-print.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
-#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "diagnostic-color.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "ordered-hash-map.h"
#include "options.h"
#include "cgraph.h"
#include "cfg.h"
#include "digraph.h"
-#include "analyzer/supergraph.h"
#include "sbitmap.h"
+#include "fold-const.h"
+#include "tree-ssa.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/supergraph.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
@@ -58,7 +39,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/sm.h"
#include "analyzer/program-state.h"
#include "text-art/dump.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -144,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
{
@@ -251,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)
@@ -270,7 +250,7 @@ struct linear_op
}
*out = linear_op (binop_sval.get_arg0 (),
- NULL,
+ nullptr,
binop_sval.get_arg1 ());
return true;
}
@@ -296,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))
{
@@ -338,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))
{
@@ -468,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
@@ -480,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. */
@@ -567,15 +547,12 @@ region::can_have_initial_svalue_p () const
case SSA_NAME:
{
+ /* Some SSA names have an implicit default defined value. */
tree ssa_name = decl;
- /* SSA names that are the default defn of a PARM_DECL
- have initial_svalues; other SSA names don't. */
- if (SSA_NAME_IS_DEFAULT_DEF (ssa_name)
- && SSA_NAME_VAR (ssa_name)
- && TREE_CODE (SSA_NAME_VAR (ssa_name)) == PARM_DECL)
- return true;
- else
- return false;
+ if (SSA_NAME_IS_DEFAULT_DEF (ssa_name))
+ return ssa_defined_default_def_p (ssa_name);
+ /* Others don't. */
+ return false;
}
}
}
@@ -632,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
@@ -792,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.
@@ -902,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)
{
@@ -1039,7 +1016,7 @@ std::unique_ptr<json::value>
region::to_json () const
{
label_text desc = get_desc (true);
- auto reg_js = ::make_unique<json::string> (desc.get ());
+ auto reg_js = std::make_unique<json::string> (desc.get ());
return reg_js;
}
@@ -1178,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));
}
@@ -1571,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)
{
}
@@ -1703,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 ())
@@ -1713,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
@@ -1723,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
@@ -1765,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
@@ -1776,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,
@@ -1788,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);
@@ -1804,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
@@ -1825,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)
@@ -1835,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;
@@ -1875,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 e9016f1..b8ae0a1 100644
--- a/gcc/analyzer/sm-fd.cc
+++ b/gcc/analyzer/sm-fd.cc
@@ -18,32 +18,21 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
-#include "diagnostic-event-id.h"
+#include "analyzer/common.h"
+
+#include "diagnostics/event-id.h"
+#include "stringpool.h"
+#include "attribs.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/function-set.h"
#include "analyzer/analyzer-selftests.h"
-#include "stringpool.h"
-#include "attribs.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
-#include "bitmap.h"
#include "analyzer/program-state.h"
#include "analyzer/supergraph.h"
#include "analyzer/analyzer-language.h"
@@ -127,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;
@@ -221,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;
@@ -230,17 +223,17 @@ public:
private:
void on_open (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call) const;
+ const gcall &call) const;
void on_creat (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call) const;
+ const gcall &call) const;
void on_close (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call) const;
+ const gcall &call) const;
void on_read (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call, const tree callee_fndecl) const;
+ const gcall &call, const tree callee_fndecl) const;
void on_write (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call, const tree callee_fndecl) const;
+ const gcall &call, const tree callee_fndecl) const;
void check_for_open_fd (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call,
+ const gimple *stmt, const gcall &call,
const tree callee_fndecl,
enum access_directions access_fn) const;
@@ -253,11 +246,11 @@ private:
const gimple *stmt,
const svalue *lhs) const;
void check_for_fd_attrs (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call,
+ const gimple *stmt, const gcall &call,
const tree callee_fndecl, const char *attr_name,
access_directions fd_attr_access_dir) const;
void check_for_dup (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call, const tree callee_fndecl,
+ const gimple *stmt, const gcall &call, const tree callee_fndecl,
enum dup kind) const;
state_t get_state_for_socket_type (const svalue *socket_type_sval) const;
@@ -268,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,
@@ -399,21 +392,22 @@ public:
return false;
}
- diagnostic_event::meaning
+ diagnostics::paths::event::meaning
get_meaning_for_state_change (
const evdesc::state_change &change) const final override
{
+ using event = diagnostics::paths::event;
if (change.m_old_state == m_sm.get_start_state ()
&& (m_sm.is_unchecked_fd_p (change.m_new_state)
|| 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 event::meaning (event::verb::acquire,
+ 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 ();
+ return event::meaning (event::verb::release,
+ event::noun::resource);
+ return event::meaning ();
}
protected:
@@ -433,7 +427,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)
{
}
@@ -488,7 +482,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
@@ -554,8 +555,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;
+ diagnostics::paths::event_id_t m_open_event;
+ std::unique_ptr<program_state> m_final_state;
};
class fd_access_mode_mismatch : public fd_param_diagnostic
@@ -698,7 +706,7 @@ public:
}
private:
- diagnostic_event_id_t m_first_close_event;
+ diagnostics::paths::event_id_t m_first_close_event;
};
class fd_use_after_close : public fd_param_diagnostic
@@ -777,7 +785,7 @@ public:
}
private:
- diagnostic_event_id_t m_first_close_event;
+ diagnostics::paths::event_id_t m_first_close_event;
};
class fd_use_without_check : public fd_param_diagnostic
@@ -847,7 +855,7 @@ public:
}
private:
- diagnostic_event_id_t m_first_open_event;
+ diagnostics::paths::event_id_t m_first_open_event;
};
/* Concrete pending_diagnostic subclass for -Wanalyzer-fd-phase-mismatch. */
@@ -1307,7 +1315,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
@@ -1316,7 +1324,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
@@ -1324,70 +1332,70 @@ fd_state_machine::on_stmt (sm_context &sm_ctxt, const supernode *node,
const gimple *stmt) const
{
if (const gcall *call = dyn_cast<const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call))
{
- if (is_named_call_p (callee_fndecl, "open", call, 2))
+ if (is_named_call_p (callee_fndecl, "open", *call, 2))
{
- on_open (sm_ctxt, node, stmt, call);
+ on_open (sm_ctxt, node, stmt, *call);
return true;
} // "open"
- if (is_named_call_p (callee_fndecl, "creat", call, 2))
+ if (is_named_call_p (callee_fndecl, "creat", *call, 2))
{
- on_creat (sm_ctxt, node, stmt, call);
+ on_creat (sm_ctxt, node, stmt, *call);
return true;
} // "creat"
- if (is_named_call_p (callee_fndecl, "close", call, 1))
+ if (is_named_call_p (callee_fndecl, "close", *call, 1))
{
- on_close (sm_ctxt, node, stmt, call);
+ on_close (sm_ctxt, node, stmt, *call);
return true;
} // "close"
- if (is_named_call_p (callee_fndecl, "write", call, 3))
+ if (is_named_call_p (callee_fndecl, "write", *call, 3))
{
- on_write (sm_ctxt, node, stmt, call, callee_fndecl);
+ on_write (sm_ctxt, node, stmt, *call, callee_fndecl);
return true;
} // "write"
- if (is_named_call_p (callee_fndecl, "read", call, 3))
+ if (is_named_call_p (callee_fndecl, "read", *call, 3))
{
- on_read (sm_ctxt, node, stmt, call, callee_fndecl);
+ on_read (sm_ctxt, node, stmt, *call, callee_fndecl);
return true;
} // "read"
- if (is_named_call_p (callee_fndecl, "dup", call, 1))
+ if (is_named_call_p (callee_fndecl, "dup", *call, 1))
{
- check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_1);
+ check_for_dup (sm_ctxt, node, stmt, *call, callee_fndecl, DUP_1);
return true;
}
- if (is_named_call_p (callee_fndecl, "dup2", call, 2))
+ if (is_named_call_p (callee_fndecl, "dup2", *call, 2))
{
- check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_2);
+ check_for_dup (sm_ctxt, node, stmt, *call, callee_fndecl, DUP_2);
return true;
}
- if (is_named_call_p (callee_fndecl, "dup3", call, 3))
+ if (is_named_call_p (callee_fndecl, "dup3", *call, 3))
{
- check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_3);
+ check_for_dup (sm_ctxt, node, stmt, *call, callee_fndecl, DUP_3);
return true;
}
{
// Handle __attribute__((fd_arg))
- check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
+ check_for_fd_attrs (sm_ctxt, node, stmt, *call, callee_fndecl,
"fd_arg", DIRS_READ_WRITE);
// Handle __attribute__((fd_arg_read))
- check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
+ check_for_fd_attrs (sm_ctxt, node, stmt, *call, callee_fndecl,
"fd_arg_read", DIRS_READ);
// Handle __attribute__((fd_arg_write))
- check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
+ check_for_fd_attrs (sm_ctxt, node, stmt, *call, callee_fndecl,
"fd_arg_write", DIRS_WRITE);
}
}
@@ -1398,7 +1406,7 @@ fd_state_machine::on_stmt (sm_context &sm_ctxt, const supernode *node,
void
fd_state_machine::check_for_fd_attrs (
sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call, const tree callee_fndecl, const char *attr_name,
+ const gcall &call, const tree callee_fndecl, const char *attr_name,
access_directions fd_attr_access_dir) const
{
/* Handle interesting fd attributes of the callee_fndecl,
@@ -1431,9 +1439,9 @@ fd_state_machine::check_for_fd_attrs (
if (bitmap_empty_p (argmap))
return;
- for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++)
+ for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (&call); arg_idx++)
{
- tree arg = gimple_call_arg (call, arg_idx);
+ tree arg = gimple_call_arg (&call, arg_idx);
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
state_t state = sm_ctxt.get_state (stmt, arg);
bool bit_set = bitmap_bit_p (argmap, arg_idx);
@@ -1449,7 +1457,7 @@ fd_state_machine::check_for_fd_attrs (
{
sm_ctxt.warn (node, stmt, arg,
- make_unique<fd_use_after_close>
+ std::make_unique<fd_use_after_close>
(*this, diag_arg,
fndecl, attr_name,
arg_idx));
@@ -1461,7 +1469,7 @@ fd_state_machine::check_for_fd_attrs (
if (!is_constant_fd_p (state))
{
sm_ctxt.warn (node, stmt, arg,
- make_unique<fd_use_without_check>
+ std::make_unique<fd_use_without_check>
(*this, diag_arg,
fndecl, attr_name,
arg_idx));
@@ -1477,13 +1485,13 @@ fd_state_machine::check_for_fd_attrs (
if (is_writeonly_fd_p (state))
{
- sm_ctxt.warn (
- node, stmt, arg,
- make_unique<fd_access_mode_mismatch> (*this, diag_arg,
- DIRS_WRITE,
- fndecl,
- attr_name,
- arg_idx));
+ sm_ctxt.warn
+ (node, stmt, arg,
+ std::make_unique<fd_access_mode_mismatch> (*this, diag_arg,
+ DIRS_WRITE,
+ fndecl,
+ attr_name,
+ arg_idx));
}
break;
@@ -1491,13 +1499,13 @@ fd_state_machine::check_for_fd_attrs (
if (is_readonly_fd_p (state))
{
- sm_ctxt.warn (
- node, stmt, arg,
- make_unique<fd_access_mode_mismatch> (*this, diag_arg,
- DIRS_READ,
- fndecl,
- attr_name,
- arg_idx));
+ sm_ctxt.warn
+ (node, stmt, arg,
+ std::make_unique<fd_access_mode_mismatch> (*this, diag_arg,
+ DIRS_READ,
+ fndecl,
+ attr_name,
+ arg_idx));
}
break;
@@ -1509,12 +1517,12 @@ fd_state_machine::check_for_fd_attrs (
void
fd_state_machine::on_open (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call) const
+ const gimple *stmt, const gcall &call) const
{
- tree lhs = gimple_call_lhs (call);
+ tree lhs = gimple_call_lhs (&call);
if (lhs)
{
- tree arg = gimple_call_arg (call, 1);
+ tree arg = gimple_call_arg (&call, 1);
enum access_mode mode = READ_WRITE;
if (TREE_CODE (arg) == INTEGER_CST)
{
@@ -1539,29 +1547,29 @@ fd_state_machine::on_open (sm_context &sm_ctxt, const supernode *node,
else
{
sm_ctxt.warn (node, stmt, NULL_TREE,
- make_unique<fd_leak> (*this, NULL_TREE));
+ std::make_unique<fd_leak> (*this, NULL_TREE, nullptr));
}
}
void
fd_state_machine::on_creat (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call) const
+ const gimple *stmt, const gcall &call) const
{
- tree lhs = gimple_call_lhs (call);
+ tree lhs = gimple_call_lhs (&call);
if (lhs)
sm_ctxt.on_transition (node, stmt, lhs, m_start, m_unchecked_write_only);
else
sm_ctxt.warn (node, stmt, NULL_TREE,
- make_unique<fd_leak> (*this, NULL_TREE));
+ std::make_unique<fd_leak> (*this, NULL_TREE, nullptr));
}
void
fd_state_machine::check_for_dup (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call,
+ const gimple *stmt, const gcall &call,
const tree callee_fndecl, enum dup kind) const
{
- tree lhs = gimple_call_lhs (call);
- tree arg_1 = gimple_call_arg (call, 0);
+ tree lhs = gimple_call_lhs (&call);
+ tree arg_1 = gimple_call_arg (&call, 0);
state_t state_arg_1 = sm_ctxt.get_state (stmt, arg_1);
if (state_arg_1 == m_stop)
return;
@@ -1587,7 +1595,7 @@ fd_state_machine::check_for_dup (sm_context &sm_ctxt, const supernode *node,
case DUP_2:
case DUP_3:
- tree arg_2 = gimple_call_arg (call, 1);
+ tree arg_2 = gimple_call_arg (&call, 1);
state_t state_arg_2 = sm_ctxt.get_state (stmt, arg_2);
tree diag_arg_2 = sm_ctxt.get_diagnostic_tree (arg_2);
if (state_arg_2 == m_stop)
@@ -1598,8 +1606,8 @@ fd_state_machine::check_for_dup (sm_context &sm_ctxt, const supernode *node,
{
sm_ctxt.warn (
node, stmt, arg_2,
- make_unique<fd_use_without_check> (*this, diag_arg_2,
- callee_fndecl));
+ std::make_unique<fd_use_without_check> (*this, diag_arg_2,
+ callee_fndecl));
return;
}
/* dup2 returns value of its second argument on success.But, the
@@ -1620,9 +1628,9 @@ fd_state_machine::check_for_dup (sm_context &sm_ctxt, const supernode *node,
void
fd_state_machine::on_close (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call) const
+ const gimple *stmt, const gcall &call) const
{
- tree arg = gimple_call_arg (call, 0);
+ tree arg = gimple_call_arg (&call, 0);
state_t state = sm_ctxt.get_state (stmt, arg);
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
@@ -1646,20 +1654,20 @@ fd_state_machine::on_close (sm_context &sm_ctxt, const supernode *node,
if (is_closed_fd_p (state))
{
sm_ctxt.warn (node, stmt, arg,
- make_unique<fd_double_close> (*this, diag_arg));
+ std::make_unique<fd_double_close> (*this, diag_arg));
sm_ctxt.set_next_state (stmt, arg, m_stop);
}
}
void
fd_state_machine::on_read (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call,
+ const gimple *stmt, const gcall &call,
const tree callee_fndecl) const
{
check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_READ);
}
void
fd_state_machine::on_write (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call,
+ const gimple *stmt, const gcall &call,
const tree callee_fndecl) const
{
check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_WRITE);
@@ -1668,18 +1676,18 @@ fd_state_machine::on_write (sm_context &sm_ctxt, const supernode *node,
void
fd_state_machine::check_for_open_fd (
sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call, const tree callee_fndecl,
+ const gcall &call, const tree callee_fndecl,
enum access_directions callee_fndecl_dir) const
{
- tree arg = gimple_call_arg (call, 0);
+ tree arg = gimple_call_arg (&call, 0);
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
state_t state = sm_ctxt.get_state (stmt, arg);
if (is_closed_fd_p (state))
{
sm_ctxt.warn (node, stmt, arg,
- make_unique<fd_use_after_close> (*this, diag_arg,
- callee_fndecl));
+ std::make_unique<fd_use_after_close> (*this, diag_arg,
+ callee_fndecl));
}
else
@@ -1690,10 +1698,10 @@ fd_state_machine::check_for_open_fd (
/* Complain about fncall on socket in wrong phase. */
sm_ctxt.warn
(node, stmt, arg,
- make_unique<fd_phase_mismatch> (*this, diag_arg,
- callee_fndecl,
- state,
- EXPECTED_PHASE_CAN_TRANSFER));
+ std::make_unique<fd_phase_mismatch> (*this, diag_arg,
+ callee_fndecl,
+ state,
+ EXPECTED_PHASE_CAN_TRANSFER));
else if (!(is_valid_fd_p (state)
|| state == m_new_datagram_socket
|| state == m_bound_unknown_socket
@@ -1704,8 +1712,8 @@ fd_state_machine::check_for_open_fd (
if (!is_constant_fd_p (state))
sm_ctxt.warn (
node, stmt, arg,
- make_unique<fd_use_without_check> (*this, diag_arg,
- callee_fndecl));
+ std::make_unique<fd_use_without_check> (*this, diag_arg,
+ callee_fndecl));
}
switch (callee_fndecl_dir)
{
@@ -1716,8 +1724,8 @@ fd_state_machine::check_for_open_fd (
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<fd_access_mode_mismatch> (
- *this, diag_arg, DIRS_WRITE, callee_fndecl));
+ std::make_unique<fd_access_mode_mismatch>
+ (*this, diag_arg, DIRS_WRITE, callee_fndecl));
}
break;
@@ -1727,8 +1735,8 @@ fd_state_machine::check_for_open_fd (
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<fd_access_mode_mismatch> (
- *this, diag_arg, DIRS_READ, callee_fndecl));
+ std::make_unique<fd_access_mode_mismatch>
+ (*this, diag_arg, DIRS_READ, callee_fndecl));
}
break;
}
@@ -1775,21 +1783,21 @@ fd_state_machine::on_socket (const call_details &cd,
sm_context &sm_ctxt,
const extrinsic_state &ext_state) const
{
- const gcall *stmt = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
engine *eng = ext_state.get_engine ();
const supergraph *sg = eng->get_supergraph ();
- const supernode *node = sg->get_supernode_for_stmt (stmt);
+ const supernode *node = sg->get_supernode_for_stmt (&call);
region_model *model = cd.get_model ();
if (successful)
{
- if (gimple_call_lhs (stmt))
+ if (gimple_call_lhs (&call))
{
conjured_purge p (model, cd.get_ctxt ());
region_model_manager *mgr = model->get_manager ();
const svalue *new_fd
= mgr->get_or_create_conjured_svalue (integer_type_node,
- stmt,
+ &call,
cd.get_lhs_region (),
p);
if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
@@ -1798,12 +1806,12 @@ fd_state_machine::on_socket (const call_details &cd,
const svalue *socket_type_sval = cd.get_arg_svalue (1);
state_machine::state_t new_state
= get_state_for_socket_type (socket_type_sval);
- sm_ctxt.on_transition (node, stmt, new_fd, m_start, new_state);
+ sm_ctxt.on_transition (node, &call, new_fd, m_start, new_state);
model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
}
else
- sm_ctxt.warn (node, stmt, NULL_TREE,
- make_unique<fd_leak> (*this, NULL_TREE));
+ sm_ctxt.warn (node, &call, NULL_TREE,
+ std::make_unique<fd_leak> (*this, NULL_TREE, nullptr));
}
else
{
@@ -1833,15 +1841,15 @@ fd_state_machine::check_for_socket_fd (const call_details &cd,
state_t old_state,
bool *complained) const
{
- const gcall *stmt = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
if (is_closed_fd_p (old_state))
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_use_after_close> (*this, diag_arg,
- cd.get_fndecl_for_call ()));
+ (node, &call, fd_sval,
+ std::make_unique<fd_use_after_close> (*this, diag_arg,
+ cd.get_fndecl_for_call ()));
if (complained)
*complained = true;
if (successful)
@@ -1852,11 +1860,11 @@ fd_state_machine::check_for_socket_fd (const call_details &cd,
/* Complain about non-socket. */
tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_type_mismatch> (*this, diag_arg,
- cd.get_fndecl_for_call (),
- old_state,
- EXPECTED_TYPE_SOCKET));
+ (node, &call, fd_sval,
+ std::make_unique<fd_type_mismatch> (*this, diag_arg,
+ cd.get_fndecl_for_call (),
+ old_state,
+ EXPECTED_TYPE_SOCKET));
if (complained)
*complained = true;
if (successful)
@@ -1866,9 +1874,9 @@ fd_state_machine::check_for_socket_fd (const call_details &cd,
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_use_without_check> (*this, diag_arg,
- cd.get_fndecl_for_call ()));
+ (node, &call, fd_sval,
+ std::make_unique<fd_use_without_check> (*this, diag_arg,
+ cd.get_fndecl_for_call ()));
if (complained)
*complained = true;
if (successful)
@@ -1929,11 +1937,11 @@ fd_state_machine::check_for_new_socket_fd (const call_details &cd,
/* Complain about "bind" or "connect" in wrong phase. */
tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
sm_ctxt.warn
- (node, cd.get_call_stmt (), fd_sval,
- make_unique<fd_phase_mismatch> (*this, diag_arg,
- cd.get_fndecl_for_call (),
- old_state,
- expected_phase));
+ (node, &cd.get_call_stmt (), fd_sval,
+ std::make_unique<fd_phase_mismatch> (*this, diag_arg,
+ cd.get_fndecl_for_call (),
+ old_state,
+ expected_phase));
if (successful)
return false;
}
@@ -1941,7 +1949,7 @@ fd_state_machine::check_for_new_socket_fd (const call_details &cd,
{
/* If we were in the start state, assume we had a new socket. */
if (old_state == m_start)
- sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval,
+ sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval,
m_new_unknown_socket);
}
@@ -1963,13 +1971,13 @@ fd_state_machine::on_bind (const call_details &cd,
sm_context &sm_ctxt,
const extrinsic_state &ext_state) const
{
- const gcall *stmt = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
engine *eng = ext_state.get_engine ();
const supergraph *sg = eng->get_supergraph ();
- const supernode *node = sg->get_supernode_for_stmt (stmt);
+ const supernode *node = sg->get_supernode_for_stmt (&call);
const svalue *fd_sval = cd.get_arg_svalue (0);
region_model *model = cd.get_model ();
- state_t old_state = sm_ctxt.get_state (stmt, fd_sval);
+ state_t old_state = sm_ctxt.get_state (&call, fd_sval);
if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
fd_sval, node, old_state,
@@ -1978,7 +1986,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)
@@ -1992,7 +2000,7 @@ fd_state_machine::on_bind (const call_details &cd,
next_state = m_stop;
else
gcc_unreachable ();
- sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval, next_state);
+ sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval, next_state);
model->update_for_zero_return (cd, true);
}
else
@@ -2015,13 +2023,13 @@ fd_state_machine::on_listen (const call_details &cd,
sm_context &sm_ctxt,
const extrinsic_state &ext_state) const
{
- const gcall *stmt = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
engine *eng = ext_state.get_engine ();
const supergraph *sg = eng->get_supergraph ();
- const supernode *node = sg->get_supernode_for_stmt (cd.get_call_stmt ());
+ const supernode *node = sg->get_supernode_for_stmt (&cd.get_call_stmt ());
const svalue *fd_sval = cd.get_arg_svalue (0);
region_model *model = cd.get_model ();
- state_t old_state = sm_ctxt.get_state (stmt, fd_sval);
+ state_t old_state = sm_ctxt.get_state (&call, fd_sval);
/* We expect a stream socket that's had "bind" called on it. */
if (!check_for_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state))
@@ -2039,18 +2047,18 @@ fd_state_machine::on_listen (const call_details &cd,
tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
if (is_stream_socket_fd_p (old_state))
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_phase_mismatch> (*this, diag_arg,
- cd.get_fndecl_for_call (),
- old_state,
- EXPECTED_PHASE_CAN_LISTEN));
+ (node, &call, fd_sval,
+ std::make_unique<fd_phase_mismatch> (*this, diag_arg,
+ cd.get_fndecl_for_call (),
+ old_state,
+ EXPECTED_PHASE_CAN_LISTEN));
else
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_type_mismatch> (*this, diag_arg,
- cd.get_fndecl_for_call (),
- old_state,
- EXPECTED_TYPE_STREAM_SOCKET));
+ (node, &call, fd_sval,
+ std::make_unique<fd_type_mismatch> (*this, diag_arg,
+ cd.get_fndecl_for_call (),
+ old_state,
+ EXPECTED_TYPE_STREAM_SOCKET));
if (successful)
return false;
}
@@ -2058,7 +2066,7 @@ fd_state_machine::on_listen (const call_details &cd,
if (successful)
{
model->update_for_zero_return (cd, true);
- sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval,
+ sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval,
m_listening_stream_socket);
}
else
@@ -2067,7 +2075,7 @@ fd_state_machine::on_listen (const call_details &cd,
model->update_for_int_cst_return (cd, -1, true);
model->set_errno (cd);
if (old_state == m_start)
- sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval,
+ sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval,
m_bound_stream_socket);
}
@@ -2084,15 +2092,15 @@ fd_state_machine::on_accept (const call_details &cd,
sm_context &sm_ctxt,
const extrinsic_state &ext_state) const
{
- const gcall *stmt = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
engine *eng = ext_state.get_engine ();
const supergraph *sg = eng->get_supergraph ();
- const supernode *node = sg->get_supernode_for_stmt (stmt);
+ const supernode *node = sg->get_supernode_for_stmt (&call);
const svalue *fd_sval = cd.get_arg_svalue (0);
const svalue *address_sval = cd.get_arg_svalue (1);
const svalue *len_ptr_sval = cd.get_arg_svalue (2);
region_model *model = cd.get_model ();
- state_t old_state = sm_ctxt.get_state (stmt, fd_sval);
+ state_t old_state = sm_ctxt.get_state (&call, fd_sval);
if (!address_sval->all_zeroes_p ())
{
@@ -2127,14 +2135,14 @@ fd_state_machine::on_accept (const call_details &cd,
old_len_sval);
const svalue *new_addr_sval
= mgr->get_or_create_conjured_svalue (NULL_TREE,
- stmt,
+ &call,
old_sized_address_reg,
p);
model->set_value (old_sized_address_reg, new_addr_sval,
cd.get_ctxt ());
const svalue *new_addr_len
= mgr->get_or_create_conjured_svalue (NULL_TREE,
- stmt,
+ &call,
len_reg,
p);
model->set_value (len_reg, new_addr_len, cd.get_ctxt ());
@@ -2148,7 +2156,7 @@ fd_state_machine::on_accept (const call_details &cd,
if (old_state == m_start || old_state == m_constant_fd)
/* If we were in the start state (or a constant), assume we had the
expected state. */
- sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval,
+ sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval,
m_listening_stream_socket);
else if (old_state == m_stop)
{
@@ -2160,18 +2168,18 @@ fd_state_machine::on_accept (const call_details &cd,
tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
if (is_stream_socket_fd_p (old_state))
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_phase_mismatch> (*this, diag_arg,
- cd.get_fndecl_for_call (),
- old_state,
- EXPECTED_PHASE_CAN_ACCEPT));
+ (node, &call, fd_sval,
+ std::make_unique<fd_phase_mismatch> (*this, diag_arg,
+ cd.get_fndecl_for_call (),
+ old_state,
+ EXPECTED_PHASE_CAN_ACCEPT));
else
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_type_mismatch> (*this, diag_arg,
- cd.get_fndecl_for_call (),
- old_state,
- EXPECTED_TYPE_STREAM_SOCKET));
+ (node, &call, fd_sval,
+ std::make_unique<fd_type_mismatch> (*this, diag_arg,
+ cd.get_fndecl_for_call (),
+ old_state,
+ EXPECTED_TYPE_STREAM_SOCKET));
if (successful)
return false;
}
@@ -2179,24 +2187,24 @@ fd_state_machine::on_accept (const call_details &cd,
if (successful)
{
/* Return new conjured FD in "connected" state. */
- if (gimple_call_lhs (stmt))
+ if (gimple_call_lhs (&call))
{
conjured_purge p (model, cd.get_ctxt ());
region_model_manager *mgr = model->get_manager ();
const svalue *new_fd
= mgr->get_or_create_conjured_svalue (integer_type_node,
- stmt,
+ &call,
cd.get_lhs_region (),
p);
if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
return false;
- sm_ctxt.on_transition (node, stmt, new_fd,
+ sm_ctxt.on_transition (node, &call, new_fd,
m_start, m_connected_stream_socket);
model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
}
else
- sm_ctxt.warn (node, stmt, NULL_TREE,
- make_unique<fd_leak> (*this, NULL_TREE));
+ sm_ctxt.warn (node, &call, NULL_TREE,
+ std::make_unique<fd_leak> (*this, NULL_TREE, nullptr));
}
else
{
@@ -2218,13 +2226,13 @@ fd_state_machine::on_connect (const call_details &cd,
sm_context &sm_ctxt,
const extrinsic_state &ext_state) const
{
- const gcall *stmt = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
engine *eng = ext_state.get_engine ();
const supergraph *sg = eng->get_supergraph ();
- const supernode *node = sg->get_supernode_for_stmt (stmt);
+ const supernode *node = sg->get_supernode_for_stmt (&call);
const svalue *fd_sval = cd.get_arg_svalue (0);
region_model *model = cd.get_model ();
- state_t old_state = sm_ctxt.get_state (stmt, fd_sval);
+ state_t old_state = sm_ctxt.get_state (&call, fd_sval);
if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
fd_sval, node, old_state,
@@ -2234,7 +2242,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)
@@ -2250,7 +2258,7 @@ fd_state_machine::on_connect (const call_details &cd,
next_state = m_stop;
else
gcc_unreachable ();
- sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval, next_state);
+ sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval, next_state);
}
else
{
@@ -2332,16 +2340,18 @@ 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 make_unique<fd_leak> (*this, var);
+ return std::make_unique<fd_leak> (*this, var, new_state);
}
} // namespace
-state_machine *
+std::unique_ptr<state_machine>
make_fd_state_machine (logger *logger)
{
- return new fd_state_machine (logger);
+ return std::make_unique<fd_state_machine> (logger);
}
static bool
@@ -2372,7 +2382,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)
@@ -2401,7 +2411,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;
@@ -2426,8 +2436,10 @@ public:
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, true));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_socket> (cd, false));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_socket> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2454,7 +2466,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;
@@ -2478,8 +2490,10 @@ public:
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, true));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_bind> (cd, false));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_bind> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2505,7 +2519,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;
@@ -2530,8 +2544,10 @@ class kf_listen : public known_function
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, true));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_listen> (cd, false));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_listen> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2557,7 +2573,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;
@@ -2584,8 +2600,10 @@ class kf_accept : public known_function
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, true));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_accept> (cd, false));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_accept> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2612,7 +2630,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;
@@ -2638,8 +2656,10 @@ public:
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, true));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_connect> (cd, false));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_connect> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2688,7 +2708,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)
@@ -2696,7 +2716,7 @@ class kf_isatty : public known_function
const svalue *fd_sval = cd.get_arg_svalue (0);
state_machine::state_t old_state
- = sm_ctxt->get_state (cd.get_call_stmt (), fd_sval);
+ = sm_ctxt->get_state (&cd.get_call_stmt (), fd_sval);
if (fd_sm->is_closed_fd_p (old_state)
|| old_state == fd_sm->m_invalid)
@@ -2716,8 +2736,10 @@ public:
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_isatty> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_isatty> (cd, true));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_isatty> (cd, false));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_isatty> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2773,7 +2795,7 @@ class kf_pipe : public known_function
conjured_purge p (model, cd.get_ctxt ());
const svalue *fd_sval
= mgr->get_or_create_conjured_svalue (integer_type_node,
- cd.get_call_stmt (),
+ &cd.get_call_stmt (),
element_reg,
p);
model->set_value (element_reg, fd_sval, cd.get_ctxt ());
@@ -2799,8 +2821,10 @@ public:
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
- cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<failure> (cd));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<success> (cd));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2848,15 +2872,15 @@ public:
void
register_known_fd_functions (known_function_manager &kfm)
{
- kfm.add ("accept", make_unique<kf_accept> ());
- kfm.add ("bind", make_unique<kf_bind> ());
- kfm.add ("connect", make_unique<kf_connect> ());
- kfm.add ("isatty", make_unique<kf_isatty> ());
- kfm.add ("listen", make_unique<kf_listen> ());
- kfm.add ("pipe", make_unique<kf_pipe> (1));
- kfm.add ("pipe2", make_unique<kf_pipe> (2));
- kfm.add ("read", make_unique<kf_read> ());
- kfm.add ("socket", make_unique<kf_socket> ());
+ kfm.add ("accept", std::make_unique<kf_accept> ());
+ kfm.add ("bind", std::make_unique<kf_bind> ());
+ kfm.add ("connect", std::make_unique<kf_connect> ());
+ kfm.add ("isatty", std::make_unique<kf_isatty> ());
+ kfm.add ("listen", std::make_unique<kf_listen> ());
+ kfm.add ("pipe", std::make_unique<kf_pipe> (1));
+ kfm.add ("pipe2", std::make_unique<kf_pipe> (2));
+ kfm.add ("read", std::make_unique<kf_read> ());
+ kfm.add ("socket", std::make_unique<kf_socket> ());
}
} // namespace ana
diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc
index 1e41dc9..c852c02 100644
--- a/gcc/analyzer/sm-file.cc
+++ b/gcc/analyzer/sm-file.cc
@@ -18,28 +18,19 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
-#include "diagnostic-event-id.h"
+#include "analyzer/common.h"
+
+#include "diagnostics/event-id.h"
+#include "selftest.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/function-set.h"
#include "analyzer/analyzer-selftests.h"
-#include "selftest.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"
@@ -82,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.
@@ -160,18 +155,20 @@ public:
return false;
}
- diagnostic_event::meaning
+ diagnostics::paths::event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
+ using event = diagnostics::paths::event;
+
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 event::meaning (event::verb::acquire,
+ 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 ();
+ return event::meaning (event::verb::release,
+ event::noun::resource);
+ return event::meaning ();
}
protected:
@@ -230,15 +227,20 @@ public:
}
private:
- diagnostic_event_id_t m_first_fclose_event;
+ diagnostics::paths::event_id_t m_first_fclose_event;
};
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"; }
@@ -296,8 +298,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;
+ diagnostics::paths::event_id_t m_fopen_event;
+ std::unique_ptr<program_state> m_final_state;
};
/* fileptr_state_machine's ctor. */
@@ -403,9 +412,9 @@ fileptr_state_machine::on_stmt (sm_context &sm_ctxt,
const gimple *stmt) const
{
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call))
{
- if (is_named_call_p (callee_fndecl, "fopen", call, 2))
+ if (is_named_call_p (callee_fndecl, "fopen", *call, 2))
{
tree lhs = gimple_call_lhs (call);
if (lhs)
@@ -417,7 +426,7 @@ fileptr_state_machine::on_stmt (sm_context &sm_ctxt,
return true;
}
- if (is_named_call_p (callee_fndecl, "fclose", call, 1))
+ if (is_named_call_p (callee_fndecl, "fclose", *call, 1))
{
tree arg = gimple_call_arg (call, 0);
@@ -433,7 +442,8 @@ fileptr_state_machine::on_stmt (sm_context &sm_ctxt,
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<double_fclose> (*this, diag_arg));
+ std::make_unique<double_fclose> (*this,
+ diag_arg));
sm_ctxt.set_next_state (stmt, arg, m_stop);
}
return true;
@@ -501,19 +511,21 @@ 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 make_unique<file_leak> (*this, var);
+ return std::make_unique<file_leak> (*this, var, new_state);
}
} // anonymous namespace
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_fileptr_state_machine (logger *logger)
{
- return new fileptr_state_machine (logger);
+ return std::make_unique<fileptr_state_machine> (logger);
}
/* Handler for various stdio-related builtins that merely have external
@@ -655,40 +667,40 @@ public:
void
register_known_file_functions (known_function_manager &kfm)
{
- kfm.add (BUILT_IN_FPRINTF, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FPRINTF_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FPUTC, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FPUTC_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FPUTS, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FPUTS_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FWRITE, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FWRITE_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PRINTF, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PRINTF_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PUTC, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PUTCHAR, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PUTCHAR_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PUTC_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PUTS, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PUTS_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_VFPRINTF, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_VPRINTF, make_unique<kf_stdio_output_fn> ());
-
- kfm.add ("ferror", make_unique<kf_ferror> ());
- kfm.add ("fgets", make_unique<kf_fgets> ());
- kfm.add ("fgets_unlocked", make_unique<kf_fgets> ()); // non-standard
- kfm.add ("fileno", make_unique<kf_fileno> ());
- kfm.add ("fread", make_unique<kf_fread> ());
- kfm.add ("getc", make_unique<kf_getc> ());
- kfm.add ("getchar", make_unique<kf_getchar> ());
+ kfm.add (BUILT_IN_FPRINTF, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FPRINTF_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FPUTC, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FPUTC_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FPUTS, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FPUTS_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FWRITE, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FWRITE_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PRINTF, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PRINTF_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PUTC, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PUTCHAR, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PUTCHAR_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PUTC_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PUTS, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PUTS_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_VFPRINTF, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_VPRINTF, std::make_unique<kf_stdio_output_fn> ());
+
+ kfm.add ("ferror", std::make_unique<kf_ferror> ());
+ kfm.add ("fgets", std::make_unique<kf_fgets> ());
+ kfm.add ("fgets_unlocked", std::make_unique<kf_fgets> ()); // non-standard
+ kfm.add ("fileno", std::make_unique<kf_fileno> ());
+ kfm.add ("fread", std::make_unique<kf_fread> ());
+ kfm.add ("getc", std::make_unique<kf_getc> ());
+ kfm.add ("getchar", std::make_unique<kf_getchar> ());
/* Some C++ implementations use the std:: copies of these functions
from <cstdio> for <stdio.h>, so we must match against these too. */
- kfm.add_std_ns ("ferror", make_unique<kf_ferror> ());
- kfm.add_std_ns ("fgets", make_unique<kf_fgets> ());
- kfm.add_std_ns ("fread", make_unique<kf_fread> ());
- kfm.add_std_ns ("getc", make_unique<kf_getc> ());
- kfm.add_std_ns ("getchar", make_unique<kf_getchar> ());
+ kfm.add_std_ns ("ferror", std::make_unique<kf_ferror> ());
+ kfm.add_std_ns ("fgets", std::make_unique<kf_fgets> ());
+ kfm.add_std_ns ("fread", std::make_unique<kf_fread> ());
+ kfm.add_std_ns ("getc", std::make_unique<kf_getc> ());
+ kfm.add_std_ns ("getchar", std::make_unique<kf_getchar> ());
}
#if CHECKING_P
diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc
index 6972a55..a6b1421 100644
--- a/gcc/analyzer/sm-malloc.cc
+++ b/gcc/analyzer/sm-malloc.cc
@@ -18,21 +18,13 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "bitmap.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
-#include "diagnostic-event-id.h"
+#include "analyzer/common.h"
+
+#include "diagnostics/event-id.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "xml-printer.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
@@ -41,13 +33,12 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/call-details.h"
-#include "stringpool.h"
-#include "attribs.h"
#include "analyzer/function-set.h"
#include "analyzer/program-state.h"
#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
@@ -150,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);
@@ -301,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;
@@ -335,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)
@@ -345,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;
};
@@ -414,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;
@@ -440,6 +435,11 @@ public:
const svalue *new_ptr_sval,
const extrinsic_state &ext_state) const;
+ void
+ add_state_to_state_graph (analyzer_state_graph &out_state_graph,
+ 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;
@@ -482,22 +482,22 @@ private:
tree ptr) const;
void on_allocator_call (sm_context &sm_ctxt,
- const gcall *call,
+ const gcall &call,
const deallocator_set *deallocators,
bool returns_nonnull = false) const;
void handle_free_of_non_heap (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
tree arg,
const deallocator *d) const;
void on_deallocator_call (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
const deallocator *d,
unsigned argno) const;
void on_realloc_call (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call) const;
+ const gcall &call) const;
void on_zero_assignment (sm_context &sm_ctxt,
const gimple *stmt,
tree lhs) const;
@@ -535,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))
{
}
@@ -579,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))
{
}
@@ -625,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
@@ -673,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);
}
@@ -796,8 +797,13 @@ public:
else
{
if (change.m_expr)
- pp_printf (&pp, "%qE is NULL",
- change.m_expr);
+ {
+ if (zerop (change.m_expr))
+ pp_printf (&pp, "using NULL here");
+ else
+ pp_printf (&pp, "%qE is NULL",
+ change.m_expr);
+ }
else
pp_printf (&pp, "%qs is NULL",
"<unknown>");
@@ -808,18 +814,18 @@ public:
return false;
}
- diagnostic_event::meaning
+ diagnostics::paths::event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
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 diagnostics::paths::event::meaning (diagnostics::paths::event::verb::acquire,
+ diagnostics::paths::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 ();
+ return diagnostics::paths::event::meaning (diagnostics::paths::event::verb::release,
+ diagnostics::paths::event::noun::memory);
+ return diagnostics::paths::event::meaning ();
}
protected:
@@ -912,7 +918,7 @@ public:
}
private:
- diagnostic_event_id_t m_alloc_event;
+ diagnostics::paths::event_id_t m_alloc_event;
const deallocator_set *m_expected_deallocators;
const deallocator *m_actual_dealloc;
};
@@ -982,7 +988,7 @@ public:
}
private:
- diagnostic_event_id_t m_first_free_event;
+ diagnostics::paths::event_id_t m_first_free_event;
const char *m_funcname;
};
@@ -1025,7 +1031,7 @@ public:
}
protected:
- diagnostic_event_id_t m_origin_of_unchecked_event;
+ diagnostics::paths::event_id_t m_origin_of_unchecked_event;
};
/* Concrete subclass for describing dereference of a possible NULL
@@ -1413,15 +1419,21 @@ public:
}
private:
- diagnostic_event_id_t m_free_event;
+ diagnostics::paths::event_id_t m_free_event;
const deallocator *m_deallocator;
};
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"; }
@@ -1481,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;
+ diagnostics::paths::event_id_t m_alloc_event;
+ std::unique_ptr<program_state> m_final_state;
};
class free_of_non_heap : public malloc_diagnostic
@@ -1577,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);
}
@@ -1749,7 +1768,7 @@ private:
return result;
}
- diagnostic_event_id_t m_first_deref_event;
+ diagnostics::paths::event_id_t m_first_deref_event;
const exploded_node *m_deref_enode;
tree m_deref_expr;
const exploded_node *m_check_enode;
@@ -1804,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 ()
@@ -1834,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::
@@ -1843,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. */
@@ -1861,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. */
@@ -1892,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. */
@@ -1955,7 +1974,7 @@ get_or_create_assumed_non_null_state_for_frame (const frame_region *frame)
builtin. */
static bool
-known_allocator_p (const_tree fndecl, const gcall *call)
+known_allocator_p (const_tree fndecl, const gcall &call)
{
/* Either it is a function we know by name and number of arguments... */
if (is_named_call_p (fndecl, "malloc", call, 1)
@@ -1997,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. */
@@ -2029,9 +2048,10 @@ malloc_state_machine::handle_nonnull (sm_context &sm_ctxt,
if (unchecked_p (state))
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
- sm_ctxt.warn (node, stmt, arg,
- make_unique<possible_null_arg> (*this, diag_arg, fndecl,
- i));
+ sm_ctxt.warn
+ (node, stmt, arg,
+ std::make_unique<possible_null_arg> (*this, diag_arg, fndecl,
+ i));
const allocation_state *astate
= as_a_allocation_state (state);
sm_ctxt.set_next_state (stmt, arg, astate->get_nonnull ());
@@ -2040,7 +2060,7 @@ malloc_state_machine::handle_nonnull (sm_context &sm_ctxt,
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<null_arg> (*this, diag_arg, fndecl, i));
+ std::make_unique<null_arg> (*this, diag_arg, fndecl, i));
sm_ctxt.set_next_state (stmt, arg, m_stop);
}
else if (state == m_start)
@@ -2054,9 +2074,11 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt,
const supernode *node,
const gimple *stmt) const
{
- if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
+ if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call_stmt))
{
+ const gcall &call = *call_stmt;
+
if (known_allocator_p (callee_fndecl, call))
{
on_allocator_call (sm_ctxt, call, &m_free);
@@ -2092,7 +2114,7 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt,
if (is_named_call_p (callee_fndecl, "alloca", call, 1)
|| is_named_call_p (callee_fndecl, "__builtin_alloca", call, 1))
{
- tree lhs = gimple_call_lhs (call);
+ tree lhs = gimple_call_lhs (&call);
if (lhs)
sm_ctxt.on_transition (node, stmt, lhs, m_start, m_non_heap);
return true;
@@ -2175,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);
}
@@ -2260,8 +2290,8 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt,
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<possible_null_deref> (*this,
- diag_arg));
+ std::make_unique<possible_null_deref> (*this,
+ diag_arg));
const allocation_state *astate = as_a_allocation_state (state);
sm_ctxt.set_next_state (stmt, arg, astate->get_nonnull ());
}
@@ -2269,7 +2299,7 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt,
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<null_deref> (*this, diag_arg));
+ std::make_unique<null_deref> (*this, diag_arg));
sm_ctxt.set_next_state (stmt, arg, m_stop);
}
else if (freed_p (state))
@@ -2277,7 +2307,7 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt,
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
const allocation_state *astate = as_a_allocation_state (state);
sm_ctxt.warn (node, stmt, arg,
- make_unique<use_after_free>
+ std::make_unique<use_after_free>
(*this, diag_arg, astate->m_deallocator));
sm_ctxt.set_next_state (stmt, arg, m_stop);
}
@@ -2339,7 +2369,7 @@ maybe_complain_about_deref_before_check (sm_context &sm_ctxt,
if (diag_ptr)
sm_ctxt.warn
(node, stmt, ptr,
- make_unique<deref_before_check> (*this, diag_ptr));
+ std::make_unique<deref_before_check> (*this, diag_ptr));
sm_ctxt.set_next_state (stmt, ptr, m_stop);
}
@@ -2349,15 +2379,15 @@ maybe_complain_about_deref_before_check (sm_context &sm_ctxt,
void
malloc_state_machine::on_allocator_call (sm_context &sm_ctxt,
- const gcall *call,
+ const gcall &call,
const deallocator_set *deallocators,
bool returns_nonnull) const
{
- tree lhs = gimple_call_lhs (call);
+ tree lhs = gimple_call_lhs (&call);
if (lhs)
{
- if (sm_ctxt.get_state (call, lhs) == m_start)
- sm_ctxt.set_next_state (call, lhs,
+ if (sm_ctxt.get_state (&call, lhs) == m_start)
+ sm_ctxt.set_next_state (&call, lhs,
(returns_nonnull
? deallocators->m_nonnull
: deallocators->m_unchecked));
@@ -2374,40 +2404,40 @@ malloc_state_machine::on_allocator_call (sm_context &sm_ctxt,
void
malloc_state_machine::handle_free_of_non_heap (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
tree arg,
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,
- make_unique<free_of_non_heap>
+ sm_ctxt.warn (node, &call, arg,
+ std::make_unique<free_of_non_heap>
(*this, diag_arg, freed_reg, d->m_name));
- sm_ctxt.set_next_state (call, arg, m_stop);
+ sm_ctxt.set_next_state (&call, arg, m_stop);
}
void
malloc_state_machine::on_deallocator_call (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
const deallocator *d,
unsigned argno) const
{
- if (argno >= gimple_call_num_args (call))
+ if (argno >= gimple_call_num_args (&call))
return;
- tree arg = gimple_call_arg (call, argno);
+ tree arg = gimple_call_arg (&call, argno);
- state_t state = sm_ctxt.get_state (call, arg);
+ state_t state = sm_ctxt.get_state (&call, arg);
/* start/assumed_non_null/unchecked/nonnull -> freed. */
if (state == m_start || assumed_non_null_p (state))
- sm_ctxt.set_next_state (call, arg, d->m_freed);
+ sm_ctxt.set_next_state (&call, arg, d->m_freed);
else if (unchecked_p (state) || nonnull_p (state))
{
const allocation_state *astate = as_a_allocation_state (state);
@@ -2416,13 +2446,13 @@ malloc_state_machine::on_deallocator_call (sm_context &sm_ctxt,
{
/* Wrong allocator. */
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
- sm_ctxt.warn (node, call, arg,
- make_unique<mismatching_deallocation>
+ sm_ctxt.warn (node, &call, arg,
+ std::make_unique<mismatching_deallocation>
(*this, diag_arg,
astate->m_deallocators,
d));
}
- sm_ctxt.set_next_state (call, arg, d->m_freed);
+ sm_ctxt.set_next_state (&call, arg, d->m_freed);
}
/* Keep state "null" as-is, rather than transitioning to "freed";
@@ -2431,9 +2461,9 @@ malloc_state_machine::on_deallocator_call (sm_context &sm_ctxt,
{
/* freed -> stop, with warning. */
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
- sm_ctxt.warn (node, call, arg,
- make_unique<double_free> (*this, diag_arg, d->m_name));
- sm_ctxt.set_next_state (call, arg, m_stop);
+ sm_ctxt.warn (node, &call, arg,
+ std::make_unique<double_free> (*this, diag_arg, d->m_name));
+ sm_ctxt.set_next_state (&call, arg, m_stop);
}
else if (state == m_non_heap)
{
@@ -2453,14 +2483,14 @@ malloc_state_machine::on_deallocator_call (sm_context &sm_ctxt,
void
malloc_state_machine::on_realloc_call (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call) const
+ const gcall &call) const
{
const unsigned argno = 0;
const deallocator *d = &m_realloc;
- tree arg = gimple_call_arg (call, argno);
+ tree arg = gimple_call_arg (&call, argno);
- state_t state = sm_ctxt.get_state (call, arg);
+ state_t state = sm_ctxt.get_state (&call, arg);
if (unchecked_p (state) || nonnull_p (state))
{
@@ -2470,11 +2500,11 @@ malloc_state_machine::on_realloc_call (sm_context &sm_ctxt,
{
/* Wrong allocator. */
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
- sm_ctxt.warn (node, call, arg,
- make_unique<mismatching_deallocation>
+ sm_ctxt.warn (node, &call, arg,
+ std::make_unique<mismatching_deallocation>
(*this, diag_arg,
astate->m_deallocators, d));
- sm_ctxt.set_next_state (call, arg, m_stop);
+ sm_ctxt.set_next_state (&call, arg, m_stop);
if (path_context *path_ctxt = sm_ctxt.get_path_context ())
path_ctxt->terminate_path ();
}
@@ -2483,9 +2513,9 @@ malloc_state_machine::on_realloc_call (sm_context &sm_ctxt,
{
/* freed -> stop, with warning. */
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
- sm_ctxt.warn (node, call, arg,
- make_unique<double_free> (*this, diag_arg, "free"));
- sm_ctxt.set_next_state (call, arg, m_stop);
+ sm_ctxt.warn (node, &call, arg,
+ std::make_unique<double_free> (*this, diag_arg, "free"));
+ sm_ctxt.set_next_state (&call, arg, m_stop);
if (path_context *path_ctxt = sm_ctxt.get_path_context ())
path_ctxt->terminate_path ();
}
@@ -2592,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 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
@@ -2627,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. */
@@ -2685,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
@@ -2700,17 +2732,71 @@ 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);
+}
+
+static enum diagnostics::state_graphs::node_dynalloc_state
+get_dynalloc_state_for_state (enum resource_state rs)
+{
+ switch (rs)
+ {
+ default:
+ gcc_unreachable ();
+ case RS_START:
+ case RS_NULL:
+ case RS_NON_HEAP:
+ case RS_STOP:
+ return diagnostics::state_graphs::node_dynalloc_state::unknown;
+
+ case RS_ASSUMED_NON_NULL:
+ return diagnostics::state_graphs::node_dynalloc_state::nonnull;
+
+ case RS_UNCHECKED:
+ return diagnostics::state_graphs::node_dynalloc_state::unchecked;
+ case RS_NONNULL:
+ return diagnostics::state_graphs::node_dynalloc_state::nonnull;
+ case RS_FREED:
+ return diagnostics::state_graphs::node_dynalloc_state::freed;
+ }
+}
+
+void
+malloc_state_machine::
+add_state_to_state_graph (analyzer_state_graph &out_state_graph,
+ const svalue &sval,
+ state_machine::state_t state) const
+{
+ if (const region *reg = sval.maybe_get_region ())
+ {
+ auto reg_node = out_state_graph.get_or_create_state_node (*reg);
+ auto alloc_state = as_a_allocation_state (state);
+ gcc_assert (alloc_state);
+
+ reg_node.set_dynalloc_state
+ (get_dynalloc_state_for_state (alloc_state->m_rs));
+ if (alloc_state->m_deallocators)
+ {
+ pretty_printer pp;
+ alloc_state->m_deallocators->dump_to_pp (&pp);
+ reg_node.m_node.set_attr (STATE_NODE_PREFIX,
+ "expected-deallocators",
+ pp_formatted_text (&pp));
+ }
+ if (alloc_state->m_deallocator)
+ reg_node.m_node.set_attr (STATE_NODE_PREFIX,
+ "deallocator",
+ alloc_state->m_deallocator->m_name);
+ }
}
} // anonymous namespace
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_malloc_state_machine (logger *logger)
{
- return new malloc_state_machine (logger);
+ return std::make_unique<malloc_state_machine> (logger);
}
/* Specialcase hook for handling realloc, for use by
diff --git a/gcc/analyzer/sm-pattern-test.cc b/gcc/analyzer/sm-pattern-test.cc
index 5b98067..12449a1 100644
--- a/gcc/analyzer/sm-pattern-test.cc
+++ b/gcc/analyzer/sm-pattern-test.cc
@@ -20,19 +20,11 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
+#include "analyzer/common.h"
+
#include "tree-pretty-print.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
@@ -130,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 ();
@@ -140,7 +132,7 @@ pattern_test_state_machine::on_condition (sm_context &sm_ctxt,
if (tree lhs_expr = sm_ctxt.get_diagnostic_tree (lhs))
{
sm_ctxt.warn (node, stmt, lhs_expr,
- make_unique<pattern_match> (lhs_expr, op, rhs_cst));
+ std::make_unique<pattern_match> (lhs_expr, op, rhs_cst));
}
}
@@ -154,10 +146,10 @@ pattern_test_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_pattern_test_state_machine (logger *logger)
{
- return new pattern_test_state_machine (logger);
+ return std::make_unique<pattern_test_state_machine> (logger);
}
} // namespace ana
diff --git a/gcc/analyzer/sm-sensitive.cc b/gcc/analyzer/sm-sensitive.cc
index 6e185cb..4611b10e 100644
--- a/gcc/analyzer/sm-sensitive.cc
+++ b/gcc/analyzer/sm-sensitive.cc
@@ -19,19 +19,10 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
-#include "diagnostic-event-id.h"
+#include "analyzer/common.h"
+
+#include "diagnostics/event-id.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
@@ -115,14 +106,15 @@ public:
return false;
}
- diagnostic_event::meaning
+ diagnostics::paths::event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
+ using event = diagnostics::paths::event;
+
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 ();
+ return event::meaning (event::verb::acquire, event::noun::sensitive);
+ return event::meaning ();
}
bool
describe_call_with_state (pretty_printer &pp,
@@ -171,7 +163,7 @@ public:
private:
const sensitive_state_machine &m_sm;
tree m_arg;
- diagnostic_event_id_t m_first_sensitive_event;
+ diagnostics::paths::event_id_t m_first_sensitive_event;
};
/* sensitive_state_machine's ctor. */
@@ -196,8 +188,8 @@ sensitive_state_machine::warn_for_any_exposure (sm_context &sm_ctxt,
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<exposure_through_output_file> (*this,
- diag_arg));
+ std::make_unique<exposure_through_output_file> (*this,
+ diag_arg));
}
}
@@ -210,9 +202,9 @@ sensitive_state_machine::on_stmt (sm_context &sm_ctxt,
const gimple *stmt) const
{
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call))
{
- if (is_named_call_p (callee_fndecl, "getpass", call, 1))
+ if (is_named_call_p (callee_fndecl, "getpass", *call, 1))
{
tree lhs = gimple_call_lhs (call);
if (lhs)
@@ -230,7 +222,7 @@ sensitive_state_machine::on_stmt (sm_context &sm_ctxt,
}
return true;
}
- else if (is_named_call_p (callee_fndecl, "fwrite", call, 4))
+ else if (is_named_call_p (callee_fndecl, "fwrite", *call, 4))
{
tree arg = gimple_call_arg (call, 0);
warn_for_any_exposure (sm_ctxt, node, stmt, arg);
@@ -251,10 +243,10 @@ sensitive_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_sensitive_state_machine (logger *logger)
{
- return new sensitive_state_machine (logger);
+ return std::make_unique<sensitive_state_machine> (logger);
}
} // namespace ana
diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc
index f8b378f..35ecde1 100644
--- a/gcc/analyzer/sm-signal.cc
+++ b/gcc/analyzer/sm-signal.cc
@@ -20,39 +20,28 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "bitmap.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
-#include "diagnostic-event-id.h"
-#include "analyzer/analyzer-logging.h"
-#include "analyzer/sm.h"
-#include "analyzer/pending-diagnostic.h"
+#include "analyzer/common.h"
+
+#include "diagnostics/event-id.h"
#include "sbitmap.h"
#include "ordered-hash-map.h"
#include "selftest.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "cgraph.h"
+#include "shortest-paths.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/sm.h"
+#include "analyzer/pending-diagnostic.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/program-state.h"
#include "analyzer/checker-path.h"
-#include "cfg.h"
-#include "gimple-iterator.h"
-#include "cgraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/diagnostic-manager.h"
-#include "shortest-paths.h"
#include "analyzer/exploded-graph.h"
#include "analyzer/function-set.h"
#include "analyzer/analyzer-selftests.h"
@@ -95,7 +84,7 @@ class signal_unsafe_call
: public pending_diagnostic_subclass<signal_unsafe_call>
{
public:
- signal_unsafe_call (const signal_state_machine &sm, const gcall *unsafe_call,
+ signal_unsafe_call (const signal_state_machine &sm, const gcall &unsafe_call,
tree unsafe_fndecl)
: m_sm (sm), m_unsafe_call (unsafe_call), m_unsafe_fndecl (unsafe_fndecl)
{
@@ -106,7 +95,7 @@ public:
bool operator== (const signal_unsafe_call &other) const
{
- return m_unsafe_call == other.m_unsafe_call;
+ return &m_unsafe_call == &other.m_unsafe_call;
}
int get_controlling_option () const final override
@@ -126,7 +115,7 @@ public:
suggesting the replacement. */
if (const char *replacement = get_replacement_fn ())
{
- location_t note_loc = gimple_location (m_unsafe_call);
+ location_t note_loc = gimple_location (&m_unsafe_call);
/* It would be nice to add a fixit, but the gimple call
location covers the whole call expression. It isn't
currently possible to cut this down to just the call
@@ -170,7 +159,7 @@ public:
private:
const signal_state_machine &m_sm;
- const gcall *m_unsafe_call;
+ const gcall &m_unsafe_call;
tree m_unsafe_fndecl;
/* Returns a replacement function as text if it exists. Currently
@@ -184,7 +173,7 @@ private:
if (id_equal ("exit", DECL_NAME (m_unsafe_fndecl)))
return "_exit";
- return NULL;
+ return nullptr;
}
};
@@ -207,7 +196,7 @@ update_model_for_signal_handler (region_model *model,
gcc_assert (model);
/* Purge all state within MODEL. */
*model = region_model (model->get_manager ());
- model->push_frame (handler_fun, NULL, NULL);
+ model->push_frame (handler_fun, nullptr, nullptr, nullptr);
}
/* Custom exploded_edge info: entry into a signal-handler. */
@@ -236,10 +225,10 @@ public:
const final override
{
emission_path->add_event
- (make_unique<precanned_custom_event>
- (event_loc_info (UNKNOWN_LOCATION, NULL_TREE, 0),
- "later on,"
- " when the signal is delivered to the process"));
+ (std::make_unique<precanned_custom_event>
+ (event_loc_info (UNKNOWN_LOCATION, NULL_TREE, 0),
+ "later on,"
+ " when the signal is delivered to the process"));
}
};
@@ -280,9 +269,9 @@ 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 */
- make_unique<signal_delivery_edge_info_t> ());
+ std::make_unique<signal_delivery_edge_info_t> ());
}
const signal_state_machine &m_sm;
@@ -342,9 +331,9 @@ signal_state_machine::on_stmt (sm_context &sm_ctxt,
if (global_state == m_start)
{
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
- if (is_named_call_p (callee_fndecl, "signal", call, 2)
- || is_std_named_call_p (callee_fndecl, "signal", call, 2))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call))
+ if (is_named_call_p (callee_fndecl, "signal", *call, 2)
+ || is_std_named_call_p (callee_fndecl, "signal", *call, 2))
{
tree handler = gimple_call_arg (call, 1);
if (TREE_CODE (handler) == ADDR_EXPR
@@ -359,12 +348,12 @@ signal_state_machine::on_stmt (sm_context &sm_ctxt,
else if (global_state == m_in_signal_handler)
{
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call))
if (signal_unsafe_p (callee_fndecl))
if (sm_ctxt.get_global_state () == m_in_signal_handler)
sm_ctxt.warn (node, stmt, NULL_TREE,
- make_unique<signal_unsafe_call>
- (*this, call, callee_fndecl));
+ std::make_unique<signal_unsafe_call>
+ (*this, *call, callee_fndecl));
}
return false;
@@ -380,10 +369,10 @@ signal_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_signal_state_machine (logger *logger)
{
- return new signal_state_machine (logger);
+ return std::make_unique<signal_state_machine> (logger);
}
#if CHECKING_P
diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc
index 5d0aec3..f2a94e8 100644
--- a/gcc/analyzer/sm-taint.cc
+++ b/gcc/analyzer/sm-taint.cc
@@ -20,20 +20,8 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "gimple-iterator.h"
#include "ordered-hash-map.h"
#include "cgraph.h"
@@ -42,6 +30,10 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "fold-const.h"
+#include "diagnostics/sarif-sink.h"
+#include "gcc-urlifier.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/supergraph.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
@@ -51,8 +43,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/program-state.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/constraint-manager.h"
-#include "diagnostic-format-sarif.h"
-#include "gcc-urlifier.h"
#if ENABLE_ANALYZER
@@ -140,7 +130,7 @@ private:
void check_for_tainted_size_arg (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
tree callee_fndecl) const;
void check_for_tainted_divisor (sm_context &sm_ctxt,
const supernode *node,
@@ -219,20 +209,22 @@ public:
return false;
}
- diagnostic_event::meaning
+ diagnostics::paths::event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
+ using event = diagnostics::paths::event;
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 ();
+ return event::meaning (event::verb::acquire,
+ event::noun::taint);
+ return event::meaning ();
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/taint_diagnostic/"
props.set (PROPERTY_PREFIX "arg", tree_to_json (m_arg));
props.set_string (PROPERTY_PREFIX "has_bounds",
@@ -505,11 +497,12 @@ public:
}
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
taint_diagnostic::maybe_add_sarif_properties (result_obj);
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/tainted_offset/"
props.set (PROPERTY_PREFIX "offset", m_offset->to_json ());
#undef PROPERTY_PREFIX
@@ -874,11 +867,12 @@ public:
}
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
taint_diagnostic::maybe_add_sarif_properties (result_obj);
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/tainted_allocation_size/"
props.set (PROPERTY_PREFIX "size_in_bytes", m_size_in_bytes->to_json ());
#undef PROPERTY_PREFIX
@@ -944,7 +938,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);
}
@@ -1070,12 +1064,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
@@ -1099,9 +1093,9 @@ taint_state_machine::on_stmt (sm_context &sm_ctxt,
const gimple *stmt) const
{
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call))
{
- if (is_named_call_p (callee_fndecl, "fread", call, 4))
+ if (is_named_call_p (callee_fndecl, "fread", *call, 4))
{
tree arg = gimple_call_arg (call, 0);
@@ -1117,14 +1111,14 @@ taint_state_machine::on_stmt (sm_context &sm_ctxt,
/* External function with "access" attribute. */
if (sm_ctxt.unknown_side_effects_p ())
- check_for_tainted_size_arg (sm_ctxt, node, call, callee_fndecl);
+ check_for_tainted_size_arg (sm_ctxt, node, *call, callee_fndecl);
if (is_assertion_failure_handler_p (callee_fndecl)
&& sm_ctxt.get_global_state () == m_tainted_control_flow)
{
sm_ctxt.warn (node, call, NULL_TREE,
- make_unique<tainted_assertion> (*this, NULL_TREE,
- callee_fndecl));
+ std::make_unique<tainted_assertion> (*this, NULL_TREE,
+ callee_fndecl));
}
}
// TODO: ...etc; many other sources of untrusted data
@@ -1185,7 +1179,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))
@@ -1204,7 +1198,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
@@ -1433,7 +1427,7 @@ taint_state_machine::combine_states (state_t s0, state_t s1) const
void
taint_state_machine::check_for_tainted_size_arg (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
tree callee_fndecl) const
{
tree fntype = TREE_TYPE (callee_fndecl);
@@ -1464,17 +1458,17 @@ taint_state_machine::check_for_tainted_size_arg (sm_context &sm_ctxt,
if (access->sizarg == UINT_MAX)
continue;
- tree size_arg = gimple_call_arg (call, access->sizarg);
+ tree size_arg = gimple_call_arg (&call, access->sizarg);
- state_t state = sm_ctxt.get_state (call, size_arg);
+ state_t state = sm_ctxt.get_state (&call, size_arg);
enum bounds b;
if (get_taint (state, TREE_TYPE (size_arg), &b))
{
const char* const access_str =
TREE_STRING_POINTER (access->to_external_string ());
tree diag_size = sm_ctxt.get_diagnostic_tree (size_arg);
- sm_ctxt.warn (node, call, size_arg,
- make_unique<tainted_access_attrib_size>
+ sm_ctxt.warn (node, &call, size_arg,
+ std::make_unique<tainted_access_attrib_size>
(*this, diag_size, b,
callee_fndecl,
access->sizarg,
@@ -1502,7 +1496,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;
@@ -1518,8 +1512,9 @@ taint_state_machine::check_for_tainted_divisor (sm_context &sm_ctxt,
return;
tree diag_divisor = sm_ctxt.get_diagnostic_tree (divisor_expr);
- sm_ctxt.warn (node, assign, divisor_expr,
- make_unique <tainted_divisor> (*this, diag_divisor, b));
+ sm_ctxt.warn
+ (node, assign, divisor_expr,
+ std::make_unique <tainted_divisor> (*this, diag_divisor, b));
sm_ctxt.set_next_state (assign, divisor_sval, m_stop);
}
}
@@ -1528,10 +1523,10 @@ taint_state_machine::check_for_tainted_divisor (sm_context &sm_ctxt,
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_taint_state_machine (logger *logger)
{
- return new taint_state_machine (logger);
+ return std::make_unique<taint_state_machine> (logger);
}
/* A closed concrete range. */
@@ -1682,8 +1677,8 @@ region_model::check_region_for_taint (const region *reg,
if (index_can_be_out_of_bounds_p (element_reg))
{
tree arg = get_representative_tree (index);
- ctxt->warn (make_unique<tainted_array_index> (taint_sm,
- arg, b));
+ ctxt->warn (std::make_unique<tainted_array_index> (taint_sm,
+ arg, b));
}
else if (ctxt->get_logger ())
ctxt->get_logger ()->log ("rejecting tainted_array_index as"
@@ -1709,8 +1704,8 @@ region_model::check_region_for_taint (const region *reg,
if (taint_sm.get_taint (state, effective_type, &b))
{
tree arg = get_representative_tree (offset);
- ctxt->warn (make_unique<tainted_offset> (taint_sm, arg, b,
- offset));
+ ctxt->warn (std::make_unique<tainted_offset> (taint_sm, arg, b,
+ offset));
}
}
break;
@@ -1727,7 +1722,7 @@ region_model::check_region_for_taint (const region *reg,
if (taint_sm.get_taint (state, size_sval->get_type (), &b))
{
tree arg = get_representative_tree (size_sval);
- ctxt->warn (make_unique<tainted_size> (taint_sm, arg, b));
+ ctxt->warn (std::make_unique<tainted_size> (taint_sm, arg, b));
}
}
break;
@@ -1773,7 +1768,7 @@ region_model::check_dynamic_size_for_taint (enum memory_space mem_space,
if (taint_sm.get_taint (state, size_in_bytes->get_type (), &b))
{
tree arg = get_representative_tree (size_in_bytes);
- ctxt->warn (make_unique<tainted_allocation_size>
+ ctxt->warn (std::make_unique<tainted_allocation_size>
(taint_sm, arg, size_in_bytes, b, mem_space));
}
}
@@ -1802,7 +1797,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 3e7fa66..c93e9c2 100644
--- a/gcc/analyzer/sm.cc
+++ b/gcc/analyzer/sm.cc
@@ -18,21 +18,11 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "function.h"
-#include "diagnostic-core.h"
-#include "pretty-print.h"
-#include "diagnostic.h"
+#define INCLUDE_LIST
+#include "analyzer/common.h"
+
#include "tree-diagnostic.h"
-#include "analyzer/analyzer.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/call-string.h"
@@ -41,7 +31,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/svalue.h"
#include "analyzer/program-state.h"
#include "analyzer/pending-diagnostic.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -83,7 +72,7 @@ state_machine::state::to_json () const
pretty_printer pp;
pp_format_decoder (&pp) = default_tree_printer;
dump_to_pp (&pp);
- return ::make_unique<json::string> (pp_formatted_text (&pp));
+ return std::make_unique<json::string> (pp_formatted_text (&pp));
}
/* class state_machine. */
@@ -127,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. */
@@ -154,11 +145,11 @@ state_machine::dump_to_pp (pretty_printer *pp) const
std::unique_ptr<json::object>
state_machine::to_json () const
{
- auto sm_obj = ::make_unique<json::object> ();
+ auto sm_obj = std::make_unique<json::object> ();
sm_obj->set_string ("name", m_name);
{
- auto states_arr = ::make_unique<json::array> ();
+ auto states_arr = std::make_unique<json::array> ();
unsigned i;
state *s;
FOR_EACH_VEC_ELT (m_states, i, s)
@@ -169,6 +160,21 @@ state_machine::to_json () const
return sm_obj;
}
+void
+state_machine::add_state_to_state_graph (analyzer_state_graph &out_state_graph,
+ const svalue &sval,
+ state_machine::state_t state) const
+{
+ // no-op
+}
+
+void
+state_machine::add_global_state_to_state_graph (analyzer_state_graph &out_state_graph,
+ state_machine::state_t state) const
+{
+ // no-op
+}
+
/* class sm_context. */
const region_model *
@@ -177,39 +183,44 @@ 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,
- and populate OUT with them. */
+ returning a vector of them. */
-void
-make_checkers (auto_delete_vec <state_machine> &out, logger *logger)
+std::vector<std::unique_ptr<state_machine>>
+make_checkers (logger *logger)
{
- out.safe_push (make_malloc_state_machine (logger));
- out.safe_push (make_fileptr_state_machine (logger));
- out.safe_push (make_fd_state_machine (logger));
- out.safe_push (make_taint_state_machine (logger));
- out.safe_push (make_sensitive_state_machine (logger));
- out.safe_push (make_signal_state_machine (logger));
- out.safe_push (make_va_list_state_machine (logger));
+ /* Start with a list so that we can filter it. */
+ std::list<std::unique_ptr<state_machine>> out;
+ out.push_back (make_malloc_state_machine (logger));
+ out.push_back (make_fileptr_state_machine (logger));
+ out.push_back (make_fd_state_machine (logger));
+ out.push_back (make_taint_state_machine (logger));
+ out.push_back (make_sensitive_state_machine (logger));
+ out.push_back (make_signal_state_machine (logger));
+ out.push_back (make_va_list_state_machine (logger));
/* We only attempt to run the pattern tests if it might have been manually
enabled (for DejaGnu purposes). */
if (flag_analyzer_checker)
- out.safe_push (make_pattern_test_state_machine (logger));
+ out.push_back (make_pattern_test_state_machine (logger));
if (flag_analyzer_checker)
{
- unsigned read_index, write_index;
- state_machine **sm;
-
- /* TODO: this leaks the machines
- Would be nice to log the things that were removed. */
- VEC_ORDERED_REMOVE_IF (out, read_index, write_index, sm,
- 0 != strcmp (flag_analyzer_checker,
- (*sm)->get_name ()));
+ out.remove_if ([] (auto &sm)
+ {
+ return 0 != strcmp (flag_analyzer_checker,
+ sm->get_name ());
+ });
}
+
+ std::vector<std::unique_ptr<state_machine>> out_vec;
+ for (auto &iter: out)
+ out_vec.push_back (std::move (iter));
+
+ return out_vec;
}
} // namespace ana
diff --git a/gcc/analyzer/sm.h b/gcc/analyzer/sm.h
index a1f96e2..4633fac 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 analyzer_state_graph;
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_state_graph (analyzer_state_graph &out_state_graph,
+ const svalue &sval,
+ state_machine::state_t state) const;
+
+ virtual void
+ add_global_state_to_state_graph (analyzer_state_graph &out_state_graph,
+ state_machine::state_t state) const;
+
protected:
state_t add_state (const char *name);
state_t add_custom_state (state *s)
@@ -235,7 +247,7 @@ public:
Use in preference to gimple_call_fndecl (and gimple_call_addr_fndecl),
since it can look through function pointer assignments and
other callback handling. */
- virtual tree get_fndecl_for_call (const gcall *call) = 0;
+ virtual tree get_fndecl_for_call (const gcall &call) = 0;
/* Get the old state of VAR at STMT. */
virtual state_machine::state_t get_state (const gimple *stmt,
@@ -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? */
@@ -341,17 +353,17 @@ protected:
/* The various state_machine subclasses are hidden in their respective
implementation files. */
-extern void make_checkers (auto_delete_vec <state_machine> &out,
- logger *logger);
-
-extern state_machine *make_malloc_state_machine (logger *logger);
-extern state_machine *make_fileptr_state_machine (logger *logger);
-extern state_machine *make_taint_state_machine (logger *logger);
-extern state_machine *make_sensitive_state_machine (logger *logger);
-extern state_machine *make_signal_state_machine (logger *logger);
-extern state_machine *make_pattern_test_state_machine (logger *logger);
-extern state_machine *make_va_list_state_machine (logger *logger);
-extern state_machine *make_fd_state_machine (logger *logger);
+extern std::vector<std::unique_ptr<state_machine>>
+make_checkers (logger *logger);
+
+extern std::unique_ptr<state_machine> make_malloc_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_fileptr_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_taint_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_sensitive_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_signal_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_pattern_test_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_va_list_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_fd_state_machine (logger *);
} // namespace ana
diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc
index b7a5260..1371db9 100644
--- a/gcc/analyzer/state-purge.cc
+++ b/gcc/analyzer/state-purge.cc
@@ -18,26 +18,21 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
+#include "analyzer/common.h"
+
#include "timevar.h"
-#include "tree-ssa-alias.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "stringpool.h"
+#include "gimple-pretty-print.h"
#include "tree-vrp.h"
#include "gimple-ssa.h"
+#include "stringpool.h"
#include "tree-ssanames.h"
#include "tree-phinodes.h"
#include "options.h"
#include "ssa-iterators.h"
-#include "diagnostic-core.h"
-#include "gimple-pretty-print.h"
-#include "analyzer/analyzer.h"
+#include "gimple-iterator.h"
+#include "gimple-walk.h"
+#include "cgraph.h"
+
#include "analyzer/call-string.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-point.h"
@@ -45,8 +40,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/state-purge.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
-#include "gimple-walk.h"
-#include "cgraph.h"
#if ENABLE_ANALYZER
@@ -666,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);
}
}
@@ -737,7 +730,7 @@ state_purge_per_decl::process_worklists (const state_purge_map &map,
worklist.safe_push (iter);
region_model model (mgr);
- model.push_frame (get_function (), NULL, NULL);
+ model.push_frame (get_function (), nullptr, nullptr, nullptr);
/* Process worklist by walking backwards until we reach a stmt
that fully overwrites the decl. */
@@ -848,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;
@@ -1081,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)
@@ -1098,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));
@@ -1160,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 ab469dd..942c945 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -18,44 +18,23 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
-#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "diagnostic-color.h"
-#include "bitmap.h"
-#include "selftest.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "ordered-hash-map.h"
-#include "options.h"
#include "cfg.h"
-#include "analyzer/supergraph.h"
#include "sbitmap.h"
+#include "stor-layout.h"
+
+#include "text-art/tree-widget.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/supergraph.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/call-summary.h"
#include "analyzer/analyzer-selftests.h"
-#include "stor-layout.h"
-#include "text-art/tree-widget.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -234,7 +213,7 @@ bit_range::dump () const
std::unique_ptr<json::object>
bit_range::to_json () const
{
- auto obj = ::make_unique<json::object> ();
+ auto obj = std::make_unique<json::object> ();
obj->set ("start_bit_offset",
bit_offset_to_json (m_start_bit_offset));
obj->set ("size_in_bits",
@@ -508,7 +487,7 @@ byte_range::dump () const
std::unique_ptr<json::object>
byte_range::to_json () const
{
- auto obj = ::make_unique<json::object> ();
+ auto obj = std::make_unique<json::object> ();
obj->set ("start_byte_offset",
byte_offset_to_json (m_start_byte_offset));
obj->set ("size_in_bytes",
@@ -679,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;
@@ -773,7 +752,7 @@ binding_map::dump (bool simple) const
std::unique_ptr<json::object>
binding_map::to_json () const
{
- auto map_obj = ::make_unique<json::object> ();
+ auto map_obj = std::make_unique<json::object> ();
auto_vec <const binding_key *> binding_keys;
for (map_t::iterator iter = m_map.begin ();
@@ -943,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
@@ -1455,7 +1434,7 @@ binding_cluster::validate () const
std::unique_ptr<json::object>
binding_cluster::to_json () const
{
- auto cluster_obj = ::make_unique<json::object> ();
+ auto cluster_obj = std::make_unique<json::object> ();
cluster_obj->set_bool ("escaped", m_escaped);
cluster_obj->set_bool ("touched", m_touched);
@@ -1585,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. */
@@ -1705,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)
@@ -1773,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. */
@@ -1821,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
@@ -1833,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,
@@ -1842,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 ();
@@ -1901,7 +1880,7 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
bit_size_t reg_bit_size;
if (!reg->get_bit_size (&reg_bit_size))
- return NULL;
+ return nullptr;
bit_range reg_range (reg_offset.get_bit_offset (),
reg_bit_size);
@@ -1930,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))
{
@@ -1964,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)
@@ -2051,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);
@@ -2208,7 +2187,7 @@ binding_cluster::mark_as_escaped ()
Use P to purge state involving conjured_svalues. */
void
-binding_cluster::on_unknown_fncall (const gcall *call,
+binding_cluster::on_unknown_fncall (const gcall &call,
store_manager *mgr,
const conjured_purge &p)
{
@@ -2221,7 +2200,7 @@ binding_cluster::on_unknown_fncall (const gcall *call,
/* Bind it to a new "conjured" value using CALL. */
const svalue *sval
= mgr->get_svalue_manager ()->get_or_create_conjured_svalue
- (m_base_region->get_type (), call, m_base_region, p);
+ (m_base_region->get_type (), &call, m_base_region, p);
bind (mgr, m_base_region, sval);
}
@@ -2340,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
@@ -2355,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);
@@ -2488,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;
@@ -2541,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
@@ -2650,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);
}
@@ -2672,7 +2651,7 @@ store::validate () const
std::unique_ptr<json::object>
store::to_json () const
{
- auto store_obj = ::make_unique<json::object> ();
+ auto store_obj = std::make_unique<json::object> ();
/* Sort into some deterministic order. */
auto_vec<const region *> base_regions;
@@ -2695,7 +2674,7 @@ store::to_json () const
{
gcc_assert (parent_reg);
- auto clusters_in_parent_reg_obj = ::make_unique<json::object> ();
+ auto clusters_in_parent_reg_obj = std::make_unique<json::object> ();
const region *base_reg;
unsigned j;
@@ -2782,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
@@ -2791,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);
}
@@ -2817,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. */
@@ -2839,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
@@ -2859,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 ()))
{
@@ -3118,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
@@ -3129,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)
@@ -3142,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. */
@@ -3259,7 +3238,7 @@ store::mark_as_escaped (const region *base_reg)
(either in this fncall, or in a prior one). */
void
-store::on_unknown_fncall (const gcall *call, store_manager *mgr,
+store::on_unknown_fncall (const gcall &call, store_manager *mgr,
const conjured_purge &p)
{
m_called_unknown_fn = true;
@@ -3342,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);
}
}
@@ -3587,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;
@@ -3612,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;
@@ -3807,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 6c84812..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)
{
@@ -666,7 +676,7 @@ public:
store_manager *mgr);
void mark_as_escaped ();
- void on_unknown_fncall (const gcall *call, store_manager *mgr,
+ void on_unknown_fncall (const gcall &call, store_manager *mgr,
const conjured_purge &p);
void on_asm (const gasm *stmt, store_manager *mgr,
const conjured_purge &p);
@@ -800,7 +810,7 @@ public:
model_merger *merger);
void mark_as_escaped (const region *base_reg);
- void on_unknown_fncall (const gcall *call, store_manager *mgr,
+ void on_unknown_fncall (const gcall &call, store_manager *mgr,
const conjured_purge &p);
bool escaped_p (const region *reg) const;
diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc
index f35adf0..8592db7 100644
--- a/gcc/analyzer/supergraph.cc
+++ b/gcc/analyzer/supergraph.cc
@@ -18,42 +18,23 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "tm.h"
-#include "toplev.h"
-#include "hash-table.h"
-#include "vec.h"
-#include "ggc.h"
-#include "basic-block.h"
-#include "function.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "gimple-fold.h"
-#include "tree-eh.h"
-#include "gimple-expr.h"
-#include "is-a.h"
+#include "analyzer/common.h"
+
#include "timevar.h"
#include "gimple-pretty-print.h"
-#include "tree-pretty-print.h"
-#include "graphviz.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "bitmap.h"
-#include "cfganal.h"
-#include "function.h"
-#include "analyzer/analyzer.h"
#include "ordered-hash-map.h"
#include "options.h"
#include "cgraph.h"
#include "cfg.h"
#include "digraph.h"
#include "tree-cfg.h"
+#include "tree-dfa.h"
+#include "cfganal.h"
+#include "except.h"
+
#include "analyzer/supergraph.h"
#include "analyzer/analyzer-logging.h"
-#include "make-unique.h"
+#include "analyzer/region-model.h"
#if ENABLE_ANALYZER
@@ -67,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 ();
}
@@ -78,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;
}
@@ -165,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))
@@ -190,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
@@ -206,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);
}
}
@@ -465,11 +447,11 @@ supergraph::dump_dot (const char *path, const dump_args_t &dump_args) const
std::unique_ptr<json::object>
supergraph::to_json () const
{
- auto sgraph_obj = ::make_unique<json::object> ();
+ auto sgraph_obj = std::make_unique<json::object> ();
/* Nodes. */
{
- auto nodes_arr = ::make_unique<json::array> ();
+ auto nodes_arr = std::make_unique<json::array> ();
unsigned i;
supernode *n;
FOR_EACH_VEC_ELT (m_nodes, i, n)
@@ -479,7 +461,7 @@ supergraph::to_json () const
/* Edges. */
{
- auto edges_arr = ::make_unique<json::array> ();
+ auto edges_arr = std::make_unique<json::array> ();
unsigned i;
superedge *n;
FOR_EACH_VEC_ELT (m_edges, i, n)
@@ -511,21 +493,25 @@ supergraph::add_node (function *fun, basic_block bb, gcall *returning_call,
/* Create a new cfg_superedge from SRC to DEST for the underlying CFG edge E,
adding it to this supergraph.
- If the edge is for a switch statement, create a switch_cfg_superedge
- subclass. */
+ If the edge is for a switch or eh_dispatch statement, create a
+ switch_cfg_superedge or eh_dispatch_cfg_superedge subclass,
+ respectively */
cfg_superedge *
supergraph::add_cfg_edge (supernode *src, supernode *dest, ::edge e)
{
- /* Special-case switch edges. */
+ /* Special-case switch and eh_dispatch edges. */
gimple *stmt = src->get_last_stmt ();
- cfg_superedge *new_edge;
+ std::unique_ptr<cfg_superedge> new_edge;
if (stmt && stmt->code == GIMPLE_SWITCH)
- new_edge = new switch_cfg_superedge (src, dest, e);
+ new_edge = std::make_unique<switch_cfg_superedge> (src, dest, e);
+ else if (stmt && stmt->code == GIMPLE_EH_DISPATCH)
+ new_edge = eh_dispatch_cfg_superedge::make (src, dest, e,
+ as_a <geh_dispatch *> (stmt));
else
- new_edge = new cfg_superedge (src, dest, e);
- add_edge (new_edge);
- return new_edge;
+ new_edge = std::make_unique<cfg_superedge> (src, dest, e);
+ add_edge (new_edge.get ());
+ return new_edge.release ();
}
/* Create and add a call_superedge representing an interprocedural call
@@ -720,7 +706,7 @@ supernode::dump_dot_id (pretty_printer *pp) const
std::unique_ptr<json::object>
supernode::to_json () const
{
- auto snode_obj = ::make_unique<json::object> ();
+ auto snode_obj = std::make_unique<json::object> ();
snode_obj->set_integer ("idx", m_index);
snode_obj->set_integer ("bb_idx", m_bb->index);
@@ -737,7 +723,7 @@ supernode::to_json () const
/* Phi nodes. */
{
- auto phi_arr = ::make_unique<json::array> ();
+ auto phi_arr = std::make_unique<json::array> ();
for (gphi_iterator gpi = const_cast<supernode *> (this)->start_phis ();
!gsi_end_p (gpi); gsi_next (&gpi))
{
@@ -752,7 +738,7 @@ supernode::to_json () const
/* Statements. */
{
- auto stmt_arr = ::make_unique<json::array> ();
+ auto stmt_arr = std::make_unique<json::array> ();
int i;
gimple *stmt;
FOR_EACH_VEC_ELT (m_stmts, i, stmt)
@@ -983,7 +969,7 @@ superedge::dump_dot (graphviz_out *gv, const dump_args_t &) const
std::unique_ptr<json::object>
superedge::to_json () const
{
- auto sedge_obj = ::make_unique<json::object> ();
+ auto sedge_obj = std::make_unique<json::object> ();
sedge_obj->set_string ("kind", edge_kind_to_string (m_kind));
sedge_obj->set_integer ("src_idx", m_src->m_index);
sedge_obj->set_integer ("dst_idx", m_dest->m_index);
@@ -999,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
@@ -1030,6 +1016,7 @@ label_text
superedge::get_description (bool user_facing) const
{
pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
dump_label_to_pp (&pp, user_facing);
return label_text::take (xstrdup (pp_formatted_text (&pp)));
}
@@ -1099,6 +1086,8 @@ cfg_superedge::get_phi_arg (const gphi *phi) const
return gimple_phi_arg_def (phi, index);
}
+/* class switch_cfg_superedge : public cfg_superedge. */
+
switch_cfg_superedge::switch_cfg_superedge (supernode *src,
supernode *dst,
::edge e)
@@ -1206,6 +1195,203 @@ switch_cfg_superedge::implicitly_created_default_p () const
return EXPR_LOCATION (case_label) == UNKNOWN_LOCATION;
}
+/* class eh_dispatch_cfg_superedge : public cfg_superedge. */
+
+/* Given an ERT_TRY region, get the eh_catch corresponding to
+ the label of DST_SNODE, if any. */
+
+static eh_catch
+get_catch (eh_region eh_reg, supernode *dst_snode)
+{
+ gcc_assert (eh_reg->type == ERT_TRY);
+
+ tree dst_snode_label = dst_snode->get_label ();
+ if (!dst_snode_label)
+ return nullptr;
+
+ for (eh_catch iter = eh_reg->u.eh_try.first_catch;
+ iter;
+ iter = iter->next_catch)
+ if (iter->label == dst_snode_label)
+ return iter;
+
+ return nullptr;
+}
+
+std::unique_ptr<eh_dispatch_cfg_superedge>
+eh_dispatch_cfg_superedge::make (supernode *src_snode,
+ supernode *dst_snode,
+ ::edge e,
+ const geh_dispatch *eh_dispatch_stmt)
+{
+ const eh_status *eh = src_snode->get_function ()->eh;
+ gcc_assert (eh);
+ int region_idx = gimple_eh_dispatch_region (eh_dispatch_stmt);
+ gcc_assert (region_idx > 0);
+ gcc_assert ((*eh->region_array)[region_idx]);
+ eh_region eh_reg = (*eh->region_array)[region_idx];
+ gcc_assert (eh_reg);
+ switch (eh_reg->type)
+ {
+ default:
+ gcc_unreachable ();
+ case ERT_CLEANUP:
+ // TODO
+ gcc_unreachable ();
+ break;
+ case ERT_TRY:
+ {
+ eh_catch ehc = get_catch (eh_reg, dst_snode);
+ return std::make_unique<eh_dispatch_try_cfg_superedge>
+ (src_snode, dst_snode,
+ e, eh_dispatch_stmt,
+ eh_reg, ehc);
+ }
+ break;
+ case ERT_ALLOWED_EXCEPTIONS:
+ return std::make_unique<eh_dispatch_allowed_cfg_superedge>
+ (src_snode, dst_snode,
+ e, eh_dispatch_stmt,
+ eh_reg);
+ break;
+ case ERT_MUST_NOT_THROW:
+ // TODO
+ gcc_unreachable ();
+ break;
+ }
+}
+
+eh_dispatch_cfg_superedge::
+eh_dispatch_cfg_superedge (supernode *src,
+ supernode *dst,
+ ::edge e,
+ const geh_dispatch *eh_dispatch_stmt,
+ eh_region eh_reg)
+: cfg_superedge (src, dst, e),
+ m_eh_dispatch_stmt (eh_dispatch_stmt),
+ m_eh_region (eh_reg)
+{
+ gcc_assert (m_eh_region);
+}
+
+const eh_status &
+eh_dispatch_cfg_superedge::get_eh_status () const
+{
+ const eh_status *eh = m_src->get_function ()->eh;
+ gcc_assert (eh);
+ return *eh;
+}
+
+// class eh_dispatch_try_cfg_superedge : public eh_dispatch_cfg_superedge
+
+/* Implementation of superedge::dump_label_to_pp for CFG superedges for
+ "eh_dispatch" statements for ERT_TRY regions. */
+
+void
+eh_dispatch_try_cfg_superedge::dump_label_to_pp (pretty_printer *pp,
+ bool user_facing) const
+{
+ if (!user_facing)
+ pp_string (pp, "ERT_TRY: ");
+ if (m_eh_catch)
+ {
+ bool first = true;
+ for (tree iter = m_eh_catch->type_list; iter; iter = TREE_CHAIN (iter))
+ {
+ if (!first)
+ pp_string (pp, ", ");
+ pp_printf (pp, "on catch %qT", TREE_VALUE (iter));
+ first = false;
+ }
+ }
+ else
+ pp_string (pp, "on uncaught exception");
+}
+
+bool
+eh_dispatch_try_cfg_superedge::
+apply_constraints (region_model *model,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out) const
+{
+ return model->apply_constraints_for_eh_dispatch_try
+ (*this, ctxt, exception_type, out);
+}
+
+// class eh_dispatch_allowed_cfg_superedge : public eh_dispatch_cfg_superedge
+
+eh_dispatch_allowed_cfg_superedge::
+eh_dispatch_allowed_cfg_superedge (supernode *src, supernode *dst, ::edge e,
+ const geh_dispatch *eh_dispatch_stmt,
+ eh_region eh_reg)
+: eh_dispatch_cfg_superedge (src, dst, e, eh_dispatch_stmt, eh_reg)
+{
+ gcc_assert (eh_reg->type == ERT_ALLOWED_EXCEPTIONS);
+
+ /* We expect two sibling out-edges at an eh_dispatch from such a region:
+
+ - one to a bb without a gimple label, with a resx,
+ for exceptions of expected types
+
+ - one to a bb with a gimple label, with a call to __cxa_unexpected,
+ for exceptions of unexpected types.
+
+ Set m_kind for this edge accordingly. */
+ gcc_assert (e->src->succs->length () == 2);
+ tree label_for_unexpected_exceptions = eh_reg->u.allowed.label;
+ tree label_for_dest_enode = dst->get_label ();
+ if (label_for_dest_enode == label_for_unexpected_exceptions)
+ m_kind = eh_kind::unexpected;
+ else
+ {
+ gcc_assert (label_for_dest_enode == nullptr);
+ m_kind = eh_kind::expected;
+ }
+}
+
+void
+eh_dispatch_allowed_cfg_superedge::dump_label_to_pp (pretty_printer *pp,
+ bool user_facing) const
+{
+ if (!user_facing)
+ {
+ switch (m_kind)
+ {
+ default:
+ gcc_unreachable ();
+ case eh_dispatch_allowed_cfg_superedge::eh_kind::expected:
+ pp_string (pp, "expected: ");
+ break;
+ case eh_dispatch_allowed_cfg_superedge::eh_kind::unexpected:
+ pp_string (pp, "unexpected: ");
+ break;
+ }
+ pp_string (pp, "ERT_ALLOWED_EXCEPTIONS: ");
+ eh_region eh_reg = get_eh_region ();
+ bool first = true;
+ for (tree iter = eh_reg->u.allowed.type_list; iter;
+ iter = TREE_CHAIN (iter))
+ {
+ if (!first)
+ pp_string (pp, ", ");
+ pp_printf (pp, "%qT", TREE_VALUE (iter));
+ first = false;
+ }
+ }
+}
+
+bool
+eh_dispatch_allowed_cfg_superedge::
+apply_constraints (region_model *model,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out) const
+{
+ return model->apply_constraints_for_eh_dispatch_allowed
+ (*this, ctxt, exception_type, out);
+}
+
/* Implementation of superedge::dump_label_to_pp for interprocedural
superedges. */
@@ -1261,13 +1447,13 @@ callgraph_superedge::get_callee_decl () const
/* Get the gcall * of this interprocedural call/return edge. */
-gcall *
+const gcall &
callgraph_superedge::get_call_stmt () const
{
if (m_cedge)
- return m_cedge->call_stmt;
+ return *m_cedge->call_stmt;
- return m_src->get_final_call ();
+ return *m_src->get_final_call ();
}
/* Get the calling fndecl at this interprocedural call/return edge. */
@@ -1289,19 +1475,19 @@ callgraph_superedge::get_arg_for_parm (tree parm_to_find,
gcc_assert (TREE_CODE (parm_to_find) == PARM_DECL);
tree callee = get_callee_decl ();
- const gcall *call_stmt = get_call_stmt ();
+ const gcall &call_stmt = get_call_stmt ();
unsigned i = 0;
for (tree iter_parm = DECL_ARGUMENTS (callee); iter_parm;
iter_parm = DECL_CHAIN (iter_parm), ++i)
{
- if (i >= gimple_call_num_args (call_stmt))
+ if (i >= gimple_call_num_args (&call_stmt))
return NULL_TREE;
if (iter_parm == parm_to_find)
{
if (out)
*out = callsite_expr::from_zero_based_param (i);
- return gimple_call_arg (call_stmt, i);
+ return gimple_call_arg (&call_stmt, i);
}
}
@@ -1319,15 +1505,15 @@ callgraph_superedge::get_parm_for_arg (tree arg_to_find,
callsite_expr *out) const
{
tree callee = get_callee_decl ();
- const gcall *call_stmt = get_call_stmt ();
+ const gcall &call_stmt = get_call_stmt ();
unsigned i = 0;
for (tree iter_parm = DECL_ARGUMENTS (callee); iter_parm;
iter_parm = DECL_CHAIN (iter_parm), ++i)
{
- if (i >= gimple_call_num_args (call_stmt))
+ if (i >= gimple_call_num_args (&call_stmt))
return NULL_TREE;
- tree param = gimple_call_arg (call_stmt, i);
+ tree param = gimple_call_arg (&call_stmt, i);
if (arg_to_find == param)
{
if (out)
@@ -1353,7 +1539,7 @@ callgraph_superedge::map_expr_from_caller_to_callee (tree caller_expr,
if (parm)
return parm;
/* Otherwise try return value. */
- if (caller_expr == gimple_call_lhs (get_call_stmt ()))
+ if (caller_expr == gimple_call_lhs (&get_call_stmt ()))
{
if (out)
*out = callsite_expr::from_return_value ();
@@ -1388,7 +1574,7 @@ callgraph_superedge::map_expr_from_callee_to_caller (tree callee_expr,
{
if (out)
*out = callsite_expr::from_return_value ();
- return gimple_call_lhs (get_call_stmt ());
+ return gimple_call_lhs (&get_call_stmt ());
}
return NULL_TREE;
diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h
index 6f94f99..f64a2f4 100644
--- a/gcc/analyzer/supergraph.h
+++ b/gcc/analyzer/supergraph.h
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple.h"
#include "gimple-iterator.h"
#include "digraph.h"
+#include "except.h"
using namespace ana;
@@ -42,6 +43,9 @@ class superedge;
class return_superedge;
class cfg_superedge;
class switch_cfg_superedge;
+ class eh_dispatch_cfg_superedge;
+ class eh_dispatch_try_cfg_superedge;
+ class eh_dispatch_allowed_cfg_superedge;
class supercluster;
class dot_annotator;
@@ -126,7 +130,7 @@ public:
return *const_cast <bb_to_node_t &> (m_bb_to_initial_node).get (bb);
}
- /* Get the supernode containing the second half of the gcall *
+ /* Get the supernode containing the second half of the gcall &
at an interprocedural call, within the caller. */
supernode *get_caller_next_node (cgraph_edge *edge) const
{
@@ -270,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;
}
@@ -283,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);
}
@@ -327,15 +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 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 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 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;
@@ -415,7 +422,7 @@ class callgraph_superedge : public superedge
function *get_caller_function () const;
tree get_callee_decl () const;
tree get_caller_decl () const;
- gcall *get_call_stmt () const;
+ const gcall &get_call_stmt () const;
tree get_arg_for_parm (tree parm, callsite_expr *out) const;
tree get_parm_for_arg (tree arg, callsite_expr *out) const;
tree map_expr_from_caller_to_callee (tree caller_expr,
@@ -587,11 +594,169 @@ 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 {
+/* A subclass for edges from eh_dispatch statements, retaining enough
+ information to identify the various types being caught, vs the
+ "unhandled type" case, and for adding labels when rendering
+ via graphviz.
+ This is abstract; there are concrete subclasses based on the type
+ of the eh_region. */
+
+class eh_dispatch_cfg_superedge : public cfg_superedge
+{
+ public:
+ static std::unique_ptr<eh_dispatch_cfg_superedge>
+ make (supernode *src,
+ supernode *dest,
+ ::edge e,
+ const geh_dispatch *eh_dispatch_stmt);
+
+ const eh_dispatch_cfg_superedge *dyn_cast_eh_dispatch_cfg_superedge () const
+ final override
+ {
+ return this;
+ }
+
+ const geh_dispatch *
+ get_eh_dispatch_stmt () const
+ {
+ return m_eh_dispatch_stmt;
+ }
+
+ const eh_status &get_eh_status () const;
+ eh_region get_eh_region () const { return m_eh_region; }
+
+ virtual bool
+ apply_constraints (region_model *model,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out) const = 0;
+
+protected:
+ eh_dispatch_cfg_superedge (supernode *src, supernode *dst, ::edge e,
+ const geh_dispatch *eh_dispatch_stmt,
+ eh_region eh_reg);
+
+private:
+ const geh_dispatch *m_eh_dispatch_stmt;
+ eh_region m_eh_region;
+};
+
+} // namespace ana
+
+template <>
+template <>
+inline bool
+is_a_helper <const eh_dispatch_cfg_superedge *>::test (const superedge *sedge)
+{
+ return sedge->dyn_cast_eh_dispatch_cfg_superedge () != nullptr;
+}
+
+namespace ana {
+
+/* A concrete subclass for edges from an eh_dispatch statements
+ for ERT_TRY regions. */
+
+class eh_dispatch_try_cfg_superedge : public eh_dispatch_cfg_superedge
+{
+ public:
+ eh_dispatch_try_cfg_superedge (supernode *src, supernode *dst, ::edge e,
+ const geh_dispatch *eh_dispatch_stmt,
+ eh_region eh_reg,
+ eh_catch ehc)
+ : eh_dispatch_cfg_superedge (src, dst, e, eh_dispatch_stmt, eh_reg),
+ m_eh_catch (ehc)
+ {
+ gcc_assert (eh_reg->type == ERT_TRY);
+ }
+
+ const eh_dispatch_try_cfg_superedge *
+ dyn_cast_eh_dispatch_try_cfg_superedge () const final override
+ {
+ return this;
+ }
+
+ void dump_label_to_pp (pretty_printer *pp,
+ bool user_facing) const final override;
+
+ eh_catch get_eh_catch () const { return m_eh_catch; }
+
+ bool
+ apply_constraints (region_model *model,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out)
+ const final override;
+
+private:
+ eh_catch m_eh_catch;
+};
+
+} // namespace ana
+
+template <>
+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 () != nullptr;
+}
+
+namespace ana {
+
+/* A concrete subclass for edges from an eh_dispatch statements
+ for ERT_ALLOWED_EXCEPTIONS regions. */
+
+class eh_dispatch_allowed_cfg_superedge : public eh_dispatch_cfg_superedge
+{
+ public:
+ enum eh_kind
+ {
+ expected,
+ unexpected
+ };
+
+ eh_dispatch_allowed_cfg_superedge (supernode *src, supernode *dst, ::edge e,
+ const geh_dispatch *eh_dispatch_stmt,
+ eh_region eh_reg);
+
+ const eh_dispatch_allowed_cfg_superedge *
+ dyn_cast_eh_dispatch_allowed_cfg_superedge () const final override
+ {
+ return this;
+ }
+
+ void dump_label_to_pp (pretty_printer *pp,
+ bool user_facing) const final override;
+
+ bool
+ apply_constraints (region_model *model,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out)
+ const final override;
+
+ enum eh_kind get_eh_kind () const { return m_kind; }
+
+private:
+ enum eh_kind m_kind;
+};
+
+} // namespace ana
+
+template <>
+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 () != nullptr;
+}
+
+namespace ana {
/* Base class for adding additional content to the .dot output
for a supergraph. */
diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc
index 2e3f051..fbbd1d2 100644
--- a/gcc/analyzer/svalue.cc
+++ b/gcc/analyzer/svalue.cc
@@ -18,39 +18,22 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "diagnostic-core.h"
+#include "analyzer/common.h"
+
+#include "tree-pretty-print.h"
#include "gimple-pretty-print.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
+#include "diagnostic.h"
+#include "tree-diagnostic.h"
+
+#include "text-art/dump.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/svalue.h"
#include "analyzer/region-model.h"
-#include "diagnostic.h"
-#include "tree-diagnostic.h"
-#include "make-unique.h"
-#include "text-art/dump.h"
#if ENABLE_ANALYZER
@@ -107,7 +90,7 @@ std::unique_ptr<json::value>
svalue::to_json () const
{
label_text desc = get_desc (true);
- auto sval_js = ::make_unique<json::string> (desc.get ());
+ auto sval_js = std::make_unique<json::string> (desc.get ());
return sval_js;
}
@@ -264,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
@@ -272,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
@@ -288,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
@@ -304,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,
@@ -312,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 ()))
@@ -341,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). */
@@ -427,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
@@ -572,8 +555,8 @@ svalue::cmp_ptr (const svalue *sval1, const svalue *sval2)
{
const poisoned_svalue *poisoned_sval1 = (const poisoned_svalue *)sval1;
const poisoned_svalue *poisoned_sval2 = (const poisoned_svalue *)sval2;
- return (poisoned_sval1->get_poison_kind ()
- - poisoned_sval2->get_poison_kind ());
+ return (static_cast<int> (poisoned_sval1->get_poison_kind ())
+ - static_cast<int> (poisoned_sval2->get_poison_kind ()));
}
break;
case SK_SETJMP:
@@ -823,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.
@@ -836,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
@@ -847,7 +830,7 @@ svalue::maybe_get_deref_base_region () const
switch (iter->get_kind ())
{
default:
- return NULL;
+ return nullptr;
case SK_REGION:
{
@@ -869,14 +852,27 @@ svalue::maybe_get_deref_base_region () const
continue;
default:
- return NULL;
+ return nullptr;
}
- return NULL;
+ return nullptr;
}
}
}
}
+/* If this svalue is a pointer to the typeinfo instance for a particular
+ type, return that type. Otherwise return NULL_TREE. */
+
+tree
+svalue::maybe_get_type_from_typeinfo () const
+{
+ if (const region *reg = maybe_get_region ())
+ if (const decl_region *decl_reg = reg->dyn_cast_decl_region ())
+ return TREE_TYPE (DECL_NAME (decl_reg->get_decl ()));
+
+ return NULL_TREE;
+}
+
/* class region_svalue : public svalue. */
/* Implementation of svalue::dump_to_pp vfunc for region_svalue. */
@@ -1151,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. */
@@ -1234,13 +1230,13 @@ poison_kind_to_str (enum poison_kind kind)
{
default:
gcc_unreachable ();
- case POISON_KIND_UNINIT:
+ case poison_kind::uninit:
return "uninit";
- case POISON_KIND_FREED:
+ case poison_kind::freed:
return "freed";
- case POISON_KIND_DELETED:
+ case poison_kind::deleted:
return "deleted";
- case POISON_KIND_POPPED_STACK:
+ case poison_kind::popped_stack:
return "popped stack";
}
}
@@ -1378,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;
}
@@ -1388,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;
@@ -1512,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. */
@@ -1841,7 +1837,7 @@ repeated_svalue::maybe_fold_bits_within (tree type,
}
}
- return NULL;
+ return nullptr;
}
/* class bits_within_svalue : public svalue. */
@@ -2397,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 bf9e12b..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;
@@ -188,6 +188,8 @@ public:
const region_model &model,
const svalue *outer_sval = nullptr) const;
+ tree maybe_get_type_from_typeinfo () const;
+
protected:
svalue (complexity c, symbol::id_t id, tree type)
: symbol (c, id), m_type (type)
@@ -244,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; }
@@ -421,19 +423,19 @@ public:
/* An enum describing a particular kind of "poisoned" value. */
-enum poison_kind
+enum class poison_kind
{
/* For use to describe uninitialized memory. */
- POISON_KIND_UNINIT,
+ uninit,
/* For use to describe freed memory. */
- POISON_KIND_FREED,
+ freed,
/* For use to describe deleted memory. */
- POISON_KIND_DELETED,
+ deleted,
/* For use on pointers to regions within popped stack frames. */
- POISON_KIND_POPPED_STACK
+ popped_stack
};
extern const char *poison_kind_to_str (enum poison_kind);
@@ -454,7 +456,7 @@ public:
hashval_t hash () const
{
inchash::hash hstate;
- hstate.add_int (m_kind);
+ hstate.add_int (static_cast<int> (m_kind));
hstate.add_ptr (m_type);
return hstate.end ();
}
@@ -528,8 +530,8 @@ namespace ana {
struct setjmp_record
{
setjmp_record (const exploded_node *enode,
- const gcall *setjmp_call)
- : m_enode (enode), m_setjmp_call (setjmp_call)
+ const gcall &setjmp_call)
+ : m_enode (enode), m_setjmp_call (&setjmp_call)
{
}
@@ -549,6 +551,7 @@ struct setjmp_record
const exploded_node *m_enode;
const gcall *m_setjmp_call;
+ // non-null, but we can't use a reference since we're putting these in a hash_map
};
/* Concrete subclass of svalue representing buffers for setjmp/sigsetjmp,
@@ -647,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; }
@@ -1544,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;
@@ -1565,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; }
@@ -1665,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;
@@ -1810,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/symbol.cc b/gcc/analyzer/symbol.cc
index 068801a..8643284 100644
--- a/gcc/analyzer/symbol.cc
+++ b/gcc/analyzer/symbol.cc
@@ -18,11 +18,8 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "analyzer/symbol.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/trimmed-graph.cc b/gcc/analyzer/trimmed-graph.cc
index 993084c..bdf378a 100644
--- a/gcc/analyzer/trimmed-graph.cc
+++ b/gcc/analyzer/trimmed-graph.cc
@@ -18,21 +18,8 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "pretty-print.h"
-#include "gcc-rich-location.h"
-#include "gimple-pretty-print.h"
-#include "function.h"
-#include "diagnostic-core.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-path.h"
-#include "bitmap.h"
-#include "ordered-hash-map.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
diff --git a/gcc/analyzer/varargs.cc b/gcc/analyzer/varargs.cc
index 0cacc9b..1fdfd34 100644
--- a/gcc/analyzer/varargs.cc
+++ b/gcc/analyzer/varargs.cc
@@ -18,18 +18,8 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#include "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
@@ -167,10 +157,10 @@ get_va_list_diag_arg (tree va_list_tree)
static const svalue *
get_va_copy_arg (const region_model *model,
region_model_context *ctxt,
- const gcall *call,
+ const gcall &call,
unsigned arg_idx)
{
- tree arg = gimple_call_arg (call, arg_idx);
+ tree arg = gimple_call_arg (&call, arg_idx);
const svalue *arg_sval = model->get_rvalue (arg, ctxt);
if (const svalue *cast = arg_sval->maybe_undo_cast ())
arg_sval = cast;
@@ -215,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;
@@ -225,16 +219,16 @@ public:
private:
void on_va_start (sm_context &sm_ctxt, const supernode *node,
- const gcall *call) const;
+ const gcall &call) const;
void on_va_copy (sm_context &sm_ctxt, const supernode *node,
- const gcall *call) const;
+ const gcall &call) const;
void on_va_arg (sm_context &sm_ctxt, const supernode *node,
- const gcall *call) const;
+ const gcall &call) const;
void on_va_end (sm_context &sm_ctxt, const supernode *node,
- const gcall *call) const;
+ const gcall &call) const;
void check_for_ended_va_list (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
const svalue *arg,
const char *usage_fnname) const;
};
@@ -256,10 +250,12 @@ va_list_state_machine::on_stmt (sm_context &sm_ctxt,
const supernode *node,
const gimple *stmt) const
{
- if (const gcall *call = dyn_cast <const gcall *> (stmt))
+ if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt))
{
- if (gimple_call_internal_p (call)
- && gimple_call_internal_fn (call) == IFN_VA_ARG)
+ const gcall &call = *call_stmt;
+
+ if (gimple_call_internal_p (call_stmt)
+ && gimple_call_internal_fn (call_stmt) == IFN_VA_ARG)
{
on_va_arg (sm_ctxt, node, call);
return false;
@@ -267,7 +263,7 @@ va_list_state_machine::on_stmt (sm_context &sm_ctxt,
if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
if (fndecl_built_in_p (callee_fndecl, BUILT_IN_NORMAL)
- && gimple_builtin_call_types_compatible_p (call, callee_fndecl))
+ && gimple_builtin_call_types_compatible_p (&call, callee_fndecl))
switch (DECL_UNCHECKED_FUNCTION_CODE (callee_fndecl))
{
default:
@@ -293,24 +289,24 @@ va_list_state_machine::on_stmt (sm_context &sm_ctxt,
IDX to CALL. */
static const svalue *
-get_stateful_arg (sm_context &sm_ctxt, const gcall *call, unsigned arg_idx)
+get_stateful_arg (sm_context &sm_ctxt, const gcall &call, unsigned arg_idx)
{
- tree ap = gimple_call_arg (call, arg_idx);
+ tree ap = gimple_call_arg (&call, arg_idx);
if (ap
&& POINTER_TYPE_P (TREE_TYPE (ap)))
{
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. */
@@ -338,17 +334,17 @@ public:
return false;
}
- diagnostic_event::meaning
+ diagnostics::paths::event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
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 diagnostics::paths::event::meaning (diagnostics::paths::event::verb::acquire,
+ diagnostics::paths::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 ();
+ return diagnostics::paths::event::meaning (diagnostics::paths::event::verb::release,
+ diagnostics::paths::event::noun::resource);
+ return diagnostics::paths::event::meaning ();
}
protected:
@@ -374,7 +370,7 @@ protected:
return "va_end";
}
}
- return NULL;
+ return nullptr;
}
const va_list_state_machine &m_sm;
@@ -456,7 +452,7 @@ public:
}
private:
- diagnostic_event_id_t m_va_end_event;
+ diagnostics::paths::event_id_t m_va_end_event;
const char *m_usage_fnname;
};
@@ -468,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
@@ -532,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;
+ diagnostics::paths::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. */
@@ -542,14 +549,14 @@ private:
void
va_list_state_machine::on_va_start (sm_context &sm_ctxt,
const supernode *,
- const gcall *call) const
+ const gcall &call) const
{
const svalue *arg = get_stateful_arg (sm_ctxt, call, 0);
if (arg)
{
/* Transition from start state to "started". */
- if (sm_ctxt.get_state (call, arg) == m_start)
- sm_ctxt.set_next_state (call, arg, m_started);
+ if (sm_ctxt.get_state (&call, arg) == m_start)
+ sm_ctxt.set_next_state (&call, arg, m_started);
}
}
@@ -558,32 +565,32 @@ va_list_state_machine::on_va_start (sm_context &sm_ctxt,
void
va_list_state_machine::check_for_ended_va_list (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
const svalue *arg,
const char *usage_fnname) const
{
- if (sm_ctxt.get_state (call, arg) == m_ended)
- sm_ctxt.warn (node, call, arg,
- make_unique<va_list_use_after_va_end>
+ if (sm_ctxt.get_state (&call, arg) == m_ended)
+ sm_ctxt.warn (node, &call, arg,
+ std::make_unique<va_list_use_after_va_end>
(*this, arg, NULL_TREE, usage_fnname));
}
/* 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,
- const gcall *call,
+ 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 *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. */
@@ -591,7 +598,7 @@ get_stateful_va_copy_arg (sm_context &sm_ctxt,
void
va_list_state_machine::on_va_copy (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call) const
+ const gcall &call) const
{
const svalue *src_arg = get_stateful_va_copy_arg (sm_ctxt, call, 1);
if (src_arg)
@@ -601,8 +608,8 @@ va_list_state_machine::on_va_copy (sm_context &sm_ctxt,
if (dst_arg)
{
/* Transition from start state to "started". */
- if (sm_ctxt.get_state (call, dst_arg) == m_start)
- sm_ctxt.set_next_state (call, dst_arg, m_started);
+ if (sm_ctxt.get_state (&call, dst_arg) == m_start)
+ sm_ctxt.set_next_state (&call, dst_arg, m_started);
}
}
@@ -611,7 +618,7 @@ va_list_state_machine::on_va_copy (sm_context &sm_ctxt,
void
va_list_state_machine::on_va_arg (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call) const
+ const gcall &call) const
{
const svalue *arg = get_stateful_arg (sm_ctxt, call, 0);
if (arg)
@@ -623,15 +630,15 @@ va_list_state_machine::on_va_arg (sm_context &sm_ctxt,
void
va_list_state_machine::on_va_end (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call) const
+ const gcall &call) const
{
const svalue *arg = get_stateful_arg (sm_ctxt, call, 0);
if (arg)
{
- state_t s = sm_ctxt.get_state (call, arg);
+ state_t s = sm_ctxt.get_state (&call, arg);
/* Transition from "started" to "ended". */
if (s == m_started)
- sm_ctxt.set_next_state (call, arg, m_ended);
+ sm_ctxt.set_next_state (&call, arg, m_ended);
else if (s == m_ended)
check_for_ended_va_list (sm_ctxt, node, call, arg, "va_end");
}
@@ -641,19 +648,21 @@ 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 make_unique<va_list_leak> (*this, nullptr, var);
+ return std::make_unique<va_list_leak> (*this, nullptr, var, new_state);
}
} // anonymous namespace
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_va_list_state_machine (logger *logger)
{
- return new va_list_state_machine (logger);
+ return std::make_unique<va_list_state_machine> (logger);
}
/* Handler for "__builtin_va_start". */
@@ -731,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
@@ -757,13 +766,13 @@ kf_va_copy::impl_call_pre (const call_details &cd) const
static int
get_num_variadic_arguments (tree callee_fndecl,
- const gcall *call_stmt)
+ const gcall &call_stmt)
{
int num_positional = 0;
for (tree iter_parm = DECL_ARGUMENTS (callee_fndecl); iter_parm;
iter_parm = DECL_CHAIN (iter_parm))
num_positional++;
- return gimple_call_num_args (call_stmt) - num_positional;
+ return gimple_call_num_args (&call_stmt) - num_positional;
}
/* An abstract subclass of pending_diagnostic for diagnostics relating
@@ -817,12 +826,12 @@ public:
const program_point &src_point = src_node->get_point ();
const int src_stack_depth = src_point.get_stack_depth ();
const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
- const gcall *call_stmt = as_a <const gcall *> (last_stmt);
+ const gcall &call_stmt = *as_a <const gcall *> (last_stmt);
int num_variadic_arguments
= get_num_variadic_arguments (dst_node->get_function ()->decl,
call_stmt);
emission_path->add_event
- (make_unique<va_arg_call_event>
+ (std::make_unique<va_arg_call_event>
(eedge,
event_loc_info (last_stmt ? last_stmt->location : UNKNOWN_LOCATION,
src_point.get_fndecl (),
@@ -1011,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". */
@@ -1078,7 +1087,7 @@ kf_va_arg::impl_call_pre (const call_details &cd) const
else
{
if (ctxt)
- ctxt->warn (make_unique <va_arg_type_mismatch>
+ ctxt->warn (std::make_unique <va_arg_type_mismatch>
(va_list_tree,
arg_reg,
lhs_type,
@@ -1089,8 +1098,9 @@ kf_va_arg::impl_call_pre (const call_details &cd) const
else
{
if (ctxt)
- ctxt->warn (make_unique <va_list_exhausted> (va_list_tree,
- arg_reg));
+ ctxt->warn
+ (std::make_unique <va_list_exhausted> (va_list_tree,
+ arg_reg));
saw_problem = true;
}
}
@@ -1139,10 +1149,10 @@ public:
void
register_varargs_builtins (known_function_manager &kfm)
{
- kfm.add (BUILT_IN_VA_START, make_unique<kf_va_start> ());
- kfm.add (BUILT_IN_VA_COPY, make_unique<kf_va_copy> ());
- kfm.add (IFN_VA_ARG, make_unique<kf_va_arg> ());
- kfm.add (BUILT_IN_VA_END, make_unique<kf_va_end> ());
+ kfm.add (BUILT_IN_VA_START, std::make_unique<kf_va_start> ());
+ kfm.add (BUILT_IN_VA_COPY, std::make_unique<kf_va_copy> ());
+ kfm.add (IFN_VA_ARG, std::make_unique<kf_va_arg> ());
+ kfm.add (BUILT_IN_VA_END, std::make_unique<kf_va_end> ());
}
} // namespace ana