summaryrefslogtreecommitdiff
path: root/gcc/analyzer/region-model.h
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2020-03-30 17:02:59 -0400
committerDavid Malcolm <dmalcolm@redhat.com>2020-04-01 15:34:40 -0400
commita96f1c38a787fbc847cb014d4b094e2787d539a7 (patch)
tree344b4bab5c1d19a4e87aac09abbd98c82c9c74b2 /gcc/analyzer/region-model.h
parent7546463b9f7a0b001cf61a94dcfc18f540721390 (diff)
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.h71
1 files changed, 53 insertions, 18 deletions
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 235db72141e..2c9ee39a38d 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);