From: Aldy Hernandez Date: Tue, 13 Oct 2020 08:40:20 +0000 (-0400) Subject: Do not save hash slots across calls to hash_table::get_or_insert. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=739526a19deaeac19c2429cc7567052834d3098e;p=gcc.git Do not save hash slots across calls to hash_table::get_or_insert. 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 ::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. --- diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc index c5ee54fec51..b42dcd6d318 100644 --- a/gcc/gimple-range-edge.cc +++ b/gcc/gimple-range-edge.cc @@ -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; }