https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92761
Bug ID: 92761
Summary: hash_table::expand invokes assignment on invalid
objects
Product: gcc
Version: 10.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: bootstrap
Assignee: unassigned at gcc dot gnu.org
Reporter: msebor at gcc dot gnu.org
Target Milestone: ---
The GCC internal hash_table::expand() function invokes the assignment operator
on invalid/empty elements. The following test case inserted into the C++
parser (where I ran into the problem) reproduces the bug:
struct S
{
S (): p (&p) { }
S (const S &s): p (&p) { gcc_assert (s.p == &s.p); }
S& operator= (const S &s) { gcc_assert (s.p == &s.p); return *this; }
~S () { gcc_assert (p == &p); }
void *p;
};
hash_map<tree, S> x;
static void test_hash_table ()
{
for (int i = 0; i != 32; ++i)
x.put ((tree)i, S ());
x.empty ();
}
/* Parse one entire translation unit. */
void
c_parse_file (void)
{
test_hash_table ();
...
}
internal compiler error: in operator=, at cp/parser.c:43418
0xaeed4f S::operator=(S const&)
/src/gcc/61339/gcc/cp/parser.c:43418
0xaf3a7e hash_map<tree_node*, S,
simple_hashmap_traits<default_hash_traits<tree_node*>, S>
>::hash_entry::operator=(hash_map<tree_node*, S,
simple_hashmap_traits<default_hash_traits<tree_node*>, S> >::hash_entry const&)
/src/gcc/61339/gcc/hash-map.h:42
0xaf3c24 hash_table<hash_map<tree_node*, S,
simple_hashmap_traits<default_hash_traits<tree_node*>, S> >::hash_entry, false,
xcallocator>::expand()
/src/gcc/61339/gcc/hash-table.h:822
0xaf21a7 hash_table<hash_map<tree_node*, S,
simple_hashmap_traits<default_hash_traits<tree_node*>, S> >::hash_entry, false,
xcallocator>::find_slot_with_hash(tree_node* const&, unsigned int,
insert_option)
/src/gcc/61339/gcc/hash-table.h:962
0xaf02e4 hash_map<tree_node*, S,
simple_hashmap_traits<default_hash_traits<tree_node*>, S> >::put(tree_node*
const&, S const&)
/src/gcc/61339/gcc/hash-map.h:165
0xaea3b8 test_hash_table
/src/gcc/61339/gcc/cp/parser.c:43428
0xaea3e5 c_parse_file()
/src/gcc/61339/gcc/cp/parser.c:43438
0xcd34ab c_common_parse_file()
/src/gcc/61339/gcc/c-family/c-opts.c:1185
Please submit a full bug report,
As the stack trace shows, the problem is due to expand() directly assigning to
the (invalid) lvalue obtained from find_empty_slot_for_expand:
template<typename Descriptor, bool Lazy,
template<typename Type> class Allocator>
void
hash_table<Descriptor, Lazy, Allocator>::expand ()
{
value_type *oentries = m_entries;
...
value_type *p = oentries;
do
{
value_type &x = *p;
if (!is_empty (x) && !is_deleted (x))
{
value_type *q = find_empty_slot_for_expand (Descriptor::hash (x));
*q = x; <<< q points to a empty slot with no object in it
}
p++;
}
while (p < olimit);
...
}