Age | Commit message (Collapse) | Author | Files | Lines |
|
This patch adds various support for debugging diagnostic paths and
events, intended initially for myself to help with debugging -fanalyzer.
It adds the optional ability for a diagnostic_event to supply a
description of the predicted state of the program at that point along
the diagnostic_path. To isolate the diagnostic subsystem from the
analyzer, this representation is currently an xml::document with custom
elements. The XML representation is similar to the analyzer's internal
state but can be easier to read - for example, rather than storing the
contents of memory via byte offsets, it uses fields for structs and
element indexes for arrays, recursively.
These states are handled by the HTML and SARIF diagnostic sinks.
The SARIF sink simply embeds the XML as a string in a property bag of the
threadFlowLocation object (SARIF v2.1.0 section 3.38).
For HTML output, the "experimental-html" sink gains a new
"show-state-diagrams=yes" option i.e.:
-fdiagnostics-add-output=experimental-html:show-state-diagrams=yes
which converts the state XML into SVG diagrams visualizing the state of
memory at each event, inspired by the "ddd" debugger. These can be seen
by pressing 'j' and 'k' to single-step forward and backward through
events, making it *much* easier to debug -fanalyzer.
An example of output can be seen here:
https://dmalcolm.fedorapeople.org/gcc/2025-06-23/state-diagram-1.c.html
showing an issue in a singly-linked list; there are various other
examples in the parent directory.
Generating the SVG diagrams requires an invocation of "dot" per event,
so it noticeable slows down diagnostic emission, hence the opt-in
command-line flag. However, I'm already finding bugs in -fanalyzer with
this that I hadn't seen before.
Given that the UI is rather clunky and there is lots of room for
improvement to the visualizations, for now this feature is marked
as being for GCC developers, not end-users.
The patch also adds a dot::ast_node class hierarachy to make it easy to
create GraphViz dot files with the correct escaping, and adds a C++
wrapper around pex adding some syntactic sugar for invoking
subprocesses.
gcc/ChangeLog:
PR other/116792
* Makefile.in (ANALYZER_OBJS): Add
analyzer/ana-state-to-diagnostic-state.o.
(OBJS): Move graphviz.o to...
(OBJS-libcommon): ...here. Add diagnostic-state-to-dot.o and pex.o.
* diagnostic-format-html.cc: Include "diagnostic-state.h" and
"graphviz.h".
(html_generation_options::html_generation_options): Initialize the
new flags.
(HTML_SCRIPT): Add function "get_any_state_diagram". Use it
when changing current focus id to update the visibility of the
pertinent diagram, if any.
(print_pre_source): New.
(html_builder::maybe_make_state_diagram): New.
(html_path_label_writer::html_path_label_writer): Add "path" param.
Initialize m_path and m_curr_event_id.
(html_path_label_writer::begin_label): Store current event id.
(html_path_label_writer::end_label): Attempt to make a state
diagram and add it if successful.
(html_path_label_writer::get_element_id): New.
(html_path_label_writer::m_path): New field.
(html_path_label_writer::m_curr_event_id): New field.
(html_builder::make_element_for_diagnostic): Pass path to label
writer.
* diagnostic-format-html.h
(html_generation_options::m_show_state_diagrams): New field.
(html_generation_options::m_show_state_diagram_xml): New field.
(html_generation_options::m_show_state_diagram_dot_src): New field.
* diagnostic-format-sarif.cc: Include "xml.h".
(populate_thread_flow_location_object): If requested, attempt to
generate xml state and add it to the proeprty bag as
"gcc/diagnostic_event/xml_state" in xml source form.
(sarif_generation_options::sarif_generation_options): Initialize
m_xml_state.
* diagnostic-format-sarif.h
(sarif_generation_options::m_xml_state): New field.
* diagnostic-path.cc: Define INCLUDE_MAP. Include "xml.h".
(diagnostic_event::maybe_make_xml_state): New.
* diagnostic-path.h (class xml::document): New forward decl.
(diagnostic_event::maybe_make_xml_state): New vfunc decl.
* diagnostic-state-to-dot.cc: New file.
* diagnostic-state.h: New file.
* digraph.cc: Define INCLUDE_STRING and INCLUDE_VECTOR.
* doc/analyzer.texi: Document state diagrams in html output.
(__analyzer_dump_dot): New.
(__analyzer_dump_xml): New.
* doc/invoke.texi (sarif): Add "xml-state" key.
(experimental-html): Add keys "show-state-diagrams",
"show-state-diagrams-dot-src" and "show-state-diagrams-xml".
* graphviz.cc: Define INCLUDE_MAP, INCLUDE_STRING, and
INCLUDE_VECTOR. Include "xml.h", "xml-printer.h", "pex.h" and
"selftest.h".
(graphviz_out::graphviz_out): Extract...
(dot::writer::writer): ...this.
(graphviz_out::write_indent): Convert to...
(dot::writer::write_indent): ...this.
(graphviz_out::print): Use get_pp.
(graphviz_out::println): Likewise.
(graphviz_out::begin_tr): Likewise.
(graphviz_out::end_tr): Likewise.
(graphviz_out::begin_td): Likewise.
(graphviz_out::end_td): Likewise.
(graphviz_out::begin_trtd): Likewise.
(graphviz_out::end_tdtr): Likewise.
(dot::ast_node::dump): New.
(dot::id::id): New.
(dot::id::print): New.
(dot::id::is_identifier_p): New.
(dot::kv_pair::print): New.
(dot::attr_list::print): New.
(dot::stmt_list::print): New.
(dot::stmt_list::add_edge): New.
(dot::stmt_list::add_attr): New.
(dot::graph::print): New.
(dot::stmt_with_attr_list::set_label): New.
(dot::node_stmt::print): New.
(dot::attr_stmt::print): New.
(dot::kv_stmt::print): New.
(dot::node_id::print): New.
(dot::port::print): New.
(dot::edge_stmt::print): New.
(dot::subgraph::print): New.
(dot::make_svg_document_buffer_from_graph): New.
(dot::make_svg_from_graph): New.
(selftest:test_ids): New.
(selftest:test_trivial_graph): New.
(selftest:test_layout_example): New.
(selftest:graphviz_cc_tests): New.
* graphviz.h (xml::node): New forward decl.
(class graphviz_out): Split out into...
(class dot::writer): ...this new class
(struct dot::ast_node): New.
(struct dot::id): New.
(struct dot::kv_pair): New.
(struct dot::attr_list): New.
(struct dot::stmt_list): New.
(struct dot::graph): New.
(struct dot::stmt): New.
(struct dot::stmt_with_attr_list): New.
(struct dot::node_stmt): New.
(struct dot::attr_stmt): New.
(struct dot::kv_stmt): New.
(enum class dot::compass_pt): New.
(struct dot::port): New.
(struct dot::node_id): New.
(struct dot::edge_stmt): New.
(struct dot::subgraph): New.
(dot::make_svg_from_graph): New.
* opts-diagnostic.cc (sarif_scheme_handler::make_sink): Add
"xml-state" flag.
(html_scheme_handler::make_sink): Add flags "show-state-diagrams",
"show-state-diagram-dot-src", and "show-state-diagram-xml".
* pex.cc: New file.
* pex.h: New file.
* selftest-run-tests.cc (selftest::run_tests): Call
graphviz_cc_tests.
* selftest.h (selftest::graphviz_cc_tests): New decl.
* xml.cc (xml::node_with_children::add_comment): New.
(xml::node_with_children::find_child_element): New.
(xml::element::get_attr): New.
(xml::comment::write_as_xml): New.
(selftest::test_printer): Add coverage of find_child_element and
get_attr.
(selftest::test_comment): New.
(selftest::xml_cc_tests): Call test_comment.
* xml.h: New forward decls.
(xml::node::dyn_cast_text): Use nullptr.
(xml::node::dyn_cast_element): New vfunc.
(xml::node_with_children::add_comment): New decl.
(xml::node_with_children::find_child_element): New decl.
(xml::element::dyn_cast_element): New vfunc impl.
(xml::element::get_attr): New decl.
(struct xml::comment): New xml::node subclass.
gcc/analyzer/ChangeLog:
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.
gcc/testsuite/ChangeLog:
PR other/116792
* g++.dg/analyzer/state-diagram.C: New test.
* gcc.dg/analyzer/analyzer-decls.h (__analyzer_dump_dot): New
decl.
(__analyzer_dump_xml): New decl.
* gcc.dg/analyzer/state-diagram-1-sarif.py: New test script.
* gcc.dg/analyzer/state-diagram-1.c: New test.
* gcc.dg/analyzer/state-diagram-2.c: New test.
* gcc.dg/analyzer/state-diagram-3.c: New test.
* gcc.dg/analyzer/state-diagram-4.c: New test.
* gcc.dg/analyzer/state-diagram-5-html.py: New test script.
* gcc.dg/analyzer/state-diagram-5-sarif.py: New test script.
* gcc.dg/analyzer/state-diagram-5.c: New test.
* gcc.dg/plugin/analyzer_cpython_plugin.cc: Define INCLUDE_STRING.
* gcc.dg/plugin/analyzer_gil_plugin.cc: Likewise.
* gcc.dg/plugin/analyzer_kernel_plugin.cc: Likewise.
* gcc.dg/plugin/analyzer_known_fns_plugin.cc: Likewise.
* lib/htmltest.py (ns): Add SVG namespace.
* lib/sarif.py (get_result_by_index): New.
(get_xml_state): New.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
Previously we used an abstract base class logical_location with
concrete subclasses to separate the diagnostics subsystem from
implementation details of "tree" and of libgdiagnostics.
This approach required allocating implementation objects on the heap
whenever working with logical locations, and made comparing logical
locations awkward.
This patch reworks things so that the type "logical_location" becomes a
boxed pointer (const void *), and client code provides a single object
implementing a new logical_location_manager abstract base class. The
manager class has responsibility for providing meaning to the boxed
pointers. Within the compiler we use a manager in which they are "tree"
pointers, whereas within libgdiagnostics we use a manager in which they
are pointers to instances of libgdiagnostics'
"struct diagnostic_logical_location". Other kinds of manager could be
implemented.
gcc/analyzer/ChangeLog:
* 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.
gcc/ChangeLog:
* diagnostic-client-data-hooks.h: Include "logical-location.h".
(diagnostic_client_data_hooks::get_logical_location_manager): New.
(diagnostic_client_data_hooks::get_current_logical_location):
Convert return type from const logical_location * to
logical_location.
* diagnostic-format-json.cc: Include
"diagnostic-client-data-hooks.h".
(make_json_for_path): Update to use logical_location_manager from
the context.
* diagnostic-format-sarif.cc
(sarif_builder::get_logical_location_manager): New.
(sarif_builder::make_location_object): Update type of logical_loc
from "const logical_location *" to "logical_location".
(sarif_builder::set_any_logical_locs_arr): Likewise.
(sarif_builder::m_logical_loc_mgr): New field.
(sarif_result::on_nested_diagnostic): Use logical_location default
ctor rather than nullptr.
(sarif_builder::sarif_builder): Initialize m_logical_loc_mgr from
context's client data hooks.
(sarif_builder::make_locations_arr): Convert type of logical_loc
from from "const logical_location *" to "logical_location".
(sarif_builder::set_any_logical_locs_arr): Likewise. Pass manager
to make_sarif_logical_location_object.
(sarif_builder::make_location_object): Likewise.
(sarif_property_bag::set_logical_location): New.
(make_sarif_logical_location_object): Update for introduction of
logical_location_manager.
(populate_thread_flow_location_object): Pass builder to
ev.maybe_add_sarif_properties.
(selftest::test_make_location_object): Use logical_location
default ctor rather than nullptr.
* diagnostic-format-sarif.h (class logical_location): Replace
forward decl with include of "logical-location.h".
(class sarif_builder): New forward decl.
(sarif_property_bag::set_logical_location): New.
(make_sarif_logical_location_object): Add "mgr" param.
* diagnostic-path.cc
(diagnostic_path::get_first_event_in_a_function): Update for
change of logical_location type.
(per_thread_summary::per_thread_summary): Pass in
"logical_loc_mgr".
(per_thread_summary::m_logical_loc_mgr): New field.
(event_range::m_logical_loc): Update for change of
logical_location type.
(path_summary::get_logical_location_manager): New accessor.
(path_summary::m_logical_loc_mgr): New field.
(path_summary::get_or_create_events_for_thread_id): Pass
m_logical_loc_mgr to per_thread_summary ctor.
(path_summary::path_summary): Initialize m_logical_loc_mgr.
(thread_event_printer::print_swimlane_for_event_range): Add param
"logical_loc_mgr". Update for change in logical_loc type.
(print_path_summary_as_text): Pass manager to
thread_event_printer::print_swimlane_for_event_range.
(diagnostic_text_output_format::print_path): Update for
introduction of logical_location_manager.
* diagnostic-path.h: Include "logical-location.h".
(class sarif_builder): New forward decl.
(diagnostic_event::get_logical_location): Convert return type from
"const logical_location *" to "logical_location".
(diagnostic_event::maybe_add_sarif_properties): Add sarif_builder
param.
(diagnostic_path::get_logical_location_manager): New accessor.
(diagnostic_path::diagnostic_path): New ctor, taking manager.
(diagnostic_path::m_logical_loc_mgr): New field.
* diagnostic.cc
(diagnostic_context::get_logical_location_manager): New.
(logical_location::function_p): Convert to...
(logical_location_manager::function_p): ...this.
* diagnostic.h (class logical_location): Replace forward decl
with...
(class logical_location_manager): ...this.
(diagnostic_context::get_logical_location_manager): New decl.
* lazy-diagnostic-path.cc
(selftest::test_lazy_path::test_lazy_path): Pass m_logical_loc_mgr
to path ctor.
(selftest::test_lazy_path::make_inner_path): Likewise.
(selftest::test_lazy_path::m_logical_loc_mgr): New field.
* lazy-diagnostic-path.h
(lazy_diagnostic_path::lazy_diagnostic_path): New ctor.
* libgdiagnostics.cc (struct diagnostic_logical_location): Convert
from subclass of logical_location to a plain struct, dropping
accessors.
(class impl_logical_location_manager): New.
(impl_diagnostic_client_data_hooks::get_logical_location_manager):
New
(impl_diagnostic_client_data_hooks::m_logical_location_manager):
New field.
(diagnostic_manager::get_logical_location_manager): New.
(libgdiagnostics_path_event::get_logical_location): Reimplement.
(diagnostic_execution_path::diagnostic_execution_path): Add
logical_loc_mgr and pass to base class.
(diagnostic_execution_path::same_function_p): Update for change to
logical_location type.
(diagnostic::add_execution_path): Pass logical_loc_mgr to path
ctor.
(impl_diagnostic_client_data_hooks::get_current_logical_location):
Reimplement.
(diagnostic_text_sink::text_starter): Reimplement printing of
logical location.
(diagnostic_manager::new_execution_path): Pass mgr to path ctor.
(diagnostic_manager_debug_dump_logical_location): Update for
changes to diagnostic_logical_location.
(diagnostic_logical_location_get_kind): Likewise.
(diagnostic_logical_location_get_parent): Likewise.
(diagnostic_logical_location_get_short_name): Likewise.
(diagnostic_logical_location_get_fully_qualified_name): Likewise.
(diagnostic_logical_location_get_decorated_name): Likewise.
* logical-location.h (class logical_location_manager): New.
(class logical_location): Convert to typedef of
logical_location_manager::key.
* selftest-diagnostic-path.cc
(selftest::test_diagnostic_path::test_diagnostic_path): Pass
m_test_logical_loc_mgr to base ctor.
(selftest::test_diagnostic_path::same_function_p): Use pointer
comparison.
(selftest::test_diagnostic_path::add_event): Use
logical_location_from_funcname.
(selftest::test_diagnostic_path::add_thread_event): Likewise.
(selftest::test_diagnostic_path::logical_location_from_funcname):
New.
(selftest::test_diagnostic_event::test_diagnostic_event): Fix
indentation. Pass logical_location rather than const char *.
* selftest-diagnostic-path.h
(selftest::test_diagnostic_event::test_diagnostic_event):
Likewise.
(selftest::test_diagnostic_event::get_logical_location): Update
for change to logical_location type.
(selftest::test_diagnostic_event::get_function_name): Drop.
(selftest::test_diagnostic_event::m_logical_loc): Convert from
test_logical_location to logical_location.
(selftest::test_diagnostic_path::logical_location_from_funcname):
New.
(selftest::test_diagnostic_path::m_test_logical_loc_mgr): New
field.
* selftest-logical-location.cc: Include "selftest.h".
(selftest::test_logical_location::test_logical_location): Drop.
(selftest::test_logical_location_manager::~test_logical_location_manager):
New.
(selftest::test_logical_location::get_short_name): Replace with...
(selftest::test_logical_location_manager::get_short_name):
...this.
(selftest::test_logical_location::get_name_with_scope): Replace
with...
(selftest::test_logical_location_manager::get_name_with_scope):
...this.
(selftest::test_logical_location::get_internal_name): Replace
with...
(selftest::test_logical_location_manager::get_internal_name):
...this.
(selftest::test_logical_location::get_kind): Replace with...
(selftest::test_logical_location_manager::get_kind): ...this.
(selftest::test_logical_location::get_name_for_path_output):
Replace with...
(selftest::test_logical_location_manager::get_name_for_path_output):
...this.
(selftest::test_logical_location_manager::logical_location_from_funcname):
New.
(selftest::test_logical_location_manager::item_from_funcname):
New.
(selftest::selftest_logical_location_cc_tests): New.
* selftest-logical-location.h (class test_logical_location):
Replace with...
(class test_logical_location_manager): ...this.
* selftest-run-tests.cc (selftest::run_tests): Call
selftest_logical_location_cc_tests.
* selftest.h (selftest::selftest_logical_location_cc_tests): New
decl.
* simple-diagnostic-path.cc
(simple_diagnostic_path::simple_diagnostic_path): Add
"logical_loc_mgr" param and pass it to base ctor.
(simple_diagnostic_event::simple_diagnostic_event): Update init of
m_logical_loc.
(selftest::test_intraprocedural_path): Update for changes to
logical locations.
* simple-diagnostic-path.h: Likewise.
* tree-diagnostic-client-data-hooks.cc
(compiler_data_hooks::get_logical_location_manger): New.
(compiler_data_hooks::get_current_logical_location): Update.
(compiler_data_hooks::m_current_fndecl_logical_loc): Replace
with...
(compiler_data_hooks::m_logical_location_manager): ...this.
* tree-logical-location.cc
(compiler_logical_location::get_short_name_for_tree): Replace
with...
(tree_logical_location_manager::get_short_name): ...this.
(compiler_logical_location::get_name_with_scope_for_tree): Replace
with...
(tree_logical_location_manager::get_name_with_scope): ...this.
(compiler_logical_location::get_internal_name_for_tree): Replace
with...
(tree_logical_location_manager::get_internal_name): ...this.
(compiler_logical_location::get_kind_for_tree): Replace with...
(tree_logical_location_manager::get_kind): ...this.
(compiler_logical_location::get_name_for_tree_for_path_output):
Replace with...
(tree_logical_location_manager::get_name_for_path_output):
...this.
(tree_logical_location::get_short_name): Drop.
(tree_logical_location::get_name_with_scope): Drop.
(tree_logical_location::get_internal_name): Drop.
(tree_logical_location::get_kind): Drop.
(tree_logical_location::get_name_for_path_output): Drop.
(current_fndecl_logical_location::get_short_name): Drop.
(current_fndecl_logical_location::get_name_with_scope): Drop.
(current_fndecl_logical_location::get_internal_name): Drop.
(current_fndecl_logical_location::get_kind): Drop.
(current_fndecl_logical_location::get_name_for_path_output): Drop.
* tree-logical-location.h (class compiler_logical_location): Drop.
(class tree_logical_location): Drop.
(class current_fndecl_logical_location): Drop.
(class tree_logical_location_manager): New.
gcc/testsuite/ChangeLog:
* gcc.dg/plugin/diagnostic_plugin_test_paths.cc: Update for
changes to simple_diagnostic_path.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
|
|
This patch eliminates the use of "tree" from diagnostic_{event,path} in
favor of const logical_location *.
No functional change intended.
gcc/analyzer/ChangeLog:
* checker-event.h (checker_event::fndecl): Drop "final" and
"override", converting from a vfunc implementation to a plain
accessor.
* checker-path.cc (checker_path::same_function_p): New.
* checker-path.h (checker_path::same_function_p): New decl.
gcc/ChangeLog:
* diagnostic.cc: Include "logical-location.h".
(diagnostic_path::get_first_event_in_a_function): Fix typo in
leading comment. Rewrite to use logical_location rather than
tree. Drop test on stack depth.
(diagnostic_path::interprocedural_p): Rewrite to use
logical_location rather than tree.
(logical_location::function_p): New.
* diagnostic-path.h (diagnostic_event::get_fndecl): Eliminate
vfunc.
(diagnostic_path::same_function_p): New pure virtual func.
* logical-location.h (logical_location::get_name_for_path_output):
New pure virtual func.
* simple-diagnostic-path.cc
(simple_diagnostic_path::same_function_p): New.
(simple_diagnostic_event::simple_diagnostic_event): Initialize
m_logical_loc.
* simple-diagnostic-path.h: Include "tree-logical-location.h".
(simple_diagnostic_event::get_fndecl): Convert from a vfunc
implementation to an accessor.
(simple_diagnostic_event::get_logical_location): Use
m_logical_loc.
(simple_diagnostic_event::m_logical_loc): New field.
(simple_diagnostic_path::same_function_p): New decl.
* tree-diagnostic-path.cc: Move pragma disabling -Wformat-diag to
cover the whole file.
(can_consolidate_events): Add params "path", "ev1_idx", and
"ev2_idx". Rewrite to use diagnostic_path::same_function_p rather
than tree.
(per_thread_summary::per_thread_summary): Add "path" param
(per_thread_summary::m_path): New field.
(event_range::event_range): Update for conversion of m_fndecl to
m_logical_loc.
(event_range::maybe_add_event): Rename param "idx" to
"new_ev_idx". Update call to can_consolidate_events to pass in
"m_path", "m_start_idx", and "new_ev_idx".
(event_range::m_fndecl): Replace with...
(event_range::m_logical_loc): ...this.
(path_summary::get_or_create_events_for_thread_id): Pass "path" to
per_thread_summary ctor.
(per_thread_summary::interprocedural_p): Rewrite to use
diagnostic_path::same_function_p rather than tree.
(print_fndecl): Delete.
(thread_event_printer::print_swimlane_for_event_range): Update for
conversion from tree to logical_location.
(default_tree_diagnostic_path_printer): Likewise.
(default_tree_make_json_for_path): Likewise.
* tree-logical-location.cc: Include "intl.h".
(compiler_logical_location::get_name_for_tree_for_path_output):
New.
(tree_logical_location::get_name_for_path_output): New.
(current_fndecl_logical_location::get_name_for_path_output): New.
* tree-logical-location.h
(compiler_logical_location::get_name_for_tree_for_path_output):
New decl.
(tree_logical_location::get_name_for_path_output): New decl.
(current_fndecl_logical_location::get_name_for_path_output): New
decl.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
As work towards eliminating the dependency on "tree" from
path-printing, move these classes to a new simple-diagnostic-path.h/cc.
No functional change intended.
gcc/analyzer/ChangeLog:
* checker-path.h: Include "simple-diagnostic-path.h".
gcc/ChangeLog:
* Makefile.in (OBJS): Add simple-diagnostic-path.o.
* diagnostic-path.h (class simple_diagnostic_event): Move to
simple-diagnostic-path.h.
(class simple_diagnostic_thread): Likewise.
(class simple_diagnostic_path): Likewise.
* diagnostic.cc (simple_diagnostic_path::simple_diagnostic_path):
Move to simple-diagnostic-path.cc.
(simple_diagnostic_path::num_events): Likewise.
(simple_diagnostic_path::get_event): Likewise.
(simple_diagnostic_path::num_threads): Likewise.
(simple_diagnostic_path::get_thread): Likewise.
(simple_diagnostic_path::add_thread): Likewise.
(simple_diagnostic_path::add_event): Likewise.
(simple_diagnostic_path::add_thread_event): Likewise.
(simple_diagnostic_path::connect_to_next_event): Likewise.
(simple_diagnostic_event::simple_diagnostic_event): Likewise.
(simple_diagnostic_event::~simple_diagnostic_event): Likewise.
* selftest-run-tests.cc (selftest::run_tests): Call
selftest::simple_diagnostic_path_cc_tests.
* selftest.h (selftest::simple_diagnostic_path_cc_tests): New
decl.
* simple-diagnostic-path.cc: New file, from the above material.
* simple-diagnostic-path.h: New file, from the above material
from diagnostic-path.h.
* tree-diagnostic-path.cc: Include "simple-diagnostic-path.h".
gcc/testsuite/ChangeLog
* gcc.dg/plugin/diagnostic_plugin_test_paths.c: Include
"simple-diagnostic-path.h".
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
|
|
This patch implements a new analyzer warning: -Wanalyzer-infinite-loop.
It works by examining the exploded graph once the latter has been
fully built. It attempts to detect cycles in the exploded graph in
which:
- no externally visible work occurs
- no escape is possible from the cycle once it has been entered
- the program state is "sufficiently concrete" at each step:
- no unknown activity could be occurring
- the worklist was fully drained for each enode in the cycle
i.e. every enode in the cycle is processed
For example, it correctly complains about this bogus "for" loop:
int sum = 0;
for (struct node *iter = n; iter; iter->next)
sum += n->val;
return sum;
like this:
infinite-loop-linked-list.c: In function ‘for_loop_noop_next’:
infinite-loop-linked-list.c:110:31: warning: infinite loop [CWE-835] [-Wanalyzer-infinite-loop]
110 | for (struct node *iter = n; iter; iter->next)
| ^~~~
‘for_loop_noop_next’: events 1-5
|
| 110 | for (struct node *iter = n; iter; iter->next)
| | ^~~~
| | |
| | (1) infinite loop here
| | (2) when ‘iter’ is non-NULL: always following ‘true’ branch...
| | (5) ...to here
| 111 | sum += n->val;
| | ~~~~~~~~~~~~~
| | | |
| | | (3) ...to here
| | (4) looping back...
|
gcc/ChangeLog:
PR analyzer/106147
* Makefile.in (ANALYZER_OBJS): Add analyzer/infinite-loop.o.
* doc/invoke.texi: Add -fdump-analyzer-infinite-loop and
-Wanalyzer-infinite-loop. Add missing CWE link for
-Wanalyzer-infinite-recursion.
* timevar.def (TV_ANALYZER_INFINITE_LOOPS): New.
gcc/analyzer/ChangeLog:
PR analyzer/106147
* analyzer.opt (Wanalyzer-infinite-loop): New option.
(fdump-analyzer-infinite-loop): New option.
* checker-event.h (start_cfg_edge_event::get_desc): Drop "final".
(start_cfg_edge_event::maybe_describe_condition): Convert from
private to protected.
* checker-path.h (checker_path::get_logger): New.
* diagnostic-manager.cc (process_worklist_item): Update for
new context param of maybe_update_for_edge.
* engine.cc
(impl_region_model_context::impl_region_model_context): Add
out_could_have_done_work param to both ctors and use it to
initialize mm_out_could_have_done_work.
(impl_region_model_context::maybe_did_work): New vfunc
implementation.
(exploded_node::on_stmt): Add out_could_have_done_work param and
pass to ctxt ctor.
(exploded_node::on_stmt_pre): Treat setjmp and longjmp as "doing
work".
(exploded_node::on_longjmp): Likewise.
(exploded_edge::exploded_edge): Add "could_do_work" param and use
it to initialize m_could_do_work_p.
(exploded_edge::dump_dot_label): Add result of could_do_work_p.
(exploded_graph::add_function_entry): Mark edge as doing no work.
(exploded_graph::add_edge): Add "could_do_work" param and pass to
exploded_edge ctor.
(add_tainted_args_callback): Treat as doing no work.
(exploded_graph::process_worklist): Likewise when merging nodes.
(maybe_process_run_of_before_supernode_enodes::item): Likewise.
(exploded_graph::maybe_create_dynamic_call): Likewise.
(exploded_graph::process_node): Likewise for phi nodes.
Pass in a "could_have_done_work" bool when handling stmts and use
when creating edges. Assume work is done at bifurcation.
(exploded_path::feasible_p): Update for new context param of
maybe_update_for_edge.
(feasibility_state::feasibility_state): New ctor.
(feasibility_state::operator=): New.
(feasibility_state::maybe_update_for_edge): Add ctxt param and use
it. Fix missing newline when logging state.
(impl_run_checkers): Call exploded_graph::detect_infinite_loops.
* exploded-graph.h
(impl_region_model_context::impl_region_model_context): Add
out_could_have_done_work param to both ctors.
(impl_region_model_context::maybe_did_work): New decl.
(impl_region_model_context::checking_for_infinite_loop_p): New.
(impl_region_model_context::on_unusable_in_infinite_loop): New.
(impl_region_model_context::m_out_could_have_done_work): New
field.
(exploded_node::on_stmt): Add "out_could_have_done_work" param.
(exploded_edge::exploded_edge): Add "could_do_work" param.
(exploded_edge::could_do_work_p): New accessor.
(exploded_edge::m_could_do_work_p): New field.
(exploded_graph::add_edge): Add "could_do_work" param.
(exploded_graph::detect_infinite_loops): New decl.
(feasibility_state::feasibility_state): New ctor.
(feasibility_state::operator=): New decl.
(feasibility_state::maybe_update_for_edge): Add ctxt param.
* infinite-loop.cc: New file.
* program-state.cc (program_state::on_edge): Log the rejected
constraint when region_model::maybe_update_for_edge fails.
* region-model.cc (region_model::on_assignment): Treat any writes
other than to the stack as "doing work".
(region_model::on_stmt_pre): Treat all asm stmts as "doing work".
(region_model::on_call_post): Likewise for all calls to functions
with unknown side effects.
(region_model::handle_phi): Add svals_changing_meaning param.
Mark widening svalue in phi nodes as changing meaning.
(unusable_in_infinite_loop_constraint_p): New.
(region_model::add_constraint): If we're checking for an infinite
loop, bail out on unusable svalues, or if we don't have a definite
true/false for the constraint.
(region_model::update_for_phis): Gather all svalues changing
meaning in phi nodes, and purge constraints involving them.
(region_model::replay_call_summary): Treat all call summaries as
doing work.
(region_model::can_merge_with_p): Purge constraints involving
svalues that change meaning.
(model_merger::on_widening_reuse): New.
(test_iteration_1): Likewise.
(selftest::test_iteration_1): Remove assertion that model6 "knows"
that i < 157.
* region-model.h (region_model::handle_phi): Add
svals_changing_meaning param
(region_model_context::maybe_did_work): New pure virtual func.
(region_model_context::checking_for_infinite_loop_p): Likewise.
(region_model_context::on_unusable_in_infinite_loop): Likewise.
(noop_region_model_context::maybe_did_work): Implement.
(noop_region_model_context::checking_for_infinite_loop_p):
Likewise.
(noop_region_model_context::on_unusable_in_infinite_loop):
Likewise.
(region_model_context_decorator::maybe_did_work): Implement.
(region_model_context_decorator::checking_for_infinite_loop_p):
Likewise.
(region_model_context_decorator::on_unusable_in_infinite_loop):
Likewise.
(model_merger::on_widening_reuse): New decl.
(model_merger::m_svals_changing_meaning): New field.
* sm-signal.cc (register_signal_handler::impl_transition): Assume
the edge "does work".
* supergraph.cc (supernode::get_start_location): Use CFG edge's
goto_locus if available.
(supernode::get_end_location): Likewise.
(cfg_superedge::dump_label_to_pp): Dump edges with a "goto_locus"
* supergraph.h (cfg_superedge::get_goto_locus): New.
* svalue.cc (svalue::can_merge_p): Call on_widening_reuse for
widening values.
(involvement_visitor::visit_widening_svalue): New.
(svalue::involves_p): Update assertion to allow widening svalues.
gcc/testsuite/ChangeLog:
PR analyzer/106147
* c-c++-common/analyzer/gzio-2.c: Add dg-warning for infinite
loop, marked as xfail.
* c-c++-common/analyzer/infinite-loop-2.c: New test.
* c-c++-common/analyzer/infinite-loop-4.c: New test.
* c-c++-common/analyzer/infinite-loop-crc32c.c: New test.
* c-c++-common/analyzer/infinite-loop-doom-d_main-IdentifyVersion.c:
New test.
* c-c++-common/analyzer/infinite-loop-doom-v_video.c: New test.
* c-c++-common/analyzer/infinite-loop-g_error.c: New test.
* c-c++-common/analyzer/infinite-loop-linked-list.c: New test.
* c-c++-common/analyzer/infinite-recursion-inlining.c: Add
dg-warning directives for infinite loop.
* c-c++-common/analyzer/inlining-4-multiline.c: Update expected
paths for event 5 having a location.
* gcc.dg/analyzer/boxed-malloc-1.c: Add dg-warning for infinite
loop.
* gcc.dg/analyzer/data-model-20.c: Likewise. Add comment about
suspect code, and create...
* gcc.dg/analyzer/data-model-20a.c: ...this new test by cleaning
it up.
* gcc.dg/analyzer/edges-1.c: Add a placeholder statement to avoid
the "...to here" from the if stmt occurring at the "while", and
thus being treated as a bogus event.
* gcc.dg/analyzer/explode-2a.c: Add dg-warning for infinite loop.
* gcc.dg/analyzer/infinite-loop-1.c: New test.
* gcc.dg/analyzer/malloc-1.c: Add dg-warning for infinite loop.
* gcc.dg/analyzer/out-of-bounds-coreutils.c: Add TODO.
* gcc.dg/analyzer/paths-4.c: Add dg-warning for infinite loop.
* gcc.dg/analyzer/pr103892.c: Likewise.
* gcc.dg/analyzer/pr93546.c: Likewise.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
This patch extends the existing diagnostic_path class so that as well
as list of events, there is a list of named threads, with each event
being associated with one of the threads.
No GCC diagnostics take advantage of this, but GCC plugins may find a
use for this; an example is provided in the testsuite.
Given that there is still a single list of events within a
diagnostic_path, the events in a diagnostic_path have a specific global
ordering even if they are in multiple threads.
Within the SARIF serialization, the patch adds the "executionOrder"
property to threadFlowLocation objects (SARIF v2.1.0 3.38.11). This is
1-based in order to match the human-readable numbering of events shown
in messages emitted by pretty-printer.cc's "%@".
With -fdiagnostics-path-format=separate-events, the threads are not
shown.
With -fdiagnostics-path-format=inline-events, the threads and the
per-thread stack activity are tracked and visalized separately. An
example can be seen in the testsuite.
gcc/analyzer/ChangeLog:
* checker-event.h (checker_event::get_thread_id): New.
* checker-path.h (class checker_path): Implement thread-related
vfuncs via a single simple_diagnostic_thread instance named
"main".
gcc/ChangeLog:
* diagnostic-event-id.h (diagnostic_thread_id_t): New typedef.
* diagnostic-format-sarif.cc (class sarif_thread_flow): New.
(sarif_thread_flow::sarif_thread_flow): New.
(sarif_builder::make_code_flow_object): Reimplement, creating
per-thread threadFlow objects, populating them with the relevant
events.
(sarif_builder::make_thread_flow_object): Delete, moving the
code into sarif_builder::make_code_flow_object.
(sarif_builder::make_thread_flow_location_object): Add
"path_event_idx" param. Use it to set "executionOrder"
property.
* diagnostic-path.h (diagnostic_event::get_thread_id): New
pure-virtual vfunc.
(class diagnostic_thread): New.
(diagnostic_path::num_threads): New pure-virtual vfunc.
(diagnostic_path::get_thread): New pure-virtual vfunc.
(diagnostic_path::multithreaded_p): New decl.
(simple_diagnostic_event::simple_diagnostic_event): Add optional
thread_id param.
(simple_diagnostic_event::get_thread_id): New accessor.
(simple_diagnostic_event::m_thread_id): New.
(class simple_diagnostic_thread): New.
(simple_diagnostic_path::simple_diagnostic_path): Move definition
to diagnostic.cc.
(simple_diagnostic_path::num_threads): New.
(simple_diagnostic_path::get_thread): New.
(simple_diagnostic_path::add_thread): New.
(simple_diagnostic_path::add_thread_event): New.
(simple_diagnostic_path::m_threads): New.
* diagnostic-show-locus.cc (layout::layout): Add pretty_printer
param for overriding the context's printer.
(diagnostic_show_locus): Likwise.
* diagnostic.cc (simple_diagnostic_path::simple_diagnostic_path):
Move here from diagnostic-path.h. Add main thread.
(simple_diagnostic_path::num_threads): New.
(simple_diagnostic_path::get_thread): New.
(simple_diagnostic_path::add_thread): New.
(simple_diagnostic_path::add_thread_event): New.
(simple_diagnostic_event::simple_diagnostic_event): Add thread_id
param and use it to initialize m_thread_id. Reformat.
* diagnostic.h: Add pretty_printer param for overriding the
context's printer.
* tree-diagnostic-path.cc: Add #define INCLUDE_VECTOR.
(can_consolidate_events): Compare thread ids.
(class per_thread_summary): New.
(event_range::event_range): Add per_thread_summary arg.
(event_range::print): Add "pp" param and use it rather than dc's
printer.
(event_range::m_thread_id): New field.
(event_range::m_per_thread_summary): New field.
(path_summary::multithreaded_p): New.
(path_summary::get_events_for_thread_id): New.
(path_summary::m_per_thread_summary): New field.
(path_summary::m_thread_id_to_events): New field.
(path_summary::get_or_create_events_for_thread_id): New.
(path_summary::path_summary): Create per_thread_summary instances
as needed and associate the event_range instances with them.
(base_indent): Move here from print_path_summary_as_text.
(per_frame_indent): Likewise.
(class thread_event_printer): New, adapted from parts of
print_path_summary_as_text.
(print_path_summary_as_text): Make static. Reimplement to
moving most of existing code to class thread_event_printer,
capturing state as per-thread as appropriate.
(default_tree_diagnostic_path_printer): Add missing 'break' on
final case.
gcc/testsuite/ChangeLog:
* gcc.dg/plugin/diagnostic-test-paths-multithreaded-inline-events.c:
New test.
* gcc.dg/plugin/diagnostic-test-paths-multithreaded-sarif.c: New
test.
* gcc.dg/plugin/diagnostic-test-paths-multithreaded-separate-events.c:
New test.
* gcc.dg/plugin/diagnostic_plugin_test_paths.c: Add support for
generating multithreaded paths.
* gcc.dg/plugin/plugin.exp: Add the new tests.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
|
|
gcc/analyzer/ChangeLog:
* analyzer.h (struct event_loc_info): New forward decl.
* bounds-checking.cc: Use event_loc_info throughout to bundle the
loc, fndecl, depth triples.
* call-info.cc: Likewise.
* checker-event.cc: Likewise.
* checker-event.h (struct event_loc_info): New decl. Use it
throughout to bundle the loc, fndecl, depth triples.
* checker-path.cc: Likewise.
* checker-path.h: Likewise.
* diagnostic-manager.cc: Likewise.
* engine.cc: Likewise.
* infinite-recursion.cc: Likewise.
* pending-diagnostic.cc: Likewise.
* pending-diagnostic.h: Likewise.
* region-model.cc: Likewise.
* sm-signal.cc: Likewise.
* varargs.cc: Likewise.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
In r13-2573-gc81b60b8c6ff3d I split up the analyzer's region-creation
events to describe the memory space and capacity of the region as two
separate events to avoid combinatorial explosion of message wordings.
However I didn't take into account r13-1405-ge6c3bb379f515b which
added a pending_diagnostic::describe_region_creation_event vfunc which
could change the wording of region creation events.
Hence for:
#include <stdlib.h>
#include <stdint.h>
void test ()
{
int32_t *ptr = malloc (1);
free (ptr);
}
trunk currently emits:
Compiler Explorer (x86_64 trunk): https://godbolt.org/z/e3Td7c9s5:
<source>: In function 'test':
<source>:6:18: warning: allocated buffer size is not a multiple of the pointee's size [CWE-131] [-Wanalyzer-allocation-size]
6 | int32_t *ptr = malloc (1);
| ^~~~~~~~~~
'test': events 1-3
|
| 6 | int32_t *ptr = malloc (1);
| | ^~~~~~~~~~
| | |
| | (1) allocated 1 bytes here
| | (2) allocated 1 bytes here
| | (3) assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4'
|
where events (1) and (2) are different region_creation_events that have
had their wording overridden (also, with a "1 bytes" issue).
This patch reorganizes region creation events so that each
pending_diagnostic instead creates the events that is appropriate for it,
and the events have responsibility for their own wording.
With this patch, the above emits:
<source>: In function 'test':
<source>:6:18: warning: allocated buffer size is not a multiple of the pointee's size [CWE-131] [-Wanalyzer-allocation-size]
6 | int32_t *ptr = malloc (1);
| ^~~~~~~~~~
'test': events 1-2
|
| 6 | int32_t *ptr = malloc (1);
| | ^~~~~~~~~~
| | |
| | (1) allocated 1 byte here
| | (2) assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4'
|
fixing the duplicate event, and fixing the singular/plural issue.
gcc/analyzer/ChangeLog:
PR analyzer/107851
* analyzer.cc (make_label_text_n): Convert param "n" from int to
unsigned HOST_WIDE_INT.
* analyzer.h (make_label_text_n): Likewise for decl.
* bounds-checking.cc: Include "analyzer/checker-event.h" and
"analyzer/checker-path.h".
(out_of_bounds::add_region_creation_events): New.
(concrete_past_the_end::describe_region_creation_event): Replace
with...
(concrete_past_the_end::add_region_creation_events): ...this.
(symbolic_past_the_end::describe_region_creation_event): Delete.
* checker-event.cc (region_creation_event::region_creation_event):
Update for dropping all member data.
(region_creation_event::get_desc): Delete, splitting out into
region_creation_event_memory_space::get_desc,
region_creation_event_capacity::get_desc, and
region_creation_event_debug::get_desc.
(region_creation_event_memory_space::get_desc): New.
(region_creation_event_capacity::get_desc): New.
(region_creation_event_allocation_size::get_desc): New.
(region_creation_event_debug::get_desc): New.
* checker-event.h: Include "analyzer/program-state.h".
(enum rce_kind): Delete.
(class region_creation_event): Drop all member data.
(region_creation_event::region_creation_event): Make protected.
(region_creation_event::get_desc): Delete.
(class region_creation_event_memory_space): New.
(class region_creation_event_capacity): New.
(class region_creation_event_allocation_size): New.
(class region_creation_event_debug): New.
* checker-path.cc (checker_path::add_region_creation_events): Add
"pd" param. Call pending_diangnostic::add_region_creation_events.
Update for conversion of RCE_DEBUG to region_creation_event_debug.
* checker-path.h (checker_path::add_region_creation_events): Add
"pd" param.
* diagnostic-manager.cc (diagnostic_manager::build_emission_path):
Pass pending_diagnostic to
emission_path::add_region_creation_events.
(diagnostic_manager::build_emission_path): Pass path_builder to
add_event_on_final_node.
(diagnostic_manager::add_event_on_final_node): Add "pb" param.
Pass pending_diagnostic to
emission_path::add_region_creation_events.
(diagnostic_manager::add_events_for_eedge): Pass
pending_diagnostic to emission_path::add_region_creation_events.
* diagnostic-manager.h
(diagnostic_manager::add_event_on_final_node): Add "pb" param.
* pending-diagnostic.cc
(pending_diagnostic::add_region_creation_events): New.
* pending-diagnostic.h (struct region_creation): Delete.
(pending_diagnostic::describe_region_creation_event): Delete.
(pending_diagnostic::add_region_creation_events): New vfunc.
* region-model.cc: Include "analyzer/checker-event.h" and
"analyzer/checker-path.h".
(dubious_allocation_size::dubious_allocation_size): Initialize
m_has_allocation_event.
(dubious_allocation_size::describe_region_creation_event): Delete.
(dubious_allocation_size::describe_final_event): Update for
replacement of m_allocation_event with m_has_allocation_event.
(dubious_allocation_size::add_region_creation_events): New.
(dubious_allocation_size::m_allocation_event): Replace with...
(dubious_allocation_size::m_has_allocation_event): ...this.
gcc/testsuite/ChangeLog:
PR analyzer/107851
* gcc.dg/analyzer/allocation-size-4.c: Update expected wording.
* gcc.dg/analyzer/allocation-size-multiline-1.c: New test.
* gcc.dg/analyzer/allocation-size-multiline-2.c: New test.
* gcc.dg/analyzer/out-of-bounds-multiline-1.c: Update expected
wording.
* gcc.dg/analyzer/out-of-bounds-multiline-2.c: New test.
* gcc.dg/analyzer/out-of-bounds-read-char-arr.c: Update expected
wording.
* gcc.dg/analyzer/out-of-bounds-read-int-arr.c: Likewise.
* gcc.dg/analyzer/out-of-bounds-write-char-arr.c: Likewise.
* gcc.dg/analyzer/out-of-bounds-write-int-arr.c: Likewise.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
gcc/analyzer/ChangeLog:
* checker-path.h: Split out checker_event and its subclasses to...
* checker-event.h: ...this new header.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
This patch adds a new -Wanalyzer-infinite-recursion warning to
-fanalyzer, which complains about certain cases of infinite recursion.
Specifically, when it detects recursion during its symbolic execution
of the user's code, it compares the state of memory to that at the
previous level of recursion, and if nothing appears to have effectively
changed, it issues a warning.
Unlike the middle-end warning -Winfinite-recursion (added by Martin
Sebor in GCC 12; r12-5483-g30ba058f77eedf), the analyzer warning
complains if there exists an interprocedural path in which recursion
occurs in which memory has not changed, whereas -Winfinite-recursion
complains if *every* intraprocedural path through the function leads to
a self-call.
Hence the warnings complement each other: there's some overlap, but each
also catches issues that the other misses.
For example, the new warning complains about a guarded recursion in
which the guard is passed unchanged:
void test_guarded (int flag)
{
if (flag)
test_guarded (flag);
}
t.c: In function 'test_guarded':
t.c:4:5: warning: infinite recursion [CWE-674] [-Wanalyzer-infinite-recursion]
4 | test_guarded (flag);
| ^~~~~~~~~~~~~~~~~~~
'test_guarded': events 1-4
|
| 1 | void test_guarded (int flag)
| | ^~~~~~~~~~~~
| | |
| | (1) initial entry to 'test_guarded'
| 2 | {
| 3 | if (flag)
| | ~
| | |
| | (2) following 'true' branch (when 'flag != 0')...
| 4 | test_guarded (flag);
| | ~~~~~~~~~~~~~~~~~~~
| | |
| | (3) ...to here
| | (4) calling 'test_guarded' from 'test_guarded'
|
+--> 'test_guarded': events 5-6
|
| 1 | void test_guarded (int flag)
| | ^~~~~~~~~~~~
| | |
| | (5) recursive entry to 'test_guarded'; previously entered at (1)
| | (6) apparently infinite recursion
|
whereas the existing warning doesn't complain, since when "flag" is
false the function doesn't recurse.
The new warning doesn't trigger for e.g.:
void test_param_variant (int depth)
{
if (depth > 0)
test_param_variant (depth - 1);
}
on the grounds that "depth" is changing, and appears to be a variant
that enforces termination of the recursion.
gcc/ChangeLog:
PR analyzer/106147
* Makefile.in (ANALYZER_OBJS): Add analyzer/infinite-recursion.o.
gcc/analyzer/ChangeLog:
PR analyzer/106147
* analyzer.opt (Wanalyzer-infinite-recursion): New.
* call-string.cc (call_string::count_occurrences_of_function):
New.
* call-string.h (call_string::count_occurrences_of_function): New
decl.
* checker-path.cc (function_entry_event::function_entry_event):
New ctor.
(checker_path::add_final_event): Delete.
* checker-path.h (function_entry_event::function_entry_event): New
ctor.
(function_entry_event::get_desc): Drop "final".
(checker_path::add_final_event): Delete.
* diagnostic-manager.cc
(diagnostic_manager::emit_saved_diagnostic): Create the final
event via a new pending_diagnostic::add_final_event vfunc, rather
than checker_path::add_final_event.
(diagnostic_manager::add_events_for_eedge): Create function entry
events via a new pending_diagnostic::add_function_entry_event
vfunc.
* engine.cc (exploded_graph::process_node): When creating a new
PK_BEFORE_SUPERNODE node, call
exploded_graph::detect_infinite_recursion on it after adding the
in-edge.
* exploded-graph.h (exploded_graph::detect_infinite_recursion):
New decl.
(exploded_graph::find_previous_entry_to): New decl.
* infinite-recursion.cc: New file.
* pending-diagnostic.cc
(pending_diagnostic::add_function_entry_event): New.
(pending_diagnostic::add_final_event): New.
* pending-diagnostic.h
(pending_diagnostic::add_function_entry_event): New vfunc.
(pending_diagnostic::add_final_event): New vfunc.
gcc/ChangeLog:
PR analyzer/106147
* doc/gcc/gcc-command-options/options-that-control-static-analysis.rst:
Add -Wanalyzer-infinite-recursion.
* doc/gcc/gcc-command-options/options-to-request-or-suppress-warnings.rst
(-Winfinite-recursion): Mention -Wanalyzer-infinite-recursion.
gcc/testsuite/ChangeLog:
PR analyzer/106147
* g++.dg/analyzer/infinite-recursion-1.C: New test.
* g++.dg/analyzer/infinite-recursion-2.C: New test, copied from
g++.dg/warn/Winfinite-recursion-2.C.
* g++.dg/analyzer/infinite-recursion-3.C: New test, adapted from
g++.dg/warn/Winfinite-recursion-3.C.
* gcc.dg/analyzer/infinite-recursion-2.c: New test.
* gcc.dg/analyzer/infinite-recursion-3.c: New test.
* gcc.dg/analyzer/infinite-recursion-4-limited-buggy.c: New test.
* gcc.dg/analyzer/infinite-recursion-4-limited.c: New test.
* gcc.dg/analyzer/infinite-recursion-4-unlimited-buggy.c: New test.
* gcc.dg/analyzer/infinite-recursion-4-unlimited.c: New test.
* gcc.dg/analyzer/infinite-recursion-5.c: New test, adapted from
gcc.dg/Winfinite-recursion.c.
* gcc.dg/analyzer/infinite-recursion-alloca.c: New test.
* gcc.dg/analyzer/infinite-recursion-inlining.c: New test.
* gcc.dg/analyzer/infinite-recursion-multiline-1.c: New test.
* gcc.dg/analyzer/infinite-recursion-multiline-2.c: New test.
* gcc.dg/analyzer/infinite-recursion-variadic.c: New test.
* gcc.dg/analyzer/infinite-recursion.c: Add dg-warning directives
where infinite recursions occur.
* gcc.dg/analyzer/malloc-ipa-12.c: Likewise.
* gcc.dg/analyzer/pr105365.c: Likewise.
* gcc.dg/analyzer/pr105366.c: Likewise.
* gcc.dg/analyzer/pr97029.c: Likewise.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
gcc/analyzer/ChangeLog:
* checker-path.cc (checker_event::debug): New.
(checker_path::add_event): Move here from checker-path.h. Add
logging.
* checker-path.h (checker_event::debug): New decl.
(checker_path::checker_path): Add logger param.
(checker_path::add_event): Move definition from here to
checker-path.cc.
(checker_path::m_logger): New field.
* diagnostic-manager.cc
(diagnostic_manager::emit_saved_diagnostic): Pass logger to
checker_path ctor.
(diagnostic_manager::add_events_for_eedge): Log scope when
processing a run of stmts.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
gcc/analyzer/ChangeLog:
* call-info.cc: Use std::unique_ptr for checker_event.
* checker-path.cc: Likewise.
* checker-path.h: Likewise.
* diagnostic-manager.cc: Likewise.
* engine.cc: Likewise.
* pending-diagnostic.cc: Likewise.
* sm-signal.cc: Likewise.
* varargs.cc: Likewise.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
This is a less ambitious version of:
[PATCH 0/6] RFC: adding support to GCC for detecting trust boundaries
https://gcc.gnu.org/pipermail/gcc-patches/2021-November/584372.html
Earlier versions of this patch attempted:
(a) various ways of identifying "untrusted" memory regions
(b) providing a way to support the Linux kernel's "__user" annotation,
either via type attributes, or via custom address spaces
(c) enough attributes to identify "copy_from_user" and "copy_to_user",
(d) wiring all of the above together to detect infoleaks and taint
This patch adds a new -Wanalyzer-exposure-through-uninit-copy, emitted
by -fanalyzer if it detects copying of uninitialized data through
a pointer to an untrusted region, but requires a plugin to tell it when
a copy crosses a trust boundary.
This patch adds a proof-of-concept gcc plugin for the analyzer for use
with the Linux kernel that special-cases calls to "copy_from_user" and
calls to "copy_to_user": calls to copy_to_user are checked for
-Wanalyzer-exposure-through-uninit-copy, and data copied via
copy_from_user is marked as tainted when -fanalyzer-checker=taint is
active.
This is very much just a proof-of-concept. A big limitation is that the
copy_{from,to}_user special-casing only happens if these functions have
no body in the TU being analyzed, which isn't the case for a normal
kernel build. I'd much prefer to provide a more general mechanism for
handling such behavior without resorting to plugins (e.g. via attributes
or custom address spaces), but in the interest of not "letting perfect
be the enemy of the good" this patch at least allows parts of this
"trust boundaries" code to be merged for experimentation with the idea.
The -Wanalyzer-exposure-through-uninit-copy diagnostic uses notes to
express what fields and padding within a struct have not been initialized.
For example:
infoleak-CVE-2011-1078-2.c: In function 'test_1':
infoleak-CVE-2011-1078-2.c:32:9: warning: potential exposure of sensitive
information by copying uninitialized data from stack across trust
boundary [CWE-200] [-Wanalyzer-exposure-through-uninit-copy]
32 | copy_to_user(optval, &cinfo, sizeof(cinfo));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'test_1': events 1-3
|
| 25 | struct sco_conninfo cinfo;
| | ^~~~~
| | |
| | (1) region created on stack here
| | (2) capacity: 6 bytes
|......
| 32 | copy_to_user(optval, &cinfo, sizeof(cinfo));
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (3) uninitialized data copied from stack here
|
infoleak-CVE-2011-1078-2.c:32:9: note: 1 byte is uninitialized
32 | copy_to_user(optval, &cinfo, sizeof(cinfo));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
infoleak-CVE-2011-1078-2.c:18:15: note: padding after field 'dev_class'
is uninitialized (1 byte)
18 | __u8 dev_class[3];
| ^~~~~~~~~
infoleak-CVE-2011-1078-2.c:25:29: note: suggest forcing
zero-initialization by providing a '{0}' initializer
25 | struct sco_conninfo cinfo;
| ^~~~~
| = {0}
For taint-detection, the patch includes a series of reproducers for
detecting CVE-2011-0521. Unfortunately the analyzer doesn't yet detect
the issue until the code has been significantly simplified from its
original form: currently only in -5.c and -6.c in the series of test
(see notes in the individual cases), such as:
taint-CVE-2011-0521-6.c:33:48: warning: use of attacker-controlled value
'*info.num' in array lookup without bounds checking [CWE-129]
[-Wanalyzer-tainted-array-index]
33 | av7110->ci_slot[info->num].num = info->num;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
'test_1': events 1-3
|
| 19 | if (copy_from_user(&sbuf, (void __user *)arg, sizeof(sbuf)) != 0)
| | ^
| | |
| | (1) following 'false' branch...
|......
| 23 | struct dvb_device *dvbdev = file->private_data;
| | ~~~~~~
| | |
| | (2) ...to here
|......
| 33 | av7110->ci_slot[info->num].num = info->num;
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (3) use of attacker-controlled value '*info.num' in array lookup without bounds checking
|
The patch also includes various infoleak and taint cases from my
antipatterns.ko kernel module:
https://github.com/davidmalcolm/antipatterns.ko
gcc/analyzer/ChangeLog:
* analyzer.opt (Wanalyzer-exposure-through-uninit-copy): New.
* checker-path.cc (region_creation_event::region_creation_event):
Add "capacity" and "kind" params.
(region_creation_event::get_desc): Generalize to different kinds
of event.
(checker_path::add_region_creation_event): Convert to...
(checker_path::add_region_creation_events): ...this.
* checker-path.h (enum rce_kind): New.
(region_creation_event::region_creation_event): Add "capacity" and
"kind" params.
(region_creation_event::m_capacity): New field.
(region_creation_event::m_rce_kind): New field.
(checker_path::add_region_creation_event): Convert to...
(checker_path::add_region_creation_events): ...this.
* diagnostic-manager.cc (diagnostic_manager::build_emission_path):
Update for multiple region creation events.
(diagnostic_manager::add_event_on_final_node): Likewise.
(diagnostic_manager::add_events_for_eedge): Likewise.
* region-model-impl-calls.cc (call_details::get_logger): New.
* region-model.cc: Define INCLUDE_MEMORY before including
"system.h". Include "gcc-rich-location.h".
(class record_layout): New.
(class exposure_through_uninit_copy): New.
(contains_uninit_p): New.
(region_model::maybe_complain_about_infoleak): New.
* region-model.h (call_details::get_logger): New decl.
(region_model::maybe_complain_about_infoleak): New decl.
(region_model::mark_as_tainted): New decl.
* sm-taint.cc (region_model::mark_as_tainted): New.
gcc/ChangeLog:
* doc/invoke.texi (Static Analyzer Options): Add
-Wanalyzer-exposure-through-uninit-copy.
gcc/testsuite/ChangeLog:
* gcc.dg/plugin/analyzer_kernel_plugin.c: New test.
* gcc.dg/plugin/copy_from_user-1.c: New test.
* gcc.dg/plugin/infoleak-1.c: New test.
* gcc.dg/plugin/infoleak-2.c: New test.
* gcc.dg/plugin/infoleak-3.c: New test.
* gcc.dg/plugin/infoleak-CVE-2011-1078-1.c: New test.
* gcc.dg/plugin/infoleak-CVE-2011-1078-2.c: New test.
* gcc.dg/plugin/infoleak-CVE-2014-1446-1.c: New test.
* gcc.dg/plugin/infoleak-CVE-2017-18549-1.c: New test.
* gcc.dg/plugin/infoleak-CVE-2017-18550-1.c: New test.
* gcc.dg/plugin/infoleak-antipatterns-1.c: New test.
* gcc.dg/plugin/infoleak-fixit-1.c: New test.
* gcc.dg/plugin/infoleak-net-ethtool-ioctl.c: New test.
* gcc.dg/plugin/infoleak-vfio_iommu_type1.c: New test.
* gcc.dg/plugin/plugin.exp (plugin_test_list): Add
analyzer_kernel_plugin.c and the new test cases.
* gcc.dg/plugin/taint-CVE-2011-0521-1-fixed.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-1.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-2-fixed.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-2.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-3-fixed.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-3.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-4.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-5.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-6.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521.h: New test.
* gcc.dg/plugin/taint-antipatterns-1.c: New test.
* gcc.dg/plugin/test-uaccess.h: New header for tests.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
This patch adds an checker that warns about code paths in which a buffer
is assigned to a incompatible type, i.e. when the allocated buffer size
is not a multiple of the pointee's size.
Regression-tested on x86_64 Linux. Also compiled coreutils, curl, openssh and
httpd with the patch enabled.
2022-07-01 Tim Lange <mail@tim-lange.me>
gcc/analyzer/ChangeLog:
PR analyzer/105900
* analyzer.opt: Added Wanalyzer-allocation-size.
* checker-path.cc (region_creation_event::get_desc): Added call to new
virtual function pending_diagnostic::describe_region_creation_event.
* checker-path.h: Added region_creation_event::get_desc.
* diagnostic-manager.cc (diagnostic_manager::add_event_on_final_node):
New function.
* diagnostic-manager.h:
Added diagnostic_manager::add_event_on_final_node.
* pending-diagnostic.h (struct region_creation): New event_desc struct.
(pending_diagnostic::describe_region_creation_event): Added virtual
function to overwrite description of a region creation.
* region-model.cc (class dubious_allocation_size): New class.
(capacity_compatible_with_type): New helper function.
(class size_visitor): New class.
(struct_or_union_with_inheritance_p): New helper function.
(is_any_cast_p): New helper function.
(region_model::check_region_size): New function.
(region_model::set_value): Added call to
region_model::check_region_size.
* region-model.h (class region_model): New function check_region_size.
* svalue.cc (region_svalue::accept): Changed to post-order traversal.
(initial_svalue::accept): Likewise.
(unaryop_svalue::accept): Likewise.
(binop_svalue::accept): Likewise.
(sub_svalue::accept): Likewise.
(repeated_svalue::accept): Likewise.
(bits_within_svalue::accept): Likewise.
(widening_svalue::accept): Likewise.
(unmergeable_svalue::accept): Likewise.
(compound_svalue::accept): Likewise.
(conjured_svalue::accept): Likewise.
(asm_output_svalue::accept): Likewise.
(const_fn_result_svalue::accept): Likewise.
gcc/ChangeLog:
PR analyzer/105900
* doc/invoke.texi: Added Wanalyzer-allocation-size.
gcc/testsuite/ChangeLog:
PR analyzer/105900
* gcc.dg/analyzer/pr96639.c: Changed buffer size to omit warning.
* gcc.dg/analyzer/allocation-size-1.c: New test.
* gcc.dg/analyzer/allocation-size-2.c: New test.
* gcc.dg/analyzer/allocation-size-3.c: New test.
* gcc.dg/analyzer/allocation-size-4.c: New test.
* gcc.dg/analyzer/allocation-size-5.c: New test.
Signed-off-by: Tim Lange <mail@tim-lange.me>
|
|
-fanalyzer runs late compared to other code analysis tools, in that in
runs on the partially-optimized gimple-ssa representation. I chose this
point to run in the hope of easy integration with LTO.
As PR analyzer/105962 notes, this means that function inlining can occur
before the -fanalyzer "sees" the user's code. For example given:
void foo (void *p)
{
__builtin_free (p);
}
void bar (void *q)
{
foo (q);
foo (q);
}
Below -O2, -fanalyzer shows the calls and returns:
inline-1.c: In function ‘foo’:
inline-1.c:3:3: warning: double-‘free’ of ‘p’ [CWE-415] [-Wanalyzer-double-free]
3 | __builtin_free (p);
| ^~~~~~~~~~~~~~~~~~
‘bar’: events 1-2
|
| 6 | void bar (void *q)
| | ^~~
| | |
| | (1) entry to ‘bar’
| 7 | {
| 8 | foo (q);
| | ~~~~~~~
| | |
| | (2) calling ‘foo’ from ‘bar’
|
+--> ‘foo’: events 3-4
|
| 1 | void foo (void *p)
| | ^~~
| | |
| | (3) entry to ‘foo’
| 2 | {
| 3 | __builtin_free (p);
| | ~~~~~~~~~~~~~~~~~~
| | |
| | (4) first ‘free’ here
|
<------+
|
‘bar’: events 5-6
|
| 8 | foo (q);
| | ^~~~~~~
| | |
| | (5) returning to ‘bar’ from ‘foo’
| 9 | foo (q);
| | ~~~~~~~
| | |
| | (6) passing freed pointer ‘q’ in call to ‘foo’ from ‘bar’
|
+--> ‘foo’: events 7-8
|
| 1 | void foo (void *p)
| | ^~~
| | |
| | (7) entry to ‘foo’
| 2 | {
| 3 | __builtin_free (p);
| | ~~~~~~~~~~~~~~~~~~
| | |
| | (8) second ‘free’ here; first ‘free’ was at (4)
|
but at -O2, -fanalyzer "sees" this gimple:
void bar (void * q)
{
<bb 2> [local count: 1073741824]:
__builtin_free (q_2(D));
__builtin_free (q_2(D));
return;
}
where "foo" has been inlined away, leading to this unhelpful output:
In function ‘foo’,
inlined from ‘bar’ at inline-1.c:9:3:
inline-1.c:3:3: warning: double-‘free’ of ‘q’ [CWE-415] [-Wanalyzer-double-free]
3 | __builtin_free (p);
| ^~~~~~~~~~~~~~~~~~
‘bar’: events 1-2
|
| 3 | __builtin_free (p);
| | ^~~~~~~~~~~~~~~~~~
| | |
| | (1) first ‘free’ here
| | (2) second ‘free’ here; first ‘free’ was at (1)
where the stack frame information in the execution path suggests that these
events are happening in "bar", in the top stack frame.
This is what the analyzer sees, but I find it hard to decipher such
output. Hence, as a workaround for the fact that -fanalyzer runs so
late, this patch attempts to reconstruct the "true" stack frame
information, and to inject events showing inline calls, based on the
inlining chain information recorded in the location_t values for the events.
Doing so leads to this output at -O2 on the above example (with
-fdiagnostics-show-path-depths):
In function ‘foo’,
inlined from ‘bar’ at inline-1.c:9:3:
inline-1.c:3:3: warning: double-‘free’ of ‘q’ [CWE-415] [-Wanalyzer-double-free]
3 | __builtin_free (p);
| ^~~~~~~~~~~~~~~~~~
‘bar’: events 1-2 (depth 1)
|
| 6 | void bar (void *q)
| | ^~~
| | |
| | (1) entry to ‘bar’
| 7 | {
| 8 | foo (q);
| | ~
| | |
| | (2) inlined call to ‘foo’ from ‘bar’
|
+--> ‘foo’: event 3 (depth 2)
|
| 3 | __builtin_free (p);
| | ^~~~~~~~~~~~~~~~~~
| | |
| | (3) first ‘free’ here
|
<------+
|
‘bar’: event 4 (depth 1)
|
| 9 | foo (q);
| | ^
| | |
| | (4) inlined call to ‘foo’ from ‘bar’
|
+--> ‘foo’: event 5 (depth 2)
|
| 3 | __builtin_free (p);
| | ^~~~~~~~~~~~~~~~~~
| | |
| | (5) second ‘free’ here; first ‘free’ was at (3)
|
reconstructing the calls and returns.
The patch also adds a new option, -fno-analyzer-undo-inlining, which can
be used to disable this reconstruction, restoring the output listed
above (this time with -fdiagnostics-show-path-depths):
In function ‘foo’,
inlined from ‘bar’ at inline-1.c:9:3:
inline-1.c:3:3: warning: double-‘free’ of ‘q’ [CWE-415] [-Wanalyzer-double-free]
3 | __builtin_free (p);
| ^~~~~~~~~~~~~~~~~~
‘bar’: events 1-2 (depth 1)
|
| 3 | __builtin_free (p);
| | ^~~~~~~~~~~~~~~~~~
| | |
| | (1) first ‘free’ here
| | (2) second ‘free’ here; first ‘free’ was at (1)
|
gcc/analyzer/ChangeLog:
PR analyzer/105962
* analyzer.opt (fanalyzer-undo-inlining): New option.
* checker-path.cc: Include "diagnostic-core.h" and
"inlining-iterator.h".
(event_kind_to_string): Handle EK_INLINED_CALL.
(class inlining_info): New class.
(checker_event::checker_event): Move here from checker-path.h.
Store original fndecl and depth, and calculate effective fndecl
and depth based on inlining information.
(checker_event::dump): Emit original depth as well as effective
depth when they differ; likewise for fndecl.
(region_creation_event::get_desc): Use m_effective_fndecl.
(inlined_call_event::get_desc): New.
(inlined_call_event::get_meaning): New.
(checker_path::inject_any_inlined_call_events): New.
* checker-path.h (enum event_kind): Add EK_INLINED_CALL.
(checker_event::checker_event): Make protected, and move
definition to checker-path.cc.
(checker_event::get_fndecl): Use effective fndecl.
(checker_event::get_stack_depth): Use effective stack depth.
(checker_event::get_logical_location): Use effective stack depth.
(checker_event::get_original_stack_depth): New.
(checker_event::m_fndecl): Rename to...
(checker_event::m_original_fndecl): ...this.
(checker_event::m_depth): Rename to...
(checker_event::m_original_depth): ...this.
(checker_event::m_effective_fndecl): New field.
(checker_event::m_effective_depth): New field.
(class inlined_call_event): New checker_event subclass.
(checker_path::inject_any_inlined_call_events): New decl.
* diagnostic-manager.cc: Include "inlining-iterator.h".
(diagnostic_manager::emit_saved_diagnostic): Call
checker_path::inject_any_inlined_call_events.
(diagnostic_manager::prune_for_sm_diagnostic): Handle
EK_INLINED_CALL.
* engine.cc (tainted_args_function_custom_event::get_desc): Use
effective fndecl.
* inlining-iterator.h: New file.
gcc/testsuite/ChangeLog:
PR analyzer/105962
* gcc.dg/analyzer/inlining-1-multiline.c: New test.
* gcc.dg/analyzer/inlining-1-no-undo.c: New test.
* gcc.dg/analyzer/inlining-1.c: New test.
* gcc.dg/analyzer/inlining-2-multiline.c: New test.
* gcc.dg/analyzer/inlining-2.c: New test.
* gcc.dg/analyzer/inlining-3-multiline.c: New test.
* gcc.dg/analyzer/inlining-3.c: New test.
* gcc.dg/analyzer/inlining-4-multiline.c: New test.
* gcc.dg/analyzer/inlining-4.c: New test.
* gcc.dg/analyzer/inlining-5-multiline.c: New test.
* gcc.dg/analyzer/inlining-5.c: New test.
* gcc.dg/analyzer/inlining-6-multiline.c: New test.
* gcc.dg/analyzer/inlining-6.c: New test.
* gcc.dg/analyzer/inlining-7-multiline.c: New test.
* gcc.dg/analyzer/inlining-7.c: New test.
gcc/ChangeLog:
PR analyzer/105962
* doc/invoke.texi: Add -fno-analyzer-undo-inlining.
* tree-diagnostic-path.cc (default_tree_diagnostic_path_printer):
Extend -fdiagnostics-path-format=separate-events so that with
-fdiagnostics-show-path-depths it prints fndecls as well as stack
depths.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
This patch adds support to gcc's diagnostic subsystem for emitting
diagnostics in SARIF, aka the Static Analysis Results Interchange Format:
https://sarifweb.azurewebsites.net/
by extending -fdiagnostics-format= to add two new options:
-fdiagnostics-format=sarif-stderr
and:
-fdiagnostics-format=sarif-file
The patch targets SARIF v2.1.0
This is a JSON-based format suited for capturing the results of static
analysis tools (like GCC's -fanalyzer), but it can also be used for plain
GCC warnings and errors.
SARIF supports per-event metadata in diagnostic paths such as
["acquire", "resource"] and ["release", "lock"] (specifically, the
threadFlowLocation "kinds" property: SARIF v2.1.0 section 3.38.8), so
the patch extends GCC"s diagnostic_event subclass with a "struct meaning"
with similar purpose. The patch implements this for -fanalyzer so that
the various state-machine-based warnings set these in the SARIF output.
The heart of the implementation is in the new file
diagnostic-format-sarif.cc. Much of the rest of the patch is interface
classes, isolating the diagnostic subsystem (which has no knowledge of
e.g. tree or langhook) from the "client" code in the compiler proper
cc1 etc).
The patch adds a langhook for specifying the SARIF v2.1.0
"artifact.sourceLanguage" property, based on the list in
SARIF v2.1.0 Appendix J.
The patch adds automated DejaGnu tests to our testsuite via new
scan-sarif-file and scan-sarif-file-not directives (although these
merely use regexps, rather than attempting to use a proper JSON parser).
I've tested the patch by hand using the validator at:
https://sarifweb.azurewebsites.net/Validation
and the react-based viewer at:
https://microsoft.github.io/sarif-web-component/
which successfully shows most of the information (although not paths,
and not CWE IDs), and I've fixed all validation errors I've seen (though
bugs no doubt remain).
I've also tested the generated SARIF using the VS Code extension linked
to from the SARIF website; I'm a novice with VS Code, but it seems to be
able to handle my generated SARIF files (e.g. showing the data in the
SARIF tab, and showing squiggly underlines under issues, and when I
click on them, it visualizes the events in the path inline within the
source window).
Has anyone written an Emacs mode for SARIF files? (pretty please)
gcc/ChangeLog:
* Makefile.in (OBJS): Add tree-diagnostic-client-data-hooks.o and
tree-logical-location.o.
(OBJS-libcommon): Add diagnostic-format-sarif.o; reorder.
(CFLAGS-tree-diagnostic-client-data-hooks.o): Add TARGET_NAME.
* common.opt (fdiagnostics-format=): Add sarif-stderr and sarif-file.
(sarif-stderr, sarif-file): New enum values.
* diagnostic-client-data-hooks.h: New file.
* diagnostic-format-sarif.cc: New file.
* diagnostic-path.h (enum diagnostic_event::verb): New enum.
(enum diagnostic_event::noun): New enum.
(enum diagnostic_event::property): New enum.
(struct diagnostic_event::meaning): New struct.
(diagnostic_event::get_logical_location): New vfunc.
(diagnostic_event::get_meaning): New vfunc.
(simple_diagnostic_event::get_logical_location): New vfunc impl.
(simple_diagnostic_event::get_meaning): New vfunc impl.
* diagnostic.cc: Include "diagnostic-client-data-hooks.h".
(diagnostic_initialize): Initialize m_client_data_hooks.
(diagnostic_finish): Clean up m_client_data_hooks.
(diagnostic_event::meaning::dump_to_pp): New.
(diagnostic_event::meaning::maybe_get_verb_str): New.
(diagnostic_event::meaning::maybe_get_noun_str): New.
(diagnostic_event::meaning::maybe_get_property_str): New.
(get_cwe_url): Make non-static.
(diagnostic_output_format_init): Handle
DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR and
DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE.
* diagnostic.h (enum diagnostics_output_format): Add
DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR and
DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE.
(class diagnostic_client_data_hooks): New forward decl.
(class logical_location): New forward decl.
(diagnostic_context::m_client_data_hooks): New field.
(diagnostic_output_format_init_sarif_stderr): New decl.
(diagnostic_output_format_init_sarif_file): New decl.
(get_cwe_url): New decl.
* doc/invoke.texi (-fdiagnostics-format=): Add sarif-stderr and
sarif-file.
* doc/sourcebuild.texi (Scan a particular file): Add
scan-sarif-file and scan-sarif-file-not.
* langhooks-def.h (lhd_get_sarif_source_language): New decl.
(LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): New macro.
(LANG_HOOKS_INITIALIZER): Add
LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE.
* langhooks.cc (lhd_get_sarif_source_language): New.
* langhooks.h (lang_hooks::get_sarif_source_language): New field.
* logical-location.h: New file.
* plugin.cc (struct for_each_plugin_closure): New.
(for_each_plugin_cb): New.
(for_each_plugin): New.
* plugin.h (for_each_plugin): New decl.
* tree-diagnostic-client-data-hooks.cc: New file.
* tree-diagnostic.cc: Include "diagnostic-client-data-hooks.h".
(tree_diagnostics_defaults): Populate m_client_data_hooks.
* tree-logical-location.cc: New file.
* tree-logical-location.h: New file.
gcc/ada/ChangeLog:
* gcc-interface/misc.cc (gnat_get_sarif_source_language): New.
(LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.
gcc/analyzer/ChangeLog:
* checker-path.cc (checker_event::get_meaning): New.
(function_entry_event::get_meaning): New.
(state_change_event::get_desc): Add dump of meaning of the event
to the -fanalyzer-verbose-state-changes output.
(state_change_event::get_meaning): New.
(cfg_edge_event::get_meaning): New.
(call_event::get_meaning): New.
(return_event::get_meaning): New.
(start_consolidated_cfg_edges_event::get_meaning): New.
(warning_event::get_meaning): New.
* checker-path.h: Include "tree-logical-location.h".
(checker_event::checker_event): Construct m_logical_loc.
(checker_event::get_logical_location): New.
(checker_event::get_meaning): New decl.
(checker_event::m_logical_loc): New.
(function_entry_event::get_meaning): New decl.
(state_change_event::get_meaning): New decl.
(cfg_edge_event::get_meaning): New decl.
(call_event::get_meaning): New decl.
(return_event::get_meaning): New decl.
(start_consolidated_cfg_edges_event::get_meaning): New.
(warning_event::get_meaning): New decl.
* pending-diagnostic.h: Include "diagnostic-path.h".
(pending_diagnostic::get_meaning_for_state_change): New vfunc.
* sm-file.cc (file_diagnostic::get_meaning_for_state_change): New
vfunc impl.
* 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.
gcc/c/ChangeLog:
* c-lang.cc (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.
(c_get_sarif_source_language): New.
* c-tree.h (c_get_sarif_source_language): New decl.
gcc/cp/ChangeLog:
* cp-lang.cc (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.
(cp_get_sarif_source_language): New.
gcc/d/ChangeLog:
* d-lang.cc (d_get_sarif_source_language): New.
(LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.
gcc/fortran/ChangeLog:
* f95-lang.cc (gfc_get_sarif_source_language): New.
(LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.
gcc/go/ChangeLog:
* go-lang.cc (go_get_sarif_source_language): New.
(LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.
gcc/objc/ChangeLog:
* objc-act.h (objc_get_sarif_source_language): New decl.
* objc-lang.cc (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.
(objc_get_sarif_source_language): New.
gcc/testsuite/ChangeLog:
* c-c++-common/diagnostic-format-sarif-file-1.c: New test.
* c-c++-common/diagnostic-format-sarif-file-2.c: New test.
* c-c++-common/diagnostic-format-sarif-file-3.c: New test.
* c-c++-common/diagnostic-format-sarif-file-4.c: New test.
* gcc.dg/analyzer/file-meaning-1.c: New test.
* gcc.dg/analyzer/malloc-meaning-1.c: New test.
* gcc.dg/analyzer/malloc-sarif-1.c: New test.
* gcc.dg/plugin/analyzer_gil_plugin.c
(gil_diagnostic::get_meaning_for_state_change): New vfunc impl.
* gcc.dg/plugin/diagnostic-test-paths-5.c: New test.
* gcc.dg/plugin/plugin.exp (plugin_test_list): Add
diagnostic-test-paths-5.c to tests for
diagnostic_plugin_test_paths.c.
* lib/gcc-dg.exp: Load scansarif.exp.
* lib/scansarif.exp: New test.
libatomic/ChangeLog:
* testsuite/lib/libatomic.exp: Add load_gcc_lib of scansarif.exp.
libgomp/ChangeLog:
* testsuite/lib/libgomp.exp: Add load_gcc_lib of scansarif.exp.
libitm/ChangeLog:
* testsuite/lib/libitm.exp: Add load_gcc_lib of scansarif.exp.
libphobos/ChangeLog:
* testsuite/lib/libphobos-dg.exp: Add load_gcc_lib of scansarif.exp.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
As of GCC 11 onwards we have required a C++11 compiler, such as GCC 4.8
or later. On the assumption that any such compiler correctly implements
"final" and "override", this patch updates the source tree to stop using
the FINAL and OVERRIDE macros from ansidecl.h, in favor of simply using
"final" and "override" directly.
libcpp/ChangeLog:
* lex.cc: Replace uses of "FINAL" and "OVERRIDE" with "final" and
"override".
gcc/analyzer/ChangeLog:
* analyzer-pass.cc: Replace uses of "FINAL" and "OVERRIDE" with
"final" and "override".
* call-info.h: Likewise.
* checker-path.h: Likewise.
* constraint-manager.cc: Likewise.
* diagnostic-manager.cc: Likewise.
* engine.cc: Likewise.
* exploded-graph.h: Likewise.
* feasible-graph.h: Likewise.
* pending-diagnostic.h: Likewise.
* region-model-impl-calls.cc: Likewise.
* region-model.cc: Likewise.
* region-model.h: Likewise.
* region.h: 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.
* state-purge.h: Likewise.
* store.cc: Likewise.
* store.h: Likewise.
* supergraph.h: Likewise.
* svalue.h: Likewise.
* trimmed-graph.h: Likewise.
* varargs.cc: Likewise.
gcc/c-family/ChangeLog:
* c-format.cc: Replace uses of "FINAL" and "OVERRIDE" with "final"
and "override".
* c-pretty-print.h: Likewise.
gcc/cp/ChangeLog:
* cxx-pretty-print.h: Replace uses of "FINAL" and "OVERRIDE" with
"final" and "override".
* error.cc: Likewise.
gcc/jit/ChangeLog:
* jit-playback.h: Replace uses of "FINAL" and "OVERRIDE" with
"final" and "override".
* jit-recording.cc: Likewise.
* jit-recording.h: Likewise.
gcc/ChangeLog:
* config/aarch64/aarch64-sve-builtins-base.cc: Replace uses of
"FINAL" and "OVERRIDE" with "final" and "override".
* config/aarch64/aarch64-sve-builtins-functions.h: Likewise.
* config/aarch64/aarch64-sve-builtins-shapes.cc: Likewise.
* config/aarch64/aarch64-sve-builtins-sve2.cc: Likewise.
* diagnostic-path.h: Likewise.
* digraph.cc: Likewise.
* gcc-rich-location.h: Likewise.
* gimple-array-bounds.cc: Likewise.
* gimple-loop-versioning.cc: Likewise.
* gimple-range-cache.cc: Likewise.
* gimple-range-cache.h: Likewise.
* gimple-range-fold.cc: Likewise.
* gimple-range-fold.h: Likewise.
* gimple-range-tests.cc: Likewise.
* gimple-range.h: Likewise.
* gimple-ssa-evrp.cc: Likewise.
* input.cc: Likewise.
* json.h: Likewise.
* read-rtl-function.cc: Likewise.
* tree-complex.cc: Likewise.
* tree-diagnostic-path.cc: Likewise.
* tree-ssa-ccp.cc: Likewise.
* tree-ssa-copy.cc: Likewise.
* tree-vrp.cc: Likewise.
* value-query.h: Likewise.
* vr-values.h: Likewise.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
This patch adds support to the analyzer for checking usage of <stdarg.h>,
with four new warnings.
It adds:
(a) a state-machine for tracking "started" and "ended" states on va_list
instances, implementing two new warnings:
-Wanalyzer-va-list-leak
for complaining about missing va_end after a va_start or va_copy
-Wanalyzer-va-list-use-after-va-end:
for complaining about va_arg or va_copy used on a va_list that's had
va_end called on it
(b) interprocedural tracking of variadic parameters, tracking symbolic
values, implementing two new warnings:
-Wanalyzer-va-arg-type-mismatch
for type-checking va_arg usage against the types of the parameters
that were actually passed to the variadic call
-Wanalyzer-va-list-exhausted
for complaining if va_arg is used too many times on a va_list
Here's an LTO example of a type mismatch in a variadic call that
straddles two source files:
stdarg-lto-1-a.c: In function 'called_by_test_type_mismatch_1':
stdarg-lto-1-a.c:19:7: warning: 'va_arg' expected 'const char *' but
received 'int' for variadic argument 1 of 'ap' [-Wanalyzer-va-arg-type-mismatch]
19 | str = va_arg (ap, const char *);
| ^
'test_type_mismatch_1': events 1-2
|
|stdarg-lto-1-b.c:3:6:
| 3 | void test_type_mismatch_1 (void)
| | ^
| | |
| | (1) entry to 'test_type_mismatch_1'
| 4 | {
| 5 | called_by_test_type_mismatch_1 (42, 1066);
| | ~
| | |
| | (2) calling 'called_by_test_type_mismatch_1' from 'test_type_mismatch_1' with 1 variadic argument
|
+--> 'called_by_test_type_mismatch_1': events 3-4
|
|stdarg-lto-1-a.c:12:1:
| 12 | called_by_test_type_mismatch_1 (int placeholder, ...)
| | ^
| | |
| | (3) entry to 'called_by_test_type_mismatch_1'
|......
| 19 | str = va_arg (ap, const char *);
| | ~
| | |
| | (4) 'va_arg' expected 'const char *' but received 'int' for variadic argument 1 of 'ap'
|
gcc/ChangeLog:
PR analyzer/105103
* Makefile.in (ANALYZER_OBJS): Add analyzer/varargs.o.
* doc/invoke.texi: Add -Wanalyzer-va-arg-type-mismatch,
-Wanalyzer-va-list-exhausted, -Wanalyzer-va-list-leak, and
-Wanalyzer-va-list-use-after-va-end.
gcc/analyzer/ChangeLog:
PR analyzer/105103
* analyzer.cc (make_label_text_n): New.
* analyzer.h (class var_arg_region): New forward decl.
(make_label_text_n): New decl.
* analyzer.opt (Wanalyzer-va-arg-type-mismatch): New option.
(Wanalyzer-va-list-exhausted): New option.
(Wanalyzer-va-list-leak): New option.
(Wanalyzer-va-list-use-after-va-end): New option.
* checker-path.cc (call_event::get_desc): Split out decl access
into..
(call_event::get_caller_fndecl): ...this new function and...
(call_event::get_callee_fndecl): ...this new function.
* checker-path.h (call_event::get_desc): Drop "FINAL".
(call_event::get_caller_fndecl): New decl.
(call_event::get_callee_fndecl): New decl.
(class call_event): Make fields protected.
* diagnostic-manager.cc (null_assignment_sm_context::warn): New
overload.
(null_assignment_sm_context::get_new_program_state): New.
(diagnostic_manager::add_events_for_superedge): Move case
SUPEREDGE_CALL to a new pending_diagnostic::add_call_event vfunc.
* engine.cc (impl_sm_context::warn): Implement new override.
(impl_sm_context::get_new_program_state): New.
* pending-diagnostic.cc: Include "analyzer/diagnostic-manager.h",
"cpplib.h", "digraph.h", "ordered-hash-map.h", "cfg.h",
"basic-block.h", "gimple.h", "gimple-iterator.h", "cgraph.h"
"analyzer/supergraph.h", "analyzer/program-state.h",
"alloc-pool.h", "fibonacci_heap.h", "shortest-paths.h",
"sbitmap.h", "analyzer/exploded-graph.h", "diagnostic-path.h",
and "analyzer/checker-path.h".
(ht_ident_eq): New.
(fixup_location_in_macro_p): New.
(pending_diagnostic::fixup_location): New.
(pending_diagnostic::add_call_event): New.
* pending-diagnostic.h (pending_diagnostic::fixup_location): Drop
no-op inline implementation in favor of the more complex
implementation above.
(pending_diagnostic::add_call_event): New vfunc.
* region-model-impl-calls.cc: Include "analyzer/sm.h",
"diagnostic-path.h", and "analyzer/pending-diagnostic.h".
* region-model-manager.cc
(region_model_manager::get_var_arg_region): New.
(region_model_manager::log_stats): Log m_var_arg_regions.
* region-model.cc (region_model::on_call_pre): Handle IFN_VA_ARG,
BUILT_IN_VA_START, and BUILT_IN_VA_COPY.
(region_model::on_call_post): Handle BUILT_IN_VA_END.
(region_model::get_representative_path_var_1): Handle RK_VAR_ARG.
(region_model::push_frame): Push variadic arguments.
* region-model.h (region_model_manager::get_var_arg_region): New
decl.
(region_model_manager::m_var_arg_regions): New field.
(region_model::impl_call_va_start): New decl.
(region_model::impl_call_va_copy): New decl.
(region_model::impl_call_va_arg): New decl.
(region_model::impl_call_va_end): New decl.
* region.cc (alloca_region::dump_to_pp): Dump the id.
(var_arg_region::dump_to_pp): New.
(var_arg_region::get_frame_region): New.
* region.h (enum region_kind): Add RK_VAR_ARG.
(region::dyn_cast_var_arg_region): New.
(class var_arg_region): New.
(is_a_helper <const var_arg_region *>::test): New.
(struct default_hash_traits<var_arg_region::key_t>): New.
* sm.cc (make_checkers): Call make_va_list_state_machine.
* sm.h (sm_context::warn): New vfunc.
(sm_context::get_old_svalue): Drop unused decl.
(sm_context::get_new_program_state): New vfunc.
(make_va_list_state_machine): New decl.
* varargs.cc: New file.
gcc/testsuite/ChangeLog:
PR analyzer/105103
* gcc.dg/analyzer/stdarg-1.c: New test.
* gcc.dg/analyzer/stdarg-2.c: New test.
* gcc.dg/analyzer/stdarg-fmtstring-1.c: New test.
* gcc.dg/analyzer/stdarg-lto-1-a.c: New test.
* gcc.dg/analyzer/stdarg-lto-1-b.c: New test.
* gcc.dg/analyzer/stdarg-lto-1.h: New test.
* gcc.dg/analyzer/stdarg-sentinel-1.c: New test.
* gcc.dg/analyzer/stdarg-types-1.c: New test.
* gcc.dg/analyzer/stdarg-types-2.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
When reviewing the output of -fanalyzer on PR analyzer/104224 I noticed
that despite very verbose paths, the diagnostic paths for
-Wanalyzer-use-of-uninitialized-value
don't show where the uninitialized memory is allocated.
This patch adapts and simplifies material from
"[PATCH 3/6] analyzer: implement infoleak detection"
https://gcc.gnu.org/pipermail/gcc-patches/2021-November/584377.html
in order to add region creation events for the pertinent region (whether
on the stack or heap).
For example, this patch extends:
malloc-1.c: In function 'test_40':
malloc-1.c:461:5: warning: use of uninitialized value '*p' [CWE-457] [-Wanalyzer-use-of-uninitialized-value]
461 | i = *p;
| ~~^~~~
'test_40': event 1
|
| 461 | i = *p;
| | ~~^~~~
| | |
| | (1) use of uninitialized value '*p' here
|
to:
malloc-1.c: In function 'test_40':
malloc-1.c:461:5: warning: use of uninitialized value '*p' [CWE-457] [-Wanalyzer-use-of-uninitialized-value]
461 | i = *p;
| ~~^~~~
'test_40': events 1-2
|
| 460 | int *p = (int*)malloc(sizeof(int*));
| | ^~~~~~~~~~~~~~~~~~~~
| | |
| | (1) region created on heap here
| 461 | i = *p;
| | ~~~~~~
| | |
| | (2) use of uninitialized value '*p' here
|
and this helps readability of the resulting warnings, especially in
more complicated cases.
gcc/analyzer/ChangeLog:
* checker-path.cc (event_kind_to_string): Handle
EK_REGION_CREATION.
(region_creation_event::region_creation_event): New.
(region_creation_event::get_desc): New.
(checker_path::add_region_creation_event): New.
* checker-path.h (enum event_kind): Add EK_REGION_CREATION.
(class region_creation_event): New subclass.
(checker_path::add_region_creation_event): New decl.
* diagnostic-manager.cc
(diagnostic_manager::emit_saved_diagnostic): Pass NULL for new
param to add_events_for_eedge when handling trailing eedge.
(diagnostic_manager::build_emission_path): Create an interesting_t
instance, allow the pending diagnostic to populate it, and pass it
to the calls to add_events_for_eedge.
(diagnostic_manager::add_events_for_eedge): Add "interest" param.
Use it to add region_creation_events for on-stack regions created
within at function entry, and when pertinent dynamically-sized
regions are created.
(diagnostic_manager::prune_for_sm_diagnostic): Add case for
EK_REGION_CREATION.
* diagnostic-manager.h (diagnostic_manager::add_events_for_eedge):
Add "interest" param.
* pending-diagnostic.cc: Include "selftest.h", "tristate.h",
"analyzer/call-string.h", "analyzer/program-point.h",
"analyzer/store.h", and "analyzer/region-model.h".
(interesting_t::add_region_creation): New.
(interesting_t::dump_to_pp): New.
* pending-diagnostic.h (struct interesting_t): New.
(pending_diagnostic::mark_interesting_stuff): New vfunc.
* region-model.cc
(poisoned_value_diagnostic::poisoned_value_diagnostic): Add
(poisoned_value_diagnostic::operator==): Compare m_pkind and
m_src_region fields.
(poisoned_value_diagnostic::mark_interesting_stuff): New.
(poisoned_value_diagnostic::m_src_region): New.
(region_model::check_for_poison): Call
get_region_for_poisoned_expr for uninit values and pass the resul
to the diagnostic.
(region_model::get_region_for_poisoned_expr): New.
(region_model::deref_rvalue): Pass NULL for
poisoned_value_diagnostic's src_region.
* region-model.h (region_model::get_region_for_poisoned_expr): New
decl.
* region.h (frame_region::get_fndecl): New.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/data-model-1.c: Add dg-message directives for
expected region creation events.
* gcc.dg/analyzer/malloc-1.c: Likewise.
* gcc.dg/analyzer/memset-CVE-2017-18549-1.c: Likewise.
* gcc.dg/analyzer/pr101547.c: Likewise.
* gcc.dg/analyzer/pr101875.c: Likewise.
* gcc.dg/analyzer/pr101962.c: Likewise.
* gcc.dg/analyzer/pr104224.c: Likewise.
* gcc.dg/analyzer/pr94047.c: Likewise.
* gcc.dg/analyzer/symbolic-1.c: Likewise.
* gcc.dg/analyzer/uninit-1.c: Likewise.
* gcc.dg/analyzer/uninit-4.c: Likewise.
* gcc.dg/analyzer/uninit-alloca.c: New test.
* gcc.dg/analyzer/uninit-pr94713.c: Add dg-message directive for
expected region creation event.
* gcc.dg/analyzer/uninit-pr94714.c: Likewise.
* gcc.dg/analyzer/zlib-3.c: Likewise.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
|
|
2021-07-29 Ankur Saini <arsenic@sourceware.org>
gcc/analyzer/ChangeLog:
PR analyzer/100546
* analysis-plan.cc (analysis_plan::use_summary_p): Don't use call
summaries if there is no callgraph edge
* checker-path.cc (call_event::call_event): Handle calls events that
are not represented by a supergraph call edge
(return_event::return_event): Likewise.
(call_event::get_desc): Work with new call_event structure.
(return_event::get_desc): Likeise.
* checker-path.h (call_event::m_src_snode): New field.
(call_event::m_dest_snode): New field.
(return_event::m_src_snode): New field.
(return_event::m_dest_snode): New field.
* diagnostic-manager.cc
(diagnostic_manager::prune_for_sm_diagnostic)<case EK_CALL_EDGE>:
Refactor to work with edges without callgraph edge.
(diagnostic_manager::prune_for_sm_diagnostic)<case EK_RETURN_EDGE>:
Likewise.
* engine.cc (dynamic_call_info_t::update_model): New function.
(dynamic_call_info_t::add_events_to_path): New function.
(exploded_graph::create_dynamic_call): New function.
(exploded_graph::process_node): Work with dynamically discovered calls.
* exploded-graph.h (class dynamic_call_info_t): New class.
(exploded_graph::create_dynamic_call): New decl.
* program-point.cc (program_point::push_to_call_stack): New function.
(program_point::pop_from_call_stack): New function.
* program-point.h (program_point::push_to_call_stack): New decl.
(program_point::pop_from_call_stack): New decl.
* program-state.cc (program_state::push_call): New function.
(program_state::returning_call): New function.
* program-state.h (program_state::push_call): New decl.
(program_state::returning_call): New decl.
* region-model.cc (region_model::update_for_gcall) New function.
(region_model::update_for_return_gcall): New function.
(egion_model::update_for_call_superedge): Get the underlying gcall and
update for gcall.
(region_model::update_for_return_superedge): Likewise.
* region-model.h (region_model::update_for_gcall): New decl.
(region_model::update_for_return_gcall): New decl.
* state-purge.cc (state_purge_per_ssa_name::process_point): Update to
work with calls without underlying cgraph edge.
* supergraph.cc (supergraph::supergraph) Split snodes at every callsite.
* supergraph.h (supernode::get_returning_call) New accessor.
gcc/testsuite/ChangeLog:
PR analyzer/100546
* gcc.dg/analyzer/function-ptr-4.c: New test.
* gcc.dg/analyzer/pr100546.c: New test.
|
|
I have followup work where a custom event's description would be better
handled via a vfunc rather that a precanned string, hence this
refactoring to make it easy to add custom_event subclasses.
gcc/analyzer/ChangeLog:
* checker-path.cc (class custom_event): Make abstract to allow for
custom vfuncs, splitting existing implementation into...
(class precanned_custom_event): New subclass.
(custom_event::get_desc): Move to...
(precanned_custom_event::get_desc): ...subclass.
* checker-path.h (class custom_event): Make abstract to allow for
custom vfuncs, splitting existing implementation into...
(class precanned_custom_event): New subclass.
* diagnostic-manager.cc (diagnostic_manager::add_events_for_eedge):
Use precanned_custom_event.
* engine.cc
(stale_jmp_buf::maybe_add_custom_events_for_superedge): Likewise.
* sm-signal.cc (signal_delivery_edge_info_t::add_events_to_path):
Likewise.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
This patch adds a simplification to analyzer paths for
repeated CFG edges generated from compound conditionals.
For example, it simplifies:
| 5 | if (a && b && c)
| | ^~~~~~~~~~~~
| | | | |
| | | | (4) ...to here
| | | | (5) following ‘true’ branch (when ‘c != 0’)...
| | | (2) ...to here
| | | (3) following ‘true’ branch (when ‘b != 0’)...
| | (1) following ‘true’ branch (when ‘a != 0’)...
| 6 | __analyzer_dump_path ();
| | ~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (6) ...to here
to:
| 5 | if (a && b && c)
| | ^
| | |
| | (1) following ‘true’ branch...
| 6 | __analyzer_dump_path ();
| | ~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (2) ...to here
gcc/analyzer/ChangeLog:
* checker-path.cc (event_kind_to_string): Handle
EK_START_CONSOLIDATED_CFG_EDGES and
EK_END_CONSOLIDATED_CFG_EDGES.
(start_consolidated_cfg_edges_event::get_desc): New.
(checker_path::cfg_edge_pair_at_p): New.
* checker-path.h (enum event_kind): Add
EK_START_CONSOLIDATED_CFG_EDGES and
EK_END_CONSOLIDATED_CFG_EDGES.
(class start_consolidated_cfg_edges_event): New class.
(class end_consolidated_cfg_edges_event): New class.
(checker_path::delete_events): New.
(checker_path::replace_event): New.
(checker_path::cfg_edge_pair_at_p): New decl.
* diagnostic-manager.cc (diagnostic_manager::prune_path): Call
consolidate_conditions.
(same_line_as_p): New.
(diagnostic_manager::consolidate_conditions): New.
* diagnostic-manager.h
(diagnostic_manager::consolidate_conditions): New decl.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/combined-conditionals-1.c: New test.
|
|
|
|
This patch adds a new GCC plugin event: PLUGIN_ANALYZER_INIT, called
when -fanalyzer is starting, allowing for GCC plugins to register
additional state-machine-based checks within -fanalyzer. The idea
is that 3rd-party code might want to add domain-specific checks for
its own APIs - with the caveat that the analyzer is itself still
rather experimental.
As an example, the patch adds a proof-of-concept plugin to the testsuite
for checking CPython code: verifying that code that relinquishes
CPython's global interpreter lock doesn't attempt to do anything with
PyObjects in the sections where the lock isn't held. It also adds a
warning about nested releases of the lock, which is forbidden.
For example:
demo.c: In function 'foo':
demo.c:11:3: warning: use of PyObject '*(obj)' without the GIL
11 | Py_INCREF (obj);
| ^~~~~~~~~
'test': events 1-3
|
| 15 | void test (PyObject *obj)
| | ^~~~
| | |
| | (1) entry to 'test'
| 16 | {
| 17 | Py_BEGIN_ALLOW_THREADS
| | ~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (2) releasing the GIL here
| 18 | foo (obj);
| | ~~~~~~~~~
| | |
| | (3) calling 'foo' from 'test'
|
+--> 'foo': events 4-5
|
| 9 | foo (PyObject *obj)
| | ^~~
| | |
| | (4) entry to 'foo'
| 10 | {
| 11 | Py_INCREF (obj);
| | ~~~~~~~~~
| | |
| | (5) PyObject '*(obj)' used here without the GIL
|
Doing so requires adding some logic for ignoring macro expansions in
analyzer diagnostics, since the insides of Py_INCREF and
Py_BEGIN_ALLOW_THREADS are not of interest to the user for these cases.
gcc/analyzer/ChangeLog:
* analyzer-pass.cc (pass_analyzer::execute): Move sorry call to...
(sorry_no_analyzer): New.
* analyzer.h (class state_machine): New forward decl.
(class logger): New forward decl.
(class plugin_analyzer_init_iface): New.
(sorry_no_analyzer): New decl.
* checker-path.cc (checker_path::fixup_locations): New.
* checker-path.h (checker_event::set_location): New.
(checker_path::fixup_locations): New decl.
* diagnostic-manager.cc
(diagnostic_manager::emit_saved_diagnostic): Call
checker_path::fixup_locations, and call fixup_location
on the primary location.
* engine.cc: Include "plugin.h".
(class plugin_analyzer_init_impl): New.
(impl_run_checkers): Invoke PLUGIN_ANALYZER_INIT callbacks.
* pending-diagnostic.h (pending_diagnostic::fixup_location): New
vfunc.
gcc/ChangeLog:
* doc/plugins.texi (Plugin callbacks): Add PLUGIN_ANALYZER_INIT.
* plugin.c (register_callback): Likewise.
(invoke_plugin_callbacks_full): Likewise.
* plugin.def (PLUGIN_ANALYZER_INIT): New event.
gcc/testsuite/ChangeLog:
* gcc.dg/plugin/analyzer_gil_plugin.c: New test.
* gcc.dg/plugin/gil-1.c: New test.
* gcc.dg/plugin/gil.h: New header.
* gcc.dg/plugin/plugin.exp (plugin_test_list): Add the new plugin
and test.
|
|
This patch adds a custom event to paths emitted by
-Wanalyzer-stale-setjmp-buffer highlighting the place where the
pertinent stack frame is popped, and updates the final event in
the path to reference this.
gcc/analyzer/ChangeLog:
* checker-path.h (checker_event::get_id_ptr): New.
* diagnostic-manager.cc (path_builder::path_builder): Add "sd"
param and use it to initialize new field "m_sd".
(path_builder::get_pending_diagnostic): New.
(path_builder::m_sd): New field.
(diagnostic_manager::emit_saved_diagnostic): Pass sd to
path_builder ctor.
(diagnostic_manager::add_events_for_superedge): Call new
maybe_add_custom_events_for_superedge vfunc.
* engine.cc (stale_jmp_buf::stale_jmp_buf): Add "setjmp_point"
param and use it to initialize new field "m_setjmp_point".
Initialize new field "m_stack_pop_event".
(stale_jmp_buf::maybe_add_custom_events_for_superedge): New vfunc
implementation.
(stale_jmp_buf::describe_final_event): New vfunc implementation.
(stale_jmp_buf::m_setjmp_point): New field.
(stale_jmp_buf::m_stack_pop_event): New field.
(exploded_node::on_longjmp): Pass setjmp_point to stale_jmp_buf
ctor.
* pending-diagnostic.h
(pending_diagnostic::maybe_add_custom_events_for_superedge): New
vfunc.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/setjmp-5.c: Update expected path output to show
an event where the pertinent stack frame is popped. Update
expected message from final event to reference this event.
|
|
This large patch reimplements how the analyzer tracks regions and
values.
Elimination of region_id and svalue_id
**************************************
The patch eliminates region_id and svalue_id in favor of simply
using pointers. I'd hoped that the ID classes would make it easier
to compare states, avoiding having to compare long hexadecimal addresses
in favor of small integers. Unfortunately it added lots of complexity,
with the need to remap IDs when comparing or purging states, and the
need to "canonicalize" when comparing states.
Various "state explosion" bugs in the old implementation were due to
failures in canonicalization, where two states that ought to be equal
were non-equal due to differences in ID ordering. I spent a lot of
time trying to fix canonicalization bugs, and there always seemed to
be one more bug. By eliminating IDs in this new implementation, lots
of tricky canonicalization goes away and no ID remapping should be
needed; almost all of the old validation code becomes redundant.
There's still some canonicalization in the new implementation, mostly
in constraint_manager, but much less than before.
Ownership of regions and svalues
********************************
In the old implementation, each region_model had its own copies of
regions and svalues, so there was heap bloat and churn as lots of
little objects were cloned when copying program_state instances. In the
new implementation the regions and svalues are immutable and are shared
thoughout the analysis, rather than being per region_model. They are
owned by a manager class, and are effectively singletons. Region and
svalue instances can now be compared by pointer rather than by comparing
their fields (the manager class takes care of uniqueness).
This is a huge simplification, and (I hope) will avoid lots
of heap churn as states are copied; all mutable state from regions and
svalues is now stored in a "store" class in the region_model.
Changes to the meaning of a "region"
************************************
Region subclasses no longer represent internal structure, but instead
represent how the regions are reached. So e.g. a global "struct coord
c;" is now a decl_region, rather than a struct_region.
In the old implementation, the values for each region were stored in the
region instances, but in the new implementation the regions are immutable.
Memory is now modeled in a new "store" class: a mapping from keys to
svalues, where the keys are both concrete bit-offsets from the start of
a "base region", and "symbolic" keys (thus hopefully making unions,
casts, aliasing etc easier to deal with). So e.g. for assignments to
the fields of a struct, it records the mapping from bit-offsets of e.g.
field to the values; if that memory is cast to another type and written
to, the appropriate clobbering of the bound values can happen.
The concept of "what the current stack is" moves from the regions to
being a field within the region_model ("m_current_frame").
Bugs fixed by this patch
************************
PR analyzer/93032 (missing leak diagnostic for zlib/contrib/minizip/mztools.c)
PR analyzer/93938 (ICE in analyzer)
PR analyzer/94011 (ICE in analyzer)
PR analyzer/94099 (ICE in analyzer)
PR analyzer/94399 (leak false positive with __attribute__((cleanup())))
PR analyzer/94458 (leak false positive)
PR analyzer/94503 (ICE on C++ return-value-optimization)
PR analyzer/94640 (leak false positive)
PR analyzer/94688 (ICE in analyzer)
PR analyzer/94689 ("arrays of functions are not meaningful" error)
PR analyzer/94839 (leak false positive)
PR analyzer/95026 (leak false positive)
PR analyzer/95042 (ICE merging const and non-const C++ object instances)
PR analyzer/95240 (leak false positive)
gcc/ChangeLog:
* Makefile.in (ANALYZER_OBJS): Add analyzer/region.o,
analyzer/region-model-impl-calls.o,
analyzer/region-model-manager.o,
analyzer/region-model-reachability.o, analyzer/store.o, and
analyzer/svalue.o.
* doc/analyzer.texi: Update for changes to analyzer
implementation.
* tristate.h (tristate::get_value): New accessor.
gcc/analyzer/ChangeLog:
* analyzer-logging.cc: Ignore "-Wformat-diag".
(logger::enter_scope): Use inc_indent in both overloads.
(logger::exit_scope): Use dec_indent.
* analyzer-logging.h (logger::inc_indent): New.
(logger::dec_indent): New.
* analyzer-selftests.cc (run_analyzer_selftests): Call
analyzer_store_cc_tests.
* analyzer-selftests.h (analyzer_store_cc_tests): New decl.
* analyzer.cc (get_stmt_location): New function.
* analyzer.h (class initial_svalue): New forward decl.
(class unaryop_svalue): New forward decl.
(class binop_svalue): New forward decl.
(class sub_svalue): New forward decl.
(class unmergeable_svalue): New forward decl.
(class placeholder_svalue): New forward decl.
(class widening_svalue): New forward decl.
(class compound_svalue): New forward decl.
(class conjured_svalue): New forward decl.
(svalue_set): New typedef.
(class map_region): Delete.
(class array_region): Delete.
(class frame_region): New forward decl.
(class function_region): New forward decl.
(class label_region): New forward decl.
(class decl_region): New forward decl.
(class element_region): New forward decl.
(class offset_region): New forward decl.
(class cast_region): New forward decl.
(class field_region): New forward decl.
(class string_region): New forward decl.
(class region_model_manager): New forward decl.
(class store_manager): New forward decl.
(class store): New forward decl.
(class call_details): New forward decl.
(struct svalue_id_merger_mapping): Delete.
(struct canonicalization): Delete.
(class function_point): New forward decl.
(class engine): New forward decl.
(dump_tree): New function decl.
(print_quoted_type): New function decl.
(readability_comparator): New function decl.
(tree_cmp): New function decl.
(class path_var): Move here from region-model.h
(bit_offset_t, bit_size_t, byte_size_t): New typedefs.
(class region_offset): New class.
(get_stmt_location): New decl.
(struct member_function_hash_traits): New struct.
(class consolidation_map): New class.
Ignore "-Wformat-diag".
* analyzer.opt (-param=analyzer-max-svalue-depth=): New param.
(-param=analyzer-max-enodes-for-full-dump=): New param.
* call-string.cc: Ignore -Wformat-diag.
* checker-path.cc: Move includes of "analyzer/call-string.h" and
"analyzer/program-point.h" to before "analyzer/region-model.h",
and also include "analyzer/store.h" before it.
(state_change_event::state_change_event): Replace "tree var" param
with "const svalue *sval". Convert "origin" param from tree to
"const svalue *".
(state_change_event::get_desc): Call get_representative_tree to
convert the var and origin from const svalue * to tree. Use
svalue::get_desc rather than %qE when describing state changes.
(checker_path::add_final_event): Use get_stmt_location.
* checker-path.h (state_change_event::state_change_event): Port
from tree to const svalue *.
(state_change_event::get_lvalue): Delete.
(state_change_event::get_dest_function): New.
(state_change_event::m_var): Replace with...
(state_change_event::m_sval): ...this.
(state_change_event::m_origin): Convert from tree to
const svalue *.
* constraint-manager.cc: Include "analyzer/call-string.h",
"analyzer/program-point.h", and "analyzer/store.h" before
"analyzer/region-model.h".
(struct bound, struct range): Move to constraint-manager.h.
(compare_constants): New function.
(range::dump): Rename to...
(range::dump_to_pp): ...this. Support NULL constants.
(range::dump): Reintroduce for dumping to stderr.
(range::constrained_to_single_element): Return result, rather than
writing to *OUT.
(range::eval_condition): New.
(range::below_lower_bound): New.
(range::above_upper_bound): New.
(equiv_class::equiv_class): Port from svalue_id to const svalue *.
(equiv_class::print): Likewise.
(equiv_class::hash): Likewise.
(equiv_class::operator==): Port from svalue_id to const svalue *.
(equiv_class::add): Port from svalue_id to const svalue *. Drop
"cm" param.
(equiv_class::del): Port from svalue_id to const svalue *.
(equiv_class::get_representative): Likewise.
(equiv_class::remap_svalue_ids): Delete.
(svalue_id_cmp_by_id): Rename to...
(svalue_cmp_by_ptr): ...this, porting from svalue_id to
const svalue *.
(equiv_class::canonicalize): Update qsort comparator.
(constraint::implied_by): New.
(constraint_manager::constraint_manager): Copy m_mgr in copy ctor.
(constraint_manager::dump_to_pp): Add "multiline" param
(constraint_manager::dump): Pass "true" for "multiline".
(constraint_manager::add_constraint): Port from svalue_id to
const svalue *. Split out second part into...
(constraint_manager::add_unknown_constraint): ...this new
function. Remove self-constraints when merging equivalence
classes.
(constraint_manager::add_constraint_internal): Remove constraints
that would be implied by the new constraint. Port from svalue_id
to const svalue *.
(constraint_manager::get_equiv_class_by_sid): Rename to...
(constraint_manager::get_equiv_class_by_svalue): ...this, porting
from svalue_id to const svalue *.
(constraint_manager::get_or_add_equiv_class): Port from svalue_id
to const svalue *.
(constraint_manager::eval_condition): Make const. Call
compare_constants and return early if it provides a known result.
(constraint_manager::get_ec_bounds): New.
(constraint_manager::eval_condition): New overloads. Make
existing one const, and use compare_constants.
(constraint_manager::purge): Convert "p" param to a template
rather that an abstract base class. Port from svalue_id to
const svalue *.
(class dead_svalue_purger): New class.
(constraint_manager::remap_svalue_ids): Delete.
(constraint_manager::on_liveness_change): New.
(equiv_class_cmp): Port from svalue_id to const svalue *.
(constraint_manager::canonicalize): Likewise. Combine with
purging of redundant equivalence classes and constraints.
(class cleaned_constraint_manager): Delete.
(class merger_fact_visitor): Make "m_cm_b" const. Add "m_merger"
field.
(merger_fact_visitor::fact): Port from svalue_id to const svalue *.
Add special case for widening.
(constraint_manager::merge): Port from svalue_id to const svalue *.
(constraint_manager::clean_merger_input): Delete.
(constraint_manager::for_each_fact): Port from svalue_id to
const svalue *.
(constraint_manager::validate): Likewise.
(selftest::test_constraint_conditions): Provide a
region_model_manager when creating region_model instances.
Add test for self-equality not creating equivalence classes.
(selftest::test_transitivity): Provide a region_model_manager when
creating region_model instances. Verify that EC-merging happens
when constraints are implied.
(selftest::test_constant_comparisons): Provide a
region_model_manager when creating region_model instances.
(selftest::test_constraint_impl): Likewise. Remove over-specified
assertions.
(selftest::test_equality): Provide a region_model_manager when
creating region_model instances.
(selftest::test_many_constants): Likewise. Provide a
program_point when testing merging.
(selftest::run_constraint_manager_tests): Move call to
test_constant_comparisons to outside the transitivity guard.
* constraint-manager.h (struct bound): Move here from
constraint-manager.cc.
(struct range): Likewise.
(struct::eval_condition): New decl.
(struct::below_lower_bound): New decl.
(struct::above_upper_bound): New decl.
(equiv_class::add): Port from svalue_id to const svalue *.
(equiv_class::del): Likewise.
(equiv_class::get_representative): Likewise.
(equiv_class::remap_svalue_ids): Drop.
(equiv_class::m_cst_sid): Convert to..
(equiv_class::m_cst_sval): ...this.
(equiv_class::m_vars): Port from svalue_id to const svalue *.
(constraint::bool implied_by): New decl.
(fact_visitor::on_fact): Port from svalue_id to const svalue *.
(constraint_manager::constraint_manager): Add mgr param.
(constraint_manager::clone): Delete.
(constraint_manager::maybe_get_constant): Delete.
(constraint_manager::get_sid_for_constant): Delete.
(constraint_manager::get_num_svalues): Delete.
(constraint_manager::dump_to_pp): Add "multiline" param.
(constraint_manager::get_equiv_class): Port from svalue_id to
const svalue *.
(constraint_manager::add_constraint): Likewise.
(constraint_manager::get_equiv_class_by_sid): Rename to...
(constraint_manager::get_equiv_class_by_svalue): ...this, porting
from svalue_id to const svalue *.
(constraint_manager::add_unknown_constraint): New decl.
(constraint_manager::get_or_add_equiv_class): Port from svalue_id
to const svalue *.
(constraint_manager::eval_condition): Likewise. Add overloads.
(constraint_manager::get_ec_bounds): New decl.
(constraint_manager::purge): Convert to template.
(constraint_manager::remap_svalue_ids): Delete.
(constraint_manager::on_liveness_change): New decl.
(constraint_manager::canonicalize): Drop param.
(constraint_manager::clean_merger_input): Delete.
(constraint_manager::m_mgr): New field.
* diagnostic-manager.cc: Move includes of
"analyzer/call-string.h" and "analyzer/program-point.h" to before
"analyzer/region-model.h", and also include "analyzer/store.h"
before it.
(saved_diagnostic::saved_diagnostic): Add "sval" param.
(diagnostic_manager::diagnostic_manager): Add engine param.
(diagnostic_manager::add_diagnostic): Add "sval" param, passing it
to saved_diagnostic ctor. Update overload to pass NULL for it.
(dedupe_winners::dedupe_winners): Add engine param.
(dedupe_winners::add): Add "eg" param. Pass m_engine to
feasible_p.
(dedupe_winner::m_engine): New field.
(diagnostic_manager::emit_saved_diagnostics): Pass engine to
dedupe_winners. Pass &eg when adding candidates. Pass svalue
rather than tree to prune_path. Use get_stmt_location to get
primary location of diagnostic.
(diagnostic_manager::emit_saved_diagnostic): Likewise.
(get_any_origin): Drop.
(state_change_event_creator::on_global_state_change): Pass NULL
const svalue * rather than NULL_TREE trees to state_change_event
ctor.
(state_change_event_creator::on_state_change): Port from tree and
svalue_id to const svalue *.
(for_each_state_change): Port from svalue_id to const svalue *.
(struct null_assignment_sm_context): New.
(diagnostic_manager::add_events_for_eedge): Add state change
events for assignment to NULL.
(diagnostic_manager::prune_path): Update param from tree to
const svalue *.
(diagnostic_manager::prune_for_sm_diagnostic): Port from tracking
by tree to by const svalue *.
* diagnostic-manager.h (saved_diagnostic::saved_diagnostic): Add sval
param.
(saved_diagnostic::m_sval): New field.
(diagnostic_manager::diagnostic_manager): Add engine param.
(diagnostic_manager::get_engine): New.
(diagnostic_manager::add_diagnostic): Add "sval" param.
(diagnostic_manager::prune_path): Likewise.
(diagnostic_manager::prune_for_sm_diagnostic): New overload.
(diagnostic_manager::m_eng): New field.
* engine.cc: Move includes of "analyzer/call-string.h" and
"analyzer/program-point.h" to before "analyzer/region-model.h",
and also include "analyzer/store.h" before it.
(impl_region_model_context::impl_region_model_context): Update for
removal of m_change field.
(impl_region_model_context::remap_svalue_ids): Delete.
(impl_region_model_context::on_svalue_leak): New.
(impl_region_model_context::on_svalue_purge): Delete.
(impl_region_model_context::on_liveness_change): New.
(impl_region_model_context::on_unknown_change): Update param
from svalue_id to const svalue *. Add is_mutable param.
(setjmp_svalue::compare_fields): Delete.
(setjmp_svalue::accept): New.
(setjmp_svalue::add_to_hash): Delete.
(setjmp_svalue::dump_to_pp): New.
(setjmp_svalue::print_details): Delete.
(impl_sm_context::impl_sm_context): Drop "change" param.
(impl_sm_context::get_fndecl_for_call): Drop "m_change".
(impl_sm_context::on_transition): Drop ATTRIBUTE_UNUSED from
"stmt" param. Drop m_change. Port from svalue_id to
const svalue *.
(impl_sm_context::warn_for_state): Drop m_change. Port from
svalue_id to const svalue *.
(impl_sm_context::get_readable_tree): Rename to...
(impl_sm_context::get_diagnostic_tree): ...this. Port from
svalue_id to const svalue *.
(impl_sm_context::is_zero_assignment): New.
(impl_sm_context::m_change): Delete field.
(leak_stmt_finder::find_stmt): Handle m_var being NULL.
(readability): Increase penalty for MEM_REF. For SSA_NAMEs,
slightly favor the underlying var over the SSA name. Heavily
penalize temporaries. Handle RESULT_DECL.
(readability_comparator): Make non-static. Consider stack depths.
(impl_region_model_context::on_state_leak): Convert from svalue_id
to const svalue *, updating for region_model changes. Use
id_equal.
(impl_region_model_context::on_inherited_svalue): Delete.
(impl_region_model_context::on_cast): Delete.
(impl_region_model_context::on_condition): Drop m_change.
(impl_region_model_context::on_phi): Likewise.
(impl_region_model_context::on_unexpected_tree_code): Handle t
being NULL.
(point_and_state::validate): Update stack checking for
region_model changes.
(eg_traits::dump_args_t::show_enode_details_p): New.
(exploded_node::exploded_node): Initialize m_num_processed_stmts.
(exploded_node::get_processed_stmt): New function.
(exploded_node::get_dot_fillcolor): Add more colors.
(exploded_node::dump_dot): Guard the printing of the point and
state with show_enode_details_p. Print the processed stmts for
this enode after the initial state.
(exploded_node::dump_to_pp): Pass true for new multiline param
of program_state::dump_to_pp.
(exploded_node::on_stmt): Drop "change" param. Log the stmt.
Set input_location. Implement __analyzer_describe. Update
implementation of __analyzer_dump and __analyzer_eval.
Remove purging of sm-state for unknown fncalls from here.
(exploded_node::on_edge): Drop "change" param.
(exploded_node::on_longjmp): Port from region_id/svalue_id to
const region */const svalue *. Call program_state::detect_leaks.
Drop state_change.
(exploded_node::detect_leaks): Update for changes to region_model.
Call program_state::detect_leaks.
(exploded_edge::exploded_edge): Drop ext_state and change params.
(exploded_edge::dump_dot): "args" is no longer used. Drop dumping
of m_change.
(exploded_graph::exploded_graph): Pass engine to
m_diagnostic_manager ctor. Use program_point::origin.
(exploded_graph::add_function_entry): Drop ctxt. Use
program_state::push_frame. Drop state_change.
(exploded_graph::get_or_create_node): Drop "change" param. Add
"enode_for_diag" param. Update dumping calls for API changes.
Pass point to can_merge_with_p. Show enode indices
within -Wanalyzer-too-complex diagnostic for hitting the per-point
limit.
(exploded_graph::add_edge): Drop "change" param. Log which nodes
are being connected. Update for changes to exploded_edge ctor.
(exploded_graph::get_per_program_point_data): New.
(exploded_graph::process_worklist): Pass point to
can_merge_with_p. Drop state_change. Update dumping call for API
change.
(exploded_graph::process_node): Drop state_change. Split the
node in-place if an sm-state-change occurs. Update
m_num_processed_stmts. Update dumping calls for API change.
(exploded_graph::log_stats): Call engine::log_stats.
(exploded_graph::dump_states_for_supernode): Update dumping
call.
(exploded_path::feasible_p): Add "eng" and "eg" params.
Rename "i" to "end_idx". Pass the manager to the region_model
ctor. Update for every processed stmt in the enode, not just the
first. Keep track of which snodes have been visited, and call
loop_replay_fixup when revisiting one.
(enode_label::get_text): Update dump call for new param.
(exploded_graph::dump_exploded_nodes): Likewise.
(exploded_graph::get_node_by_index): New.
(impl_run_checkers): Create engine instance and pass its address
to extrinsic_state ctor.
* exploded-graph.h
(impl_region_model_context::impl_region_model_context): Drop
"change" params.
(impl_region_model_context::void remap_svalue_ids): Delete.
(impl_region_model_context::on_svalue_purge): Delete.
(impl_region_model_context::on_svalue_leak): New.
(impl_region_model_context::on_liveness_change): New.
(impl_region_model_context::on_state_leak): Update signature.
(impl_region_model_context::on_inherited_svalue): Delete.
(impl_region_model_context::on_cast): Delete.
(impl_region_model_context::on_unknown_change): Update signature.
(impl_region_model_context::m_change): Delete.
(eg_traits::dump_args_t::show_enode_details_p): New.
(exploded_node::on_stmt): Drop "change" param.
(exploded_node::on_edge): Likewise.
(exploded_node::get_processed_stmt): New decl.
(exploded_node::m_num_processed_stmts): New field.
(exploded_edge::exploded_edge): Drop ext_state and change params.
(exploded_edge::m_change): Delete.
(exploded_graph::get_engine): New accessor.
(exploded_graph::get_or_create_node): Drop "change" param. Add
"enode_for_diag" param.
(exploded_graph::add_edge): Drop "change" param.
(exploded_graph::get_per_program_point_data): New decl.
(exploded_graph::get_node_by_index): New decl.
(exploded_path::feasible_p): Add "eng" and "eg" params.
* program-point.cc: Include "analyzer/store.h" before including
"analyzer/region-model.h".
(function_point::function_point): Move here from
program-point.h.
(function_point::get_function): Likewise.
(function_point::from_function_entry): Likewise.
(function_point::before_supernode): Likewise.
(function_point::next_stmt): New function.
* program-point.h (function_point::function_point): Move
implementation from here to program-point.cc.
(function_point::get_function): Likewise.
(function_point::from_function_entry): Likewise.
(function_point::before_supernode): Likewise.
(function_point::next_stmt): New decl.
(program_point::operator!=): New.
(program_point::origin): New.
(program_point::next_stmt): New.
(program_point::m_function_point): Make non-const.
* program-state.cc: Move includes of "analyzer/call-string.h" and
"analyzer/program-point.h" to before "analyzer/region-model.h",
and also include "analyzer/store.h" before it.
(extrinsic_state::get_model_manager): New.
(sm_state_map::sm_state_map): Pass in sm and sm_idx to ctor,
rather than pass the around.
(sm_state_map::clone_with_remapping): Delete.
(sm_state_map::print): Remove "sm" param in favor of "m_sm". Add
"simple" and "multiline" params and support multiline vs single
line dumping.
(sm_state_map::dump): Remove "sm" param in favor of "m_sm". Add
"simple" param.
(sm_state_map::hash): Port from svalue_id to const svalue *.
(sm_state_map::operator==): Likewise.
(sm_state_map::get_state): Likewise. Call canonicalize_svalue on
input. Handle inheritance of sm-state. Call get_default_state.
(sm_state_map::get_origin): Port from svalue_id to const svalue *.
(sm_state_map::set_state): Likewise. Pass in ext_state. Reject
attempts to set state on UNKNOWN.
(sm_state_map::impl_set_state): Port from svalue_id to
const svalue *. Pass in ext_state. Call canonicalize_svalue on
input.
(sm_state_map::purge_for_unknown_fncall): Delete.
(sm_state_map::on_svalue_leak): New.
(sm_state_map::remap_svalue_ids): Delete.
(sm_state_map::on_liveness_change): New.
(sm_state_map::on_unknown_change): Reimplement.
(sm_state_map::on_svalue_purge): Delete.
(sm_state_map::on_inherited_svalue): Delete.
(sm_state_map::on_cast): Delete.
(sm_state_map::validate): Delete.
(sm_state_map::canonicalize_svalue): New.
(program_state::program_state): Update to pass manager to
region_model's ctor. Constify num_states and pass state machine
and index to sm_state_map ctor.
(program_state::print): Update for changes to dump API.
(program_state::dump_to_pp): Ignore the summarize param. Add
"multiline" param.
(program_state::dump_to_file): Add "multiline" param.
(program_state::dump): Pass "true" for new "multiline" param.
(program_state::push_frame): New.
(program_state::on_edge): Drop "change" param. Call
program_state::detect_leaks.
(program_state::prune_for_point): Add enode_for_diag param.
Reimplement based on store class. Call detect_leaks
(program_state::remap_svalue_ids): Delete.
(program_state::get_representative_tree): Port from svalue_id to
const svalue *.
(program_state::can_merge_with_p): Add "point" param. Add early
reject for sm-differences. Drop id remapping.
(program_state::validate): Drop region model and sm_state_map
validation.
(state_change::sm_change::dump): Delete.
(state_change::sm_change::remap_svalue_ids): Delete.
(state_change::sm_change::on_svalue_purge): Delete.
(log_set_of_svalues): New.
(state_change::sm_change::validate): Delete.
(state_change::state_change): Delete.
(state_change::add_sm_change): Delete.
(state_change::affects_p): Delete.
(state_change::dump): Delete.
(state_change::remap_svalue_ids): Delete.
(state_change::on_svalue_purge): Delete.
(state_change::validate): Delete.
(selftest::assert_dump_eq): Delete.
(ASSERT_DUMP_EQ): Delete.
(selftest::test_sm_state_map): Update for changes to region_model
and sm_state_map, porting from svalue_id to const svalue *.
(selftest::test_program_state_dumping): Likewise. Drop test of
dumping, renaming to...
(selftest::test_program_state_1): ...this.
(selftest::test_program_state_dumping_2): Likewise, renaming to...
(selftest::test_program_state_2): ...this.
(selftest::test_program_state_merging): Update for changes to
region_model.
(selftest::test_program_state_merging_2): Likewise.
(selftest::analyzer_program_state_cc_tests): Update for renamed
tests.
* program-state.h (extrinsic_state::extrinsic_state): Add logger
and engine params.
(extrinsic_state::get_logger): New accessor.
(extrinsic_state::get_engine): New accessor.
(extrinsic_state::get_model_manager): New accessor.
(extrinsic_state::m_logger): New field.
(extrinsic_state::m_engine): New field.
(struct default_hash_traits<svalue_id>): Delete.
(pod_hash_traits<svalue_id>::hash): Delete.
(pod_hash_traits<svalue_id>::equal): Delete.
(pod_hash_traits<svalue_id>::mark_deleted): Delete.
(pod_hash_traits<svalue_id>::mark_empty): Delete.
(pod_hash_traits<svalue_id>::is_deleted): Delete.
(pod_hash_traits<svalue_id>::is_empty): Delete.
(sm_state_map::entry_t::entry_t): Port from svalue_id to
const svalue *.
(sm_state_map::entry_t::m_origin): Likewise.
(sm_state_map::map_t): Likewise.
(sm_state_map::sm_state_map): Add state_machine and index params.
(sm_state_map::clone_with_remapping): Delete.
(sm_state_map::print): Drop sm param; add simple and multiline
params.
(sm_state_map::dump): Drop sm param; add simple param.
(sm_state_map::get_state): Port from svalue_id to const svalue *.
Add ext_state param.
(sm_state_map::get_origin): Likewise.
(sm_state_map::set_state): Likewise.
(sm_state_map::impl_set_state): Likewise.
(sm_state_map::purge_for_unknown_fncall): Delete.
(sm_state_map::remap_svalue_ids): Delete.
(sm_state_map::on_svalue_purge): Delete.
(sm_state_map::on_svalue_leak): New.
(sm_state_map::on_liveness_change): New.
(sm_state_map::on_inherited_svalue): Delete.
(sm_state_map::on_cast): Delete.
(sm_state_map::validate): Delete.
(sm_state_map::on_unknown_change): Port from svalue_id to
const svalue *. Add is_mutable and ext_state params.
(sm_state_map::canonicalize_svalue): New.
(sm_state_map::m_sm): New field.
(sm_state_map::m_sm_idx): New field.
(program_state::operator=): Delete.
(program_state::dump_to_pp): Drop "summarize" param, adding
"simple" and "multiline".
(program_state::dump_to_file): Likewise.
(program_state::dump): Rename "summarize" to "simple".
(program_state::push_frame): New.
(program_state::get_current_function): New.
(program_state::on_edge): Drop "change" param.
(program_state::prune_for_point): Likewise. Add enode_for_diag
param.
(program_state::remap_svalue_ids): Delete.
(program_state::get_representative_tree): Port from svalue_id to
const svalue *.
(program_state::can_purge_p): Likewise. Pass ext_state to get_state.
(program_state::can_merge_with_p): Add point param.
(program_state::detect_leaks): New.
(state_change_visitor::on_state_change): Port from tree and
svalue_id to a pair of const svalue *.
(class state_change): Delete.
* region.cc: New file.
* region-model-impl-calls.cc: New file.
* region-model-manager.cc: New file.
* region-model-reachability.cc: New file.
* region-model-reachability.h: New file.
* region-model.cc: Include "analyzer/call-string.h",
"analyzer/program-point.h", and "analyzer/store.h" before
"analyzer/region-model.h". Include
"analyzer/region-model-reachability.h".
(dump_tree): Make non-static.
(dump_quoted_tree): Make non-static.
(print_quoted_type): Make non-static.
(path_var::dump): Delete.
(dump_separator): Delete.
(class impl_constraint_manager): Delete.
(svalue_id::print): Delete.
(svalue_id::dump_node_name_to_pp): Delete.
(svalue_id::validate): Delete.
(region_id::print): Delete.
(region_id::dump_node_name_to_pp): Delete.
(region_id::validate): Delete.
(region_id_set::region_id_set): Delete.
(svalue_id_set::svalue_id_set): Delete.
(svalue::operator==): Delete.
(svalue::hash): Delete.
(svalue::print): Delete.
(svalue::dump_dot_to_pp): Delete.
(svalue::remap_region_ids): Delete.
(svalue::walk_for_canonicalization): Delete.
(svalue::get_child_sid): Delete.
(svalue::maybe_get_constant): Delete.
(region_svalue::compare_fields): Delete.
(region_svalue::add_to_hash): Delete.
(region_svalue::print_details): Delete.
(region_svalue::dump_dot_to_pp): Delete.
(region_svalue::remap_region_ids): Delete.
(region_svalue::merge_values): Delete.
(region_svalue::walk_for_canonicalization): Delete.
(region_svalue::eval_condition): Delete.
(constant_svalue::compare_fields): Delete.
(constant_svalue::add_to_hash): Delete.
(constant_svalue::merge_values): Delete.
(constant_svalue::eval_condition): Move to svalue.cc.
(constant_svalue::print_details): Delete.
(constant_svalue::get_child_sid): Delete.
(unknown_svalue::compare_fields): Delete.
(unknown_svalue::add_to_hash): Delete.
(unknown_svalue::print_details): Delete.
(poison_kind_to_str): Move to svalue.cc.
(poisoned_svalue::compare_fields): Delete.
(poisoned_svalue::add_to_hash): Delete.
(poisoned_svalue::print_details): Delete.
(region_kind_to_str): Move to region.cc and reimplement.
(region::operator==): Delete.
(region::get_parent_region): Delete.
(region::set_value): Delete.
(region::become_active_view): Delete.
(region::deactivate_any_active_view): Delete.
(region::deactivate_view): Delete.
(region::get_value): Delete.
(region::get_inherited_child_sid): Delete.
(region_model::copy_region): Delete.
(region_model::copy_struct_region): Delete.
(region_model::copy_union_region): Delete.
(region_model::copy_array_region): Delete.
(region::hash): Delete.
(region::print): Delete.
(region::dump_dot_to_pp): Delete.
(region::dump_to_pp): Delete.
(region::dump_child_label): Delete.
(region::validate): Delete.
(region::remap_svalue_ids): Delete.
(region::remap_region_ids): Delete.
(region::add_view): Delete.
(region::get_view): Delete.
(region::region): Move to region.cc.
(region::add_to_hash): Delete.
(region::print_fields): Delete.
(region::non_null_p): Delete.
(primitive_region::clone): Delete.
(primitive_region::walk_for_canonicalization): Delete.
(map_region::map_region): Delete.
(map_region::compare_fields): Delete.
(map_region::print_fields): Delete.
(map_region::validate): Delete.
(map_region::dump_dot_to_pp): Delete.
(map_region::dump_child_label): Delete.
(map_region::get_or_create): Delete.
(map_region::get): Delete.
(map_region::add_to_hash): Delete.
(map_region::remap_region_ids): Delete.
(map_region::unbind): Delete.
(map_region::get_tree_for_child_region): Delete.
(map_region::get_tree_for_child_region): Delete.
(tree_cmp): Move to region.cc.
(map_region::can_merge_p): Delete.
(map_region::walk_for_canonicalization): Delete.
(map_region::get_value_by_name): Delete.
(struct_or_union_region::valid_key_p): Delete.
(struct_or_union_region::compare_fields): Delete.
(struct_region::clone): Delete.
(struct_region::compare_fields): Delete.
(union_region::clone): Delete.
(union_region::compare_fields): Delete.
(frame_region::compare_fields): Delete.
(frame_region::clone): Delete.
(frame_region::valid_key_p): Delete.
(frame_region::print_fields): Delete.
(frame_region::add_to_hash): Delete.
(globals_region::compare_fields): Delete.
(globals_region::clone): Delete.
(globals_region::valid_key_p): Delete.
(code_region::compare_fields): Delete.
(code_region::clone): Delete.
(code_region::valid_key_p): Delete.
(array_region::array_region): Delete.
(array_region::get_element): Delete.
(array_region::clone): Delete.
(array_region::compare_fields): Delete.
(array_region::print_fields): Delete.
(array_region::validate): Delete.
(array_region::dump_dot_to_pp): Delete.
(array_region::dump_child_label): Delete.
(array_region::get_or_create): Delete.
(array_region::get): Delete.
(array_region::add_to_hash): Delete.
(array_region::remap_region_ids): Delete.
(array_region::get_key_for_child_region): Delete.
(array_region::key_cmp): Delete.
(array_region::walk_for_canonicalization): Delete.
(array_region::key_from_constant): Delete.
(array_region::constant_from_key): Delete.
(function_region::compare_fields): Delete.
(function_region::clone): Delete.
(function_region::valid_key_p): Delete.
(stack_region::stack_region): Delete.
(stack_region::compare_fields): Delete.
(stack_region::clone): Delete.
(stack_region::print_fields): Delete.
(stack_region::dump_child_label): Delete.
(stack_region::validate): Delete.
(stack_region::push_frame): Delete.
(stack_region::get_current_frame_id): Delete.
(stack_region::pop_frame): Delete.
(stack_region::add_to_hash): Delete.
(stack_region::remap_region_ids): Delete.
(stack_region::can_merge_p): Delete.
(stack_region::walk_for_canonicalization): Delete.
(stack_region::get_value_by_name): Delete.
(heap_region::heap_region): Delete.
(heap_region::compare_fields): Delete.
(heap_region::clone): Delete.
(heap_region::walk_for_canonicalization): Delete.
(root_region::root_region): Delete.
(root_region::compare_fields): Delete.
(root_region::clone): Delete.
(root_region::print_fields): Delete.
(root_region::validate): Delete.
(root_region::dump_child_label): Delete.
(root_region::push_frame): Delete.
(root_region::get_current_frame_id): Delete.
(root_region::pop_frame): Delete.
(root_region::ensure_stack_region): Delete.
(root_region::get_stack_region): Delete.
(root_region::ensure_globals_region): Delete.
(root_region::get_code_region): Delete.
(root_region::ensure_code_region): Delete.
(root_region::get_globals_region): Delete.
(root_region::ensure_heap_region): Delete.
(root_region::get_heap_region): Delete.
(root_region::remap_region_ids): Delete.
(root_region::can_merge_p): Delete.
(root_region::add_to_hash): Delete.
(root_region::walk_for_canonicalization): Delete.
(root_region::get_value_by_name): Delete.
(symbolic_region::symbolic_region): Delete.
(symbolic_region::compare_fields): Delete.
(symbolic_region::clone): Delete.
(symbolic_region::walk_for_canonicalization): Delete.
(symbolic_region::print_fields): Delete.
(region_model::region_model): Add region_model_manager * param.
Reimplement in terms of store, dropping impl_constraint_manager
subclass.
(region_model::operator=): Reimplement in terms of store
(region_model::operator==): Likewise.
(region_model::hash): Likewise.
(region_model::print): Delete.
(region_model::print_svalue): Delete.
(region_model::dump_dot_to_pp): Delete.
(region_model::dump_dot_to_file): Delete.
(region_model::dump_dot): Delete.
(region_model::dump_to_pp): Replace "summarize" param with
"simple" and "multiline". Port to store-based implementation.
(region_model::dump): Replace "summarize" param with "simple" and
"multiline".
(dump_vec_of_tree): Delete.
(region_model::dump_summary_of_rep_path_vars): Delete.
(region_model::validate): Delete.
(svalue_id_cmp_by_constant_svalue_model): Delete.
(svalue_id_cmp_by_constant_svalue): Delete.
(region_model::canonicalize): Drop "ctxt" param. Reimplement in
terms of store and constraints.
(region_model::canonicalized_p): Remove NULL arg to canonicalize.
(region_model::loop_replay_fixup): New.
(poisoned_value_diagnostic::emit): Tweak wording of warnings.
(region_model::check_for_poison): Delete.
(region_model::get_gassign_result): New.
(region_model::on_assignment): Port to store-based implementation.
(region_model::on_call_pre): Delete calls to check_for_poison.
Move implementations to region-model-impl-calls.c and port to
store-based implementation.
(region_model::on_call_post): Likewise.
(class reachable_regions): Move to region-model-reachability.h/cc
and port to store-based implementation.
(region_model::handle_unrecognized_call): Port to store-based
implementation.
(region_model::get_reachable_svalues): New.
(region_model::on_setjmp): Port to store-based implementation.
(region_model::on_longjmp): Likewise.
(region_model::handle_phi): Drop is_back_edge param and the logic
using it.
(region_model::get_lvalue_1): Port from region_id to const region *.
(region_model::make_region_for_unexpected_tree_code): Delete.
(assert_compat_types): If the check fails, use internal_error to
show the types.
(region_model::get_lvalue): Port from region_id to const region *.
(region_model::get_rvalue_1): Port from svalue_id to const svalue *.
(region_model::get_rvalue): Likewise.
(region_model::get_or_create_ptr_svalue): Delete.
(region_model::get_or_create_constant_svalue): Delete.
(region_model::get_svalue_for_fndecl): Delete.
(region_model::get_region_for_fndecl): Delete.
(region_model::get_svalue_for_label): Delete.
(region_model::get_region_for_label): Delete.
(build_cast): Delete.
(region_model::maybe_cast_1): Delete.
(region_model::maybe_cast): Delete.
(region_model::get_field_region): Delete.
(region_model::get_store_value): New.
(region_model::region_exists_p): New.
(region_model::deref_rvalue): Port from svalue_id to const svalue *.
(region_model::set_value): Likewise.
(region_model::clobber_region): New.
(region_model::purge_region): New.
(region_model::zero_fill_region): New.
(region_model::mark_region_as_unknown): New.
(region_model::eval_condition): Port from svalue_id to
const svalue *.
(region_model::eval_condition_without_cm): Likewise.
(region_model::compare_initial_and_pointer): New.
(region_model::add_constraint): Port from svalue_id to
const svalue *.
(region_model::maybe_get_constant): Delete.
(region_model::get_representative_path_var): New.
(region_model::add_new_malloc_region): Delete.
(region_model::get_representative_tree): Port to const svalue *.
(region_model::get_representative_path_var): Port to
const region *.
(region_model::get_path_vars_for_svalue): Delete.
(region_model::set_to_new_unknown_value): Delete.
(region_model::update_for_phis): Don't pass is_back_edge to handle_phi.
(region_model::update_for_call_superedge): Port from svalue_id to
const svalue *.
(region_model::update_for_return_superedge): Port to store-based
implementation.
(region_model::update_for_call_summary): Replace
set_to_new_unknown_value with mark_region_as_unknown.
(region_model::get_root_region): Delete.
(region_model::get_stack_region_id): Delete.
(region_model::push_frame): Delete.
(region_model::get_current_frame_id): Delete.
(region_model::get_current_function): Delete.
(region_model::pop_frame): Delete.
(region_model::on_top_level_param): New.
(region_model::get_stack_depth): Delete.
(region_model::get_function_at_depth): Delete.
(region_model::get_globals_region_id): Delete.
(region_model::add_svalue): Delete.
(region_model::replace_svalue): Delete.
(region_model::add_region): Delete.
(region_model::get_svalue): Delete.
(region_model::get_region): Delete.
(make_region_for_type): Delete.
(region_model::add_region_for_type): Delete.
(region_model::on_top_level_param): New.
(class restrict_to_used_svalues): Delete.
(region_model::purge_unused_svalues): Delete.
(region_model::push_frame): New.
(region_model::remap_svalue_ids): Delete.
(region_model::remap_region_ids): Delete.
(region_model::purge_regions): Delete.
(region_model::get_descendents): Delete.
(region_model::delete_region_and_descendents): Delete.
(region_model::poison_any_pointers_to_bad_regions): Delete.
(region_model::can_merge_with_p): Delete.
(region_model::get_current_function): New.
(region_model::get_value_by_name): Delete.
(region_model::convert_byte_offset_to_array_index): Delete.
(region_model::pop_frame): New.
(region_model::get_or_create_mem_ref): Delete.
(region_model::get_stack_depth): New.
(region_model::get_frame_at_index): New.
(region_model::unbind_region_and_descendents): New.
(struct bad_pointer_finder): New.
(region_model::get_or_create_pointer_plus_expr): Delete.
(region_model::poison_any_pointers_to_descendents): New.
(region_model::get_or_create_view): Delete.
(region_model::can_merge_with_p): New.
(region_model::get_fndecl_for_call): Port from svalue_id to
const svalue *.
(struct append_ssa_names_cb_data): New.
(get_ssa_name_regions_for_current_frame): New.
(region_model::append_ssa_names_cb): New.
(model_merger::dump_to_pp): Add "simple" param. Drop dumping of
remappings.
(model_merger::dump): Add "simple" param to both overloads.
(model_merger::can_merge_values_p): Delete.
(model_merger::record_regions): Delete.
(model_merger::record_svalues): Delete.
(svalue_id_merger_mapping::svalue_id_merger_mapping): Delete.
(svalue_id_merger_mapping::dump_to_pp): Delete.
(svalue_id_merger_mapping::dump): Delete.
(region_model::create_region_for_heap_alloc): New.
(region_model::create_region_for_alloca): New.
(region_model::record_dynamic_extents): New.
(canonicalization::canonicalization): Delete.
(canonicalization::walk_rid): Delete.
(canonicalization::walk_sid): Delete.
(canonicalization::dump_to_pp): Delete.
(canonicalization::dump): Delete.
(inchash::add): Delete overloads for svalue_id and region_id.
(engine::log_stats): New.
(assert_condition): Add overload comparing svalues.
(assert_dump_eq): Pass "true" for multiline.
(selftest::test_dump): Update for rewrite of region_model.
(selftest::test_dump_2): Rename to...
(selftest::test_struct): ...this. Provide a region_model_manager
when creating region_model instance. Remove dump test. Add
checks for get_offset.
(selftest::test_dump_3): Rename to...
(selftest::test_array_1): ...this. Provide a region_model_manager
when creating region_model instance. Remove dump test.
(selftest::test_get_representative_tree): Port from svalue_id to
new API. Add test coverage for various expressions.
(selftest::test_unique_constants): Provide a region_model_manager
for the region_model. Add test coverage for comparing const vs
non-const.
(selftest::test_svalue_equality): Delete.
(selftest::test_region_equality): Delete.
(selftest::test_unique_unknowns): New.
(class purge_all_svalue_ids): Delete.
(class purge_one_svalue_id): Delete.
(selftest::test_purging_by_criteria): Delete.
(selftest::test_initial_svalue_folding): New.
(selftest::test_unaryop_svalue_folding): New.
(selftest::test_binop_svalue_folding): New.
(selftest::test_sub_svalue_folding): New.
(selftest::test_purge_unused_svalues): Delete.
(selftest::test_descendent_of_p): New.
(selftest::test_assignment): Provide a region_model_manager for
the region_model. Drop the dump test.
(selftest::test_compound_assignment): Likewise.
(selftest::test_stack_frames): Port to new implementation.
(selftest::test_get_representative_path_var): Likewise.
(selftest::test_canonicalization_1): Rename to...
(selftest::test_equality_1): ...this. Port to new API, and add
(selftest::test_canonicalization_2): Provide a
region_model_manager when creating region_model instances.
Remove redundant canicalization.
(selftest::test_canonicalization_3): Provide a
region_model_manager when creating region_model instances.
Remove param from calls to region_model::canonicalize.
(selftest::test_canonicalization_4): Likewise.
(selftest::assert_region_models_merge): Constify
out_merged_svalue. Port to new API.
(selftest::test_state_merging): Provide a
region_model_manager when creating region_model instances.
Provide a program_point point when merging them. Replace
set_to_new_unknown_value with usage of placeholder_svalues.
Drop get_value_by_name. Port from svalue_id to const svalue *.
Add test of heap allocation.
(selftest::test_constraint_merging): Provide a
region_model_manager when creating region_model instances.
Provide a program_point point when merging them. Eliminate use
of set_to_new_unknown_value.
(selftest::test_widening_constraints): New.
(selftest::test_iteration_1): New.
(selftest::test_malloc_constraints): Port to store-based
implementation.
(selftest::test_var): New test.
(selftest::test_array_2): New test.
(selftest::test_mem_ref): New test.
(selftest::test_POINTER_PLUS_EXPR_then_MEM_REF): New.
(selftest::test_malloc): New.
(selftest::test_alloca): New.
(selftest::analyzer_region_model_cc_tests): Update for renamings.
Call new functions.
* region-model.h (class path_var): Move to analyzer.h.
(class svalue_id): Delete.
(class region_id): Delete.
(class id_map): Delete.
(svalue_id_map): Delete.
(region_id_map): Delete.
(id_map<T>::id_map): Delete.
(id_map<T>::put): Delete.
(id_map<T>::get_dst_for_src): Delete.
(id_map<T>::get_src_for_dst): Delete.
(id_map<T>::dump_to_pp): Delete.
(id_map<T>::dump): Delete.
(id_map<T>::update): Delete.
(one_way_svalue_id_map): Delete.
(one_way_region_id_map): Delete.
(class region_id_set): Delete.
(class svalue_id_set): Delete.
(struct complexity): New.
(class visitor): New.
(enum svalue_kind): Add SK_SETJMP, SK_INITIAL, SK_UNARYOP,
SK_BINOP, SK_SUB,SK_UNMERGEABLE, SK_PLACEHOLDER, SK_WIDENING,
SK_COMPOUND, and SK_CONJURED.
(svalue::operator==): Delete.
(svalue::operator!=): Delete.
(svalue::clone): Delete.
(svalue::hash): Delete.
(svalue::dump_dot_to_pp): Delete.
(svalue::dump_to_pp): New.
(svalue::dump): New.
(svalue::get_desc): New.
(svalue::dyn_cast_initial_svalue): New.
(svalue::dyn_cast_unaryop_svalue): New.
(svalue::dyn_cast_binop_svalue): New.
(svalue::dyn_cast_sub_svalue): New.
(svalue::dyn_cast_unmergeable_svalue): New.
(svalue::dyn_cast_widening_svalue): New.
(svalue::dyn_cast_compound_svalue): New.
(svalue::dyn_cast_conjured_svalue): New.
(svalue::maybe_undo_cast): New.
(svalue::unwrap_any_unmergeable): New.
(svalue::remap_region_ids): Delete
(svalue::can_merge_p): New.
(svalue::walk_for_canonicalization): Delete
(svalue::get_complexity): New.
(svalue::get_child_sid): Delete
(svalue::accept): New.
(svalue::live_p): New.
(svalue::implicitly_live_p): New.
(svalue::svalue): Add complexity param.
(svalue::add_to_hash): Delete
(svalue::print_details): Delete
(svalue::m_complexity): New field.
(region_svalue::key_t): New struct.
(region_svalue::region_svalue): Port from region_id to
const region_id *. Add complexity.
(region_svalue::compare_fields): Delete.
(region_svalue::clone): Delete.
(region_svalue::dump_dot_to_pp): Delete.
(region_svalue::get_pointee): Port from region_id to
const region_id *.
(region_svalue::remap_region_ids): Delete.
(region_svalue::merge_values): Delete.
(region_svalue::dump_to_pp): New.
(region_svalue::accept): New.
(region_svalue::walk_for_canonicalization): Delete.
(region_svalue::eval_condition): Make params const.
(region_svalue::add_to_hash): Delete.
(region_svalue::print_details): Delete.
(region_svalue::m_rid): Replace with...
(region_svalue::m_reg): ...this.
(is_a_helper <region_svalue *>::test): Convert to...
(is_a_helper <const region_svalue *>::test): ...this.
(template <> struct default_hash_traits<region_svalue::key_t>):
New.
(constant_svalue::constant_svalue): Add complexity.
(constant_svalue::compare_fields): Delete.
(constant_svalue::clone): Delete.
(constant_svalue::add_to_hash): Delete.
(constant_svalue::dump_to_pp): New.
(constant_svalue::accept): New.
(constant_svalue::implicitly_live_p): New.
(constant_svalue::merge_values): Delete.
(constant_svalue::eval_condition): Make params const.
(constant_svalue::get_child_sid): Delete.
(constant_svalue::print_details): Delete.
(is_a_helper <constant_svalue *>::test): Convert to...
(is_a_helper <const constant_svalue *>::test): ...this.
(class unknown_svalue): Update leading comment.
(unknown_svalue::unknown_svalue): Add complexity.
(unknown_svalue::compare_fields): Delete.
(unknown_svalue::add_to_hash): Delete.
(unknown_svalue::dyn_cast_unknown_svalue): Delete.
(unknown_svalue::print_details): Delete.
(unknown_svalue::dump_to_pp): New.
(unknown_svalue::accept): New.
(poisoned_svalue::key_t): New struct.
(poisoned_svalue::poisoned_svalue): Add complexity.
(poisoned_svalue::compare_fields): Delete.
(poisoned_svalue::clone): Delete.
(poisoned_svalue::add_to_hash): Delete.
(poisoned_svalue::dump_to_pp): New.
(poisoned_svalue::accept): New.
(poisoned_svalue::print_details): Delete.
(is_a_helper <poisoned_svalue *>::test): Convert to...
(is_a_helper <const poisoned_svalue *>::test): ...this.
(template <> struct default_hash_traits<poisoned_svalue::key_t>):
New.
(setjmp_record::add_to_hash): New.
(setjmp_svalue::key_t): New struct.
(setjmp_svalue::compare_fields): Delete.
(setjmp_svalue::clone): Delete.
(setjmp_svalue::add_to_hash): Delete.
(setjmp_svalue::setjmp_svalue): Add complexity.
(setjmp_svalue::dump_to_pp): New.
(setjmp_svalue::accept): New.
(setjmp_svalue::void print_details): Delete.
(is_a_helper <const setjmp_svalue *>::test): New.
(template <> struct default_hash_traits<setjmp_svalue::key_t>): New.
(class initial_svalue : public svalue): New.
(is_a_helper <const initial_svalue *>::test): New.
(class unaryop_svalue): New.
(is_a_helper <const unaryop_svalue *>::test): New.
(template <> struct default_hash_traits<unaryop_svalue::key_t>): New.
(class binop_svalue): New.
(is_a_helper <const binop_svalue *>::test): New.
(template <> struct default_hash_traits<binop_svalue::key_t>): New.
(class sub_svalue): New.
(is_a_helper <const sub_svalue *>::test): New.
(template <> struct default_hash_traits<sub_svalue::key_t>): New.
(class unmergeable_svalue): New.
(is_a_helper <const unmergeable_svalue *>::test): New.
(class placeholder_svalue): New.
(is_a_helper <placeholder_svalue *>::test): New.
(class widening_svalue): New.
(is_a_helper <widening_svalue *>::test): New.
(template <> struct default_hash_traits<widening_svalue::key_t>): New.
(class compound_svalue): New.
(is_a_helper <compound_svalue *>::test): New.
(template <> struct default_hash_traits<compound_svalue::key_t>): New.
(class conjured_svalue): New.
(is_a_helper <conjured_svalue *>::test): New.
(template <> struct default_hash_traits<conjured_svalue::key_t>): New.
(enum region_kind): Delete RK_PRIMITIVE, RK_STRUCT, RK_UNION, and
RK_ARRAY. Add RK_LABEL, RK_DECL, RK_FIELD, RK_ELEMENT, RK_OFFSET,
RK_CAST, RK_HEAP_ALLOCATED, RK_ALLOCA, RK_STRING, and RK_UNKNOWN.
(region_kind_to_str): Delete.
(region::~region): Move implementation to region.cc.
(region::operator==): Delete.
(region::operator!=): Delete.
(region::clone): Delete.
(region::get_id): New.
(region::cmp_ids): New.
(region::dyn_cast_map_region): Delete.
(region::dyn_cast_array_region): Delete.
(region::region_id get_parent): Delete.
(region::get_parent_region): Convert to a simple accessor.
(region::void set_value): Delete.
(region::svalue_id get_value): Delete.
(region::svalue_id get_value_direct): Delete.
(region::svalue_id get_inherited_child_sid): Delete.
(region::dyn_cast_frame_region): New.
(region::dyn_cast_function_region): New.
(region::dyn_cast_decl_region): New.
(region::dyn_cast_field_region): New.
(region::dyn_cast_element_region): New.
(region::dyn_cast_offset_region): New.
(region::dyn_cast_cast_region): New.
(region::dyn_cast_string_region): New.
(region::accept): New.
(region::get_base_region): New.
(region::base_region_p): New.
(region::descendent_of_p): New.
(region::maybe_get_frame_region): New.
(region::maybe_get_decl): New.
(region::hash): Delete.
(region::rint): Delete.
(region::dump_dot_to_pp): Delete.
(region::get_desc): New.
(region::dump_to_pp): Convert to vfunc, changing signature.
(region::dump_child_label): Delete.
(region::remap_svalue_ids): Delete.
(region::remap_region_ids): Delete.
(region::dump): New.
(region::walk_for_canonicalization): Delete.
(region::non_null_p): Drop region_model param.
(region::add_view): Delete.
(region::get_view): Delete.
(region::get_active_view): Delete.
(region::is_view_p): Delete.
(region::cmp_ptrs): New.
(region::validate): Delete.
(region::get_offset): New.
(region::get_byte_size): New.
(region::get_bit_size): New.
(region::get_subregions_for_binding): New.
(region::region): Add complexity param. Convert parent from
region_id to const region *. Drop svalue_id. Drop copy ctor.
(region::symbolic_for_unknown_ptr_p): New.
(region::add_to_hash): Delete.
(region::print_fields): Delete.
(region::get_complexity): New accessor.
(region::become_active_view): Delete.
(region::deactivate_any_active_view): Delete.
(region::deactivate_view): Delete.
(region::calc_offset): New.
(region::m_parent_rid): Delete.
(region::m_sval_id): Delete.
(region::m_complexity): New.
(region::m_id): New.
(region::m_parent): New.
(region::m_view_rids): Delete.
(region::m_is_view): Delete.
(region::m_active_view_rid): Delete.
(region::m_cached_offset): New.
(is_a_helper <region *>::test): Convert to...
(is_a_helper <const region *>::test): ... this.
(class primitive_region): Delete.
(class space_region): New.
(class map_region): Delete.
(is_a_helper <map_region *>::test): Delete.
(class frame_region): Reimplement.
(template <> struct default_hash_traits<frame_region::key_t>):
New.
(class globals_region): Reimplement.
(is_a_helper <globals_region *>::test): Convert to...
(is_a_helper <const globals_region *>::test): ...this.
(class struct_or_union_region): Delete.
(is_a_helper <struct_or_union_region *>::test): Delete.
(class code_region): Reimplement.
(is_a_helper <const code_region *>::test): New.
(class struct_region): Delete.
(is_a_helper <struct_region *>::test): Delete.
(class function_region): Reimplement.
(is_a_helper <function_region *>::test): Convert to...
(is_a_helper <const function_region *>::test): ...this.
(class union_region): Delete.
(is_a_helper <union_region *>::test): Delete.
(class label_region): New.
(is_a_helper <const label_region *>::test): New.
(class scope_region): Delete.
(class stack_region): Reimplement.
(is_a_helper <stack_region *>::test): Convert to...
(is_a_helper <const stack_region *>::test): ...this.
(class heap_region): Reimplement.
(is_a_helper <heap_region *>::test): Convert to...
(is_a_helper <const heap_region *>::test): ...this.
(class root_region): Reimplement.
(is_a_helper <root_region *>::test): Convert to...
(is_a_helper <const root_region *>::test): ...this.
(class symbolic_region): Reimplement.
(is_a_helper <const symbolic_region *>::test): New.
(template <> struct default_hash_traits<symbolic_region::key_t>):
New.
(class decl_region): New.
(is_a_helper <const decl_region *>::test): New.
(class field_region): New.
(template <> struct default_hash_traits<field_region::key_t>): New.
(class array_region): Delete.
(class element_region): New.
(is_a_helper <array_region *>::test): Delete.
(is_a_helper <const element_region *>::test): New.
(template <> struct default_hash_traits<element_region::key_t>):
New.
(class offset_region): New.
(is_a_helper <const offset_region *>::test): New.
(template <> struct default_hash_traits<offset_region::key_t>):
New.
(class cast_region): New.
(is_a_helper <const cast_region *>::test): New.
(template <> struct default_hash_traits<cast_region::key_t>): New.
(class heap_allocated_region): New.
(class alloca_region): New.
(class string_region): New.
(is_a_helper <const string_region *>::test): New.
(class unknown_region): New.
(class region_model_manager): New.
(struct append_ssa_names_cb_data): New.
(class call_details): New.
(region_model::region_model): Add region_model_manager param.
(region_model::print_svalue): Delete.
(region_model::dump_dot_to_pp): Delete.
(region_model::dump_dot_to_file): Delete.
(region_model::dump_dot): Delete.
(region_model::dump_to_pp): Drop summarize param in favor of
simple and multiline.
(region_model::dump): Likewise.
(region_model::summarize_to_pp): Delete.
(region_model::summarize): Delete.
(region_model::void canonicalize): Drop ctxt param.
(region_model::void check_for_poison): Delete.
(region_model::get_gassign_result): New.
(region_model::impl_call_alloca): New.
(region_model::impl_call_analyzer_describe): New.
(region_model::impl_call_analyzer_eval): New.
(region_model::impl_call_builtin_expect): New.
(region_model::impl_call_calloc): New.
(region_model::impl_call_free): New.
(region_model::impl_call_malloc): New.
(region_model::impl_call_memset): New.
(region_model::impl_call_strlen): New.
(region_model::get_reachable_svalues): New.
(region_model::handle_phi): Drop is_back_edge param.
(region_model::region_id get_root_rid): Delete.
(region_model::root_region *get_root_region): Delete.
(region_model::region_id get_stack_region_id): Delete.
(region_model::push_frame): Convert from region_id and svalue_id
to const region * and const svalue *.
(region_model::get_current_frame_id): Replace with...
(region_model::get_current_frame): ...this.
(region_model::pop_frame): Convert from region_id to
const region *. Drop purge and stats param. Add out_result.
(region_model::function *get_function_at_depth): Delete.
(region_model::get_globals_region_id): Delete.
(region_model::add_svalue): Delete.
(region_model::replace_svalue): Delete.
(region_model::add_region): Delete.
(region_model::add_region_for_type): Delete.
(region_model::get_svalue): Delete.
(region_model::get_region): Delete.
(region_model::get_lvalue): Convert from region_id to
const region *.
(region_model::get_rvalue): Convert from svalue_id to
const svalue *.
(region_model::get_or_create_ptr_svalue): Delete.
(region_model::get_or_create_constant_svalue): Delete.
(region_model::get_svalue_for_fndecl): Delete.
(region_model::get_svalue_for_label): Delete.
(region_model::get_region_for_fndecl): Delete.
(region_model::get_region_for_label): Delete.
(region_model::get_frame_at_index (int index) const;): New.
(region_model::maybe_cast): Delete.
(region_model::maybe_cast_1): Delete.
(region_model::get_field_region): Delete.
(region_model::id deref_rvalue): Convert from region_id and
svalue_id to const region * and const svalue *. Drop overload,
passing in both a tree and an svalue.
(region_model::set_value): Convert from region_id and svalue_id to
const region * and const svalue *.
(region_model::set_to_new_unknown_value): Delete.
(region_model::clobber_region (const region *reg);): New.
(region_model::purge_region (const region *reg);): New.
(region_model::zero_fill_region (const region *reg);): New.
(region_model::mark_region_as_unknown (const region *reg);): New.
(region_model::copy_region): Convert from region_id to
const region *.
(region_model::eval_condition): Convert from svalue_id to
const svalue *.
(region_model::eval_condition_without_cm): Likewise.
(region_model::compare_initial_and_pointer): New.
(region_model:maybe_get_constant): Delete.
(region_model::add_new_malloc_region): Delete.
(region_model::get_representative_tree): Convert from svalue_id to
const svalue *.
(region_model::get_representative_path_var): Delete decl taking a
region_id in favor of two decls, for svalue vs region, with an
svalue_set to ensure termination.
(region_model::get_path_vars_for_svalue): Delete.
(region_model::create_region_for_heap_alloc): New.
(region_model::create_region_for_alloca): New.
(region_model::purge_unused_svalues): Delete.
(region_model::remap_svalue_ids): Delete.
(region_model::remap_region_ids): Delete.
(region_model::purge_regions): Delete.
(region_model::get_num_svalues): Delete.
(region_model::get_num_regions): Delete.
(region_model::get_descendents): Delete.
(region_model::get_store): New.
(region_model::delete_region_and_descendents): Delete.
(region_model::get_manager): New.
(region_model::unbind_region_and_descendents): New.
(region_model::can_merge_with_p): Add point param. Drop
svalue_id_merger_mapping.
(region_model::get_value_by_name): Delete.
(region_model::convert_byte_offset_to_array_index): Delete.
(region_model::get_or_create_mem_ref): Delete.
(region_model::get_or_create_pointer_plus_expr): Delete.
(region_model::get_or_create_view): Delete.
(region_model::get_lvalue_1): Convert from region_id to
const region *.
(region_model::get_rvalue_1): Convert from svalue_id to
const svalue *.
(region_model::get_ssa_name_regions_for_current_frame): New.
(region_model::append_ssa_names_cb): New.
(region_model::get_store_value): New.
(region_model::copy_struct_region): Delete.
(region_model::copy_union_region): Delete.
(region_model::copy_array_region): Delete.
(region_model::region_exists_p): New.
(region_model::make_region_for_unexpected_tree_code): Delete.
(region_model::loop_replay_fixup): New.
(region_model::poison_any_pointers_to_bad_regions): Delete.
(region_model::poison_any_pointers_to_descendents): New.
(region_model::dump_summary_of_rep_path_vars): Delete.
(region_model::on_top_level_param): New.
(region_model::record_dynamic_extents): New.
(region_model::m_mgr;): New.
(region_model::m_store;): New.
(region_model::m_svalues;): Delete.
(region_model::m_regions;): Delete.
(region_model::m_root_rid;): Delete.
(region_model::m_current_frame;): New.
(region_model_context::remap_svalue_ids): Delete.
(region_model_context::can_purge_p): Delete.
(region_model_context::on_svalue_leak): New.
(region_model_context::on_svalue_purge): Delete.
(region_model_context::on_liveness_change): New.
(region_model_context::on_inherited_svalue): Delete.
(region_model_context::on_cast): Delete.
(region_model_context::on_unknown_change): Convert from svalue_id to
const svalue * and add is_mutable.
(class noop_region_model_context): Update for region_model_context
changes.
(model_merger::model_merger): Add program_point. Drop
svalue_id_merger_mapping.
(model_merger::dump_to_pp): Add "simple" param.
(model_merger::dump): Likewise.
(model_merger::get_region_a): Delete.
(model_merger::get_region_b): Delete.
(model_merger::can_merge_values_p): Delete.
(model_merger::record_regions): Delete.
(model_merger::record_svalues): Delete.
(model_merger::m_point): New field.
(model_merger::m_map_regions_from_a_to_m): Delete.
(model_merger::m_map_regions_from_b_to_m): Delete.
(model_merger::m_sid_mapping): Delete.
(struct svalue_id_merger_mapping): Delete.
(class engine): New.
(struct canonicalization): Delete.
(inchash::add): Delete decls for hashing svalue_id and region_id.
(test_region_model_context::on_unexpected_tree_code): Require t to
be non-NULL.
(selftest::assert_condition): Add overload comparing a pair of
const svalue *.
* sm-file.cc: Include "tristate.h", "selftest.h",
"analyzer/call-string.h", "analyzer/program-point.h",
"analyzer/store.h", and "analyzer/region-model.h".
(fileptr_state_machine::get_default_state): New.
(fileptr_state_machine::on_stmt): Remove calls to
get_readable_tree in favor of get_diagnostic_tree.
* sm-malloc.cc: Include "tristate.h", "selftest.h",
"analyzer/call-string.h", "analyzer/program-point.h",
"analyzer/store.h", and "analyzer/region-model.h".
(malloc_state_machine::get_default_state): New.
(malloc_state_machine::reset_when_passed_to_unknown_fn_p): New.
(malloc_diagnostic::describe_state_change): Handle change.m_expr
being NULL.
(null_arg::emit): Avoid printing "NULL '0'".
(null_arg::describe_final_event): Avoid printing "(0) NULL".
(malloc_leak::emit): Handle m_arg being NULL.
(malloc_leak::describe_final_event): Handle ev.m_expr being NULL.
(malloc_state_machine::on_stmt): Don't call get_readable_tree.
Call get_diagnostic_tree when creating pending diagnostics.
Update for is_zero_assignment becoming a member function of
sm_ctxt.
Don't transition to m_non_heap for ADDR_EXPR(MEM_REF()).
(malloc_state_machine::reset_when_passed_to_unknown_fn_p): New
vfunc implementation.
* sm-sensitive.cc (sensitive_state_machine::warn_for_any_exposure): Call
get_diagnostic_tree and pass the result to warn_for_state.
* sm-signal.cc: Move includes of "analyzer/call-string.h" and
"analyzer/program-point.h" to before "analyzer/region-model.h",
and also include "analyzer/store.h" before it.
(signal_unsafe_call::describe_state_change): Use
get_dest_function to get handler.
(update_model_for_signal_handler): Pass manager to region_model
ctor.
(register_signal_handler::impl_transition): Update for changes to
get_or_create_node and add_edge.
* sm-taint.cc (taint_state_machine::on_stmt): Remove calls to
get_readable_tree, replacing them when calling warn_for_state with
calls to get_diagnostic_tree.
* sm.cc (is_zero_assignment): Delete.
(any_pointer_p): Move to within namespace ana.
* sm.h (is_zero_assignment): Remove decl.
(any_pointer_p): Move decl to within namespace ana.
(state_machine::get_default_state): New vfunc.
(state_machine::reset_when_passed_to_unknown_fn_p): New vfunc.
(sm_context::get_readable_tree): Rename to...
(sm_context::get_diagnostic_tree): ...this.
(sm_context::is_zero_assignment): New vfunc.
* store.cc: New file.
* store.h: New file.
* svalue.cc: New file.
gcc/testsuite/ChangeLog:
PR analyzer/93032
PR analyzer/93938
PR analyzer/94011
PR analyzer/94099
PR analyzer/94399
PR analyzer/94458
PR analyzer/94503
PR analyzer/94640
PR analyzer/94688
PR analyzer/94689
PR analyzer/94839
PR analyzer/95026
PR analyzer/95042
PR analyzer/95240
* g++.dg/analyzer/pr93212.C: Add dg-warning for dangling
reference.
* g++.dg/analyzer/pr93950.C: Remove xfail.
* g++.dg/analyzer/pr94011.C: New test.
* g++.dg/analyzer/pr94028.C: Remove leak false positives; mark as
failing on C++98.
* g++.dg/analyzer/pr94503.C: New test.
* g++.dg/analyzer/pr95042.C: New test.
* gcc.dg/analyzer/CVE-2005-1689-dedupe-issue-2.c: New test.
* gcc.dg/analyzer/CVE-2005-1689-dedupe-issue.c: Add xfail.
* gcc.dg/analyzer/CVE-2005-1689-minimal.c:
Include "analyzer-decls.h".
(test_4, test_5, test_6, test_7, test_8): New tests.
* gcc.dg/analyzer/abs-1.c: New test.
* gcc.dg/analyzer/aliasing-1.c: New test.
* gcc.dg/analyzer/aliasing-2.c: New test.
* gcc.dg/analyzer/analyzer-decls.h (__analyzer_describe): New
decl.
(__analyzer_dump_num_heap_regions): Remove.
* gcc.dg/analyzer/attribute-nonnull.c: Add dg-warnings for cases
where NULL is directly used as an argument.
* gcc.dg/analyzer/bzero-1.c: New test.
* gcc.dg/analyzer/casts-1.c: New test.
* gcc.dg/analyzer/casts-2.c: New test.
* gcc.dg/analyzer/compound-assignment-1.c
(test_4): Remove xfail from leak false positive.
(called_by_test_5a): Add "allocated here" expected message.
(called_by_test_5b): Make expected leak message more precise.
* gcc.dg/analyzer/compound-assignment-3.c: Update expected leak
message.
* gcc.dg/analyzer/compound-assignment-4.c: New test.
* gcc.dg/analyzer/compound-assignment-5.c: New test.
* gcc.dg/analyzer/conditionals-notrans.c: Remove xfails.
* gcc.dg/analyzer/data-model-1.c (test_12d): Update expected
results.
(test_13): Remove xfail.
(test_14): Remove xfail.
(test_15): Remove xfail.
(test_16): Remove xfails. Add out-of-bounds access.
(test_16_alt): Remove xfails.
(test_23): Remove xfail.
(test_24): Remove xfail.
(test_25): Remove xfail.
(test_26): Update expected result. Remove xfail. Add xfail.
(test_27): Remove xfails.
(test_29): Add __analyzer_eval pointer comparisons.
(test_41): Generalize expected output for u.ptr comparison with
NULL for targets where this could be known to be false.
(test_42): Remove xfail.
(test_51): Remove xfails.
* gcc.dg/analyzer/data-model-13.c: Update for improvements to
source location and wording of leak message.
* gcc.dg/analyzer/data-model-14.c: Remove -fanalyzer-fine-grained.
(test_1): Update for improvement to expected message.
(test_2): Remove xfail.
* gcc.dg/analyzer/data-model-18.c: Remove xfail.
* gcc.dg/analyzer/data-model-20.c: New test.
* gcc.dg/analyzer/data-model-5.c: Add dg-warning for deref of
NULL. Add xfailing false leak.
* gcc.dg/analyzer/data-model-5b.c: Add xfailing false leak.
* gcc.dg/analyzer/data-model-5c.c: Update xfailing false leak.
* gcc.dg/analyzer/data-model-5d.c: Reimplement.
* gcc.dg/analyzer/data-model-6.c: Delete test.
* gcc.dg/analyzer/data-model-8.c: Remove xfail.
* gcc.dg/analyzer/describe-1.c: New test.
* gcc.dg/analyzer/dot-output.c: Remove xfail.
* gcc.dg/analyzer/explode-1.c: Add expected leak warning.
* gcc.dg/analyzer/explode-2.c: Add expected leak warnings. Mark
double-free warnings as xfail for now.
* gcc.dg/analyzer/feasibility-1.c: New test.
* gcc.dg/analyzer/first-field-1.c: New test.
* gcc.dg/analyzer/first-field-2.c: New test.
* gcc.dg/analyzer/init.c: New test.
* gcc.dg/analyzer/leak-2.c: New test.
* gcc.dg/analyzer/loop-0-up-to-n-by-1-with-iter-obj.c: New test.
* gcc.dg/analyzer/loop-0-up-to-n-by-1.c: New test.
* gcc.dg/analyzer/loop-2a.c: Update expected behavior.
* gcc.dg/analyzer/loop-3.c: Mark use-after-free as xfail. Add
expected warning about deref of unchecked pointer.
* gcc.dg/analyzer/loop-4.c: Remove -fno-analyzer-state-purge.
Update expected behavior.
* gcc.dg/analyzer/loop-n-down-to-1-by-1.c: New test.
* gcc.dg/analyzer/loop-start-down-to-end-by-1.c: New test.
* gcc.dg/analyzer/loop-start-down-to-end-by-step.c: New test.
* gcc.dg/analyzer/loop-start-to-end-by-step.c: New test.
* gcc.dg/analyzer/loop-start-up-to-end-by-1.c: New test.
* gcc.dg/analyzer/loop.c: Remove -fno-analyzer-state-purge.
Update expected behavior.
* gcc.dg/analyzer/malloc-1.c: Remove xfails from leak false
positives. Update expected wording of global_link.m_ptr leak.
(test_49): New test.
* gcc.dg/analyzer/malloc-4.c: Remove leak false positive. Update
expected wording of leak warning.
* gcc.dg/analyzer/malloc-in-loop.c: New test.
* gcc.dg/analyzer/malloc-ipa-8-double-free.c: Update expected path
to show call to wrapped_malloc.
* gcc.dg/analyzer/malloc-ipa-8-unchecked.c: Remove
-fanalyzer-verbose-state-changes.
* gcc.dg/analyzer/malloc-paths-9.c: Remove comment about duplicate
warnings. Remove duplicate use-after-free paths.
* gcc.dg/analyzer/malloc-vs-local-1a.c: Add dg-warning for deref
of unchecked pointer. Update expected number of enodes.
* gcc.dg/analyzer/malloc-vs-local-2.c: Likewise.
* gcc.dg/analyzer/malloc-vs-local-3.c: Add dg-warning for deref of
unchecked pointer. Update expected number of enodes. Avoid
overspecifying the leak message.
* gcc.dg/analyzer/memset-1.c: New test.
* gcc.dg/analyzer/paths-3.c: Update expected number of enodes.
* gcc.dg/analyzer/paths-4.c: Likewise.
* gcc.dg/analyzer/paths-6.c: Likewise.
* gcc.dg/analyzer/paths-7.c: Likewise.
* gcc.dg/analyzer/pr93032-mztools-simplified.c: New test.
* gcc.dg/analyzer/pr93032-mztools.c: New test.
* gcc.dg/analyzer/pr93382.c: Mark taint tests as failing.
* gcc.dg/analyzer/pr93938.c: New test.
* gcc.dg/analyzer/pr94099.c: Replace uninit dg-warning with
dg-warning for NULL dereference.
* gcc.dg/analyzer/pr94399.c: New test.
* gcc.dg/analyzer/pr94447.c: Add dg-warning for NULL dereference.
* gcc.dg/analyzer/pr94458.c: New test.
* gcc.dg/analyzer/pr94640.c: New test.
* gcc.dg/analyzer/pr94688.c: New test.
* gcc.dg/analyzer/pr94689.c: New test.
* gcc.dg/analyzer/pr94839.c: New test.
* gcc.dg/analyzer/pr95026.c: New test.
* gcc.dg/analyzer/pr95240.c: New test.
* gcc.dg/analyzer/refcounting-1.c: New test.
* gcc.dg/analyzer/single-field.c: New test.
* gcc.dg/analyzer/stale-frame-1.c: New test.
* gcc.dg/analyzer/symbolic-1.c: New test.
* gcc.dg/analyzer/symbolic-2.c: New test.
* gcc.dg/analyzer/symbolic-3.c: New test.
* gcc.dg/analyzer/symbolic-4.c: New test.
* gcc.dg/analyzer/symbolic-5.c: New test.
* gcc.dg/analyzer/symbolic-6.c: New test.
* gcc.dg/analyzer/taint-1.c: Mark the "gets unchecked value"
events as failing for now. Update dg-message directives to avoid
relying on numbering.
* gcc.dg/analyzer/torture/loop-inc-ptr-1.c: New test.
* gcc.dg/analyzer/torture/loop-inc-ptr-2.c: New test.
* gcc.dg/analyzer/torture/loop-inc-ptr-3.c: New test.
* gcc.dg/analyzer/unknown-fns-2.c: New test.
* gcc.dg/analyzer/unknown-fns-3.c: New test.
* gcc.dg/analyzer/unknown-fns-4.c: New test.
* gcc.dg/analyzer/unknown-fns.c: Update dg-warning to reflect fixed
source location for leak diagnostic.
* gcc.dg/analyzer/use-after-free.c: New test.
* gcc.dg/analyzer/vla-1.c: New test.
* gcc.dg/analyzer/zlib-4.c: Rewrite to avoid "exit" calls. Add
expected leak warnings.
* gfortran.dg/analyzer/pr93993.f90: Remove leak of tm warning,
which seems to have been a false positive.
|
|
PR analyzer/93993 reports another ICE within
diagnostic_manager::prune_for_sm_diagnostic in which the expression
of interest becomes a non-lvalue (similar to PR 93544, PR 93647, and
PR 93950), due to attempting to get an lvalue for a non-lvalue with a
NULL context, leading to an ICE when the failure is reported to
make_region_for_unexpected_tree_code. The tree in question is
an ADDR_EXPR of a VAR_DECL, due to:
event 11: switching var of interest from ‘tm’ in callee to ‘&qb’ in caller
This patch adds more bulletproofing to the routine by introducing
a tentative_region_model_context class that can be passed in such
circumstances which records that an error occurred, and then
checking to see if an error was recorded, thus avoiding the ICE.
This is papering over the problem, but a better solution seems more
like stage 1 material.
The patch also refactors the error-checking for CONSTANT_CLASS_P.
The testcase pr93993.f90 has a false positive:
pr93993.f90:19:0:
19 | allocate (tm) ! { dg-warning "dereference of possibly-NULL" }
|
Warning: dereference of possibly-NULL ‘_6’ [CWE-690] [-Wanalyzer-possible-null-dereference]
which appears to be a pre-existing bug affecting any allocate call in
Fortran, which I will fix in a followup.
gcc/analyzer/ChangeLog:
PR analyzer/93993
* checker-path.h (state_change_event::get_lvalue): Add ctxt param
and pass it to region_model::get_value call.
* diagnostic-manager.cc (get_any_origin): Pass a
tentative_region_model_context to the calls to get_lvalue and reject
the comparison if errors occur.
(can_be_expr_of_interest_p): New function.
(diagnostic_manager::prune_for_sm_diagnostic): Replace checks for
CONSTANT_CLASS_P with calls to update_for_unsuitable_sm_exprs.
Pass a tentative_region_model_context to the calls to
state_change_event::get_lvalue and reject the comparison if errors
occur.
(diagnostic_manager::update_for_unsuitable_sm_exprs): New.
* diagnostic-manager.h
(diagnostic_manager::update_for_unsuitable_sm_exprs): New decl.
* region-model.h (class tentative_region_model_context): New class.
gcc/testsuite/ChangeLog:
PR analyzer/93993
* gfortran.dg/analyzer/pr93993.f90: New test.
|
|
This patch removes the hack in is_setjmp_call_p of looking for
"setjmp" and "_setjmp", replacing it with some logic adapted from
special_function_p in calls.c, ignoring up to 2 leading underscores from
the fndecl's name when checking for a function by name.
It also requires that such functions are "extern" and at file scope
for them to be matched.
The patch also generalizes the setjmp/longjmp handling in the analyzer
to also work with sigsetjmp/siglongjmp. Doing so requires generalizing
some hardcoded functions in diagnostics (which were hardcoded to avoid
user-facing messages referring to "_setjmp", which is an implementation
detail) - the patch adds a new function, get_user_facing_name for this,
for use on calls that matched is_named_call_p and
is_specical_named_call_p.
gcc/analyzer/ChangeLog:
* analyzer.cc (is_named_call_p): Check that fndecl is "extern"
and at file scope. Potentially disregard prefix _ or __ in
fndecl's name. Bail if the identifier is NULL.
(is_setjmp_call_p): Expect a gcall rather than plain gimple.
Remove special-case check for leading prefix, and also check for
sigsetjmp.
(is_longjmp_call_p): Also check for siglongjmp.
(get_user_facing_name): New function.
* analyzer.h (is_setjmp_call_p): Expect a gcall rather than plain
gimple.
(get_user_facing_name): New decl.
* checker-path.cc (setjmp_event::get_desc): Use
get_user_facing_name to avoid hardcoding the function name.
(rewind_event::rewind_event): Add rewind_info param, using it to
initialize new m_rewind_info field, and strengthen the assertion.
(rewind_from_longjmp_event::get_desc): Use get_user_facing_name to
avoid hardcoding the function name.
(rewind_to_setjmp_event::get_desc): Likewise.
* checker-path.h (setjmp_event::setjmp_event): Add setjmp_call
param and use it to initialize...
(setjmp_event::m_setjmp_call): New field.
(rewind_event::rewind_event): Add rewind_info param.
(rewind_event::m_rewind_info): New protected field.
(rewind_from_longjmp_event::rewind_from_longjmp_event): Add
rewind_info param.
(class rewind_to_setjmp_event): Move rewind_info field to parent
class.
* diagnostic-manager.cc (diagnostic_manager::add_events_for_eedge):
Update setjmp-handling for is_setjmp_call_p requiring a gcall;
pass the call to the new setjmp_event.
* engine.cc (exploded_node::on_stmt): Update for is_setjmp_call_p
requiring a gcall.
(stale_jmp_buf::emit): Use get_user_facing_name to avoid
hardcoding the function names.
(exploded_node::on_longjmp): Pass the longjmp_call when
constructing rewind_info.
(rewind_info_t::add_events_to_path): Pass the rewind_info_t to the
rewind_from_longjmp_event's ctor.
* exploded-graph.h (rewind_info_t::rewind_info_t): Add
longjmp_call param.
(rewind_info_t::get_longjmp_call): New.
(rewind_info_t::m_longjmp_call): New.
* region-model.cc (region_model::on_setjmp): Update comment to
indicate this is also for sigsetjmp.
* region-model.h (struct setjmp_record): Likewise.
(class setjmp_svalue): Likewise.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/sigsetjmp-5.c: New test.
* gcc.dg/analyzer/sigsetjmp-6.c: New test.
|
|
PR analyzer/93307 reports that in an LTO bootstrap, there are ODR
violations between:
- the "region" type:
gcc/analyzer/region-model.h:792
vs:
gcc/sched-int.h:1443
- the "constraint" type:
gcc/analyzer/constraint-manager.h:121
vs:
gcc/tree-ssa-structalias.c:533
This patches solves this clash by putting all of the analyzer names
within a namespace. I chose "ana" as it is short (to save typing).
The analyzer selftests are moved from namespace "selftest" to
"ana::selftest".
There are various places where the namespace has to be closed
and reopened, to allow e.g. for specializations of templates
in the global namespace.
gcc/analyzer/ChangeLog:
PR analyzer/93307
* analysis-plan.h: Wrap everything namespace "ana".
* analyzer-logging.cc: Likewise.
* analyzer-logging.h: Likewise.
* analyzer-pass.cc (pass_analyzer::execute): Update for "ana"
namespace.
* analyzer-selftests.cc: Wrap everything namespace "ana".
* analyzer-selftests.h: Likewise.
* analyzer.h: Likewise for forward decls of types.
* call-string.h: Likewise.
* checker-path.cc: Likewise.
* checker-path.h: Likewise.
* constraint-manager.cc: Likewise.
* constraint-manager.h: Likewise.
* diagnostic-manager.cc: Likewise.
* diagnostic-manager.h: Likewise.
* engine.cc: Likewise.
* engine.h: Likewise.
* exploded-graph.h: Likewise.
* function-set.cc: Likewise.
* function-set.h: Likewise.
* pending-diagnostic.cc: Likewise.
* pending-diagnostic.h: Likewise.
* program-point.cc: Likewise.
* program-point.h: Likewise.
* program-state.cc: Likewise.
* program-state.h: Likewise.
* region-model.cc: Likewise.
* region-model.h: 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.
* sm.h: Likewise.
* state-purge.h: Likewise.
* supergraph.cc: Likewise.
* supergraph.h: Likewise.
gcc/ChangeLog:
PR analyzer/93307
* gdbinit.in (break-on-saved-diagnostic): Update for move of
diagnostic_manager into "ana" namespace.
* selftest-run-tests.c (selftest::run_tests): Update for move of
selftest::run_analyzer_selftests to
ana::selftest::run_analyzer_selftests.
|
|
This patch adds DISABLE_COPY_AND_ASSIGN to checker_path, and makes its
fields private.
gcc/analyzer/ChangeLog:
* checker-path.h (checker_path::get_checker_event): New function.
(checker_path): Add DISABLE_COPY_AND_ASSIGN; make fields private.
* diagnostic-manager.cc
(diagnostic_manager::prune_for_sm_diagnostic): Replace direct
access to checker_path::m_events with accessor functions. Fix
overlong line.
(diagnostic_manager::prune_interproc_events): Replace direct
access to checker_path::m_events with accessor functions.
(diagnostic_manager::finish_pruning): Likewise.
|
|
checker_event has a clone vfunc implemented by all the concrete
subclasses, but this is never used (a holdover from a very early
implementation). This patch deletes it.
gcc/analyzer/ChangeLog:
* checker-path.h (checker_event::clone): Delete vfunc decl.
(debug_event::clone): Delete vfunc impl.
(custom_event::clone): Delete vfunc impl.
(statement_event::clone): Delete vfunc impl.
(function_entry_event::clone): Delete vfunc impl.
(state_change_event::clone): Delete vfunc impl.
(start_cfg_edge_event::clone): Delete vfunc impl.
(end_cfg_edge_event::clone): Delete vfunc impl.
(call_event::clone): Delete vfunc impl.
(return_event::clone): Delete vfunc impl.
(setjmp_event::clone): Delete vfunc impl.
(rewind_from_longjmp_event::clone): Delete vfunc impl.
(rewind_to_setjmp_event::clone): Delete vfunc impl.
(warning_event::clone): Delete vfunc impl.
|
|
This patch adds a static analysis pass to the middle-end, focusing
for this release on C code, and malloc/free issues in particular.
See:
https://gcc.gnu.org/wiki/DavidMalcolm/StaticAnalyzer
gcc/ChangeLog:
* Makefile.in (lang_opt_files): Add analyzer.opt.
(ANALYZER_OBJS): New.
(OBJS): Add digraph.o, graphviz.o, ordered-hash-map-tests.o,
tristate.o and ANALYZER_OBJS.
(TEXI_GCCINT_FILES): Add analyzer.texi.
* common.opt (-fanalyzer): New driver option.
* config.in: Regenerate.
* configure: Regenerate.
* configure.ac (--disable-analyzer, ENABLE_ANALYZER): New option.
(gccdepdir): Also create depdir for "analyzer" subdir.
* digraph.cc: New file.
* digraph.h: New file.
* doc/analyzer.texi: New file.
* doc/gccint.texi ("Static Analyzer") New menu item.
(analyzer.texi): Include it.
* doc/invoke.texi ("Static Analyzer Options"): New list and new section.
("Warning Options"): Add static analysis warnings to the list.
(-Wno-analyzer-double-fclose): New option.
(-Wno-analyzer-double-free): New option.
(-Wno-analyzer-exposure-through-output-file): New option.
(-Wno-analyzer-file-leak): New option.
(-Wno-analyzer-free-of-non-heap): New option.
(-Wno-analyzer-malloc-leak): New option.
(-Wno-analyzer-possible-null-argument): New option.
(-Wno-analyzer-possible-null-dereference): New option.
(-Wno-analyzer-null-argument): New option.
(-Wno-analyzer-null-dereference): New option.
(-Wno-analyzer-stale-setjmp-buffer): New option.
(-Wno-analyzer-tainted-array-index): New option.
(-Wno-analyzer-use-after-free): New option.
(-Wno-analyzer-use-of-pointer-in-stale-stack-frame): New option.
(-Wno-analyzer-use-of-uninitialized-value): New option.
(-Wanalyzer-too-complex): New option.
(-fanalyzer-call-summaries): New warning.
(-fanalyzer-checker=): New warning.
(-fanalyzer-fine-grained): New warning.
(-fno-analyzer-state-merge): New warning.
(-fno-analyzer-state-purge): New warning.
(-fanalyzer-transitivity): New warning.
(-fanalyzer-verbose-edges): New warning.
(-fanalyzer-verbose-state-changes): New warning.
(-fanalyzer-verbosity=): New warning.
(-fdump-analyzer): New warning.
(-fdump-analyzer-callgraph): New warning.
(-fdump-analyzer-exploded-graph): New warning.
(-fdump-analyzer-exploded-nodes): New warning.
(-fdump-analyzer-exploded-nodes-2): New warning.
(-fdump-analyzer-exploded-nodes-3): New warning.
(-fdump-analyzer-supergraph): New warning.
* doc/sourcebuild.texi (dg-require-dot): New.
(dg-check-dot): New.
* gdbinit.in (break-on-saved-diagnostic): New command.
* graphviz.cc: New file.
* graphviz.h: New file.
* ordered-hash-map-tests.cc: New file.
* ordered-hash-map.h: New file.
* passes.def (pass_analyzer): Add before
pass_ipa_whole_program_visibility.
* selftest-run-tests.c (selftest::run_tests): Call
selftest::ordered_hash_map_tests_cc_tests.
* selftest.h (selftest::ordered_hash_map_tests_cc_tests): New
decl.
* shortest-paths.h: New file.
* timevar.def (TV_ANALYZER): New timevar.
(TV_ANALYZER_SUPERGRAPH): Likewise.
(TV_ANALYZER_STATE_PURGE): Likewise.
(TV_ANALYZER_PLAN): Likewise.
(TV_ANALYZER_SCC): Likewise.
(TV_ANALYZER_WORKLIST): Likewise.
(TV_ANALYZER_DUMP): Likewise.
(TV_ANALYZER_DIAGNOSTICS): Likewise.
(TV_ANALYZER_SHORTEST_PATHS): Likewise.
* tree-pass.h (make_pass_analyzer): New decl.
* tristate.cc: New file.
* tristate.h: New file.
gcc/analyzer/ChangeLog:
* ChangeLog: New file.
* analyzer-selftests.cc: New file.
* analyzer-selftests.h: New file.
* analyzer.opt: New file.
* analysis-plan.cc: New file.
* analysis-plan.h: New file.
* analyzer-logging.cc: New file.
* analyzer-logging.h: New file.
* analyzer-pass.cc: New file.
* analyzer.cc: New file.
* analyzer.h: New file.
* call-string.cc: New file.
* call-string.h: New file.
* checker-path.cc: New file.
* checker-path.h: New file.
* constraint-manager.cc: New file.
* constraint-manager.h: New file.
* diagnostic-manager.cc: New file.
* diagnostic-manager.h: New file.
* engine.cc: New file.
* engine.h: New file.
* exploded-graph.h: New file.
* pending-diagnostic.cc: New file.
* pending-diagnostic.h: New file.
* program-point.cc: New file.
* program-point.h: New file.
* program-state.cc: New file.
* program-state.h: New file.
* region-model.cc: New file.
* region-model.h: New file.
* sm-file.cc: New file.
* sm-malloc.cc: New file.
* sm-malloc.dot: New file.
* sm-pattern-test.cc: New file.
* sm-sensitive.cc: New file.
* sm-signal.cc: New file.
* sm-taint.cc: New file.
* sm.cc: New file.
* sm.h: New file.
* state-purge.cc: New file.
* state-purge.h: New file.
* supergraph.cc: New file.
* supergraph.h: New file.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/CVE-2005-1689-minimal.c: New test.
* gcc.dg/analyzer/abort.c: New test.
* gcc.dg/analyzer/alloca-leak.c: New test.
* gcc.dg/analyzer/analyzer-decls.h: New header.
* gcc.dg/analyzer/analyzer-verbosity-0.c: New test.
* gcc.dg/analyzer/analyzer-verbosity-1.c: New test.
* gcc.dg/analyzer/analyzer-verbosity-2.c: New test.
* gcc.dg/analyzer/analyzer.exp: New suite.
* gcc.dg/analyzer/attribute-nonnull.c: New test.
* gcc.dg/analyzer/call-summaries-1.c: New test.
* gcc.dg/analyzer/conditionals-2.c: New test.
* gcc.dg/analyzer/conditionals-3.c: New test.
* gcc.dg/analyzer/conditionals-notrans.c: New test.
* gcc.dg/analyzer/conditionals-trans.c: New test.
* gcc.dg/analyzer/data-model-1.c: New test.
* gcc.dg/analyzer/data-model-2.c: New test.
* gcc.dg/analyzer/data-model-3.c: New test.
* gcc.dg/analyzer/data-model-4.c: New test.
* gcc.dg/analyzer/data-model-5.c: New test.
* gcc.dg/analyzer/data-model-5b.c: New test.
* gcc.dg/analyzer/data-model-5c.c: New test.
* gcc.dg/analyzer/data-model-5d.c: New test.
* gcc.dg/analyzer/data-model-6.c: New test.
* gcc.dg/analyzer/data-model-7.c: New test.
* gcc.dg/analyzer/data-model-8.c: New test.
* gcc.dg/analyzer/data-model-9.c: New test.
* gcc.dg/analyzer/data-model-11.c: New test.
* gcc.dg/analyzer/data-model-12.c: New test.
* gcc.dg/analyzer/data-model-13.c: New test.
* gcc.dg/analyzer/data-model-14.c: New test.
* gcc.dg/analyzer/data-model-15.c: New test.
* gcc.dg/analyzer/data-model-16.c: New test.
* gcc.dg/analyzer/data-model-17.c: New test.
* gcc.dg/analyzer/data-model-18.c: New test.
* gcc.dg/analyzer/data-model-19.c: New test.
* gcc.dg/analyzer/data-model-path-1.c: New test.
* gcc.dg/analyzer/disabling.c: New test.
* gcc.dg/analyzer/dot-output.c: New test.
* gcc.dg/analyzer/double-free-lto-1-a.c: New test.
* gcc.dg/analyzer/double-free-lto-1-b.c: New test.
* gcc.dg/analyzer/double-free-lto-1.h: New header.
* gcc.dg/analyzer/equivalence.c: New test.
* gcc.dg/analyzer/explode-1.c: New test.
* gcc.dg/analyzer/explode-2.c: New test.
* gcc.dg/analyzer/factorial.c: New test.
* gcc.dg/analyzer/fibonacci.c: New test.
* gcc.dg/analyzer/fields.c: New test.
* gcc.dg/analyzer/file-1.c: New test.
* gcc.dg/analyzer/file-2.c: New test.
* gcc.dg/analyzer/function-ptr-1.c: New test.
* gcc.dg/analyzer/function-ptr-2.c: New test.
* gcc.dg/analyzer/function-ptr-3.c: New test.
* gcc.dg/analyzer/gzio-2.c: New test.
* gcc.dg/analyzer/gzio-3.c: New test.
* gcc.dg/analyzer/gzio-3a.c: New test.
* gcc.dg/analyzer/gzio.c: New test.
* gcc.dg/analyzer/infinite-recursion.c: New test.
* gcc.dg/analyzer/loop-2.c: New test.
* gcc.dg/analyzer/loop-2a.c: New test.
* gcc.dg/analyzer/loop-3.c: New test.
* gcc.dg/analyzer/loop-4.c: New test.
* gcc.dg/analyzer/loop.c: New test.
* gcc.dg/analyzer/malloc-1.c: New test.
* gcc.dg/analyzer/malloc-2.c: New test.
* gcc.dg/analyzer/malloc-3.c: New test.
* gcc.dg/analyzer/malloc-callbacks.c: New test.
* gcc.dg/analyzer/malloc-dce.c: New test.
* gcc.dg/analyzer/malloc-dedupe-1.c: New test.
* gcc.dg/analyzer/malloc-ipa-1.c: New test.
* gcc.dg/analyzer/malloc-ipa-10.c: New test.
* gcc.dg/analyzer/malloc-ipa-11.c: New test.
* gcc.dg/analyzer/malloc-ipa-12.c: New test.
* gcc.dg/analyzer/malloc-ipa-13.c: New test.
* gcc.dg/analyzer/malloc-ipa-2.c: New test.
* gcc.dg/analyzer/malloc-ipa-3.c: New test.
* gcc.dg/analyzer/malloc-ipa-4.c: New test.
* gcc.dg/analyzer/malloc-ipa-5.c: New test.
* gcc.dg/analyzer/malloc-ipa-6.c: New test.
* gcc.dg/analyzer/malloc-ipa-7.c: New test.
* gcc.dg/analyzer/malloc-ipa-8-double-free.c: New test.
* gcc.dg/analyzer/malloc-ipa-8-lto-a.c: New test.
* gcc.dg/analyzer/malloc-ipa-8-lto-b.c: New test.
* gcc.dg/analyzer/malloc-ipa-8-lto-c.c: New test.
* gcc.dg/analyzer/malloc-ipa-8-lto.h: New test.
* gcc.dg/analyzer/malloc-ipa-8-unchecked.c: New test.
* gcc.dg/analyzer/malloc-ipa-9.c: New test.
* gcc.dg/analyzer/malloc-macro-inline-events.c: New test.
* gcc.dg/analyzer/malloc-macro-separate-events.c: New test.
* gcc.dg/analyzer/malloc-macro.h: New header.
* gcc.dg/analyzer/malloc-many-paths-1.c: New test.
* gcc.dg/analyzer/malloc-many-paths-2.c: New test.
* gcc.dg/analyzer/malloc-many-paths-3.c: New test.
* gcc.dg/analyzer/malloc-paths-1.c: New test.
* gcc.dg/analyzer/malloc-paths-10.c: New test.
* gcc.dg/analyzer/malloc-paths-2.c: New test.
* gcc.dg/analyzer/malloc-paths-3.c: New test.
* gcc.dg/analyzer/malloc-paths-4.c: New test.
* gcc.dg/analyzer/malloc-paths-5.c: New test.
* gcc.dg/analyzer/malloc-paths-6.c: New test.
* gcc.dg/analyzer/malloc-paths-7.c: New test.
* gcc.dg/analyzer/malloc-paths-8.c: New test.
* gcc.dg/analyzer/malloc-paths-9.c: New test.
* gcc.dg/analyzer/malloc-vs-local-1a.c: New test.
* gcc.dg/analyzer/malloc-vs-local-1b.c: New test.
* gcc.dg/analyzer/malloc-vs-local-2.c: New test.
* gcc.dg/analyzer/malloc-vs-local-3.c: New test.
* gcc.dg/analyzer/malloc-vs-local-4.c: New test.
* gcc.dg/analyzer/operations.c: New test.
* gcc.dg/analyzer/params-2.c: New test.
* gcc.dg/analyzer/params.c: New test.
* gcc.dg/analyzer/paths-1.c: New test.
* gcc.dg/analyzer/paths-1a.c: New test.
* gcc.dg/analyzer/paths-2.c: New test.
* gcc.dg/analyzer/paths-3.c: New test.
* gcc.dg/analyzer/paths-4.c: New test.
* gcc.dg/analyzer/paths-5.c: New test.
* gcc.dg/analyzer/paths-6.c: New test.
* gcc.dg/analyzer/paths-7.c: New test.
* gcc.dg/analyzer/pattern-test-1.c: New test.
* gcc.dg/analyzer/pattern-test-2.c: New test.
* gcc.dg/analyzer/pointer-merging.c: New test.
* gcc.dg/analyzer/pr61861.c: New test.
* gcc.dg/analyzer/pragma-1.c: New test.
* gcc.dg/analyzer/scope-1.c: New test.
* gcc.dg/analyzer/sensitive-1.c: New test.
* gcc.dg/analyzer/setjmp-1.c: New test.
* gcc.dg/analyzer/setjmp-2.c: New test.
* gcc.dg/analyzer/setjmp-3.c: New test.
* gcc.dg/analyzer/setjmp-4.c: New test.
* gcc.dg/analyzer/setjmp-5.c: New test.
* gcc.dg/analyzer/setjmp-6.c: New test.
* gcc.dg/analyzer/setjmp-7.c: New test.
* gcc.dg/analyzer/setjmp-7a.c: New test.
* gcc.dg/analyzer/setjmp-8.c: New test.
* gcc.dg/analyzer/setjmp-9.c: New test.
* gcc.dg/analyzer/signal-1.c: New test.
* gcc.dg/analyzer/signal-2.c: New test.
* gcc.dg/analyzer/signal-3.c: New test.
* gcc.dg/analyzer/signal-4a.c: New test.
* gcc.dg/analyzer/signal-4b.c: New test.
* gcc.dg/analyzer/strcmp-1.c: New test.
* gcc.dg/analyzer/switch.c: New test.
* gcc.dg/analyzer/taint-1.c: New test.
* gcc.dg/analyzer/zlib-1.c: New test.
* gcc.dg/analyzer/zlib-2.c: New test.
* gcc.dg/analyzer/zlib-3.c: New test.
* gcc.dg/analyzer/zlib-4.c: New test.
* gcc.dg/analyzer/zlib-5.c: New test.
* gcc.dg/analyzer/zlib-6.c: New test.
* lib/gcc-defs.exp (dg-check-dot): New procedure.
* lib/target-supports.exp (check_dot_available): New procedure.
(check_effective_target_analyzer): New.
* lib/target-supports-dg.exp (dg-require-dot): New procedure.
|