3

Consider the following toy program(prog.cpp):

class A {
public:
    vector<int> vec;
    A() noexcept {}
    A(vector<int> s) : vec(s) {}
};

class B {

private:
    vector<atomic<A>> a_table;

public:
    B(int capacity) : a_table(capacity) {}

    void update(int index) {
        A newValue(vector<int>(10,1));
        a_table[index].store(newValue);
    }
};


int main(int argc, char** argv) 
{
B b(5);
b.update(2);
return 0;
}

This when compiled normally (g++ prog.cpp -latomic), works fine. But when compiled as g++ -fsanitize=address -fno-omit-frame-pointer prog.cpp -latomic produces Double Free error when executed. A program based on similar lines as above has to be used in a multi-threaded application, where even the normal compilation is producing Double Free error. I read up Rule of Three/Five, which is generally referred to in case of Double Free, and various other documentations but nothing worked.

Also, removing noexcept specifier from the class A's default constructor produces this strange error, which also I would like to know about.

error: function ‘std::atomic<_Tp>::atomic() [with _Tp = A]’ defaulted on its first declaration with an exception-specification that differs from the implicit declaration ‘std::atomic<A>::atomic()’
   atomic() noexcept = default;
   ^
stillanoob
  • 1,279
  • 2
  • 16
  • 29

1 Answers1

4

std::atomic requires a trivially copyable type, which your A is not, because its member of type vector<int> (e.g.) is not trivially copy constructible.

GCC only detects a violation of that requirement since version 5.0.

The fact that older gcc versions compile the code does not mean that it is valid.

  • So the issue here would be that the vector is being trivial-copied instead of properly copy-constructor-copied, so multiple vectors have pointers to the same heap memory? – ruakh Oct 08 '16 at 21:45
  • @ruakh Presumably. I have not looked at the implementation of std::atomic in libstdc++, but I was able to reproduce the double-free and the developers probably assumed that memcpy or similar is always ok in this case. –  Oct 08 '16 at 21:50
  • @Eichhörnchen So what is the workaround? All I want is a *container* in `A`, so are there any trivially copyable ones? – stillanoob Oct 09 '16 at 00:23
  • @ibrahim5253 Except for arrays maybe you cannot have any container in an std::atomic. What do you want to do with it? –  Oct 09 '16 at 00:35
  • @Eichhörnchen How is even an array possible? Won't I be required to write my custom copy ctor, assignment, and destructor (The Big Three) when using dynamically allocated array (as size will be available at run-time), making the class again non-trivial? – stillanoob Oct 09 '16 at 00:38
  • @ibrahim5253 Yes, I meant static arrays, i.e. `std::array`, actually. There is no way to have dynamic allocation in there. –  Oct 09 '16 at 00:40
  • @ibrahim5253: I have some thoughts about how you can do what you want. If you open a question about it, please post a link here to let me know. :-) – ruakh Oct 10 '16 at 23:03