0

The following MWE gives a strange address sanitizer report:

#include <vector>

class A {
public:
    A(){}
    ~A(){}
};

class B{
public:

    B(){
        m_grid = new A();
    }
    ~B(){ delete m_grid;}

    A * m_grid = nullptr;

    std::size_t n;
};


int  main(){
    std::vector<B> l;
    l.emplace_back(B{});
}

AsanMangler Report with:

=================================================================
==14729==ERROR: AddressSanitizer: attempting double-free on 0x60200000eff0 in thread T0:
    #0 0x7f4207f6e6af in operator delete(void*) (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x586af)
    #1 0x40126f in B::~B() /src/main.cpp:113
    #2 0x401efb in void std::_Destroy<B>(B*) /usr/include/c++/4.9/bits/stl_construct.h:93
    #3 0x401caa in void std::_Destroy_aux<false>::__destroy<B*>(B*, B*) /usr/include/c++/4.9/bits/stl_construct.h:103
    #4 0x4019c8 in void std::_Destroy<B*>(B*, B*) /usr/include/c++/4.9/bits/stl_construct.h:126
    #5 0x401546 in void std::_Destroy<B*, B>(B*, B*, std::allocator<B>&) /usr/include/c++/4.9/bits/stl_construct.h:151
    #6 0x40130f in std::vector<B, std::allocator<B> >::~vector() /usr/include/c++/4.9/bits/stl_vector.h:424
    #7 0x401057 in main /src/main.cpp:170
    #8 0x7f42075d9a3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x20a3f)
    #9 0x400ea8 in _start (/src/MAIN+0x400ea8)

0x60200000eff0 is located 0 bytes inside of 1-byte region [0x60200000eff0,0x60200000eff1)
freed by thread T0 here:
    #0 0x7f4207f6e6af in operator delete(void*) (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x586af)
    #1 0x40126f in B::~B() /src/main.cpp:113
    #2 0x401045 in main /src/main.cpp:124
    #3 0x7f42075d9a3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x20a3f)

previously allocated by thread T0 here:
    #0 0x7f4207f6e1af in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x581af)
    #1 0x4011ea in B::B() /src/main.cpp:111
    #2 0x401020 in main /src/main.cpp:124
    #3 0x7f42075d9a3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x20a3f)

SUMMARY: AddressSanitizer: double-free ??:0 operator delete(void*)
==14729==ABORTING

Compiled with:

/usr/bin/g++   -std=c++11 -ftree-vectorize -ftree-vectorizer-verbose=0 -fmessage-length=0 -Wno-enum-compare -g -fsanitize=address -o MAIN main.cpp

Does somebody know where the problem lies? Something is extremely fishy here, compiler bug or strange std libraries??, I have not done anything with the c++ 4.9 headers in ubuntu vivid so far. Or might it be a false positive of the address sanitizer?

I installed clang-3.6 and

it also crashes with the line:

clang++   -std=c++14 -fmessage-length=0 -Wno-enum-compare -g -o MAIN main.cpp
Gabriel
  • 8,990
  • 6
  • 57
  • 101

2 Answers2

3

Nothing strange. There is no move for pointers, pointer will be just shallowly-copied and then you will have double free. You can use std::unique_ptr, instead of raw pointer, or write move constructor, that will assign nullptr to pointer.

B(B&& rhs) : m_grid(rhs.m_grid), n(rhs.n)
{
   rhs.m_grid = nullptr;
   rhs.n = 0;
}
ForEveR
  • 55,233
  • 2
  • 119
  • 133
0

That's not how you use emplace_back. The whole point of the function is that it avoids move or copy construction and does an in-place construction instead, forwarding arguments to the constructor. In fact, push_back delegates to emplace_back. So you have an unnecessary move/copy.

Second, why the Rule of Three? Why not the Rule of Zero?

class B{
public:
    std::vector<A> m_grid;
};

There, now you don't need to worry about manual resource management.

  • Thats, exactly why we always should use memory management functionality from the stdandart library. std::unique_ptr, not using pointers when ever possible and so one :-) – Gabriel Oct 05 '15 at 11:54
  • and you are right the example was en extract of something, and correct: emplace_back should not be used as such! – Gabriel Oct 05 '15 at 11:55