记一个linux系统c++动态库全局符号重名问题

首先,简单说明下问题情境,一共三个代码文件,一个主执行程序,两个动态库程序,结构与之前写的弱符号,weak symbol一致:

#include <string>

std::string g_name;

void init_name_lib1()
{
    g_name = "lib1";
}

const char* get_name_lib1()
{
    return g_name.c_str();
}
#include <string>

std::string g_name;

void init_name_lib2()
{
    g_name = "lib2";
}

const char* get_name_lib2()
{
    return g_name.c_str();
}
#include <iostream>

void init_name_lib1();
void init_name_lib2();
const char* get_name_lib1();
const char* get_name_lib2();

int main()
{
    init_name_lib1();
    init_name_lib2();

    std::cout << "name from lib1: " << get_name_lib1() << std::endl;
    std::cout << "name from lib2: " << get_name_lib2() << std::endl;

    return EXIT_SUCCESS;
}

编译运行命令也与之前那篇基本一样:

 1986  g++ -c -fpic cpp_lib2.cpp
 1987  g++ -c -fpic cpp_lib1.cpp
 1988  g++ -shared -o lib1.so cpp_lib1.o
 1989  g++ -shared -o lib2.so cpp_lib2.o
 1990  g++  -L./ main.cpp -l1 -l2
 1991  LD_LIBRARY_PATH=./ ./a.out

运行后会发现输出的两个lib库返回字符串一样,均为lib2(某些初始化方式,比如用fmt库时还有可能在主程序退出是出现double free异常)!其原因是因为linux下gcc默认动态库全部符号导出,而两个不同库中的全局变量g_name重名,因此在main主执行程序加载时,会出现后加载的覆盖掉先加载的情况(同名函数符号也一样,例如两个不同动态库同时用了同一个公共代码,但版本不同,这样就有可能导致其中一个库功能出现异常,因为调成了错误版本的同名函数!)。

知道了原因解决的办法就好说了,要不改下名字,或者套个不同的namespace,又或者加上static,隐藏进.o内部就可以了。

博主友情提示:

如您在评论中需要提及如QQ号、电子邮件地址或其他隐私敏感信息,欢迎使用>>博主专用加密工具v3<<处理后发布,原文只有博主可以看到。