diff options
author | David Malcolm <dmalcolm@redhat.com> | 2020-03-30 17:02:59 -0400 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2020-04-01 15:34:40 -0400 |
commit | a96f1c38a787fbc847cb014d4b094e2787d539a7 (patch) | |
tree | 344b4bab5c1d19a4e87aac09abbd98c82c9c74b2 /gcc/analyzer/region-model.h | |
parent | 7546463b9f7a0b001cf61a94dcfc18f540721390 (diff) | |
download | gcc-a96f1c38a787fbc847cb014d4b094e2787d539a7.zip gcc-a96f1c38a787fbc847cb014d4b094e2787d539a7.tar.gz gcc-a96f1c38a787fbc847cb014d4b094e2787d539a7.tar.bz2 |
analyzer: handle compound assignments [PR94378]
PR analyzer/94378 reports a false -Wanalyzer-malloc-leak
when returning a struct containing a malloc-ed pointer.
The issue is that the assignment code was not handling
compound copies, only copying top-level values from region to region,
and not copying child values.
This patch introduces a region_model::copy_region function, using
it for assignments and when analyzing function return values.
It recursively copies nested values within structs, unions, and
arrays, fixing the bug.
gcc/analyzer/ChangeLog:
PR analyzer/94378
* checker-path.cc: Include "bitmap.h".
* constraint-manager.cc: Likewise.
* diagnostic-manager.cc: Likewise.
* engine.cc: Likewise.
(exploded_node::detect_leaks): Pass null region_id to pop_frame.
* program-point.cc: Include "bitmap.h".
* program-state.cc: Likewise.
* region-model.cc (id_set<region_id>::id_set): Convert to...
(region_id_set::region_id_set): ...this.
(svalue_id_set::svalue_id_set): New ctor.
(region_model::copy_region): New function.
(region_model::copy_struct_region): New function.
(region_model::copy_union_region): New function.
(region_model::copy_array_region): New function.
(stack_region::pop_frame): Drop return value. Add
"result_dst_rid" param; if it is non-null, use copy_region to copy
the result to it. Rather than capture and pass a single "known
used" return value to be used by purge_unused_values, instead
gather and pass a set of known used return values.
(root_region::pop_frame): Drop return value. Add "result_dst_rid"
param.
(region_model::on_assignment): Use copy_region.
(region_model::on_return): Likewise for the result.
(region_model::on_longjmp): Pass null for pop_frame's
result_dst_rid.
(region_model::update_for_return_superedge): Pass the region for the
return value of the call, if any, to pop_frame, rather than setting
the lvalue for the lhs of the result.
(region_model::pop_frame): Drop return value. Add
"result_dst_rid" param.
(region_model::purge_unused_svalues): Convert third param from an
svalue_id * to an svalue_id_set *, updating the initial populating
of the "used" bitmap accordingly. Don't remap it when done.
(struct selftest::coord_test): New selftest fixture, extracted from...
(selftest::test_dump_2): ...here.
(selftest::test_compound_assignment): New selftest.
(selftest::test_stack_frames): Pass null to new param of pop_frame.
(selftest::analyzer_region_model_cc_tests): Call the new selftest.
* region-model.h (class id_set): Delete template.
(class region_id_set): Reimplement, using old id_set implementation.
(class svalue_id_set): Likewise. Convert from auto_sbitmap to
auto_bitmap.
(region::get_active_view): New accessor.
(stack_region::pop_frame): Drop return value. Add
"result_dst_rid" param.
(root_region::pop_frame): Likewise.
(region_model::pop_frame): Likewise.
(region_model::copy_region): New decl.
(region_model::purge_unused_svalues): Convert third param from an
svalue_id * to an svalue_id_set *.
(region_model::copy_struct_region): New decl.
(region_model::copy_union_region): New decl.
(region_model::copy_array_region): New decl.
gcc/testsuite/ChangeLog:
PR analyzer/94378
* gcc.dg/analyzer/compound-assignment-1.c: New test.
* gcc.dg/analyzer/compound-assignment-2.c: New test.
* gcc.dg/analyzer/compound-assignment-3.c: New test.
Diffstat (limited to 'gcc/analyzer/region-model.h')
-rw-r--r-- | gcc/analyzer/region-model.h | 71 |
1 files changed, 53 insertions, 18 deletions
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 235db72..2c9ee39 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -370,25 +370,24 @@ one_way_id_map<T>::update (T *id) const *id = get_dst_for_src (*id); } -/* A set of IDs within a region_model (either svalue_id or region_id). */ +/* A set of region_ids within a region_model. */ -template <typename T> -class id_set +class region_id_set { public: - id_set (const region_model *model); + region_id_set (const region_model *model); - void add_region (T id) + void add_region (region_id rid) { - if (!id.null_p ()) - bitmap_set_bit (m_bitmap, id.as_int ()); + if (!rid.null_p ()) + bitmap_set_bit (m_bitmap, rid.as_int ()); } - bool region_p (T id) const + bool region_p (region_id rid) const { - gcc_assert (!id.null_p ()); + gcc_assert (!rid.null_p ()); return bitmap_bit_p (const_cast <auto_sbitmap &> (m_bitmap), - id.as_int ()); + rid.as_int ()); } unsigned int num_regions () @@ -400,7 +399,29 @@ private: auto_sbitmap m_bitmap; }; -typedef id_set<region_id> region_id_set; +/* A set of svalue_ids within a region_model. */ + +class svalue_id_set +{ +public: + svalue_id_set (); + + void add_svalue (svalue_id sid) + { + if (!sid.null_p ()) + bitmap_set_bit (m_bitmap, sid.as_int ()); + } + + bool svalue_p (svalue_id sid) const + { + gcc_assert (!sid.null_p ()); + return bitmap_bit_p (const_cast <auto_bitmap &> (m_bitmap), + sid.as_int ()); + } + +private: + auto_bitmap m_bitmap; +}; /* Various operations delete information from a region_model. @@ -890,6 +911,7 @@ public: void add_view (region_id view_rid, region_model *model); region_id get_view (tree type, region_model *model) const; + region_id get_active_view () const { return m_active_view_rid; } bool is_view_p () const { return m_is_view; } virtual void validate (const region_model &model) const; @@ -1450,8 +1472,9 @@ public: void push_frame (region_id frame_rid); region_id get_current_frame_id () const; - svalue_id pop_frame (region_model *model, bool purge, purge_stats *stats, - region_model_context *ctxt); + void pop_frame (region_model *model, region_id result_dst_rid, + bool purge, purge_stats *stats, + region_model_context *ctxt); void remap_region_ids (const region_id_map &map) FINAL OVERRIDE; @@ -1555,8 +1578,9 @@ public: vec<svalue_id> *arg_sids, region_model_context *ctxt); region_id get_current_frame_id (const region_model &model) const; - svalue_id pop_frame (region_model *model, bool purge, purge_stats *stats, - region_model_context *ctxt); + void pop_frame (region_model *model, region_id result_dst_rid, + bool purge, purge_stats *stats, + region_model_context *ctxt); region_id ensure_stack_region (region_model *model); region_id get_stack_region_id () const { return m_stack_rid; } @@ -1724,8 +1748,9 @@ class region_model region_model_context *ctxt); region_id get_current_frame_id () const; function * get_current_function () const; - svalue_id pop_frame (bool purge, purge_stats *stats, - region_model_context *ctxt); + void pop_frame (region_id result_dst_rid, + bool purge, purge_stats *stats, + region_model_context *ctxt); int get_stack_depth () const; function *get_function_at_depth (unsigned depth) const; @@ -1781,6 +1806,9 @@ class region_model svalue_id set_to_new_unknown_value (region_id dst_rid, tree type, region_model_context *ctxt); + void copy_region (region_id dst_rid, region_id src_rid, + region_model_context *ctxt); + tristate eval_condition (svalue_id lhs, enum tree_code op, svalue_id rhs) const; @@ -1804,7 +1832,7 @@ class region_model void purge_unused_svalues (purge_stats *out, region_model_context *ctxt, - svalue_id *known_used_sid = NULL); + svalue_id_set *known_used_sids = NULL); void remap_svalue_ids (const svalue_id_map &map); void remap_region_ids (const region_id_map &map); @@ -1858,6 +1886,13 @@ class region_model region_id get_lvalue_1 (path_var pv, region_model_context *ctxt); svalue_id get_rvalue_1 (path_var pv, region_model_context *ctxt); + void copy_struct_region (region_id dst_rid, struct_region *dst_reg, + struct_region *src_reg, region_model_context *ctxt); + void copy_union_region (region_id dst_rid, union_region *src_reg, + region_model_context *ctxt); + void copy_array_region (region_id dst_rid, array_region *dst_reg, + array_region *src_reg, region_model_context *ctxt); + region_id make_region_for_unexpected_tree_code (region_model_context *ctxt, tree t, const dump_location_t &loc); |