Boost C++ Libraries: Ticket #10389: [container] Double free problem on boost::containers::vector<std::unique_ptr<T>> https://svn.boost.org/trac10/ticket/10389 <p> Using boost::container::vector with std::unique_ptr causes double-free problem. </p> <h3 class="section" id="Compiler">Compiler</h3> <p> clang++ on Mac OSX 10.9.4 </p> <div class="wiki-code"><div class="code"><pre>$ clang++ --version $ Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn) $ Target: x86_64-apple-darwin13.3.0 $ Thread model: posix </pre></div></div><h3 class="section" id="Boostversion">Boost version</h3> <p> 1.54, 1.55, 1.56, HEAD(d811937 on <a class="ext-link" href="https://github.com/boostorg/boost.git"><span class="icon">​</span>https://github.com/boostorg/boost.git</a>) </p> <h3 class="section" id="Howtoreproduce">How to reproduce</h3> <p> Compile the sample code below and run. </p> <div class="wiki-code"><div class="code"><pre><span class="c1">//file: container_vector_double_free.cpp</span> <span class="c1">//clang++ container_vector_double_free.cpp -std=c++11 -I/Users/kbinani/Documents/github/boostorg/boost</span> <span class="cp">#include</span> <span class="cpf">&lt;boost/container/vector.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;memory&gt;</span><span class="cp"></span> <span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> <span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">object_ptr_t</span><span class="p">;</span> <span class="k">typedef</span> <span class="n">boost</span><span class="o">::</span><span class="n">container</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">object_ptr_t</span><span class="o">&gt;</span> <span class="n">container_t</span><span class="p">;</span> <span class="n">container_t</span> <span class="n">c</span><span class="p">;</span> <span class="c1">// if the number of object to &#39;push_back&#39; is less than 3, double-free problem does not occur.</span> <span class="kt">int</span> <span class="k">const</span> <span class="n">kNum</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span> <span class="c1">// when &#39;reserve&#39; called before &#39;push_back&#39;, double-free problem does not occur.</span> <span class="c1">//c.reserve(kNum);</span> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">kNum</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> <span class="n">object_ptr_t</span> <span class="n">item</span><span class="p">(</span><span class="k">new</span> <span class="kt">int</span><span class="p">(</span><span class="mi">0</span><span class="p">));</span> <span class="n">c</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">item</span><span class="p">));</span> <span class="p">}</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div></div><p> Result: </p> <div class="wiki-code"><div class="code"><pre>a.out(31615,0x7fff79acb310) malloc: *** error for object 0x7ff170403980: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug Abort trap: 6 </pre></div></div><p> Stack trace: </p> <div class="wiki-code"><div class="code"><pre>#3 0x00007fff8da6707f in free () #4 0x0000000100002560 in std::__1::default_delete&lt;int&gt;::operator()(int*) const [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/memory:2488 #5 0x0000000100002539 in std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;::reset(int*) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/memory:2687 #6 0x00000001000024e3 in std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;::~unique_ptr() [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/memory:2655 #7 0x00000001000024e3 in std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;::~unique_ptr() [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/memory:2655 #8 0x00000001000024e3 in std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt;::destroy(std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/memory:1739 #9 0x00000001000024af in void boost::container::allocator_traits&lt;std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt; &gt;::priv_destroy&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt;(boost::integral_constant&lt;bool, true&gt;, std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt;&amp;, std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*) at /Users/kbinani/Documents/github/boostorg/boost/libs/container/boost_container_vector_test/../../../boost/container/allocator_traits.hpp:300 #10 0x0000000100002471 in void boost::container::allocator_traits&lt;std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt; &gt;::destroy&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt;(std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt;&amp;, std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*) at /Users/kbinani/Documents/github/boostorg/boost/libs/container/boost_container_vector_test/../../../boost/container/allocator_traits.hpp:242 #11 0x0000000100002259 in void boost::container::destroy_alloc_n&lt;std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt;, std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*&gt;(std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt;&amp;, std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*, std::__1::iterator_traits&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*&gt;::difference_type, boost::container::container_detail::enable_if_c&lt;!(boost::has_trivial_destructor&lt;std::__1::iterator_traits&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*&gt;::value_type&gt;::value), void&gt;::type*) at /Users/kbinani/Documents/github/boostorg/boost/libs/container/boost_container_vector_test/../../../boost/container/detail/utilities.hpp:1073 #12 0x0000000100001f2d in void boost::container::vector&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;, std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt; &gt;::priv_forward_range_insert_new_allocation&lt;boost::container::container_detail::insert_move_proxy&lt;std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt;, std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*&gt; &gt;(std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*, unsigned long, std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*, unsigned long, boost::container::container_detail::insert_move_proxy&lt;std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt;, std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*&gt;) at /Users/kbinani/Documents/github/boostorg/boost/libs/container/boost_container_vector_test/../../../boost/container/vector.hpp:2417 #13 0x0000000100001aee in boost::container::container_detail::vec_iterator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*, false&gt; boost::container::vector&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;, std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt; &gt;::priv_forward_range_insert_no_capacity&lt;boost::container::container_detail::insert_move_proxy&lt;std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt;, std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*&gt; &gt;(std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;* const&amp;, unsigned long, boost::container::container_detail::insert_move_proxy&lt;std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt;, std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;*&gt;, boost::container::container_detail::integral_constant&lt;unsigned int, 1u&gt;) at /Users/kbinani/Documents/github/boostorg/boost/libs/container/boost_container_vector_test/../../../boost/container/vector.hpp:2045 #14 0x000000010000193c in void boost::container::vector&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;, std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt; &gt;::priv_push_back&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt;(std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;&amp;&amp;) at /Users/kbinani/Documents/github/boostorg/boost/libs/container/boost_container_vector_test/../../../boost/container/vector.hpp:1944 #15 0x0000000100001810 in boost::container::vector&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;, std::__1::allocator&lt;std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt; &gt; &gt;::push_back(std::__1::unique_ptr&lt;int, std::__1::default_delete&lt;int&gt; &gt;&amp;&amp;) at /Users/kbinani/Documents/github/boostorg/boost/libs/container/boost_container_vector_test/../../../boost/container/vector.hpp:1467 #16 0x0000000100001581 in main at /Users/kbinani/Documents/github/boostorg/boost/libs/container/boost_container_vector_test/boost_container_vector_test/main.cpp:14 </pre></div></div> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/10389 Trac 1.4.3 Ion Gaztañaga Fri, 22 Aug 2014 12:19:05 GMT owner, component changed https://svn.boost.org/trac10/ticket/10389#comment:1 https://svn.boost.org/trac10/ticket/10389#comment:1 <ul> <li><strong>owner</strong> changed from <span class="trac-author">Ion Gaztañaga</span> to <span class="trac-author">John Maddock</span> </li> <li><strong>component</strong> <span class="trac-field-old">container</span> → <span class="trac-field-new">type_traits</span> </li> </ul> <p> I've found boost::has_trivial_copy returns true for unique_ptr in Clang. I've found related issues here: </p> <p> <a class="ext-link" href="http://stackoverflow.com/questions/12754886/has-trivial-copy-behaves-differently-in-clang-and-gcc-whos-right"><span class="icon">​</span>http://stackoverflow.com/questions/12754886/has-trivial-copy-behaves-differently-in-clang-and-gcc-whos-right</a> </p> <p> and </p> <p> <a class="ext-link" href="http://stackoverflow.com/questions/22812183/a-deleted-default-constructor-could-still-be-trivial"><span class="icon">​</span>http://stackoverflow.com/questions/22812183/a-deleted-default-constructor-could-still-be-trivial</a> </p> <p> the problem is that it's not clear if types with deleted copy constructor can still be trivially copy constructible. </p> <p> I don't know if boost::has_trivial_copy has defined behaviour on this and this might be a bug, I'm reassining to <a class="missing wiki">TypeTraits</a> (John) in case it's considered a bug. </p> <p> If not, please reassign it to Container. The workaround is to use is_copy_constructible &amp;&amp; has_trivial_copy to know if a type has a copy constructor that is trivial, and memcpy can be used to move objects. </p> Ticket John Maddock Sat, 23 Aug 2014 12:40:07 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/10389#comment:2 https://svn.boost.org/trac10/ticket/10389#comment:2 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> I believe this is now fixed in <a class="ext-link" href="https://github.com/boostorg/type_traits/commit/df74811a4c996f0e5fd5551622aefed803db27d4"><span class="icon">​</span>https://github.com/boostorg/type_traits/commit/df74811a4c996f0e5fd5551622aefed803db27d4</a> </p> <p> Note that has_trivial_assign and has_trivial_construct very likely have the same issues, but I don't know how to fix those! </p> Ticket Ion Gaztañaga Sat, 23 Aug 2014 15:29:06 GMT <link>https://svn.boost.org/trac10/ticket/10389#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10389#comment:3</guid> <description> <p> I think we are missing is_copy_assignable in Boost. The implementation seems to be possible only in C++11 using decltype but Boost could support noncopyable and Boost.Move, just like is_copy_constructible does. </p> <p> Once we have it, we can apply a similar patch to has_trivial_assign. Does this make sense? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>John Maddock</dc:creator> <pubDate>Sat, 23 Aug 2014 17:04:14 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/10389#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10389#comment:4</guid> <description> <p> If you can implement it, then yes, lets add it. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Ion Gaztañaga</dc:creator> <pubDate>Sat, 23 Aug 2014 19:58:27 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/10389#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10389#comment:5</guid> <description> <p> Ok, I'll create a pull request when I manage to implement it. </p> </description> <category>Ticket</category> </item> </channel> </rss>