You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用dlsym获取函数赋值给std::function导致段错误

问题分析与解决方案

首先,咱们直接定位触发段错误的核心原因——你在创建std::function之前就调用了dlclose(handle),这会直接卸载共享库,此时function指针已经变成了悬空指针,std::function尝试引用这个无效指针时,自然会触发段错误。

另外,你的代码还有一个潜在的未定义行为:extern "C"修饰的函数使用了C++专属类型std::array<double, 1>作为参数。extern "C"是让函数按照C语言的调用约定和命名规则处理,但C语言并不认识std::array,这会导致函数的ABI(应用二进制接口)不兼容,后续调用可能出现各种奇怪问题。

修复步骤

1. 修正共享库中的函数定义

把std::array替换为C兼容的类型,比如直接用double(因为你的数组长度固定为1),如果需要支持更长数组,可以用double*加长度参数。修改后的function.cpp如下:

#include <array>
#ifdef __cplusplus
extern "C" {
#endif
// 改用C兼容的double类型作为参数
double function(double arg) {
    return arg * 2;
}
#ifdef __cplusplus
}
#endif

2. 调整主程序的执行流程

将dlclose(handle)移到std::function使用完成之后,确保共享库在函数指针被引用期间保持加载状态。修改后的main.cpp如下:

#include <functional>
#include <iostream>
#include <fstream>
#include <array>
#include <cstdlib> // 补充exit需要的头文件
#ifdef __linux__
#include <dlfcn.h>
#endif

int main() {
    void *handle;
    // 对应修改函数指针的类型
    double (*function)(double);
    char *error;

    handle = dlopen("/home/oleg/MyProjects/shared_library_test/libFunction.so", RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE);
    }

    dlerror();
    *(void **) (&function) = dlsym(handle, "function");
    if ((error = dlerror()) != NULL) {
        fprintf(stderr, "%s\n", error);
        exit(EXIT_FAILURE);
    }

    std::cout << "Native function output: " << function(3.0) << std::endl;

    // 先创建std::function并调用,再关闭共享库
    std::function<double(double)> std_function(function);
    std::cout << "std::function output: " << std_function(3.0) << std::endl;

    // 现在可以安全关闭库了
    dlclose(handle);

    exit(EXIT_SUCCESS);
}

3. 重新编译运行

保持原来的编译命令不变:
编译共享库:

g++ -Wall -Wextra -g -std=c++17 -shared -o libFunction.so -fPIC function.cpp

编译主程序:

g++ -Wall -Wextra -g -std=c++17 main.cpp -ldl

运行后应该会正常输出:

Native function output: 6
std::function output: 6

额外说明

如果你的业务场景需要std::function长期持有函数指针(比如在库关闭后仍要使用),可以在dlopen时添加RTLD_NODELETE标志,这样即使调用dlclose,库也不会被真正卸载,直到进程退出:

handle = dlopen("/home/oleg/MyProjects/shared_library_test/libFunction.so", RTLD_LAZY | RTLD_NODELETE);

不过这种方式要注意内存占用,建议仅在必要时使用。

内容的提问来源于stack exchange,提问作者Oleg Yablokov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:34:05