Using dlsym() in C++

srccsm.png

I've spent quite some time on this problem, and it keeps popping up every time I'm coding with dynamically loadable modules in C++. The POSIX-interface to use dynamically loadable modules (libdl) defines a number of C functions to work with these modules: dlopen() and friends.

These functions are all nice in that they work nicely when used in C++ with one major exception: dlsym(). This function is used to find a symbol inside a dynamically loaded module. The symbol which is looked up can be any symbol: a pointer, a variable, a function, etc. The way to return a pointer to some unknown type is by using a void pointer.

Returning a void pointer might seem logical for this, but there is one big problem: it can return either a variable or a function. There is no issue when type-casting a void pointer to a pointer to some other type. Type-casting a void pointer (which is in essence a variable) to a function pointer is not that straightforward: function pointers can be fundamentally different.

Imagine a system where there are separate memories for code and for data. Because the system works with loads of code but small amounts of data, the code memory will need 32 bits pointers while the data memory only needs 16 bits pointers. The void pointer returned by dlsym() will be a pointer to data: it will be 16 bits. When this is actually a function, it has to be type-casted to a function pointer, but that requires a 32 bits pointer. There is no way that all 32 bits can be retrieved from the 16 bits of information we got from dlsym().

It is because of the above example that the behavior of type-casting between data-pointers and function-pointers is undefined in C. Most compilers nevertheless provide working behavior for this though, and it is exactly this behavior that the dlsym() function requires. In the revised C99 standard, it is mentioned as a common extension to the language.

When it comes to C++, the C++ Standard Core Language Defect #195 is exactly about this issue: converting between function and object (data, variable) pointers. They've worked out a (not yet officially accepted) proposal to fix this issue: on implementations which can provide this sort of casts it works and on implementations which cannot provide a cast between function and object pointers the cast would either be undefined or throw an error or warning during compile time.

With the default warning levels, most compilers do not complain about casting an object pointer to a function pointer. I, however, tend to code with certain strict checking flags on to catch some small mistakes or ambiguities that might get in my code. When compiling the module code of IRC Cantus , about which i will blog soon, this means that I will get a warning every time i use dlsym():

g++ -W -Wall -g -pedantic -g -O2 -export-dynamic -I../include -c cantus.cpp
g++ -W -Wall -g -pedantic -g -O2 -export-dynamic -I../include -c argument.cpp
g++ -W -Wall -g -pedantic -g -O2 -export-dynamic -I../include -c config.cpp
g++ -W -Wall -g -pedantic -g -O2 -export-dynamic -I../include -c log.cpp
g++ -W -Wall -g -pedantic -g -O2 -export-dynamic -I../include -c log_facilities.cpp
g++ -W -Wall -g -pedantic -g -O2 -export-dynamic -I../include -c main.cpp
g++ -W -Wall -g -pedantic -g -O2 -export-dynamic -I../include -c module.cpp
g++ -W -Wall -g -pedantic -g -O2 -export-dynamic -I../include -c modulesupport.cpp
modulesupport.cpp: In member function ‘void module::Instance::open()’:
modulesupport.cpp:85: warning: dereferencing type-punned pointer will break
                               strict-aliasing rules
modulesupport.cpp: In member function ‘void module::Instance::close()’:
modulesupport.cpp:109: warning: dereferencing type-punned pointer will break
                                strict-aliasing rules
g++ -W -Wall -g -pedantic -g -O2 -export-dynamic -I../include cantus.o argument.o
    config.o log.o log_facilities.o main.o module.o modulesupport.o -o cantus -ldl

This warnings obviously ruin the clean, warning-less output I would get without these issues ;) For now there is no way to get this to compile without warnings without dropping some of the warning reporting flags, which is obviously not what I want. There seems to be no solution to this problem at all; people I ask about it do not come any further than joking about the choice of wording for type-punned...

Comments (1)

Posted by Jeremy on 19 Sep 2011 at 19:45

FYI you *can* silence the warning by defining a union type containing your function pointer and a void * object pointer. Assign the result of dlsym to the object pointer, and use the function pointer to execute calls.

Very hackish, I know.

Post your own comment
Name:
Email: (optional)
Website: (optional)
Comment: