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++项目开发过程中命名空间的重要性,注意开发规范。

  • 相关阅读:
    MS CRM 2011 RC中的新特性(4)——活动方面之批量编辑、自定义活动
    最近的一些有关MS CRM 2011的更新
    MS CRM 2011 RC中的新特性(6)——连接
    MS CRM 2011 RC中的新特性(7)—仪表板
    参加MS CRM2011深度培训课程——第一天
    MS CRM 2011插件调试工具
    MS CRM2011实体介绍(四)——目标管理方面的实体
    MS CRM 2011 RC中的新特性(3)——客户服务管理方面
    MS CRM 2011 RC中的新特性(8)—数据管理
    ExtAspNet 登陆
  • 原文地址:https://www.cnblogs.com/nuoforever/p/15583800.html
Copyright © 2011-2022 走看看