为什么从共享库中加载对象会引起段错误?

问题描述 投票:0回答:1

拥有此文件: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返回的“成功”,我也无法重现该段错误,因为不知道错误在哪里。

c segmentation-fault shared-libraries position-independent-code
1个回答
0
投票
尽管对代码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

© www.soinside.com 2019 - 2024. All rights reserved.