首页 > 其他分享 >库的符号冲突问题

库的符号冲突问题

时间:2022-12-11 17:22:41浏览次数:52  
标签:include lib 符号 int Server 问题 冲突 server open

库的符号冲突问题

程序示例

文件结构

tree-code
工程最终生成动态库 libNet.so 和 test 可执行程序,test 链接动态库libNet.so

示例代码

// lib/net.h
#ifndef _NET_H_
#define _NET_H_

class Net
{
public:
    Net(){};
    virtual ~Net(){};
    virtual int open()=0;
};

class Server : public Net
{
public:
    Server();
    virtual ~Server();
    virtual int open();
};

#endif
// lib/net.cpp
#include "net.h"
#include <cstdio>

Server::Server():Net(){
}

Server::~Server(){
}

int Server::open(){
    printf("lib: open socket\n");
}
// lib/include/lib_api.h
#ifndef _LIB_API_H_
#define _LIB_API_H_

#ifdef __cplusplus
extern "C" {
#endif

int lib_open();

#ifdef __cplusplus
}
#endif

#endif
// lib/lib_api.cpp
#include <unistd.h>
#include "lib_api.h"
#include "net.h"

int lib_open(){
#if 1
    // 此方式导致程序挂死
    Net* server = new Server();
    if (server != NULL){
        return server->open();
    }
#else
    // 此方式不会导致程序挂死
    Server server;
    server.open();
#endif
    return  -1;
}
// src/server.h
#ifndef _SERVER_H_
#define _SERVER_H_

class Server
{
public:
    Server();
    virtual ~Server();
    int user_open();
};

#endif
// src/server.cpp
#include <cstdio>
#include "lib_api.h"
#include "server.h"

Server::Server(){
}

Server::~Server(){
}

int Server::user_open(){
    lib_open();
    printf("User: open socket\n");
    return 0;
}
// src/main.cpp
#include <iostream>
#include "lib_api.h"
#include "server.h"

int main(int argc, char** argv)
{
    Server* server = new Server;
    if(server != NULL){
        server->user_open();
        printf("User Server call open\n");
    }
    return 0;
}

libNet.so对外提供lib_api.h头文件,其中并没有Server的类声明,使用库的一方并不知道库内声明了Server的类名,而外部程序恰好声明了同名的Server类。

运行结果

coredump

原因分析

通过堆栈查看server的虚函数表并没有open函数,所以运行到server->open()时出现了异常。

为什么server的虚函数表里没有open函数?考虑到外部程序声明了同名的Server类型,怀疑在lib_open()内的调用的new Server(),创建的实例其实是外部声明的类型,而不是动态库内声明的Server类型。

通过在各自的Server构造函数内添加打印,查看运行结果:

// lib/net.cpp
Server::Server():Net(){
    printf("Lib Server construct\n");
}

// src/server.cpp
Server::Server(){
    printf("User Server construct\n");
}

add_print_debug

现在可以得出结论了:lib/net.cpp内new出的Server对象,实际是外部程序src/server.h声明的Server对象,而不是lib/net.h中声明的Server。存在符号冲突问题。

所谓符号冲突,就是库与库之间有相同的符号,使用者不知道用哪个;例如:A 库有个符号a,B 库也有个符号a,最终app调用a时,可能用的是A 库的a,也可能是B 库的a;这样的话,就会产生歧义,假如app想调用A 库的a,但可能实际调用的却是B 库的a,这样就会造成app行为异常,或是崩溃。app本质上也是一个动态库。

解决方式

库内对Server的声明和定义,用命名空间包裹

// lib/net.h
namespace LIB{
    ...
class Server : public Net{
    ...
};
 
}

重新编译执行,并未存在异常。通过gdb单步调试如下:
namespace-gdb-debug
此时对比未加命名空间的代码,查看server的虚函数表,存在open函数,因此程序运行未出现异常。

参考链接

  1. https://www.jianshu.com/p/fb5a5550f858

标签:include,lib,符号,int,Server,问题,冲突,server,open
From: https://www.cnblogs.com/hjx168/p/16973922.html

相关文章