最近开发遇到一个特别简单却又是十分难查的一个bug,反正我是查了一天。
关于动态库的默认链接装载和使用dlopen装载,区别。
我主框架调用同事的一个注册函数,然后传递一个回调(函数指针)给了同事的动态库,本来这是一个很寻常的操作,但是实际操作过程中出现了问题,他在本地声明的同类型函数变量在指针赋值时段错误,你没听错段错误。把一个函数的指针赋值给另一个同类型的函数变量怎么会错?就是这个类型。
#include<stdio.h>
#include<stdlib.h>
typedef int (*fun)(int , int);
int add(int a,int b)
{
return a+b;
}
fun p=NULL;
int main(void)
{
p=add;
printf("%d\n",p(3,4));
return 0;
}
事实是一直错误,而且是段错误。我把同样的库用在python框架中,成功了。
介于这个bug,我的初步判断是:
1.函数指针类型不对
2.指针传递丢失
针对一:我在传地址前打印函数的地址,传递过去的参数的地址也打印出来。结果2个函数地址相同
针对二:我在传递函数的赋值函数之前,直接运行,结果是原行ok,但是赋值还是失败。
介于上述的调试结果,有一个感觉,就是函数的声明被const了,可是库中并没有用const修饰,而且库的编译和框架的编译都是无报错的通过了。但是运行时出错。
我就在想是不是库装载方式不同导致的,使用系统自动装载(c框架这么做的)和使用dlopen在运行时代码装载(python这样子做的)区别,那么区别到底在哪,找了很多网上资料,并没有什么实际的结果,这个问题卡住了。
周末在家细细思考,忽然出现了一个神奇的想法,是不是同名函数的锅,我的框架和对方的库中有一个同名的函数,导致运行时指向错误,而且假设他赋值给我已经实现的函数那不就等于const吗?带着这个问题我全局查找了一下,果然,在另一个库中包含了一个同名函数,我要求同事在命名是加上库前缀。
问题解决了但是还要思考下,为什么dlopen没有问题,系统链接就不对呢?
看了下函数的声明其实很简单就可以发现,函数的装载dlsym是需要指明库的,需要先dlopen返回句柄,而默认装载,是 把所以的运行代码都加载到内存,结果可想而知。
总结:在链接多个动态库的时候,一定小心同名函数。