【问题标题】:Crash when using a global object, but not when using a local object使用全局对象时崩溃,但使用本地对象时不会崩溃
【发布时间】:2018-05-24 13:41:59
【问题描述】:

我正在尝试使用libconfig 为我的程序创建配置文件。有两种情况,一种可以完美运行(本地范围对象),另一种失败(全局范围对象)。我试图理解为什么一个失败而另一个成功,因为我的理解是两者都是创建相同对象的定义(只是在不同的范围内)。

第一个(不起作用):我在全局范围内定义了一个 Config 对象。然后我在 Config 对象上调用 readFile。程序在这里崩溃。

#include <libconfig.h++>

libconfig::Config cfg;

int __attribute__((constructor)) Init()
{
  cfg.readFile("/home/jalius/csgo-internal/hack.cfg");
}

第二个(有效):我定义了一个本地 Config 对象并在其上调用 readFile。

#include <libconfig.h++>

int __attribute__((constructor)) Init()
{
  libconfig::Config cfg;
  cfg.readFile("/home/jalius/csgo-internal/hack.cfg");
}

【问题讨论】:

  • 什么是运行时错误?
  • 我将如何提取这些信息?这个共享库使用 dlopen 注入到另一个进程中。我在进程上打开了 gdb,并看到主线程在 libconfig.c 中的某个地方收到了 SIGSEGV(我没有调试符号)。
  • SIGSEGV 信号表示分段错误。

标签: c++ class constructor segmentation-fault


【解决方案1】:

当您当时调用int __attribute__((constructor)) Init() 函数时,cfg 对象不会在您的情况下创建。因为调用带有属性constructor 和具有静态存储持续时间的C++ 对象的函数的顺序是未指定的。由于对象不存在,因此您收到分段错误错误,即SIGSEGV 信号。

以下是GCC website的摘录:

目前,具有静态存储持续时间的 C++ 对象的构造函数和使用属性 constructor 修饰的函数的调用顺序未指定。在混合声明中,属性init_priority 可用于强加特定的顺序。

有关详细信息,请参阅 this page 上的 constructor 部分。

【讨论】:

    【解决方案2】:

    无法保证您的函数 int __attribute__((constructor)) Init() 将在构造Config 对象之前被调用。

    当您尝试从中读取数据时,您实际上可能会尝试访问未构造的对象。这将导致未定义的行为。

    当您在本地创建它时,可以保证您的对象将在您使用它之前完全初始化。


    实验:

    #include <iostream>
    
    enum {
        OBJECT_CONSTRUCTOR,
        FUNCTION_CONSTRUCTOR,
    };
    
    int order[10], cur = 0;
    
    class TestClass {
      public:
       TestClass() { order[cur++] = OBJECT_CONSTRUCTOR; }
       ~TestClass() { }
    };
    
    TestClass abc;
    int __attribute__((constructor)) Init() {
       order[cur++] = FUNCTION_CONSTRUCTOR;
    }
    
    int main ()
    {
        std::cout << "Order of execution:\n";
        for(int i = 0; i < cur; i++)
        {
            switch(order[i])
            {
                case OBJECT_CONSTRUCTOR:
                    std::cout<<"Object Constructor\n";
                    break;
                case FUNCTION_CONSTRUCTOR:
                    std::cout<<"Function Constructor\n";
                    break;
            }
        }
        return 0;
    }
    

    结果:

    Order of execution:
    Function Constructor
    Object Constructor
    

    【讨论】:

    • 有趣。我假设可以保证所有全局变量都将像在 main 中一样构造。
    猜你喜欢
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 2014-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-09
    • 1970-01-01
    相关资源
    最近更新 更多