zoukankan      html  css  js  c++  java
  • 静态链接导致的一个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++项目开发过程中命名空间的重要性,注意开发规范。

  • 相关阅读:
    leetcode562- Longest Line of Consecutive One in Matrix- medium
    leetcode118- Pascal's Triangle I & II- easy
    leetcode524- Longest Word in Dictionary through Deleting- medium
    leetcode128- Longest Consecutive Sequence- hard
    leetcode22- Generate Parentheses- medium
    leetcode17- Letter Combinations of a Phone Number- medium
    leetcode678- Valid Parenthesis String- medium
    php截取字符串的实例代码(支持utf-8)
    php中封装的curl函数(抓取数据)
    linux计划任务运行php文件的方法分享
  • 原文地址:https://www.cnblogs.com/nuoforever/p/15583800.html
Copyright © 2011-2022 走看看