aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer/analyzer.cc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2021-07-15 15:07:07 -0400
committerDavid Malcolm <dmalcolm@redhat.com>2021-07-15 15:07:07 -0400
commit33255ad3ac14e3953750fe0f2d82b901c2852ff6 (patch)
tree24cff3eaf638921b62d7c0586b180af1633b7c3e /gcc/analyzer/analyzer.cc
parent98cd4d123aa14598b1f0d54c22663c8200a96d9c (diff)
downloadgcc-33255ad3ac14e3953750fe0f2d82b901c2852ff6.zip
gcc-33255ad3ac14e3953750fe0f2d82b901c2852ff6.tar.gz
gcc-33255ad3ac14e3953750fe0f2d82b901c2852ff6.tar.bz2
analyzer: reimplement -Wanalyzer-use-of-uninitialized-value [PR95006 et al]
The initial gcc 10 era commit of the analyzer (in 757bf1dff5e8cee34c0a75d06140ca972bfecfa7) had an implementation of -Wanalyzer-use-of-uninitialized-value, but was sufficiently buggy that I removed it in 78b9783774bfd3540f38f5b1e3c7fc9f719653d7 before the release of gcc 10.1 This patch reintroduces the warning, heavily rewritten, with (I hope) a less buggy implementation this time, for GCC 12. gcc/analyzer/ChangeLog: PR analyzer/95006 PR analyzer/94713 PR analyzer/94714 * analyzer.cc (maybe_reconstruct_from_def_stmt): Split out GIMPLE_ASSIGN case into... (get_diagnostic_tree_for_gassign_1): New. (get_diagnostic_tree_for_gassign): New. * analyzer.h (get_diagnostic_tree_for_gassign): New decl. * analyzer.opt (Wanalyzer-write-to-string-literal): New. * constraint-manager.cc (class svalue_purger): New. (constraint_manager::purge_state_involving): New. * constraint-manager.h (constraint_manager::purge_state_involving): New. * diagnostic-manager.cc (saved_diagnostic::supercedes_p): New. (dedupe_winners::handle_interactions): New. (diagnostic_manager::emit_saved_diagnostics): Call it. * diagnostic-manager.h (saved_diagnostic::supercedes_p): New decl. * engine.cc (impl_region_model_context::warn): Convert return type to bool. Return false if the diagnostic isn't saved. (impl_region_model_context::purge_state_involving): New. (impl_sm_context::get_state): Use NULL ctxt when querying old rvalue. (impl_sm_context::set_next_state): Use new sval when querying old state. (class dump_path_diagnostic): Move to region-model.cc (exploded_node::on_stmt): Move to on_stmt_pre and on_stmt_post. Remove call to purge_state_involving. (exploded_node::on_stmt_pre): New, based on the above. Move most of it to region_model::on_stmt_pre. (exploded_node::on_stmt_post): Likewise, moving to region_model::on_stmt_post. (class stale_jmp_buf): Fix parent class to use curiously recurring template pattern. (feasibility_state::maybe_update_for_edge): Call on_call_pre and on_call_post on gcalls. * exploded-graph.h (impl_region_model_context::warn): Return bool. (impl_region_model_context::purge_state_involving): New decl. (exploded_node::on_stmt_pre): New decl. (exploded_node::on_stmt_post): New decl. * pending-diagnostic.h (pending_diagnostic::use_of_uninit_p): New. (pending_diagnostic::supercedes_p): New. * program-state.cc (sm_state_map::get_state): Inherit state for conjured_svalue as well as initial_svalue. (sm_state_map::purge_state_involving): Also support SK_CONJURED. * region-model-impl-calls.cc (call_details::get_uncertainty): Handle m_ctxt being NULL. (call_details::get_or_create_conjured_svalue): New. (region_model::impl_call_fgets): New. (region_model::impl_call_fread): New. * region-model-manager.cc (region_model_manager::get_or_create_initial_value): Return an uninitialized poisoned value for regions that can't have initial values. * region-model-reachability.cc (reachable_regions::mark_escaped_clusters): Handle ctxt being NULL. * region-model.cc (region_to_value_map::purge_state_involving): New. (poisoned_value_diagnostic::use_of_uninit_p): New. (poisoned_value_diagnostic::emit): Handle POISON_KIND_UNINIT. (poisoned_value_diagnostic::describe_final_event): Likewise. (region_model::check_for_poison): New. (region_model::on_assignment): Call it. (class dump_path_diagnostic): Move here from engine.cc. (region_model::on_stmt_pre): New, based on exploded_node::on_stmt. (region_model::on_call_pre): Move the setting of the LHS to a conjured svalue to before the checks for specific functions. Handle "fgets", "fgets_unlocked", and "fread". (region_model::purge_state_involving): New. (region_model::handle_unrecognized_call): Handle ctxt being NULL. (region_model::get_rvalue): Call check_for_poison. (selftest::test_stack_frames): Use NULL for context when getting uninitialized rvalue. (selftest::test_alloca): Likewise. * region-model.h (region_to_value_map::purge_state_involving): New decl. (call_details::get_or_create_conjured_svalue): New decl. (region_model::on_stmt_pre): New decl. (region_model::purge_state_involving): New decl. (region_model::impl_call_fgets): New decl. (region_model::impl_call_fread): New decl. (region_model::check_for_poison): New decl. (region_model_context::warn): Return bool. (region_model_context::purge_state_involving): New. (noop_region_model_context::warn): Return bool. (noop_region_model_context::purge_state_involving): New. (test_region_model_context:: warn): Return bool. * region.cc (region::get_memory_space): New. (region::can_have_initial_svalue_p): New. (region::involves_p): New. * region.h (enum memory_space): New. (region::get_memory_space): New decl. (region::can_have_initial_svalue_p): New decl. (region::involves_p): New decl. * sm-malloc.cc (use_after_free::supercedes_p): New. * store.cc (binding_cluster::purge_state_involving): New. (store::purge_state_involving): New. * store.h (class symbolic_binding): New forward decl. (binding_key::dyn_cast_symbolic_binding): New. (symbolic_binding::dyn_cast_symbolic_binding): New. (binding_cluster::purge_state_involving): New. (store::purge_state_involving): New. * svalue.cc (svalue::can_merge_p): Reject attempts to merge poisoned svalues with other svalues, so that we identify paths in which a variable is conditionally uninitialized. (involvement_visitor::visit_conjured_svalue): New. (svalue::involves_p): Also handle SK_CONJURED. (poison_kind_to_str): Handle POISON_KIND_UNINIT. (poisoned_svalue::maybe_fold_bits_within): New. * svalue.h (enum poison_kind): Add POISON_KIND_UNINIT. (poisoned_svalue::maybe_fold_bits_within): New decl. gcc/ChangeLog: PR analyzer/95006 PR analyzer/94713 PR analyzer/94714 * doc/invoke.texi: Add -Wanalyzer-use-of-uninitialized-value. gcc/testsuite/ChangeLog: PR analyzer/95006 PR analyzer/94713 PR analyzer/94714 * g++.dg/analyzer/pr93212.C: Update location of warning. * g++.dg/analyzer/pr94011.C: Add -Wno-analyzer-use-of-uninitialized-value. * g++.dg/analyzer/pr94503.C: Likewise. * gcc.dg/analyzer/clobbers-1.c: Convert "f" from a local to a param to avoid uninitialized warning. * gcc.dg/analyzer/data-model-1.c (test_12): Add test for uninitialized value on result of alloca. (test_12a): Add expected warning. (test_12c): Likewise. (test_19): Likewise. (test_29b): Likewise. (test_29c): Likewise. (test_37): Remove xfail. (test_37a): Likewise. * gcc.dg/analyzer/data-model-20.c: Add warning about leak. * gcc.dg/analyzer/explode-2.c: Remove params; add -Wno-analyzer-too-complex, -Wno-analyzer-malloc-leak, and xfails. Initialize the locals. * gcc.dg/analyzer/explode-2a.c: Initialize the locals. Add expected leak. * gcc.dg/analyzer/fgets-1.c: New test. * gcc.dg/analyzer/fread-1.c: New test. * gcc.dg/analyzer/malloc-1.c (test_16): Add expected warning. (test_40): Likewise. * gcc.dg/analyzer/memset-CVE-2017-18549-1.c: Check for uninitialized padding. * gcc.dg/analyzer/pr93355-localealias-feasibility.c (fread): New decl. (read_alias_file): Call it. * gcc.dg/analyzer/pr94047.c: Add expected warnings. * gcc.dg/analyzer/pr94851-2.c: Likewise. * gcc.dg/analyzer/pr96841.c: Convert local to a param. * gcc.dg/analyzer/pr98628.c: Likewise. * gcc.dg/analyzer/pr99042.c: Updated expected location of leak diagnostics. * gcc.dg/analyzer/symbolic-1.c: Add expected warnings. * gcc.dg/analyzer/symbolic-7.c: Likewise. * gcc.dg/analyzer/torture/pr93649.c: Add expected warning. Skip with -fno-fat-lto-objects. * gcc.dg/analyzer/uninit-1.c: New test. * gcc.dg/analyzer/uninit-2.c: New test. * gcc.dg/analyzer/uninit-3.c: New test. * gcc.dg/analyzer/uninit-4.c: New test. * gcc.dg/analyzer/uninit-pr94713.c: New test. * gcc.dg/analyzer/uninit-pr94714.c: New test. * gcc.dg/analyzer/use-after-free-2.c: New test. * gcc.dg/analyzer/use-after-free-3.c: New test. * gcc.dg/analyzer/zlib-3.c: Add expected warning. * gcc.dg/analyzer/zlib-6.c: Convert locals to params to avoid uninitialized warnings. Remove xfail. * gcc.dg/analyzer/zlib-6a.c: New test, based on the old version of the above. * gfortran.dg/analyzer/pr97668.f: Add -Wno-analyzer-use-of-uninitialized-value and -Wno-analyzer-too-complex. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc/analyzer/analyzer.cc')
-rw-r--r--gcc/analyzer/analyzer.cc95
1 files changed, 56 insertions, 39 deletions
diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
index a8ee1a1..ddace9a 100644
--- a/gcc/analyzer/analyzer.cc
+++ b/gcc/analyzer/analyzer.cc
@@ -63,6 +63,51 @@ get_stmt_location (const gimple *stmt, function *fun)
static tree
fixup_tree_for_diagnostic_1 (tree expr, hash_set<tree> *visited);
+/* Attemp to generate a tree for the LHS of ASSIGN_STMT.
+ VISITED must be non-NULL; it is used to ensure termination. */
+
+static tree
+get_diagnostic_tree_for_gassign_1 (const gassign *assign_stmt,
+ hash_set<tree> *visited)
+{
+ enum tree_code code = gimple_assign_rhs_code (assign_stmt);
+
+ /* Reverse the effect of extract_ops_from_tree during
+ gimplification. */
+ switch (get_gimple_rhs_class (code))
+ {
+ default:
+ case GIMPLE_INVALID_RHS:
+ gcc_unreachable ();
+ case GIMPLE_TERNARY_RHS:
+ case GIMPLE_BINARY_RHS:
+ case GIMPLE_UNARY_RHS:
+ {
+ tree t = make_node (code);
+ TREE_TYPE (t) = TREE_TYPE (gimple_assign_lhs (assign_stmt));
+ unsigned num_rhs_args = gimple_num_ops (assign_stmt) - 1;
+ for (unsigned i = 0; i < num_rhs_args; i++)
+ {
+ tree op = gimple_op (assign_stmt, i + 1);
+ if (op)
+ {
+ op = fixup_tree_for_diagnostic_1 (op, visited);
+ if (op == NULL_TREE)
+ return NULL_TREE;
+ }
+ TREE_OPERAND (t, i) = op;
+ }
+ return t;
+ }
+ case GIMPLE_SINGLE_RHS:
+ {
+ tree op = gimple_op (assign_stmt, 1);
+ op = fixup_tree_for_diagnostic_1 (op, visited);
+ return op;
+ }
+ }
+}
+
/* Subroutine of fixup_tree_for_diagnostic_1, called on SSA names.
Attempt to reconstruct a a tree expression for SSA_NAME
based on its def-stmt.
@@ -91,45 +136,8 @@ maybe_reconstruct_from_def_stmt (tree ssa_name,
/* Can't handle these. */
return NULL_TREE;
case GIMPLE_ASSIGN:
- {
- enum tree_code code = gimple_assign_rhs_code (def_stmt);
-
- /* Reverse the effect of extract_ops_from_tree during
- gimplification. */
- switch (get_gimple_rhs_class (code))
- {
- default:
- case GIMPLE_INVALID_RHS:
- gcc_unreachable ();
- case GIMPLE_TERNARY_RHS:
- case GIMPLE_BINARY_RHS:
- case GIMPLE_UNARY_RHS:
- {
- tree t = make_node (code);
- TREE_TYPE (t) = TREE_TYPE (ssa_name);
- unsigned num_rhs_args = gimple_num_ops (def_stmt) - 1;
- for (unsigned i = 0; i < num_rhs_args; i++)
- {
- tree op = gimple_op (def_stmt, i + 1);
- if (op)
- {
- op = fixup_tree_for_diagnostic_1 (op, visited);
- if (op == NULL_TREE)
- return NULL_TREE;
- }
- TREE_OPERAND (t, i) = op;
- }
- return t;
- }
- case GIMPLE_SINGLE_RHS:
- {
- tree op = gimple_op (def_stmt, 1);
- op = fixup_tree_for_diagnostic_1 (op, visited);
- return op;
- }
- }
- }
- break;
+ return get_diagnostic_tree_for_gassign_1
+ (as_a <const gassign *> (def_stmt), visited);
case GIMPLE_CALL:
{
gcall *call_stmt = as_a <gcall *> (def_stmt);
@@ -193,6 +201,15 @@ fixup_tree_for_diagnostic (tree expr)
return fixup_tree_for_diagnostic_1 (expr, &visited);
}
+/* Attempt to generate a tree for the LHS of ASSIGN_STMT. */
+
+tree
+get_diagnostic_tree_for_gassign (const gassign *assign_stmt)
+{
+ hash_set<tree> visited;
+ return get_diagnostic_tree_for_gassign_1 (assign_stmt, &visited);
+}
+
} // namespace ana
/* Helper function for checkers. Is the CALL to the given function name,