Note that there are some explanatory texts on larger screens.

plurals
  1. POWhy is this use of union, class and lambda producing a segmentation fault?
    primarykey
    data
    text
    <p>I got a very strange bug in my code and managed to reduce it to the following single function.</p> <pre><code>#include "either.hpp" #include &lt;string&gt; #include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;functional&gt; int main() { using std::string; using std::vector; auto callback = []() { auto either = data::either&lt;string,vector&lt;int&gt;&gt;(string("test")); return either; return data::either&lt;string,vector&lt;int&gt;&gt;(string("test")); }; callback(); } </code></pre> <p>When run, this program generate a segmentation fault on <code>std::string</code>'s destructor. But if we remove the second <code>return</code> statement, it work perfectly.</p> <p>Now, the <code>data::either</code> class is using a union with two members, and the lambda's return statement will cause the destruction of the stack-allcated variable.</p> <p>Is there a problem with my use of those features, is it undefined behaviour for a reason I don't know, or is it simply a compiler bug?</p> <p>Here is the <code>either</code> class:</p> <pre><code>#ifndef EITHER_HPP #define EITHER_HPP #include &lt;cassert&gt; #include &lt;functional&gt; #include &lt;type_traits&gt; #include &lt;utility&gt; // Model the haskel Data.Either data type. // http://hackage.haskell.org/package/base-4.6.0.1/docs/Data-Either.html namespace data { template&lt;class Left, class Right&gt; class either { static_assert( !std::is_same&lt; typename std::remove_cv&lt;Left&gt;::type, typename std::remove_cv&lt;Right&gt;::type &gt;::value, "data::either&lt;A,B&gt;: type A and B must be different."); bool m_is_right; union { Left m_left; Right m_right; }; public: explicit either(Left l) : m_is_right(false) , m_left(std::move(l)) { } explicit either(Right r) : m_is_right(true) , m_right(std::move(r)) { } either(either const&amp; other) : m_is_right(other.is_right()) { if (other.is_left()) { m_left = other.left(); } else { m_right = other.right(); } } either(either&amp;&amp; other) : m_is_right(other.is_right()) { if (other.is_left()) { m_left = std::move(other.left()); } else { m_right = std::move(other.right()); } } ~either() { if (is_right()) { right().~Right(); } else { left().~Left(); } } either&amp; operator=(either const&amp; other) { m_is_right = other.is_right(); if (other.is_left()) { m_left = other.left(); } else { m_right = other.right(); } return *this; } either&amp; operator=(either&amp;&amp; other) { m_is_right = other.is_right(); if (other.is_left()) { m_left = std::move(other.left()); } else { m_right = std::move(other.right()); } return *this; } bool is_left() const { return !is_right(); } bool is_right() const { return m_is_right; } Left&amp; left() { assert(is_left()); return m_left; } Left const&amp; left() const { assert(is_left()); return m_left; } Right&amp; right() { assert(is_right()); return m_right; } Right const&amp; right() const { assert(is_right()); return m_right; } }; } #endif </code></pre> <p>I tested it with the following compilers:</p> <pre><code>$ clang++ -std=c++11 test.cpp &amp;&amp; ./a.out Segmentation fault $ clang++ --version Debian clang version 3.2-11 (tags/RELEASE_32/final) (based on LLVM 3.2) Target: x86_64-pc-linux-gnu Thread model: posix $ g++ -std=c++11 test.cpp &amp;&amp; ./a.out Segmentation fault $ g++ --version g++ (Debian 4.7.3-4) 4.7.3 Copyright (C) 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload