静态链接导致的一个bug分析

环境介绍和问题重现

在Linux环境下,有两个静态链接库,分别为staticA和staticB,一个应用程序为app。

其中,静态库A中包含两个类:TestA和Object,如下所示:

 1 /********* object.h *******/
 2 class Object
 3 {
 4 public:
 5     Object();
 6     ~Object();
 7     void setValue(int val);
 8     int getValue() const;
 9 private:
10     int m_value;
11 };
12 
13 /********* object.cpp *******/
14 #include "object.h"
15 
16 Object::Object()
17 {
18 }
19 
20 Object::~Object()
21 {
22 }
23 
24 void Object::setValue(int val)
25 {
26     m_value = val;
27 }
28 
29 int Object::getValue() const
30 {
31     return m_value;
32 }
33 
34 /********* testa.h *******/
35 class TestA
36 {
37 public:
38     TestA();
39 };
40 
41 /********* testa.cpp *******/
42 #include "testa.h"
43 #include "object.h"
44 #include <iostream>
45 
46 TestA::TestA()
47 {
48     Object o;
49     o.setValue(9999);
50     std::cout << o.getValue() << std::endl;
51 }

静态库B中包含两个类:TestB和Object,对,你没有看错,两个静态库中都有Object类,但是实现不同,这里先留个伏笔。

 1 /********* object.h *******/
 2 #include <string>
 3 class Object
 4 {
 5 public:
 6     Object();
 7     ~Object();
 8     void setName(const std::string& n);
 9     std::string getName() const;
10 private:
11     std::string m_name;
12 };
13 
14 /********* object.cpp *******/
15 #include "object.h"
16 
17 Object::Object()
18 {
19 }
20  
21 Object::~Object()
22 {
23 }
24 
25 void Object::setName(const std::string& n)
26 {
27     m_name = n;
28 }
29 
30 std::string Object::getName() const
31 {
32     return m_name;
33 }
34 
35 /********* testb.h *******/
36 class TestB
37 {
38 public:
39     TestB();
40 };
41 
42 /********* testb.cpp *******/
43 #include "testb.h"
44 #include "object.h"
45 #include <iostream>
46 
47 TestB::TestB()
48 {
49     Object o;
50     o.setName("testb");
51     std::cout << o.getName() << std::endl;
52 }

在app项目中只有一个main.cpp,这个app中会使用TestA和TestB,但是不会使用任何Object。

1 #include "testa.h"
2 #include "testb.h"
3 
4 int main(int argc, char* argv[])
5 {
6     TestA ta;
7     TestB tb;
8     return 0;
9 }

编译该项目,打开debug选项,执行后会崩溃,但不是每次都崩溃,出现崩溃的位置在TestB中的o.setName("testb"),提示为stl的字符串赋值错误。

bug分析

该项目中两个静态库之间无引用关系,虽然都有Object类,但实现不同,且由于未相互引用,编译过程和链接过程始终未报重定义错误。实际项目中并没有前述那么清楚。实际的情况是程序总崩溃,而该项目远比上述复杂,实际项目中模块很多,并且开发者也不止一位,遇到程序崩溃问题的开发者只知道两个静态库中的一个staticB,对另一个staticA是完全不知情的,开发者可以看到的现象是调用setName一直崩溃。

下面来分析问题,虽然代码定位到了B中的setName,调试器提示string无法赋值,在两个测试类A和B中加入输出信息,都可以正常输出,说明库编译没有问题。排除了库的编译问题之后,分析可能是执行中函数定位错误导致的。因此可以试验一下两个库中的Object对象是否都有实际对象,分别在两个Object的构造函数中增加输出信息,经试验后发现,A中对象始终无法构造出来。

找到这些后给我们解决问题提供了一个很好的思路,那么在应用中直接构造A中的Object对象,看看是否能够创建该对象。

经试验发现,在app中创建A的Object对象时会报重定义错误,到此终于查明了问题,验证了之前的判断,就是由于符号重定义导致的函数跳转错误,然而比较隐蔽。

解决方案

解决方案比较简单,可以修改为不同的类名,也可以通过加命名空间解决。

问题总结

这个问题解决还比较顺利,同时也提醒了开发者在开发过程中,尤其是C++项目开发过程中命名空间的重要性,注意开发规范。

原文地址:https://www.cnblogs.com/nuoforever/p/15583800.html