【问题标题】:At what point does dereferencing the null pointer become undefined behavior?在什么时候取消引用空指针成为未定义的行为?
【发布时间】:2011-10-31 03:31:26
【问题描述】:

如果我实际上没有访问被取消引用的“对象”,那么取消引用空指针是否仍然未定义?

int* p = 0;
int& r = *p;    // undefined?
int* q = &*p;   // undefined?

一个更实际的例子:我可以取消引用空指针来区分重载吗?

void foo(Bar&);
void foo(Baz&);

foo(*(Bar*)0);  // undefined?

好的,参考示例根据标准肯定是未定义的行为:

空引用不能存在于定义明确的程序中,因为创建此类引用的唯一方法是将其绑定到通过取消引用空指针获得的“对象”,这会导致未定义的行为强>。

不幸的是,强调的部分是模棱两可的。是 binding 部分导致了未定义的行为,还是 dereferencing 部分就足够了?

【问题讨论】:

标签: c++ object null undefined-behavior dereference


【解决方案1】:

是的,这是未定义的行为,因为规范说“左值指定一个对象或函数”(在第 3.10 条)并且它说对于*-operator“[取消引用]的结果是一个左值,指表达式指向的对象或函数”(第 5.3.1 节)。

这意味着没有描述取消引用空指针时会发生什么。这只是未定义的行为。

【讨论】:

    【解决方案2】:

    我认为What every C programmer should know about Undefined Behavior 的第二部作品可能有助于说明这个问题。

    以博客为例:

    void contains_null_check(int *P) {
      int dead = *P;
      if (P == 0)
        return;
      *P = 4;
    }
    

    可能会优化为(RNCE:冗余空检查消除):

    void contains_null_check_after_RNCE(int *P) {
      int dead = *P;
      if (false)  // P was dereferenced by this point, so it can't be null 
        return;
      *P = 4;
    }
    

    优化成(DCE:Dead Code Elimination):

    void contains_null_check_after_RNCE_and_DCE(int *P) {
      //int dead = *P; -- dead store
      //if (false)     -- unreachable branch
      //  return;
      *P = 4;
    }
    

    如您所见,即使dead从未使用过,简单的int dead = *P 赋值也会导致未定义行为在程序中蔓延。

    为了区分重载,我建议使用指针(可能为空)而不是人为地创建空引用并将自己暴露于未定义的行为。

    【讨论】:

      【解决方案3】:
      int& r = *p;    // undefined?
      

      我认为即使你实际上不使用r(或*p)——取消引用的对象,你也有未定义的行为。因为在这一步之后(即取消引用空指针),语言不能保证程序的行为,因为程序可能会立即崩溃,这是 UB 的可能性之一。您似乎认为只有读取r 的值以便在real 目的中使用 才会调用UB。我不这么认为。

      此外,语言规范明确指出“取消引用空指针的效果” 调用未定义的行为。它确实实际上使用来自空指针的解引用对象的效果”调用了UB。取消引用空指针(或换句话说未定义的行为)的效果并不意味着您将立即遇到问题,或者它必须立即崩溃 在取消引用空指针之后。不,它只是意味着,程序行为不是在取消引用空指针之后定义的。也就是说,程序可以按预期从头到尾正常运行。或者它可能会立即崩溃,或者在一段时间后 - 几分钟、几小时或几天之后。 任何时候 取消引用空指针之后,任何事情都可能发生。

      【讨论】:

      • 我在标准中找不到“取消引用空指针的效果”。你到底是在哪里找到的?
      • @FredOverflow : §1.9/4 (C++03) 说Certain other operations are described in this International Standard as undefined (for example, the effect of dereferencing the null pointer). [Note: this International Standard imposes no requirements on the behavior of programs that contain undefined behavior. ]
      • FDIS 将空指针示例替换为for example, the effect of attempting to modify a const object,这可能表明有关取消引用空指针的规则已更改。
      • @Fred 没有。他们替换了它,因为他们希望从长远来看(c++0x 后)将其更改为已定义的行为,并且想要一个更好的未定义行为示例。
      • 它实际上比“取消引用空指针后任何时候都可能发生任何事情”更糟糕。此外,“此外,在取消引用空指针之前,任何时候都可能发生任何事情。” q.v. Raymond Chen 的Undefined behavior can result in time travel.
      猜你喜欢
      • 2011-10-11
      • 1970-01-01
      • 1970-01-01
      • 2019-07-22
      • 2011-02-24
      • 1970-01-01
      • 2017-02-17
      • 2018-07-11
      • 1970-01-01
      相关资源
      最近更新 更多