Problems might occur when using MyClass objects .
It depends on how you use them.
Take the following scenario (bogus code here).
MyClass* ptr = SharedLibHandle->CreateMyClass();
ptr->doStuffNonVirtual(); //1 this might work fine
ptr->doStuffVirtual(); //2 this will work fine
ptr->myThing= 5; // 3 this might work fine
MyClass* localAllocPtr = new MyClass();
SharedLibHandle()->DoSomethingWithTheClass(localAllocPtr);
...
void DoSomethingWithTheClass(MyClass* ptr)
{
ptr->myFourthThing = " mama " ; // 4 this might seem to work fine
}
In the example above there are several possible use cases based on the place of instantiation and usage :
ptr handles the scenario where the class is instantiated in the so with the size defined in the so , then used by your executable with the size defined there.
localAllocPtr handles the reverse scenario (class instantiated in your executable then passed to .so).
Taking each one :
- Call to non virtual function.
Non virtual functions are resolved at compile time, this meaning that if you have a different code implementation inside your executable, the stack pointer will jump to your function implementation instead of the one in the .so . It will work as expected if your code is the same in both of the executable and so , and the structure alignment remains the same (which is most likely).
- Call to virtual function
This will work fine, since it will jump into a vftable then jump to the correct memory address in the .so . The .so initialized the class, so offsets, jumps and everything will be legal.
- Access of commonly defined member
This will work fine only if myThing has the same alignment inside the structure, meaning he's at *(ptr+0) offset inside the structure. If by any chance inside your class myThing is first and mySecondThing is second, while in the .so mySecondThing is first while myThing is second, then you will change the wrong parameter. Which ironically will have no effect if you continue to use the class inside your executable and not pass it back to the .so (Let's say ignorance is a bliss).
- Access to a non-allocated member
When your executable allocs localAllocPtr it will allocate it with the sizeof(MyClass) as defined in your executable. In your executable the class doesn't define a string and a u32. When passing this allocated structure to the .so , the .so will consider the class as having the members and size according to it's definition. When accessing myFourthThing it will access a zone of memory that would normally be *(ptr + 8). If that zone of memory is in use (someone allocated there) you will write outside your ptr bounds into someone else's memory, and it might seem to work fine but you will end up with one of the hardest bugs to find. If after *(ptr +8) nothing is allocated, you'll get lucky and get a segmentation fault.
In order to avoid the sort of problem you are describing a common approach is the pImpl idiom , which allows you to make the class specific implementation private, so you can add virtual functions and member variables while keeping the exposed definition of the class the same.