zoukankan      html  css  js  c++  java
  • 一个可遇不可求的 bug 全局变量初始化顺序问题 哈哈

    这是今天下午帮同事查的一个客户端 C++ 的 bug,前人留下的谜之代码。。

    具体情况是,客户端实现了有一个简单的内存池,每次申请内存的时候会把新申请到的内存信息存到一个 map 里,据说是为了检查内存泄漏。

    大致是像下面这段代码

     1 std::map<unsigned long, int> m;
     2 
     3 template<typename T>
     4 char* jnew(int count)
     5 {
     6     char* p = new char[sizeof(T) * count];
     7     if (count == 1)
     8         m[(unsigned long)p] = 1;
     9     return p;
    10 }

    同事把第 7 行注释掉了,结果客户端就开始崩溃。神奇哟~

    报错信息中有 0x00000005 字样,显然是空指针的问题,断点第 8 行,查看 count,是个很大的数,进入到 map 的代码里,看到果然里面的指针全他妈是空的,似乎没有被初始化。

    然后我取消注释,断点第 7 行,和第 1 行。

    程序启动,进入到第 7 行的断点,count 很大,continue,又在第 7 行停下来,count 还是很大。

    于是取消第 7 行断点,继续断第 8 行,continue,

    啪!停在了第 1 行!基本证实了是初始化的问题。就是最初 count != 1 时访问到 m,m 还没有被初始化,然后崩溃。

    那么可以推断,程序第一次调用 jnew 的时候,是在初始化另外一个全局变量或者静态变量。

    然后查看调用堆栈,果然是在一个类的静态成员两变量初始化中。

    同事感叹,印象中只是在某本书上见过类似的问题,没想到今天自己遇上了。

    重现一下车祸现场:

    简单说就是,如果有两个全局变量 a 和 b,a 和 b 分别在两个文件中,a 的初始化又依赖 b,那么就有可能 a 初始化的时候 b 还没又被初始化,导致程序崩溃

    nofuck.cpp

    1 #include <map>
    2 
    3 static std::map<int, int> m;
    4 
    5 std::map<int, int>& GetMap()
    6 {
    7 return m;  
    8 }

    main.cpp

     1 #include <map>
     2 
     3 std::map<int, int>& GetMap();
     4 
     5 class Fuck{
     6 public:
     7     Fuck(){
     8         GetMap().clear();
     9     }
    10 };
    11 
    12 static Fuck fuck;
    13 
    14 int main(int argc, char** argv)
    15 {
    16     return 0;
    17 }

    解决方法是,把 static std::map<int, int> m; 放到 GetMap 函数内部。

    这一类 bug 的特征是,在进入 main 函数之前程序就挂掉。

    最后,还是那个原则,全局的东西能不用的尽量不用。

    参考链接

    http://stackoverflow.com/questions/1005685/c-static-initialization-order

    http://coolshell.cn/articles/10115.html

  • 相关阅读:
    day11
    day10
    day9
    day8
    day7
    day6
    day14
    day13
    day12
    day11
  • 原文地址:https://www.cnblogs.com/hangj/p/6567724.html
Copyright © 2011-2022 走看看