通过动态库dlsym一个类,如果这个类有虚函数,外面引用的头文件和类中定义的头文件虚函数声明顺序不一样,会不会有问题? 例如: DynamicLib.h class A { virtual int funcA() = 0; virtual int funcB() = 0; virtual int funcC() = 0; };
class B : public A { int funcA() {printf(“B::funcA”);} int funcB() {printf(“B::funcB”);} int funcC() {printf(“B::funcC”);} }
extern “C” A* getInstanceOfA() { return new B(); }
Android.mk将其编译成一个动态库libDynamic.so
如果我们在使用libDyanmic.so都时候,提供了一个错误的头文件, DynamicLib_err.h
class A { virtual int funcC() = 0; virtual int funcA() = 0; virtual int funcB() = 0; };
int main() { void* handle = dlopen(“libDynamic.so”); typedef A* (*FUNC)(); FUNC getInstance = dlsym(handle, “getInstanceOfA”); A* aa = getInstance(); aa->funcA(); aa->funcB(); aa->funcC(); }
打印如下: B::funcB() B::funcC() B::funcA()
虚函数在虚函数表中是按声明顺序排列的,是通过虚函数表来调用的。
那如果不是纯虚函数,是否能正确打印呢?通过验证发现,如果某个函数不是纯虚函数,而被调用到,本身无法编译通过,所以如果要通过dlsym出一个类,这个类的所有函数都应该是纯虚函数。
20180824:今天工作中又出现一次,和前面分析是吻合的, 今天出现的案例是算法库中的头文件和定义正确的头文件相比没有对齐,少了一个函数,由于虚函数在虚函数表中是按声明顺序排列的,所以调用func2的时候会调用到前面的那个虚函数func1, 这次func1参数列表中需要传入数组指针指针,结果直接报空指针解析crash了
声明:virtual void func1(int* a) = 0 ; virtual void func2() = 0;
定义: void func1(int* a) { a[0] = 1; ///null poiter a[1] = 2; }
void func2() { }
本来如果是正确调用func2的话,func2是没有函数参数入栈的,但func1被调用起来之后,它会按照规则去找压栈的入参,而且是指针,再在错误地址解析,地址正好是0,然后解析就出现crash了