void* to pointer - c++

Normally when calling a dynamically loaded function I usually do a standard straight cast:
typedef int (*GenericFn)(); // matches x86 FARPROC, minus explicit calling convention
typedef bool (*DesiredFn)(int,int);
GenericFn address = GetProcAddress(module, "MyFunction");
DesiredFn target = reinterpret_cast<DesiredFn>(address);
Today I did something a little different (and braindead).
DesiredFn target = nullptr;
void* temp = static_cast<void*>(&target); // pointer to function pointer
GenericFn* address = static_cast<GenericFn*>(temp);
*address = GetProcAddress(module, "MyFunction"); // supposedly valid?
// temp is declared void* because a void** cannot be cast to GenericFn* without
// first doing a void** -> void* conversion
assert(target == MyFunction); // true on VC10, presumably GCC
My questions:
Is the behavior of a void* (note: not a void**) to an object pointer type well-defined?
Why does the compiler allow static_cast<void*> on a void**?
Why am I stupid enough to try this?
Do you see anything else that's wrong with this example?
I've since decided to use method #1 again because of code clarity (and because I know it's supposed to work). I'm still interested in why method #2 worked though :).
In case you're wondering (about my explanation)
Today I was removing <windows.h> dependencies in several public interfaces, and rather than redeclare FARPROC like I should have, I experimentally changed my FARPROC return-type function to instead accept a void* output parameter (I know, it should probably have been a void**).
// implemented in some library cpp file
void detail::FunctionResolve(std::string export, void* output)
{
FARPROC* address = static_cast<FARPROC*>(output);
*address = GetProcAddress(...);
}
// header-defined interface class
template<typename F>
class RuntimeFunction {
F* target;
void SetFunction(std::string export) {
// old: this->target = reinterpret_cast<F*>(detail::FunctionResolve(...));
// new:
detail::FunctionResolve(export, static_cast<void*>(&this->target));
}
};

typedef int (*GenericFn)(); // matches x86 FARPROC, minus explicit calling convention
typedef bool (*DesiredFn)(int,int);
DesiredFn target = nullptr;
void* temp = static_cast<void*>(&target); // pointer to function pointer
There's nothing wrong here, but the cast is unnecessary. A pointer to any object (a pointer to a function is an object) can be converted to a pointer to void without a cast. e.g.
void* temp = &target;
GenericFn* address = static_cast<GenericFn*>(temp);
You can convert from a pointer to void to a pointer to any object type but the results are only defined if you cast a value the was converted to a void* back to the original type that it was converted from. Technically, only a static_cast<DesiredFn*>(temp) would have a well defined result.
*address = GetProcAddress(module, "MyFunction"); // supposedly valid?
This isn't technically correct as you have lied about the type of the value that you assigned to address so address isn't pointing to an object that matches its type information.
Having said all that, in many implementations function pointers are all represented in the same way and any cast and conversions don't have any effect on the value that is actually stored. So long as you call the function throught a pointer that actually matches the type of the pointer you won't have any problems.
After all, you have to rely on your implementation's behaviour of reinterpret_cast and GetProcAddress for the original method to work at all, but - as you say - I would recommend sticking with the reinterpret_cast approach in this case as it is clearer what is going on.

It doesn't matter because void* and void** are the same size. You're just changing the type. Why not just cast directly to the type you want?
DesiredFn target =
reinterpret_cast<DesiredFn>(GetProcAddress(module, "MyFunction"));

Related

How can understand the *(void **)(&m_handle) = dlsym("./haldle_lib.so", "custom_func");

Just want to understand the following code:
Why we use option (1) other than option (2)? I don't know what's the use of (void**) here? really confused.
Class Handle{
private:
int unique_id;
int (*m_handle)(int arg1, int arg2);
public:
bool init(){
*(void **)(&m_handle) = dlsym(dlopen(./haldle_lib.so, RTLD_NOW), "custom_func"); // (1)
//m_handle = (decltype(m_handle))dlsym(dlopen(./haldle_lib.so, RTLD_NOW), "custom_func");//(2)
}
}
add reference https://www.tldp.org/HOWTO/pdf/C++-dlopen.pdf
Converting a pointer of type void* to a function pointer is not allowed. In other words, from C++ point of view, function pointers and object pointers are not the same thing.
In option 1, the trick is that you first get the address of the function pointer (&m_handle). Then you pretend that this pointer (i.e. &m_handle) points to an ordinary object pointer (of type void*) and not to a pointer to a function pointer. Using this pointer ((void **)(&m_handle)), you use operator* to deference it and and write the value returned by dlsym(..) into the function pointer.
The code should be:
void *m = dlsym(....);
m_handle = reinterpret_cast<decltype(m_handle)>(m);
The second line is conditionally-supported in C++ so we presume the code is being built by a compiler that does support converting void * to function pointer.
The original code causes undefined behaviour due to strict aliasing violation, it tries to pretend that m_handle is actually a void * object when it is not .
Being undefined behaviour, the original code may or may not appear to work the same as the correct version . It is certainly not a good idea to rely on undefined behaviour.

