Marcus
Marcus

Reputation: 199

A lambda's closures can be mangled when another calling lambda uses default capture?

This seems like a compiler bug, but it occurs in both gcc and clang (and maybe others).

If a function takes a lambda f and it creates a thread from another lambda g which calls f, f can quietly lose access to its captured variables. Here's a demonstration.

#include <thread>
#include <iostream>

using std::cout;
using std::endl;
using std::thread;

template<typename F>
__attribute__((noinline)) // inlining hides the bug
thread* callMeLater1(F f)
{
  return new thread(
    [&]() {
      // ...
      // Insert sleep logic.
      // ...

      f();
    });
}

template<typename F>
__attribute__((noinline))
thread* callMeLater2(F f)
{
  return new thread(
    [f]() {
      // ...
      // Insert sleep logic.
      // ...

      f();
    });
}


int main(int argc, const char * argv[]) {
  int a = 42;

  cout << "orign: " << ((void*) &a) << endl;

  auto f = [&]() {
             cout << "later: " << ((void*) &a) << endl;
           };

  thread* t1 = callMeLater1(f);
  t1->join();
  delete t1;

  thread* t2 = callMeLater2(f);
  t2->join();
  delete t2;

  return 0;
}

Here are the results.

orign: 0x7ffee88727ac
later: 0
later: 0x7ffee88727ac

The call to f inside callMeLater1 is corrupted. f's accesses to a will be broken, causing silent bugs or segfaults. When f is called inside callMeLater2, which doesn't use default capture &, the function works correctly.

Is this expected?

Upvotes: 0

Views: 45

Answers (1)

Sam Varshavchik
Sam Varshavchik

Reputation: 118300

This is undefined behavior.

The lambda captures, by reference, the parameter to callMeLater1. This parameter gets destroyed, of course, as soon as callMeLater1 returns.

Nothing guarantees you that the new execution thread invokes the passed-in closure before callmeLater1 returns. As such, the passed-in callable object can get destroyed before the new thread attempts to invoke it, resulting in undefined behavior.

Upvotes: 2

Related Questions