How to get the "raw" ptr of a lambda *capture* function - c++

I want to make a C++ assembly hooking using lambda captures but for this i need to get the pointer of a lambda capture function.
something like this:
int val0 = 42;
auto lambdaCap = new auto([&]() -> int { return val0++; });
uint64_t pLambdaFn = static_cast<uint64_t>(&decltype(*lambdaCap)::operator()); // need this
I understand than a lambda function capture seems like an instance of class with a functor, but i want get the static address of lambda::operator(). In memory "lambdaCap" is just a ptr to the variables members used in the lambda.
Thanks

&decltype(*lambdaCap)::operator()) is not valid because decltype(*lambdaCap) is actually an lvalue reference to the closure type.
Instead, std::remove_pointer_t<decltype(lambdaCap)> would give you the closure type itself. So you can write &std::remove_pointer_t<decltype(lambdaCap)>::operator() to get the pointer-to-member-function corresponding to the closure type's function call operator.
However, this expression has type int (T::*)(), which cannot be converted into an integer type. You can store it as-is, and call it using a pointer to an instance of the closure type (such as lambdaCap itself) but you can't convert it to uint64_t. There is no way to convert a pointer-to-nonstatic-member to an integer type, whether with static_cast or reinterpret_cast or any other cast.

Related

Why isn't it possible to assign the result of std::bind to a function pointer

The result of an std::bind can be assigned to an std::function
A function pointer can be assigned to an std::function.
So far I was under the impression std::function can generally hold any function pointer. And anything an std::function can hold can be assigned to a function pointer.
And found that the reult of an std::bind can't be assigned to a function pointer
int add(int x, int y)
{
return x+y;
}
int main()
{
std::function<int (int, int)> fp = &add; // a func pointor can be assined to an std::function
int result = fp(3,5) // this works fine
std::function<int (int, int)> add_v2 = std::bind(&add, _1,_2); // std:: bind can be assigned to an std::function
int result = add_v2(3,5); // works fine
int (*add_v3)(int, int);
add_v3 = std::bind(&add, _1,_2); // does not compile
}
Can you please explain why I can't assign the result of std::bind to a function pointr
std::function knows how to invoke calls to multiple callable types, including plain functions, lambdas, and the result of std::bind(). Just because std::function can handle multiple callable types does not means the individual types are interchangeable/assignable with each other.
The return value of std::bind() returns a callable object of an unspecified type determined by the implementation. That type has an operator() that std::function calls. The bound object carries state information about the target object and class method it needs to call inside its operator(). So, by definition, such an object could never be assignable to a plain function pointer. There would be nowhere to store the state data, or even the bound object's own this pointer. The same reasons why a capturing lambda cannot be assigned to a plain function pointer, either.
add_v3 = std::bind(&add, _1,_2); // does not compile
As just the most obvious reason this can't be made to work, consider that all that's left after this line of code executes is a naked pointer. What can it point to?
The resulting bound function (the result of binding add to _1 and _2) clearly didn't exist before this line of code executes. And whatever std::bind created, it's a temporary that will no longer exist after this line executes.
So what could add_v3, a simple raw pointer, possibly point to? What would own it? What would manage its lifetime? When would it be destroyed?

Where is the function that a decayed lambda points to stored? How is it freed?

I've recently learned that I can do this:
auto a = +[]{return true;};
a = +[]{return false;};
And understood that the capture-free lambda decays to a function pointer, as confirmed by GCC:
bool (*)()
But where is the actual function object stored?
How is it freed? Why can I store a pointer to a temporary lambda? I understand that corner-case of the the language where constant references extend the lifetime of an object, so I expected the lambda to decay to something of that kind, not a raw pointer.
The lambda is not a pointer, but can be converted into a pointer-to-function.
Functions are not "stored" like values in C++. In practice, they exist in a code segment of the executable, and are loaded into write-protected execute-bit-set pages by the executable/dll loader.
The stateless lambda's code is no different. The conversion just returns a pointer to a function with the same effect as the body of the lambda, no more, no less.
Remember this only works with stateless lambdas. There is no non-static data to be stored.
Now, the + thing is a bit of a trick, in that when you apply unary operator+ to an object, conversion is attempted, and one uniqie type (conversion of the function object to function pointer) is found.
I guess concrete code may help.
struct fake_lambda {
static void action(){ std::cout<<"hello?\n"; }
void operator()()const{action();}
using ptr=void(*)();
operator ptr()const{return &fake_lambda::action;}
};
Now auto f=+fake_lambda{}; is a pointer to a function that prints "hello?\n".
This is basically the same as auto f=+[](){std::cout<<"hello\n";};, but more verbose.

Why isn't a lambda that captures variables by reference convertible to a function pointer?

If I have a lambda which captures all automatic variables by reference ([&] {}), why can't it be converted to a function pointer? A regular function can modify variables just like a lambda that captures everything by reference can, so why is it not the same?
I guess in other words, what is the functional difference between a lambda with a & capture list and a regular function such that the lambda is not convertible to a function pointer?
So let's take the example of a trivial lambda:
Object o;
auto foo = [&]{ return o; };
What does the type of foo look like? It might look something like this:
struct __unique_unspecified_blah
{
operator()() const {
return o;
}
Object& o;
};
Can you create a function pointer to that operator()? No, you can't. That function needs some extra information that comes from its object. This is the same reason that you can't convert a typical class method to a raw function pointer (without the extra first argument where this goes). Supposing you did create some this pointer - how would it know where to get o from?
The "reference" part of the question is not relevant - if your lambda captures anything, then its operator() will need to reference some sort of storage in the object. If it needs storage, it can't convert to a raw function pointer.
I guess in other words, what is the functional difference between a
lambda with a & capture list and a regular function such that the
lambda is not convertible to a function pointer?
References, though they aren't objects, need to be stored somewhere. A regular function cannot access local variables of another function; Only references (e.g. as parameters) that could refer to local variables. A Lambda with a & as the capture-default can, because every variable needed can be captured. In other words: A regular function doesn't have state. A closure object with captured variables does have state. So a closure object cannot be reduced to a regular function, because the state would be lost.

non returning lambda with captures as function pointer

My code (C++) need to pass lambda as function pointer. My lambdas always: a) return void; b) never takes any parameter; and c) can have zero or more capture arguments. I want to pass this lambda as a function pointer but unable to do so. Any advice ?
Sample code:
void fptrfunc(void (*fptr)()){
fptr();
}
int main(){
int x = 2;
fptrfunc([](){cout << "LAMBDA CALL--1"<< endl; }); // Works
fptrfunc([x](){cout << "LAMBDA CALL--2"<< endl; }); // Does not compile
return 0;
}
Lambda functions which are really just functions, i.e., don't carry and data, can be converted to function pointers. To not have any data clearly the capture has to be empty. The other parts of the signature do't matter: as long as the types match, you can assign a lambda function [with an empty capture] to a function pointer.
The moment you need to have data with your lambda function you won't be able to convert it to a function pointer because there is no place to store the additional data. If you have a sensible interface where you need to pass the lambda function you may have some user data being passed along, often a void*. You could a combination of an auxiliary function pointer and a lambda, probably wrapped by a suitable std::function<Sig>, pointed to by the user data to still call a lambda function.
What you want, is not possible in C++. Lambdas that capture variables are not convertible to a function pointer.
You need to do drop the requirement c) and only use lambdas without captures. Or you must change the declaration of fptrfunc. You can change the parameter type to std::function or make it a template that can accept any type of functor that implements the operator().

Convert lambda with capture clause stored in std::function to raw function pointer

Since my last recent question was unfortunately worded and resulted in a solution to another problem then mine, here I will try to formulate my actual problem in a clear way.
Before we start, as a sidenote, I am integrating the Javascript Engine V8 into my C++ application. That's where all the types in the example come from. And that's also the reason for the fact that I need a raw function pointer in the end. But I elaborate on this below.
From inside a class I need to pass a lambda expression with the capture clause [=] as parameter of the type std::function to another function and cast it to a raw function pointer there.
In this code, InvocationCallback is simply a typedef for a function with the signature Handle<Value>(Arguments const &).
typedef Handle<Value> (*InvocationCallback)(Arguments const &);
void Bind(string Name, function<Handle<Value>(Arguments const &)> Function)
{
InvocationCallback* function = Function.target<InvocationCallback>();
}
All the lambda expressions have the same signature, too. Note that Handle<String> is compatible to Handle<Value> in this example. It's given by the Javascript Engine V8, too.
Bind("name", [=](const Arguments& args) -> Handle<Value>{
Handle<String> result = String::New(Name().c_str());
return result;
});
C++ allows me to pass this lambda as std::function to the function above. But I guess a lambda expression also stores a reference to object it refers. Somehow the access specified by [=] must be realized. That might be the reasons that casting the std::function to a raw function pointer fails.
InvocationCallback* function = Function.target<InvocationCallback>();
There is neither a compile time error nor a runtime error but the debugger tells me that it results in a null pointer. But I need the raw function pointer for further processing. I guess I could convert the lambda after std::binding the reference or this-pointer first.
Update: Since it seems to be impossible to get the state out of the lambda, this is what I tried. It compiles but function come out to be a null pointer.
Bind("name", this, [](Base* object, const Arguments& args) -> Handle<Value>{
return v8::String::New(((Derived*)object)->Name().c_str());
});
void Bind(string Name, Module *Object, function<Handle<Value>(Module*, Arguments const &)> Function)
{
function<Handle<Value>(Arguments const &)> method = std::bind(Function, Object, std::placeholders::_1);
InvocationCallback* function = method.target<InvocationCallback>();
}
You can't, because a lambda which captures is a closure, so it has state (it is an object with instance variables). A function pointer has no state. Thus, you cannot do this without either 1) the API you are using that requires the function pointer also allows you to pass a user data argument where you pass the state, or 2) storing the state in a global variable or something.
Search around Stack Overflow for "member function to callback" and you will get an idea (basically, you are wanting to use a member function, the operator(), as a callback).
You can convert a capturing lambda/functor into a function pointer, but you need to be careful when doing it:
https://codereview.stackexchange.com/questions/79612/c-ifying-a-capturing-lambda