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).

Reply via email to