Do not save hash slots across calls to hash_table::get_or_insert.
authorAldy Hernandez <aldyh@redhat.com>
Tue, 13 Oct 2020 08:40:20 +0000 (04:40 -0400)
committerAldy Hernandez <aldyh@redhat.com>
Tue, 13 Oct 2020 15:02:18 +0000 (11:02 -0400)
There's a read of a freed block while accessing the default_slot in
calc_switch_ranges.

      default_slot->intersect (def_range);

It seems the default_slot got swiped from under us, and the valgrind
dump indicates the free came from the get_or_insert in the same
function:

      irange *&slot = m_edge_table->get_or_insert (e, &existed);

So it looks like the get_or_insert is actually freeing the value of
the previously allocated default_slot.  Looking down the chain
from get_or_insert, we see it calls hash_table<>::expand, which
actually does a free while doing a resize of sorts:

  if (!m_ggc)
    Allocator <value_type> ::data_free (oentries);
  else
    ggc_free (oentries);

This patch avoids keeping a pointer to the default_slot across multiple
calls to get_or_insert in the loop.

gcc/ChangeLog:

PR tree-optimization/97379
* gimple-range-edge.cc (outgoing_range::calc_switch_ranges): Do
not save hash slot across calls to hash_table<>::get_or_insert.

gcc/gimple-range-edge.cc

index c5ee54fec51a2b293a180f700f1a2cc6d41e6ca8..b42dcd6d31868d576b5038b68bdd37bcf2b76546 100644 (file)
@@ -106,19 +106,14 @@ outgoing_range::calc_switch_ranges (gswitch *sw)
   unsigned x, lim;
   lim = gimple_switch_num_labels (sw);
   tree type = TREE_TYPE (gimple_switch_index (sw));
-  
   edge default_edge = gimple_switch_default_edge (cfun, sw);
-  irange *&default_slot = m_edge_table->get_or_insert (default_edge, &existed);
 
-  // This should be the first call into this switch.  For the default
-  // range case, start with varying and intersect each other case from
-  // it.
-
-  gcc_checking_assert (!existed);
-
-  // Allocate an int_range_max for default case.
-  default_slot = m_range_allocator.allocate (255);
-  default_slot->set_varying (type);
+  // This should be the first call into this switch.
+  //
+  // Allocate an int_range_max for the default range case, start with
+  // varying and intersect each other case from it.
+  irange *default_range = m_range_allocator.allocate (255);
+  default_range->set_varying (type);
 
   for (x = 1; x < lim; x++)
     {
@@ -137,7 +132,7 @@ outgoing_range::calc_switch_ranges (gswitch *sw)
       int_range_max def_range (low, high);
       range_cast (def_range, type);
       def_range.invert ();
-      default_slot->intersect (def_range);
+      default_range->intersect (def_range);
 
       // Create/union this case with anything on else on the edge.
       int_range_max case_range (low, high);
@@ -157,6 +152,11 @@ outgoing_range::calc_switch_ranges (gswitch *sw)
       // intrusive than allocating max ranges for each case.
       slot = m_range_allocator.allocate (case_range);
     }
+
+  irange *&slot = m_edge_table->get_or_insert (default_edge, &existed);
+  // This should be the first call into this switch.
+  gcc_checking_assert (!existed);
+  slot = default_range;
 }