Manually calling C function with arbitrary stack data at run time - c

I know the reasons why this is a bad idea and I also know that this is the reason C++ templates were created, but I'm doing it in C for the fun and learning.
I'm embedding Python into my application and I wanted to make it possible to register certain C functions, with any arbitrary type, to be callable at the application run-time. Because of this a pointer to them is stored (as a simple void*).
With some basic macro fun I have gotten all the information I need about these functions and stored that too - the function pointer, the size of the return value (and if it is void), the number of arguments and each of their sizes.
So I'm stuck at the final stage - which is the actual calling of the function pointer with the appropriate data. I'm fairly certain this sort of thing should be possible (I've caused stack errors in my own time), but I was wondering if there was a more...legitimate way to do it.
I guess the ideal would look something like this:
void call_function(void* function, void* return, void* arg_data, int arg_data_size);
Does such a thing exists?
Thanks

You can declare a function pointer void* (*f) (void*); that points to a function that takes a void* argument and returns a void* return value -- you can put this in the first parameter of call_function.
Then call call_function as:
void* function(void*);
ret_type ret;
arg_type arg_data;
call_function(&function, (void*)&ret, (void*)&arg_data, sizeof(arg_data));
where arg_type is the actual argument type you want to use inside function and ret_type is the actual type of the return value of function.
Note: you might want to specify the size of the return value type as well.
Note: this will work with any function of one argument. The solution can be extended to a fixed/known number of arguments in function, but not to handle an unknown number of arguments.
Note: naming the second parameter return is not allowed as return is a keyword.

Related

C callbacks - optional argument?

Hey I have implemented some callbacks in my C program.
typedef void (*server_end_callback_t)(void *callbackArg);
then I have variable inside structure to store this callback
server->server_end_callback = on_sever_end;
What I have noticed it that I can pass in on_server_end callback function implementation that skips void *callbackArg and the code works correctly (no errors).
Is it correct to skip some arguments like void * implementing callback functions which prototypes takes such arguments?
void on_server_end(void) {
// some code goes here
}
I believe it is an undefined behavior from the C point of view, but it works because of the calling convention you are using.
For example, AMD64 ABI states that the first six arguments get passed to the calling function using CPU registers, not stack. So neither caller nor callee need no clean-up for the first six arguments and it works fine.
For more info please refer the Wikipedia.
The code works correctly because of the convention of passing arguments. Caller knows that callee expects some arguments - exactly one. So, it prepares the argument(s) (either in register or on stack - depending on ABI on your platform). Then callee uses those parameters or not. After return from callee, caller cleans up the stack if necessary. That's the mistery.
However, you shall not abuse this specific behaviour by passing incompatible function. It is a good practice to always compile your code with options -W -Wall -Werror (clang/gcc and compatible). Enabling such option would provide you a compilation error.
C allows a certain amount of playing fast and loose with function arguments. So
void (*fptr) ();
means "a pointer to a function which takes zero or more arguments". However this is for backwards compatibility, it's not wise to use it in new C code. The other way round
void (*fptr)(void *ptr)
{
/* don't use the void */
}
/* in another scope */
(*fptr)(); /* call with no arguments */
also works, as long as you don't use the void *, and I believe it is guaranteed to work though I'm not completely sure about that (on a modern machine the calling convention is to pass the first arguments in registers, so you just get a garbage register, and it will work). Again, it is a very bad idea to rely on it.
You can pass a void *, which you then cast to a structure of appropriate type containing as many arguments as you wish. That is a good idea and a sensible use of C's flexibility.
Is it correct to skip some arguments like void * implementing callback functions which prototypes takes such arguments?
No it is not. Any function with a given function declaration is not compatile with a function of a different function declaration. This rule applies for pointers to functions too.
So if you have a function such as pthread_create(..., my_callback, ...); and it expects you to pass a function pointer of type void* (*) (void*), then you cannot pass a function pointer of a different format. This invokes undefined behavior and compilers may generate incorrect code.
That being said, function pointer compatibility is a common non-standard extension on many systems. If the calling convention of the system is specified in a way that the function format doesn't matter, and the specific compiler port supports it, then such code might work just fine.
Such code is however not portable and not standard. It is best to avoid it whenever possible.

Calling C functions with too many arguments

I am currently changing the function signatures of a class of functions in an application. These functions are being stored in a function table, so I was expecting to change this function table as well. I have just realised that in certain instances, we already use the new function signature. But because everything is casted to the correct function type as it is put into the function table, no warnings are being raised.
When the function is called, it will be passed extra parameters that are not really part of the function declaration, but they are on the end of the parameter list.
I can't determine if this is guaranteed by the way function parameters are passed in C. I guess to do variadic functions like sprintf, it has to be the case that earlier arguments can be resolved correctly whatever is on the end of the parameter list?
It evidently works just fine across multiple platforms but out of curiosity I'd like to know how and why it works.
But because everything is casted to the correct function type as it is put into the function table, no warnings are being raised.
So the compiler gets to be no help to speak of. C programmers cast too much. >_<
I can't determine if this is guaranteed by the way function parameters are passed in C. I guess to do variadic functions like sprintf, it has to be the case that earlier arguments can be resolved correctly whatever is on the end of the parameter list?
Technically, you've got undefined behavior. But it's defined for your platform to use the standard C calling conventions (see Scott's answer), or something that maps directly to them (usually by mapping the first N parameters to a certain set of processor registers).
This comes up a lot with variable argument lists, too. For example, printf is declared something like:
int printf(const char* format, ...);
And its definition usually uses the stdarg system to handle the extra arguments, which looks like:
#include <stdarg.h>
int printf(const char* format, ...)
{
va_list ap;
int result;
va_start(ap, format);
result = vprintf(format, ap);
va_end(ap);
return result;
}
If you're on a platform with standard C calling conventions, that va_end(ap) macro usually turns into a do-nothing. In this case, you can get away with passing extra arguments to a function. But on some platforms, the va_end() call is required to restore the stack to a predictable state (i.e. where it was before the call to va_start); in those cases, your functions will not leave the stack the way it found it (it won't pop enough arguments back off the stack) so your calling function could, for example, crash on exit when it fetches a bogus value for a return address.
Your functions must certainly be using the cdecl calling convention (http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl). This pushes arguments on the stack in reverse order, from right to left, ensuring that the last argument can be easily located (top of the stack) and used to interpret the remainder, such as a printf format string. It is also the responsibility of the caller to clean up the stack, which is a bit less compact than the function itself doing so (as in pascal/stdcall convention), but ensures that variable argument lists can be used, and implies that trailing arguments can be ignored.

How to best fix both warnings(old style c-function declaration isn't a prototype)

I was fixing some functions in a piece of someone else code that included a number of functions that took no arguments.
They were declared as
return_type_t func();
instead of
return_type_t func(void);
Then I found that a bunch of these were put in a array of structs with function pointers.
When I fixed the function pointer to take void it gave me another warning since 1 of the function took a char* instead of void ptr.
What's the best solution for this sort of thing without a large rewrite(as the code is complex I was mainly cleaning it up around the edges and wish to avoid changing how it flows)?
The struct definition needs to list the correct function type in the member, there is no way around that if you want type safety.
In C, the old-style declaration return_type_t func() doesn't mean that func takes no arguments, it means that the number and types of its arguments (if any) are not specified. You cannot just assume that you can add void inside the parentheses.
Without seeing more of your code, my advice is to investigate each function separately and find out the correct number and types of parameters for each, and then fill out the prototype accordingly.
You can rewrite all your prototype to take a char* and then cast to (void) parameter where the parameter is not usefull

Function callers (callbacks) in C?

So I was wondering how they work. To explain what I mean by a "function caller" a good example of what I mean would be glutTimerFunc, it is able to take in a function as a parameter and call it even with it not knowing it is declared. How is it doing this?
What you're talking about is called a callback and is implemented with function pointers in C and C++.
Since you mentioned glut, let's take a real example directly from the freeglut source code. I'll use glutIdleFunc instead of glutTimerFunc because the code is simpler.
In glut, the idle function callback (what you supply to glutIdleFunc) is a pointer to a function that takes no parameters and returns nothing. A typedef is used to give such a function type a name:
typedef void (* FGCBIdle)( void );
Here, FGCBIdle (short for FreeGlut CallBack Idle) is defined as a pointer to a function that takes no parameters and whose return type is void. This is just a type definition that makes writing expression easier, it doesn't allocate any storage.
Freeglut has a structure called SFG_State that holds various settings. Part of the definition of that structure is:
struct tagSFG_State
{
/* stuff */
FGCBIdle IdleCallback; /* The global idle callback */
/* stuff */
};
The struct holds a variable of type FGCBIdle, which we established is another name for a specific function pointer. You can set the IdleCallback field to point to the address of a function that is supplied by the user using the glutIdleFunc function. The (simplified) definition of that function is:
void glutIdleFunc( void (* callback)( void ) )
{
fgState.IdleCallback = callback;
}
Here, fgState is a SFG_State variable. As you can see, the glutIdleFunc takes one parameter which is a function pointer to a function that takes no parameters and returns nothing, this parameter's name is callback. Inside the function, the IdleCallback inside the global fgState variable is set to the user supplied callback. When you call the glutIdleFunc function, you pass the name of your own function (e.g. glutIdleFunc(myIdle)), but what you're really passing is the address of the function.
Later, inside the big glut event processing loop initiated by glutMainLoop, you'll find this code:
if( fgState.IdleCallback )
{
/* stuff */
fgState.IdleCallback( );
}
If a user supplied idle callback is available, it is called in the loop. If you check the function pointer tutorial at the beginning of my post you will understand the syntax better, but I hope the general concept makes more sense now.
The parameter is a pointer to a function. It is the caller's responsibility to ensure that the function declaration matches the requirements (e.g., number and type of parameters, calling convention).
A function passed as a paramter is passed as a function pointer.
In compiled code, a function is nothing more than an address which the CPU can vector off to to execute. When you are passing a function pointer, the compiler (and later the linker) insert the correct address into the call.
Function parameters must match exactly as the executing code will simply push values on the stack (or registers, depending on the architecture) and expect to pop off (read out) the return value.

Casting a void pointer (data) to a function pointer

I know this has been asked before but none of the cases I've seen here are like this one.
I am importing some API functions at runtime, the general declaration on those functions would be like:
// Masks for UnmapViewOfFile and MapViewOfFile
typedef BOOL (WINAPI *MyUnmapViewOfFile)(LPCVOID);
typedef LPVOID (WINAPI *MyMapViewOfFile)(HANDLE, DWORD, DWORD, DWORD, SIZE_T);
// Declarations
MyUnmapViewOfFile LoadedUnmapViewOfFile;
MyMapViewOfFile LoadedMapViewOfFile;
I then call a generic "load" function where it calles GetProcAddress to get the address of the exported function from the proper DLL. That address is returned on a void**. This void** is one of the parameters in the generic load, something like:
int GenericLoad(char* lib, void** Address, char* TheFunctionToLoad)
and I would call this function:
void *Address;
GenericLoad("kernel32.dll", &Address, "UnmapViewOfFile");
LoadedUnmapViewOfFile = (MyUnmapViewOfFile) Address;
Or something similar to this.
Now, of course the compiler complains about trying to cast a data void* to a function pointer. How do I do this then?
I've read countless sites and all kinds of nasty casts, so I'd appreciate it if you add code to the explanation.
Thanks
Jess
The correct code would be this one line:
GenericLoad("kernel32.dll", (void**)&LoadedUnmapViewOfFile, "UnmapViewOfFile");
What is done here basically is this: the address of the pointer variable (the one in which you want the address of the function to be put) is passed to GenericLoad - which is basically what it expects. void** was to denote "give me the address of your pointer". All the type casting is a magic around it. C would not allow specifying "a pointer to any function pointer", so the API author preferred void**.
Now, of course the compiler complains about trying to cast a data void* to a function pointer
My compilers don't complain at all with your code (then again, I don't have warnings cranked up - I'm using more-or-less default options). This is with a variety of compilers from MS, GCC,and others. Can you give more details about the compiler and compiler options you're using and the exact warning you're seeing?
That said, C doesn't guarantee that a function pointer can be cast to/from a void pointer without problems, but in practice this will work fine on Windows.
If you want something that's standards compliant, you'll need to use a 'generic' function pointer instead of a void pointer - C guarantees that a function pointer can be converted to any other function pointer and back without loss, so this will work regardless of your platform. That's probably why the return value of the Win32 GetProcAddress() API returns a FARPROC, which is just a typedef for a function pointer to a function that takes no parameters (or at least unspecified parameters) and returns a pointer-sized int. Something like:
typedef INT_PTR (FAR WINAPI *FARPROC)();
FARPROC would be Win32's idea of a 'generic' function pointer. So all you should need to do is have a similar typedef (if you don't want to use FARPROC for some reason):
typedef intptr_t (*generic_funcptr_t)(); // intptr_t is typedef'ed appropriately elsewhere,
// like in <stdint.h> or something
int GenericLoad(char* lib, generic_funcptr_t* Address, char* TheFunctionToLoad)
generic_funcptr_t Address;
GenericLoad("kernel32.dll", &Address, "UnmapViewOfFile");
LoadedUnmapViewOfFile = (MyUnmapViewOfFile) Address;
Or you can dispense with the middle-man and pass the pointer you really want to get the value into:
GenericLoad2("kernel32.dll", (generic_funcptr_t *) &LoadedUnmapViewOfFile, "UnmapViewOfFile");
Though that's more dangerous than the method using the intermediate variable - for example the compiler will not give a diagnostic if you leave off the ampersand in this last example, however in the previous example, it would generally give at least a warning if you left off the ampersand from the Address argument. Similar to Bug #1 here: http://blogs.msdn.com/sdl/archive/2009/07/28/atl-ms09-035-and-the-sdl.aspx
Now you should be set. However, any way you look at it you'll need to perform some dangerous casting. Even in C++ with templates you'd have to perform a cast at some level (though you might be able to hide it in the template function) because the GetProcAddress() API doesn't know the actual type of the function pointer you're retrieving.
Also note that your interface for GenericLoad() has a possibly serious design problem - it provides no way to manage the lifetime of the library. That may not be a problem if your intent is to not allow unloading a library, but it's something that users may want so you should consider the issue.
Addresses to data and addresses to functions are incompatible things. I believe that your Address variable must be a function pointer as in your BOOL definition: (WINAPI *MyUnmapViewOfFile)(LPCVOID). This type of declaration is required because in order to have a pointer to a function, the return type, and the type and number of arguments must be known. This is because when you call your function, the correct amount of space must be allocated on the stack to contain these return value and args.
Given that, I believe that the correction in Pavel's answer is correct (FYI, his (void**) cast is a type safety measure).

Resources