How to parse *(void **) (&cosine) if cosine is a fptr

Found this code example
void *handle;
double (*cosine)(double);
handle = dlopen("libm.so", RTLD_LAZY);
*(void **) (&cosine) = dlsym(handle, "cos");
I use rightmost-to-left reading rule to parse the variable's type:
double (*cosine)(double);
Here I write left-to-right but move LTR: "cosine" -> "*" -> "is a pointer"
then "(" we go outside the innermost () scope -> "(double)" -> "to function taking one double" -> and returning leftmost "double"
but what the hell is THIS? I even don't know where to start the parse from) is "&cosine" a address or reference? what does the (void **) mean? why it has leftmost "*" outside??? is it dereference or type?
*(void **) (&cosine)
Yup, that's a mouthful.
cosine is a function pointer. So &cosine is a pointer to that pointer. And then when we slap a * in front of it, we're changing the original pointer, to make it point somewhere else.
It's sort of like this:
int i = 5;
int *ip = &i;
*ip = 6; /* changes i to 6 */
Or it's more like this:
char a[10], b[10];
char *p = a;
*(&p) = b; /* changes p to point to b */
But in your case it's even trickier, because cosine is a pointer to a function, not a pointer to data. Most of the time, function pointers point to functions you have defined in your program. But here, we're arranging to make cosine point to a dynamically-loaded function, loaded by the dlsym() function.
dlsym is super special because it can return pointers to data, as well as pointers to functions. So it's got an impossible-to-define return type. It's declared as returning void *, of course, because that's the "generic" pointer type in C. (Think malloc.) But in pure C, void * is a generic data pointer type; it's not guaranteed to be able to be used with function pointers.
The straightforward thing to do would be to just say
cosine = dlsym(handle, "cos");
But a modern compiler will complain, because dlsym returns void *, and cosine has type double (*)(double) (that is, pointer to function taking double and returning double), and that's not a portable conversion.
So we go around the barn, and set cosine's value indirectly, not by saying
cosine = something
but rather by saying
*(&cosine) = something
But that's still no good in the dlsym case, because the types still don't match. We've got void * on the right, so we need void * on the left. And the solution is to take the address &cosine, which is otherwise a pointer-to-pointer-to-function, and cast it to a pointer-to-pointer-to-void, or void **, so that when we slap a * in front of it we've got a void * again, which is a proper destination to assign dlsym's return value to. So we end up with the line you were asking about:
* (void **) (&cosine) = dlsym(handle, "cos");
Now, it's important to note that we're on thin ice here. We've used the & and the cast to get around the fact that assigning a pointer-to-void to a `pointer-to-function isn't strictly legal. In the process we've successfully silenced the compiler's warning that what we're doing isn't strictly legal. (Indeed, silencing the warning was precisely the original programmer's intent in employing this dodge.)
The potential problem is, what if data pointers and function pointers have different sizes or representations? This code goes to some length to treat a function pointer, cosine, as if it were a data pointer, jamming the bits of a data pointer into it. If, say, a data pointer were somehow bigger than a function pointer, this would have terrible effects. (And, before you ask "But how could a data pointer ever be bigger than a function pointer?", that's exactly how they were, for example, in the "compact" memory model, back in the days of MS-DOS programming.)
Normally, playing games like this to break the rules and shut off compiler warnings is a bad idea. In the case of dlsym, though, it's fine, I would say perfectly acceptable. dlsym can't exist on a system where function pointers are different from data pointers, so if you're using dlsym at all, you must be on a machine where all pointers are the same, and this code will work.
It's also worth asking, if we have to play games with casts when calling dlsym, why take the extra trip around the barm with the pointer-to-pointer? Why not just say
cosine = (double (*)(double))dlsym(handle, "cos");
And the answer is, I don't know. I'm pretty sure this simpler cast will work just as well (again, as long as we're on a system where dlsym can exist at all). Perhaps there are compilers that warn about this case, that can only be tricked into silence by using the tricker, double-pointer trick.
See also Casting when using dlsym() .
This is nasty stuff. cosine is a pointer to a function that takes an argument of type double and returns double. &cosine is the address of that pointer. The cast says to pretend that that address is a pointer-to-pointer-to-void. The * in front of the cast is the usual dereference operator, so the result is to tell the compiler to pretend that the type of cosine is void*, so that the code can assign the return value from the call to dlsym to cosine. Phew; that hurts.
And, just for fun, a void* and a pointer-to-function are not at all related, which is why the code has to go through all that casting. The C++ language definition does not guarantee that this will work. I.e., the result is undefined behavior.
For C, a pointer to void can be converted to any pointer to an object without a cast. However, the C standard does not guarantee that void * can be converted to a pointer to a function - at all, since functions are not objects.
The dlsym is a POSIX function; and POSIX requires that as an extension, a pointer to a function must be convertable to void * and back again. However C++ wouldn't allow such a conversion without a cast.
In any case the *(void **) (&cosine) = dlsym(handle, "cos"); cast means that the pointer to the pointer to a function (double) returning double is cast as pointer to pointer to void, then dereferenced to get a lvalue of type void *, to which the return value of dlsym is assigned to. This is rather ugly, and should be better written as cosine = (double (*)(double))dlsym(handle, "cos") wherever a cast is required. Both are undefined behaviour when it comes to C, but the latter is not as much dark magic.

Mental model for void* and void**?

Note: I'm a experienced C++ programmer, so I don't need any pointer basics. It's just that I never worked with void** and have kind of a hard time getting my mental model adjusted to void* vs. void**. I am hoping someone can explain this in a good way, so that I can remember the semantics more easily.
Consider the following code: (compiles with e.g. VC++ 2005)
int main() {
int obj = 42;
void* ptr_to_obj = &obj;
void* addr_of_ptr_to_obj = &ptr_to_obj;
void** ptr_to_ptr_to_obj = &ptr_to_obj;
void* another_addr = ptr_to_ptr_to_obj[0];
// another_addr+1; // not allowed : 'void*' unknown size
ptr_to_ptr_to_obj+1; // allowed
}
void* is a pointer to something, but you don't know what. Because you don't know what it is, you don't know how much room it takes up, so you can't increment the pointer.
void** is a pointer to void*, so it's a pointer to a pointer. We know how much room pointers take up, so we can increment the void** pointer to point to the next pointer.
A void* points to an object whose type is unknown to the compiler.
A void** points to a variable which stores such a void*.
A void * can point at anything (except functions). So it can even point at pointers, so it can even point at other void * objects.
A void ** is a pointer-to-void *, so it can only be used to point at void * objects.
void is misleading because it sounds like null. However, it's better to think of void as an unspecified type. So a void* is pointer for an unspecified type, and a void** is a pointer to a pointer for an unspecified type.
void is a type which has no objects.
void * is a conventional scalar type.
void ** is also a conventional scalar type that happens to point to void *.
void * can be used to point to anything, but I prefer to use it only for uninitialized storage. There is usually a better alternative to pointing a void * at an actual object.

What is void* and to what variables/objects it can point to

Specifically, can it point to int/float etc.?
What about objects like NSString and the like?
Any examples will be greatly appreciated.
void* is such a pointer, that any pointer can be implicitly converted to void*.
For example;
int* p = new int;
void* pv = p; //OK;
p = pv; //Error, the opposite conversion must be explicit in C++ (in C this is OK too)
Also note that pointers to const cannot be converted to void* without a const_cast
E.g.
const int * pc = new const int(4);
void * pv = pc; //Error
const void* pcv = pc; //OK
Hth.
In C any pointer can point to any address in memory, as the type information is in the pointer, not in the target. So an int* is just a pointer to some memory location, which is believed to be an integer. A void* pointer, is just a pointer to a memory location where the type is not defined (could be anything).
Thus any pointer can be cast to void*, but not the other way around, because casting (for example) a void pointer to an int pointer is adding information to it - by performing the cast, you are declaring that the target data is integer, so naturally you have to explicitly say this. The other way around, all you are doing is saying that the int pointer is some kind of pointer, which is fine.
It's probably the same in C++.
A void * can point at any data-like thing in memory, like an integer value, a struct, or whatever.
Do note, however, that you cannot freely convert between void * and function pointers. This is because on some architectures, code is not in the same address space as data, and thus it's possible that address 0x00000000 for code refers to a different set of bits than address 0x00000000 for data does.
It would be possible to implement the compiler so that void * is large enough to remember the difference, but in general I think this is not done, instead the language leaves it undefined.
On typical/mainstream computers, code and data reside in the same address space, and then the compilers typically generate sensible results if you do store a function pointer into a void *, since it can be quite useful.
Besides everything else that was already said by the other users, a void* it's commonly used in callback definitions. This allows your callback to receive user data of any type, including your own defined objects/structs, which should be casted to the appropriate type before using it:
void my_player_cb(int reason, void* data)
{
Player_t* player = (Player_t*)data;
if (reason == END_OF_FILE)
{
if (player->playing)
{
// execute stop(), release allocated resources and
// start() playing the next file on the list
}
}
}
void* can point to an address in memory but the syntax has no type-information. you can cast it to any pointer-type you want but it is your responsibility that that type matches the semantics of the data.

What does (void**) mean in C?

I would look this up, but honestly I wouldn't know where to start because I don't know what it is called. I've seen variables passed to functions like this:
myFunction((void**)&variable);
Which confuses the heck out of me cause all of those look familiar to me; I've just never seen them put together like that before.
What does it mean? I am a newb so the less jargon, the better, thanks!
void* is a "pointer to anything". void ** is another level of indirection - "pointer to pointer to anything". Basically, you pass that in when you want to allow the function to return a pointer of any type.
&variable takes the address of variable. variable should already be some kind of a pointer for that to work, but it's probably not void * - it might be, say int *, so taking its address would result in a int **. If the function takes void ** then you need to cast to that type.
(Of course, it needs to actually return an object of the right type, otherwise calling code will fail down the track when it tries to use it the wrong way.)
Take it apart piece by piece...
myFunction takes a pointer to a pointer of type void (which pretty much means it could point to anything). It might be declared something like this:
myFunction(void **something);
Anything you pass in has to have that type. So you take the address of a pointer, and cast it with (void**) to make it be a void pointer. (Basically stripping it of any idea about what it points to - which the compiler might whine about otherwise.)
This means that &variable is the address (& does this) of a pointer - so variable is a pointer. To what? Who knows!
Here is a more complete snippet, to give an idea of how this fits together:
#include <stdio.h>
int myInteger = 1;
int myOtherInt = 2;
int *myPointer = &myInteger;
myFunction(void **something){
*something = &myOtherInt;
}
main(){
printf("Address:%p Value:%d\n", myPointer, *myPointer);
myFunction((void**)&myPointer);
printf("Address:%p Value:%d\n", myPointer, *myPointer);
}
If you compile and run this, it should give this sort of output:
Address:0x601020 Value:1
Address:0x601024 Value:2
You can see that myFunction changed the value of myPointer - which it could only do because it was passed the address of the pointer.
It's a cast to a pointer to a void pointer.
You see this quite often with functions like CoCreateInstance() on Windows systems.
ISomeInterface* ifaceptr = 0;
HRESULT hr = ::CoCreateInstance(CLSID_SomeImplementation, NULL, CLSCTX_ALL,
IID_ISomeInterface, (void**)&ifaceptr);
if(SUCCEEDED(hr))
{
ifaceptr->DoSomething();
}
The cast converts the pointer to an ISomeInterface pointer into a pointer to a void pointer so that CoCreateInstance() can set ifaceptr to a valid value.
Since it is a pointer to a void pointer, the function can output pointers of any type, depending on the interface ID (such as IID_ISomeInterface).
It's a pointer to a pointer to a variable with an unspecified type. All pointers are the same size, so void* just means "a pointer to something but I have no idea what it is". A void** could also be a 2D array of unspecified type.
That casts &variable to a void** (that is, a pointer to a pointer to void).
For example, if you have something along the lines of
void myFunction(void** arg);
int* variable;
This passes the address of variable (that's what the unary-& does, it takes the address) to myFunction().
The variable is a pointer to something of undefined (void) type. The & operator returns the address of that variable, so you now have a pointer to a pointer of something. The pointer is therefore passed into the function by reference. The function might have a side effect which changes the memory referenced by that pointer. In other words, calling this function might change the something that the original pointer is referencing.