https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88199
Bug ID: 88199
Summary: [7/8/9 Regression] memory leak on unordered container
move assignment
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: redi at gcc dot gnu.org
Target Milestone: ---
Since allocator propagation was implemented in GCC 4.9, move assignment with
non-equal allocators has leaked the original buckets in the LHS of the
assignment:
#include <unordered_set>
template<typename T>
struct Alloc : std::allocator<T>
{
Alloc(int i) : id(i) { }
template<typename U>
Alloc(const Alloc<U>& a) : id(a.id) { }
template<typename U>
struct rebind { using other = Alloc<U>; };
using propagate_on_container_move_assignment = std::false_type;
using is_always_equal = std::false_type;
int id;
};
template<typename T, typename U>
bool operator==(const Alloc<T>& lhs, const Alloc<U>& rhs)
{ return lhs.id == rhs.id; }
template<typename T, typename U>
bool operator!=(const Alloc<T>& lhs, const Alloc<U>& rhs)
{ return lhs.id != rhs.id; }
int main()
{
Alloc<int> a1(1), a2(2);
std::hash<int> h;
std::equal_to<int> eq;
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>,
Alloc<int>>;
Set s1(1, h, eq, a1);
Set s2(5, h, eq, a2);
s1.insert(0);
s2.insert(0);
s1 = std::move(s2);
}
=================================================================
==30693==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 16 byte(s) in 1 object(s) allocated from:
#0 0x7fa9c95207f0 in operator new(unsigned long)
/home/jwakely/src/gcc/gcc/libsanitizer/asan/asan_new_delete.cc:104
#1 0x405b16 in
__gnu_cxx::new_allocator<std::__detail::_Hash_node_base*>::allocate(unsigned
long, void const*)
/home/jwakely/gcc/9/include/c++/9.0.0/ext/new_allocator.h:114
#2 0x405402 in std::allocator_traits<Alloc<std::__detail::_Hash_node_base*>
>::allocate(Alloc<std::__detail::_Hash_node_base*>&, unsigned long)
/home/jwakely/gcc/9/include/c++/9.0.0/bits/alloc_traits.h:306
#3 0x4047f8 in
std::__detail::_Hashtable_alloc<Alloc<std::__detail::_Hash_node<int, false> >
>::_M_allocate_buckets(unsigned long)
/home/jwakely/gcc/9/include/c++/9.0.0/bits/hashtable_policy.h:2114
#4 0x4031a9 in std::_Hashtable<int, int, Alloc<int>,
std::__detail::_Identity, std::equal_to<int>, std::hash<int>,
std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash,
std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false,
true, true> >::_M_allocate_buckets(unsigned long)
/home/jwakely/gcc/9/include/c++/9.0.0/bits/hashtable.h:366
#5 0x4027a7 in std::_Hashtable<int, int, Alloc<int>,
std::__detail::_Identity, std::equal_to<int>, std::hash<int>,
std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash,
std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false,
true, true> >::_Hashtable(unsigned long, std::hash<int> const&,
std::__detail::_Mod_range_hashing const&, std::__detail::_Default_ranged_hash
const&, std::equal_to<int> const&, std::__detail::_Identity const&, Alloc<int>
const&) /home/jwakely/gcc/9/include/c++/9.0.0/bits/hashtable.h:961
#6 0x401b35 in std::_Hashtable<int, int, Alloc<int>,
std::__detail::_Identity, std::equal_to<int>, std::hash<int>,
std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash,
std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false,
true, true> >::_Hashtable(unsigned long, std::hash<int> const&,
std::equal_to<int> const&, Alloc<int> const&)
/home/jwakely/gcc/9/include/c++/9.0.0/bits/hashtable.h:446
#7 0x401836 in std::unordered_set<int, std::hash<int>, std::equal_to<int>,
Alloc<int> >::unordered_set(unsigned long, std::hash<int> const&,
std::equal_to<int> const&, Alloc<int> const&)
/home/jwakely/gcc/9/include/c++/9.0.0/bits/unordered_set.h:149
#8 0x401219 in main /tmp/ht.cc:34
#9 0x7fa9c87a5fe9 in __libc_start_main ../csu/libc-start.c:308
SUMMARY: AddressSanitizer: 16 byte(s) leaked in 1 allocation(s).