1

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

Biao Cao
  • 141
  • 1
  • 10
  • `dlopen(./haldle_lib.so, RTLD_NOW)` is a syntax error, the `.` operator must have a left operand. Please check this is the actual code – M.M Jun 13 '20 at 23:31
  • @M.M: Looks like missing quotes. But I agree, not real code. – MSalters Jun 15 '20 at 10:40

2 Answers2

1

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.

TonySalimi
  • 8,257
  • 4
  • 33
  • 62
  • thanks, it's really helpful to understand the trick. BTW, is the type of m_handle changed after the trick(i.e *(void **)(&m_handle)). Also is the size of function pointer the same as object pointer? – Biao Cao Jun 14 '20 at 04:09
  • @BiaoCao No, the type of m_handle is not changed after the assignment. It will always remain a function pointer. And about the size, YES. Size of object pointers and function pointers are the same. – TonySalimi Jun 14 '20 at 08:00
  • Or, to be more precise: if `dlsym` exists in a platform (natively or implemented by a third party), then a data-pointer has to be able to store a code-pointer, – Lorinczy Zsigmond Jun 14 '20 at 08:08
  • @LorinczyZsigmond Exactly! – TonySalimi Jun 14 '20 at 10:44
1

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.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • >>The original code causes undefined behaviour due to strict aliasing violation ==>thanks for your reply, could you give more details or some reference about "strict aliasing violation" – Biao Cao Jun 14 '20 at 04:03
  • @BiaoCao You can take a look at [this Q/A](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) . – TonySalimi Jun 14 '20 at 10:44