function_ref
function_ref copied to clipboard
Member function: Passing object by value cause dangling
struct S {
int foo() const { return 3; }
};
int main() {
tl::function_ref<int(S)> f = &S::foo;
f(S{}); // crash with GCC 9.1
}
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
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