Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::future<neither::Either<int, std::string>> segmentation fault

Tags:

c++

c++14

either

The code in this question uses the Either<> implementation found here: https://github.com/LoopPerfect/neither. To be clear, I doubt that this is a problem with this specific library, otherwise I would have created an issue there.

The following snippet works as expected:

std::future<std::string> f = std::async(std::launch::async, []()
{
    return "test";
}

std::cout << f.get() << std::endl;

And the following generates a segmentation fault:

std::future<neither::Either<int, std::string>> f = std::async(std::launch::async, []()
{
    return neither::Either<int, std::string>(neither::right(std::string("test")));
});

neither::Either<int, std::string> v = f.get(); // Segmentation fault
std::cout << v.right().value << std::endl;

Returning left(-1) works, as does neither::Either<int, int> for both left() and right(). I know that std::future::get might generate a segfault is that you've called it twice, in which case std::future::valid will return false just prior to calling get, but valid returns true.

Is there something I'm missing here?

like image 795
David Freitag Avatar asked Dec 19 '22 07:12

David Freitag


1 Answers

Is there something I'm missing here?

The library isn't properly implemented. Specifically for the purposes of this question, the copy constructor is wrong:

constexpr Either( Either<L, R> const& e )
  : isLeft(e.isLeft) {
  if(isLeft) {
    leftValue = e.leftValue;
  } else {
    rightValue = e.rightValue; // (*)
  }
}

We can't assign to this->rightValue there, there isn't a std::string in existence at that spot - we have uninitialized memory.

A correct copy constructor would be:

Either(Either<L, R> const& e)
  : isLeft(e.isLeft)
{
  if(isLeft) {
    new (&leftValue) L(e.leftValue);
  } else {
    new (&rightValue) R(e.rightValue);
  }
}

or, since we're writing generic library code that could be used by all sorts of evil types, you'll want:

::new (static_cast<void*>(std::addressof(leftValue))) L(e.leftValue);
like image 146
Barry Avatar answered Dec 24 '22 00:12

Barry