aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer/checker-path.h
AgeCommit message (Collapse)AuthorFilesLines
2024-06-18diagnostics: eliminate "tree" from diagnostic_{event,path}David Malcolm1-0/+4
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>
2024-06-18diagnostics: move simple_diagnostic_{path,thread,event} to their own .h/ccDavid Malcolm1-0/+1
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>
2024-01-03Update copyright years.Jakub Jelinek1-1/+1
2023-11-17analyzer: new warning: -Wanalyzer-infinite-loop [PR106147]David Malcolm1-0/+1
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>
2023-09-14diagnostics: support multithreaded diagnostic pathsDavid Malcolm1-1/+16
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>
2023-01-16Update copyright years.Jakub Jelinek1-1/+1
2022-12-02analyzer: introduce struct event_loc_infoDavid Malcolm1-2/+1
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>
2022-12-02analyzer: fixes to region creation messages [PR107851]David Malcolm1-1/+2
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>
2022-11-11analyzer: split out checker_event classes to their own headerDavid Malcolm1-582/+2
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>
2022-11-11analyzer: new warning: -Wanalyzer-infinite-recursion [PR106147]David Malcolm1-5/+3
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>
2022-11-09analyzer: better logging of event creationDavid Malcolm1-5/+5
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>
2022-11-03analyzer: use std::unique_ptr for checker_eventDavid Malcolm1-2/+2
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>
2022-09-09analyzer: implement trust boundaries via a plugin for Linux kernelDavid Malcolm1-4/+30
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>
2022-07-02analyzer: add allocation size checker [PR105900]Tim Lange1-1/+1
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>
2022-06-15analyzer: fix up paths for inlining (PR analyzer/105962)David Malcolm1-13/+45
-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>
2022-06-02diagnostics: add SARIF output formatDavid Malcolm1-1/+21
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>
2022-05-20Use "final" and "override" directly, rather than via macrosDavid Malcolm1-26/+26
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>
2022-05-16analyzer: implement four new warnings for <stdarg.h> misuses [PR105103]David Malcolm1-1/+5
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>
2022-01-27analyzer: show region creation events for uninit warningsDavid Malcolm1-0/+21
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>
2022-01-03Update copyright years.Jakub Jelinek1-1/+1
2021-08-18analyzer: detect and analyze calls via function pointerAnkur Saini1-0/+6
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.
2021-06-18analyzer: refactor custom_event, introducing precanned_custom_event classDavid Malcolm1-5/+17
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>
2021-01-29analyzer: consolidate conditionals in pathsDavid Malcolm1-0/+55
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.
2021-01-04Update copyright years.Jakub Jelinek1-1/+1
2020-11-30Add analyzer plugin support and CPython GIL exampleDavid Malcolm1-0/+4
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.
2020-11-11analyzer: precision-of-wording for -Wanalyzer-stale-setjmp-bufferDavid Malcolm1-0/+6
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.
2020-08-13analyzer: rewrite of region and value-handlingDavid Malcolm1-6/+6
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.
2020-03-04analyzer: fix ICE on non-lvalue in prune_for_sm_diagnostic [PR93993]David Malcolm1-2/+2
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.
2020-01-27analyzer: fix setjmp-detection and support sigsetjmpDavid Malcolm1-12/+18
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.
2020-01-22analyzer: introduce namespace to avoid ODR clashes (PR 93307)David Malcolm1-0/+4
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.
2020-01-14analyzer: cleanups to checker_pathDavid Malcolm1-0/+8
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.
2020-01-14analyzer: delete checker_event::cloneDavid Malcolm1-72/+0
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.
2020-01-14Initial commit of analyzerDavid Malcolm1-0/+586
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.