【问题标题】:gcc 6.1.0 segmentation fault - gcc bug?gcc 6.1.0 分段错误 - gcc 错误?
【发布时间】:2016-07-13 12:54:39
【问题描述】:

让我们考虑以下代码。事实上,这是我使用 gmock 和模拟 void(void) 方法发现的缩小问题。

class Base {
 public:
  virtual ~Base() {}
};

class Derived : public Base
{
 public:
  void GetValueAndDelete()  { delete this; } //here we crash
};

int main() {
  Derived* p = 0;
  p->GetValueAndDelete();
}

构建它:

/tools/gcc6.1/bin/g++ --version
g++ (GCC) 6.1.0

优化级别不同于 -O0 并且运行结果会导致分段错误。

是 gcc 错误还是 c++ 代码的问题(是的,是的,我知道它使用副作用,但它可以与其他编译器一起使用,并且也没有优化)

【问题讨论】:

  • 你取消引用一个空指针,你期望会发生什么?
  • 我相信在任何情况下取消引用空指针都是分段错误的理由;这是未定义的行为。
  • 什么?你在一个空指针上调用一个函数,想知道为什么它不起作用?
  • delete this的时候要非常小心,基本上和拆你所在的建筑是一样的。如果你小心,碎片不会杀死你,但大多数情况下都是坏事会发生的。
  • "它可以与其他编译器一起使用" 你的意思是它不打印崩溃消息吗?

标签: c++ gcc gcc6


【解决方案1】:

是gcc的bug吗

没有。

或者用 c++ 代码的东西

是的。您在不指向有效对象的指针上使用箭头运算符。这具有未定义的行为。

以这种不使用任何成员的方式取消引用空指针和调用方法是可以的。

按照标准,这不是好的。是 UB。

什么是指针上的调用方法?

具体实现。

删除这个没什么特别的。

删除this很特别。

你应该只注意不要在之后使用任何成员

是的,并且您必须确保只有new 用于创建所有调用该函数的实例。没有自动对象,没有静态对象,没有 new[],没有 malloc + 新位置。

所以是的,你可以 delete this,但要小心。

【讨论】:

    【解决方案2】:

    你的直觉似乎是:

    1. p-> 是可以的,因为它只是填写this 的语法。
    2. delete this 没问题,因为在 delete 之后不要使用 this

    但上述情况实际上可能并不正确,因为取消引用空指针始终是未定义的行为。如果不启用优化,这可能不会造成任何麻烦,因为编译器正在执行“基本编译”,这在某种程度上与您“在脑海中编译”时的想象相匹配。然而,通过优化,GCC 会做很多它通常不会做的事情,例如在面对不正确的源代码时不会费心发出“正确”的指令。当你说p-> 作为程序的第一幕时,它实际上根本不需要做任何事情——它可以假装main() 是空的(或者崩溃,就像你的情况一样)。

    【讨论】:

    • Drerferencing nullptr - 我同意,但要删除 nullptr?这是标准允许的,不是吗?
    • @Kamil_H:你说得对,虽然我最初认为这不适用于这里,但在二读时我认为它适用,所以我编辑了我的答案。
    【解决方案3】:

    我知道在 nullptr 上调用方法不符合标准,但到目前为止,我还没有看到无法以所述方式处理的编译器。似乎 gcc6.1 的工作方式不同(仍然根据规范)。所以这是 gmock 错误。我想知道有多少其他项目依赖于这种编译器行为:)

    值得一提的是,方法被调用,里面的'this'按预期为零,然后删除失败。我查看了程序集,其中有 mov (%rax), %rbx 失败,因为 rax 包含零。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-16
      • 2016-10-13
      • 1970-01-01
      • 2014-05-16
      • 2011-10-02
      • 2020-09-08
      相关资源
      最近更新 更多