【问题标题】:Why does the compiler not reserve enough space on the stack?为什么编译器没有在堆栈上保留足够的空间?
【发布时间】:2012-04-22 22:26:48
【问题描述】:

我有一个带有数组和默认构造函数的 C++ 类 Matrix22

class Matrix22{
  /* something more */
  double mat[2][2];
  Matrix22(){
    for(int i=0; i<2; i++)
      for(int j=0; j<2; j++)
        mat[i][j] = i==j ? 1.0 : 0.0;
  }
};

我在我的程序中使用它并遇到了分段错误。由于其余部分相当困难和复杂,我编写了一个简单的测试例程,只调用Matrix22()。没有更多的段错误。

然后我运行gdb 来调试问题。如果我从单独的测试例程调用构造函数,gcc 会为成员mat 保留一些内存。我可以在堆栈中导航并在数组后面的一些字节中查看返回地址。

在主程序中编译器没有预留足够的空间。第一个元素 (mat[0][0]) 被写入,但任何进一步的写入只会覆盖下一个堆栈帧。我还可以验证,与构造函数之前一样,命令btreturns 正确的回溯,在关键分配之后回溯已损坏。

所以我的问题是:为什么在一种情况下编译器(或链接器?)没有为数组保留足够的空间,而在另一种情况下却没有发生?

PS:两个“测试用例”都使用相同的编译器和标志进行编译,并且链接到相同的目标文件。

编辑:

这是一个没有段错误的“简单”测试用例:

void test_Matrix22()
{
  Framework::Math::Matrix22 matrix;
}

创建 seg 错误的代码在类 ModuleShaddower 中(混合标头和实现):

class ModuleShaddower{
    public:
        ModuleShaddower(PVModule& module, const EnvironmentalSetup& setup, const Position& position);
    private:
        Matrix22 rotMatrix90;
};

ModuleShaddower::ModuleShaddower(PVModule& module, const EnvironmentalSetup& setup, const Position& position)
  : module (module), position(position), setup(setup), logger(LoggerFactory::getLoggerInstance())
{
    double mat[][2] = {{0, -1},{1, 0}}; // This line will never be reached
    rotMatrix90 = Matrix22(mat);
}

如您所见,它完全来自其他地方。我可能会尝试提取有问题的代码,但我认为这不会有太大帮助。

【问题讨论】:

  • 你能提供完整的测试用例吗? (失败的那个)
  • Oli 说了什么:向我们展示您是如何使用该课程的。
  • 短测没问题。长版有几千行代码。我会尽量贡献一部分
  • 通常堆栈空间不足/堆栈溢出条件是由具有不良(或缺失)终止条件的递归引起的。发布的代码中没有任何内容会导致堆栈问题——事实上,该构造函数可能根本不需要任何堆栈。
  • 在内存快用完的意义上,它不是堆栈溢出。此构造函数覆盖另一个堆栈帧使用的堆栈上的(有效)内存。因此堆栈被破坏,随后程序崩溃,因为它试图跳转到它无法跳转到的地方(如果相关帧完成并且应该退出)。

标签: c++ multidimensional-array linker stack segmentation-fault


【解决方案1】:

如果未达到您的 ModuleShaddower 构造函数代码(根据您的代码注释),那么构造函数初始化列表中的某些内容(与模块的构造、位置等有关)会导致问题。

【讨论】:

  • 我同意你的看法。但是如果我使用调试器,我会输入构造函数 Matrix22()。一开始堆栈是好的(通过bt检查)。循环完成后,堆栈已损坏。所以对我来说很明显有问题的代码在 Matrix22() 构造函数中。 PS:其他参数均为​​参考。它们是在外部创建的,没有问题。如果他们是问题所在,那么在我看来,整个问题应该发生在另一个位置,还是我错了?
【解决方案2】:

问题是由于不同位置的两个目标文件具有相同的名称。在从该目标代码创建的生成的静态库中,有时会替换错误的文件(两者都称为Shaddower.o)。当我重命名其中一个文件时,一切顺利,没有更多错误。

我不知道这个问题的确切根源,但可以这样解决。

【讨论】:

    猜你喜欢
    • 2014-02-28
    • 2013-10-29
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    • 2014-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多