拥有此文件:plusone.c:
int op(int i){ return i+1; }
main.c:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **argv){
if (argc<3){
printf("usage %s <library> <number>\n",argv[0]);
exit(1);
}
char *lname = argv[1];
int num = atoi(argv[2]);
void *handle = dlopen(lname, RTLD_LAZY);
if(!handle)
perror("dlopen");
int (*opp)(int);
opp=dlsym(handle, "op");
if(!opp)
perror("dlsym");
printf("number before:%i\nnumber after:%i\n",num,opp(num));
dlclose(handle);
}
编译为:
$cc -fPIC -shared -o plusone.so -ldl plusone.c
$cc -o main.exe -ldl -Wpedantic main.c
warning: ISO C forbids assignment between function pointer and ‘void *’ [-Wpedantic]
$ls
main.c main.exe plusone.so main.exe
$main.exe
usage main.exe <library> <number>
$main plusone.so 1
dlopen: Success
dlsym: Success
Segmentation fault
为什么会出现段错误?从bash输出可以看出,dlopen和dlsym都给出了成功(但它们甚至不应该输出,否则意味着条件为真,并且从这些函数返回的值是NULL?-从条件开始)。但是,即使perror
返回的“成功”,我也无法重现该段错误,因为不知道错误在哪里。
dlopen()
和dlysym()
的调用无法正确处理错误,尽管代码测试了结果,但对这两个函数的失败没有采取正确的措施。此代码
void *handle = dlopen(lname, RTLD_LAZY);
if(!handle)
perror("dlopen");
在dlopen()
上正确分支,返回指示错误的NULL
,但是随后代码执行了错误的操作。
dlopen()
未设置errno
,因此使用perror ()
记录错误没有意义,因为perror
依赖于errno
指示错误,但没有。因此,在dlopen()
失败时,您会看到perror()
打印
dlopen: Success
这完全误导并收缩了perror()
的事实,实际上只有在dlopen()
返回NULL
时才会发生,这表明失败了。如果dloepn()
成功,则根本不会调用perror()
,也不会打印任何内容。要记录有关
dl*()
系列功能失败的错误信息,请调用dlerror()
。有关如何正确和完全实现错误处理的示例,请参见下文:
void *handle = dlopen(lname, RTLD_LAZY); if (!handle) { fprintf(stderr, "dlopen: %s\n", dlerror("dlopen")); exit(EXIT_FAILURE); } #ifdef DEBUG else { fputs("dlopen: Success\n", stderr); } #endif