Let's say I have a struct defined in MyType.h
struct MyType {
int x;
int y;
};
And I build a lib myLib.so
which exposes a function that takes the above type as a parameter.
#include "MyType.h"
extern "C" void myLibFunc(MyType myType) {
...
}
Then I update my MyType.h
changing the definition of MyType
to include an extra member variable.
struct MyType {
int x;
int y;
int z;
};
Now in my executable, I open myLib.so
and load myLibFunc
symbol from it which was built with old definition of MyType
, but cast the void *
returned by dlsym using a function signature that uses the new definition of MyType
.
#include <dlfcn.h>
#include "MyType.h" //updated version
typedef void(*myLibFuncType)(MyType myType);
int main() {
auto myLibHandle = dlopen("myLib.so", RTLD_LOCAL | RTLD_NOW);
auto myLibFunc = (myLibFuncType) dlsym(myLibHandle, "myLibFunc");
...
return 0;
}
Is this supposed to work?
I have read this answer but could not figure out if the case presented here satisfies "compatible function pointer" requirement.
The two instance of the struct types are not compatible because the members are different. Section 6.2.7p1 of the C standard regarding compatible types states:
... Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: If one is declared with a tag, the other shall be declared with the same tag. If both are completed anywhere within their respective translation units, then the following additional requirements apply: there shall be a one-to-one correspondence between their members such that each pair of corresponding members are declared with compatible types; if one member of the pair is declared with an alignment specifier, the other is declared with an equivalent alignment specifier; and if one member of the pair is declared with a name, the other is declared with the same name. For two structures, corresponding members shall be declared in the same order. For two structures or unions, corresponding bit-fields shall have the same widths. For two enumerations, corresponding members shall have the same values.
And since the struct types are not compatible, the function pointers are not compatible because their parameters are not compatible, as noted in the post you linked.
This means that attempting to call the function through that function pointer will trigger undefined behavior.
As a side note, casting an void *
, which is an object pointer, to a function pointer is not strictly allowed by the C standard. The man page for dlsym
contains the following example regarding the proper way to handle this:
/* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
would seem more natural, but the C99 standard leaves
casting from "void *" to a function pointer undefined.
The assignment used below is the POSIX.1-2003 (Technical
Corrigendum 1) workaround; see the Rationale for the
POSIX specification of dlsym(). */
*(void **) (&cosine) = dlsym(handle, "cos");