Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Member function: Passing object by value cause dangling #12

Open
LesleyLai opened this issue Jun 27, 2019 · 2 comments
Open

Member function: Passing object by value cause dangling #12

LesleyLai opened this issue Jun 27, 2019 · 2 comments

Comments

@LesleyLai
Copy link

struct S {
  int foo() const { return 3; }
};

int main() {
    tl::function_ref<int(S)> f = &S::foo;
    f(S{}); // crash with GCC 9.1
}
@rollbear
Copy link

rollbear commented Jul 3, 2019

I took the liberty of analyzing this, and if you compile with -fsanitize=address, you get to see the problem also on clang++.

What happens is that in the pointer to member function constructor, the parameter f is a temporary, and obj_ will point to that temporary. The temporary is destroyed once the function_ref<> object has been constructed. When the call is made, obj_ refers to the corpse. Changing the program to avoid the temporary works:

int main() {
    auto mf = &S::foo;
    tl::function_ref<int(S)> f = mf;
    f({S});
}

I don't know how to fix it, unfortunately.

Demo: https://gcc.godbolt.org/z/XfYrtO

@nitronoid
Copy link

This is the same undefined behaviour you would get when storing a temporary lambda and invoking the ref.

tl::function_ref<int(S)> f = [](){};
f();

Of course, the below snippet works and is why a function_ref is constructable from an rvalue in the first place.

// Any rvalue passed to this function will live as long as the function scope
int proxy(tl::function_ref<int(S)> f)
{
  return f(S{});
}

int main()
{
  return proxy(&S::foo);
}

See the "Possible Issues" section: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0792r4.html

A more subtle example, and the reason why you may have tried this:

int foo()
{
  return 3;
}

int main()
{
  // Works fine
  {
      tl::function_ref<int()> f = foo;
      f();
  }
  // Segfault, taking the address produces a temporary
  {
      tl::function_ref<int()> f = &foo;
      f();
  }
}

All compiled with GCC 9.1 at O3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants