Call a function from its address via a templated function - c++

Assuming I have the runtime memory address of a function in an Application and I know the return type of said function, is it possible to call the function, knowing the functions return type, its arguments and calling convention, using a variadic template?
The templated function has to support both void and non-void return types. Due to the fact that we are dealing with function pointers, the compiler shouldn't complain, despite return ptr.
I thought about doing something like this:
template<typename ReturnType, typename Address, typename... Args>
ReturnType function_caller(Address address, Args... args)
{
ReturnType(*ptr)(Args...) = address;
return ptr(args...);
}
int main()
{
auto address = 0x100;
auto address2 = 0x200;
function_caller<void>(&address, 1, 1); // Function with return type void.
int result = function_caller<int>(&address2, 1, 2, 3.f, "hello");
// result should contain the int value we received by calling the function at 0x200
}
Sadly the compiler throws the error C2440: It can't convert the Address "address" to 'ReturnType (__cdecl *)(int,int)'
I would really appreciate your help with this problem. I know i could just split this wrapper into 2 functions: one for void calls and one for non-void calls, but i hope there is a more elegant, template-supported solution.
Thank you and have a nice day!

the answer is yes, but doing it with variadic template is dangerous .
to enforce the compiler to cast the address to a function pointer you need to use reinterpret_cast or a c cast .
note : you are improperly casting an integral address to a pointer because you are really trying to cast the address of the variable containing the address to the pointer not the address itself !
so this line :
function_caller<void>(&address, 1, 1); // Function with return type void.
should be :
function_caller<void>(address, 1, 1); // Function with return type void.
and always use the address type as uintptr_t which will fit for any address available for the architecture (64 bit or 32)
but doing so with variadic template isn't safe at all . the reason is that the function have particular arguments type like this :
int fn(std::string& str, const char* ptr, uint64_t& i);
but when you cast with variadic template the compiler will deduce the types from the arguments passed however some conversions may be required !
so in your current version :
int i;
function_caller<int>(0x15216516, "str", "ptr", i);
the compile will assume that the function signature is something like :
int fn(const char*, const char*, int); // wrong types means stack corruptions and undefined behaviors
also see this :
std::string to_string(std::string_view v);
function_caller<std::string>(0x15216516, "str"); // wrong the compiler won't convert the string literal for you and the function will end up with a dangling view
function_caller<std::string>(0x15216516, std::string("str")); // wrong again there is no conversion from std::string to std::string_view here
so it is really reliable only to specify the whole function type and use that to cast the address like what boost.dll does

Related

Address of overloaded function cannot be static_cast to type [duplicate]

I have a function that takes a string, an array of strings, and an array of pointers, and looks for the string in the array of strings, and returns the corresponding pointer from the array of pointers. Since I use this for several different things, the pointer array is declared as an array of (void *), and the caller should know what kind of pointers are actually there (and hence what kind of a pointer it gets back as the return value).
When I pass in an array of function pointers, however, I get a warning when I compile with -Wpedantic:
clang:
test.c:40:8: warning: assigning to 'voidfunc' (aka 'void (*)(void)') from 'void *' converts
between void pointer and function pointer [-Wpedantic]
gcc:
test.c:40:8: warning: ISO C forbids assignment between function pointer and ‘void *’ [-Wpedantic]
fptr = find_ptr("quux", name_list, (void **)ptr_list,
Here's a test file, which despite the warning does correctly print "quux":
#include <stdio.h>
#include <string.h>
void foo(void)
{
puts("foo");
}
void bar(void)
{
puts("bar");
}
void quux(void)
{
puts("quux");
}
typedef void (* voidfunc)(void);
voidfunc ptr_list[] = {foo, bar, quux};
char *name_list[] = {"foo", "bar", "quux"};
void *find_ptr(char *name, char *names[], void *ptrs[], int length)
{
int i;
for (i = 0; i < length; i++) {
if (strcmp(name, names[i]) == 0) {
return ptrs[i];
}
}
return NULL;
}
int main() {
voidfunc fptr;
fptr = find_ptr("quux", name_list, (void **)ptr_list,
sizeof(ptr_list) / sizeof(ptr_list[0]));
fptr();
return 0;
}
Is there any way to fix the warning, other than not compiling with -Wpedantic, or duplicating my find_ptr function, once for function pointers and once for non-function pointers? Is there a better way to achieve what I'm trying to do?
You can't fix the warning. In fact, in my opinion it should be a hard error since it's illegal to cast function pointers to other pointers because there are architectures out there today where this isn't just a violation of the C standard but an actual error that will make the code not work. Compilers allow it because many architectures get away with it even though those programs will crash badly on some other architectures. But it's not just a theoretical standard violation, it's something that causes real bugs.
For example on ia64 function pointers are (or at least used to be last time I looked) actually two values, both necessary to make function calls across shared libraries or a program and a shared library. Likewise, the common practice to cast and call function pointers to functions returning a value to a pointer to a function returning void because you know you'll ignore the return value anyway is also illegal on ia64 because that can lead to trap values leaking into registers causing crashes in some unrelated piece of code many instructions later.
Don't cast function pointers. Always have them match types. This is not just standards pedantry, it's an important best practice.
One solution is to add a level of indirection. This helps with lots of things. Instead of storing a pointer to a function, store a pointer to a struct storing a pointer to a function.
typedef struct
{
void (*ptr)(void);
} Func;
Func vf = { voidfunc };
ptrlist[123] = &vf;
etc.
This is something that has long been broken in the C standard and has never been fixed -- there is no generic pointer type that can be used for pointers to functions and pointers to data.
Before the C89 standard, all C compilers allowed converting between pointers of different types, and char * was generally used as a generic pointer that might point to any data type or any function. C89 added void *, but put in a clause that only object pointers could be converted to void *, without ever defining what an object is. The POSIX standard fixes this issue by mandating that void * and function pointers are safely convertable back and forth. So much code exists that converts function pointers to void * and expects it to work properly. As a result, pretty much all C compilers still allow it, and still generate the correct code, as any compiler that did not would be rejected as unusable.
Strictly speaking, if you want to have a generic pointer in C, you need to define a union that can hold either a void * or a void (*)() and use an explicit cast of the function pointer to the correct function pointer type before calling it.
The language lawyering reason is "because C standard does not explicitly allow it." C11 6.3.2.3p1/p8
1. A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a
pointer to void and back again; the result shall compare equal to the
original pointer.
8. A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall
compare equal to the original pointer. If a converted pointer is used
to call a function whose type is not compatible with the referenced
type, the behavior is undefined.
Notice that a function is not an object in C terminology, hence there is nothing that allows you to convert a pointer to a function to a pointer to void, hence the behaviour is undefined.
Castability to void * is a common extension though. C11 J.5 Common extensions 7:
J.5.7 Function pointer casts
1. A pointer to an object or to void may be cast to a pointer to a function, allowing data to be invoked as a function (6.5.4).
2. A pointer to a function may be cast to a pointer to an object or to void, allowing a function to be inspected or modified (for example, by a debugger) (6.5.4).
This is required by for example POSIX - POSIX has a function dlsym that returns void * but in fact it returns either a pointer to a function or a pointer to an object, depending of the type of the symbol resolved.
As to why this happens - nothing in C standard is undefined or unspecified if the implementations could agree on it. However there were and are platforms where the assumption that a void pointer and function pointer would be of the same width would really make things difficult. One of these is the 8086 16-bit real mode.
And what to use instead then? You can still cast any function pointer to another function pointer, so you can use a generic function pointer void (*)(void) everywhere. If you need both void * and a function pointer, you must use a struct or union or allocate void * to point to the function pointer, or ensure that your code only runs on platforms where J.5.7 is implemented ;)
void (*)() is recommended by some sources too, but right now it seems to trigger a warning in latest GCCs because it doesn't have a prototype.
With some modification you can avoid pointer conversations:
#include <stdio.h>
#include <string.h>
void foo(void)
{
puts("foo");
}
void bar(void)
{
puts("bar");
}
void quux(void)
{
puts("quux");
}
typedef void (* voidfunc)(void);
voidfunc ptr_list[] = {foo, bar, quux};
char *name_list[] = {"foo", "bar", "quux"};
voidfunc find_ptr(char *name, char *names[], voidfunc ptrs[], int length)
{
int i;
for (i = 0; i < length; i++) {
if (strcmp(name, names[i]) == 0) {
return ptrs[i];
}
}
return NULL;
}
int main() {
voidfunc fptr;
fptr = find_ptr("quux", name_list, ptr_list,
sizeof(ptr_list) / sizeof(ptr_list[0]));
fptr();
return 0;
}
As pointed out in other answers you shouldn't be allowed to assign a function pointer to an object pointer such as a void*. But you can safely assign a function pointer to any function pointer. Use reinterpret_cast in C++.
Let me give an example:
typedef void(*pFun)(void);
double increase(double a){return a+1.0;}
pFun ptrToFunc = reinterpret_cast<void(*)(void)>(increase);
the plain
pFun ptrToFunc = increase;
doesn't compile on several compilers.
I'm answering this old question because it seems that one possible solution is missing from existing answers.
The reason why the compiler forbids the conversion is that sizeof(void(*)(void)) can be different than sizeof(void*). We can make the function more generic, so that it can handle entries of any size:
void *find_item(char *name, char *names[], void *items, int item_size, int item_count)
{
int i;
for (i = 0; i < item_count; i++) {
if (strcmp(name, names[i]) == 0) {
return (char*)items + i * item_size;
}
}
return NULL;
}
int main() {
voidfunc fptr;
fptr = *(voidfunc*)find_item("quux", name_list, ptr_list,
sizeof(ptr_list[0]),
sizeof(ptr_list) / sizeof(ptr_list[0]));
fptr();
return 0;
}
Now the find_entry() function doesn't need to directly handle the item at all. Instead it just returns a pointer to the array, and the caller can cast it to a pointer-to-funcpointer before dereferencing it.
(The code snippet above assumes the definitions from original question. You can see full code also here: try it online!)

Casting lambda with non-void return type to function pointer

I am trying to cast a lambda function to a function pointer. However, the cast fails when the lambda has a non-void return type. Details see the code snippet.
Is it possible to cast fun2 into a generic function pointer which I can save for later usage?
Update: My intention is to cast all kinds of functions to a "generic function pointer" which can be saved in a std::map. Upon usage, I will cast it back to its original function type.
#include <iostream>
int fun3() { return 1; }
int main(int argc, char *argv[]) {
typedef void (*voidFunctionType)(void);
// Case 1: lambda, return type void
auto fun1 = []() { std::cout << "hello" << std::endl; };
// -> compiles
auto casted_fun1 = (voidFunctionType)fun1;
// Case 2: lambda, return type int
auto fun2 = []() { std::cout << "world" << std::endl; return -1;};
// -> error: invalid cast from type ‘main(int, char**)::<lambda()>’ to type ‘voidFunctionType {aka void (*)()}’
auto casted_fun2 = (voidFunctionType)fun2;
// Case 3: free function, return type int -> compiles
auto casted_fun3 = (voidFunctionType)fun3;
return 0;
}
The problem is that you are using C-style explicit casts. These are notoriously dangerous.
Here in this case the problem is that fun3 (in contrast to fun2) already decays to a function pointer of type int(*)().
You then cast it to void(*)(). This works because the C-style cast will try to do different C++ cast expressions until one works. In particular it will also try a reinterpret_cast.
reinterpret_cast<voidFunctionType>(fun3)
works, because reinterpret_cast can cast any function pointer to any other function pointer.
However, you are not allowed to call the function through the obtained pointer. Doing so causes your program to have undefined behavior. As you can see this cast is of very limited use and dangerous if you are not aware of it.
Don't use C-style casts, use static_cast<voidFunctionType>(fun3) instead and you will get the appropriate compile-time error in both cases.
You cannot use a function (whether free function or lambda) that returns one type as if it returned another (or no) type. Casting the lambda that returns int to void(*)() therefore doesn't make sense.
If you really want to save arbitrary function pointers you can make the lambda cast work by first converting it to a function pointer and then casting it to the destination function pointer type with a reinterpret_cast. I would still not use C style casts, because the reinterpret_cast will at least make it clear what kind of cast you are intending to do:
auto casted_fun2 = reinterpret_cast<voidFunctionType>(+fun2);
The unary + is a common trick to force lambda to function pointer conversion. Note however also that only lambdas without capture can be converted to function pointers.
As I explained above though, you must cast the pointer back to its original type before calling it, so you need to store the type information somewhere. I am not sure how you intend to do that, but you probably need to implement some extended version of std::function, see e.g. this question for how std::function does it.

Why cant i assign a function to function pointer?

While doing my homework i decided to use function pointer as a callback function. I am not going to post the whole homework here as it is too large. Here i wrote small test code to illustrate the error i am getting.
#include <iostream>
void function()
{
std::cout << "test";
}
int main()
{
void* functionPtr(int) = function;
functionPtr();
}
I am getting error C2059: syntax error: '=' here void* functionPtr(int) = function;. If i hower my mouse over = sign it says next: "function functionPtr cannot be initialized". If i change that to ...
void* functionPtr();
functionPtr = function;
...i will be getting error C2659: '=': function as left operand.
Am i using function pointers wrong way?
I use Visual Studio 2019 btw.
Thank you for any help.
This isn't the right syntax. You declare a function, not a function pointer.
Here's how a function pointer is declared:
void(*functionPtr)(int);
As you noticed, the star is beside the name. If there is no parenthesis, the star will apply to the return type and not the name.
Or with a trailing return type:
auto(*functionPtr)(int) -> void;
Also, your function called function don't take an int as parameter. So it should be like this:
void(*functionPtr)() = function;
You got the types wrong. There is no int parameter for in function and you missed a *. Your declare functionPtr as a function. For a function pointer you need:
void(*functionPtr)() = function;
// ^--- "pointer to function"
However, since C++11, using function pointers got much simpler, as you can do
using functionPtrType = void(*)();
functionPtrType p = function;
Or
using functionPtrType = decltype(&function);
functionPtrType p = function;
which has a tiny disadvantage of not making it obvious that a function pointer is involved. The advantage is that it wont break when you change the signature of function.
On the other hand, once you use decltype (and you do not need the type of the function pointer elsewhere) you can as well shorten it to:
decltype(&function) functionPtr = function;
Eventually, this is already avoiding so much to spell out the type that you can simply use auto:
auto functionPtr = &function;
To create a pointer to a function, you need to use parentheses to override the normal binding of the *. void *f() means f is a function returning a pointer to void. To instead get a pointer to a function returning void, you need void (*f)();
So in your case, the code would look something like void (*functionPtr)() = function;

incompactable pointer type passing int to parameter of type void(*)(void) in coretelephony obj c

The function defined in coreTelephony.h is
void _CTServerConnectionRegisterForNotification(CTServerConnectionRef,void *,void(*callback)(void));
Then I tried to call this function
int x = 0; //placehoder for callback
_CTServerConnectionRegisterForNotification(conn,kCTCellMonitorUpdateNotification,&x);
it return the error
incompatible pointer type passing int to parameter of type void(*)(void) in coretelephony obj c
What am I missing?
The third argument of _CTServerConnectionRegisterForNotification is a function pointer, and you pass a pointer to an int. Even if you succeeded to do it using casts, later when the connection needs to notify you it will try to use the value you passed as a function, and since it is not a function, you most likely will see a crash.
Use a function not an int:
void callback()
{
}
and then in your current code:
_CTServerConnectionRegisterForNotification(conn,kCTCellMonitorUpdateNotification,&callback);
Here, the third argument to _CTServerConnectionRegisterForNotification() is meant to be a pointer to a function having
void return type
Accepting no parameter.
You cannot pass the address of an int in that case. It is wrong and will cause undefined behavior.

Can I convert a pointer to member function to a char array and back using reinterpret_cast?

I have some code that looks like this:
char member_data[16];
template<typename T>
void set(void (T::*member)(void)) {
memcpy(member_data, (char*) &member, sizeof(member));
}
template<typename T>
void (T::*)(void) get() {
void (T::*member)(void);
memcpy((char*) &member, member_data, sizeof(member));
return member;
}
In the full context, I can be sure that set always uses the same type as the following get.
Can this be safely rewritten to use reinterpret_cast?
Edit:
Does this code do the same thing as above?
char member_data[16];
template<typename T>
using member_func = void (T::*)();
template<typename T>
void set(member_func<T> member) {
reinterpret_cast<member_func<T>&>(member_data) = member;
}
template<typename T>
member_func<T> get() {
return reinterpret_cast<member_func<T>&>(member_data));
}
Seems to work
The version you have in your edited part is not valid: you can't access an arbitrary char array as any other type. It may be possible to achieve something like this in a valid way by using std::aligned_storage<..> instead of a plain char array.
If member_data is declared as
std::aligned_storage<sizeof(member_func<T>), alignof(member_func<T>)>::type member_data;
or (essentially equivalently)
alignas(member_func<T>) char member_data[sizeof(member_func<T>)];
then your reinterpret_cast<..> approach should actually work. Instead of the template parameter dependent sizeof and alignof expressions, you can try using any fixed member_func<some_class>. It is highly unlikely that an implementation has different size or alignment requirements for pointers to member functions of different classes. If you want to be really safe use static asserts to check.
Can this be safely rewritten to use reinterpret_cast?
Other than what is described in your edit, you can directly cast a member function pointer, like reinterpret_cast<SomeType>(member), only, if SomeType is also a pointer-to-member type. So you can choose one pointer-to-member function type as "generic member function pointer storage", if all you do with that value is to convert it back to the original member pointer type.
You can't convert a pointer to member into a pointer to object (or vice versa).
In both cases your code is unsafe as is, because it will overrun the member_data buffer, if sizeof (void (T::*)()) > 16.
And by the way: the first code example already does use reinterpret_cast: The old-style cast to (char*) from void (T::**)() already is equivalent to a reinterpret_cast ;-)