奇怪的seg故障问题

时间:2010-06-04 21:14:58

标签: c++

问候,

我遇到了一个奇怪的seg故障问题。我的应用程序在运行时转储核心文件。在深入研究之后,我发现它在这个区块中死了:

#include <lib1/c.h>  
...  
x::c obj;  
obj.func1();  

我在库lib1中定义了类c:

namespace x  
{  
    struct c  
    {  
        c();  
        ~c();  
        void fun1();  
        vector<char *> _data;  
    };  
}  

x::c::c()  
{  
}  

x::c::~c()  
{  
    for ( int i = 0; i < _data.size(); ++i )  
        delete _data[i];  
}  

直到我在lib1.so文件上运行nm时,我才弄明白:我的函数定义多于我定义的函数:

x::c::c()  
x::c::c()  
x::c::~c()  
x::c::~c()  
x::c::func1()  
x::c::func2()  

在代码库中搜索后,我发现其他人在同一名称空间中定义了一个具有相同名称的类,但在另一个库lib2中定义如下:

namespace x  
{  
    struct c  
    {  
       c();  
       ~c();  
       void func2();  
       vector<string> strs_;  
    };  
}  

x::c::c()
{
}

x::c::~c()
{
}

我的应用程序链接到lib2,它依赖于lib1。这个有趣的行为带来了几个问题:

  1. 为什么它会起作用?我期望在链接lib2(取决于lib1)时出现“多个定义”错误,但从未有过这样的错误。该应用程序似乎正在执行func1中定义的内容,除非它在运行时转储核心。

  2. 附加调试器后,我发现我的应用程序在lib2中调用了c类的ctor,然后调用func1(在lib1中定义)。当超出范围时,它会在lib2中调用c类的dtor,其中发生seg错误。任何人都可以教我怎么会发生这种情况?

  3. 如何防止此类问题再次发生?我可以使用任何C ++语法吗?

  4. 忘记提及我在RHEL4上使用g ++ 4.1,非常感谢!

5 个答案:

答案 0 :(得分:1)

1

不必由编译器诊断违反“一个定义规则”。实际上,当您将多个目标文件链接在一起时,它们通常只会在链接时被识别。

在链接时,有关原始类定义的信息可能不再存在(在编译器步骤之后不需要它们),因此具有多个类定义通常不容易标记给用户。

2

一旦你有两个不同的定义,几乎任何事情都可能发生,你就处于未定义的行为领域。无论发生什么,这都是可能的结果。

3

最明智的做法是与团队中的其他成员进行沟通。同意谁将使用哪些命名空间,您将不会遇到这些问题。否则,您将指向整个项目的文档工具或静态分析工具。许多此类工具将能够诊断多个不一致的类定义。

答案 1 :(得分:0)

只是一个猜测,但我没有看到任何using namespace x;所以也许它使用了一个命名空间而不是另一个?

答案 2 :(得分:0)

随着模板的出现,有必要允许具有相同名称的代码体的多个定义;编译器无法知道是否已在另一个编译单元(即源文件)中生成相同的模板代码。当链接器找到这些重复项时,它假定它们是相同的。您需要确保它们的负担 - 这称为One Definition Rule

答案 3 :(得分:0)

在链接器级别,这是库插入。遗憾的是,有效符号绑定取决于链接器命令行上的目标文件的顺序(这是叹息,历史)。

根据您的描述,lib1首先出现在链接器参数列表中,lib2位于第二个,而插入来自lib1的符号。这解释了lib2对构造函数和析构函数的调用,但是从func1调用了lib1(因为在func1中没有lib2 - 派生符号,所以有没有“隐藏”,呼叫绑定到lib1。)

此特定问题的解决方案是在链接器调用命令上反转库的顺序。

答案 4 :(得分:0)

关于一个定义规则有很多答案。但是,对我而言,这看起来更像是一个缺少复制的构造函数。

详细说明:

如果在对象上调用了复制构造函数,那么就会出现内存泄漏。这是因为删除将在同一组指针上调用两次。

namespace x  
{  
    struct c  
    {
        c() {
        }

        ~c() {
            for ( int i = 0; i < _data.size(); ++i )  
                delete _data[i];
        }

        c(const c & rhs) {
            for (int i=0; i< rhs.size(); ++i) {
                int len = strlen(rhs[i]);
                char *mem = malloc(len + 1); 
                strncpy(mem, rhs[i], len + 1);
                _data.push_back(mem);
        }

        void fun1();  
        vector<char *> _data;  
    };  
}