潜在的空指针取消引用或编译器错误



我发现了另一种情况,编译器认为static_cast可能会在非nullptr参数上返回nullptr。这一次似乎没有像以前那样的未定义行为,但也许我错过了什么。以下是使用带有-O1 -fPIC -Wnull-dereference -Werror选项的gcc编译的代码:

struct IR { 
virtual ~IR() = default;
};
struct IF {
virtual ~IF() = default;
virtual void get() {};
};
struct SC : IR, IF {
bool h(); // { return true; };
};
struct HD : public IR {
virtual void g() {
if (r_ && r_->h()) {
static_cast<IF*>(r_)->get();
}
}
SC* r_ = nullptr;
};
bool SC::h() { return true; }
HD hd;

以下任何一种情况都将消除potential null pointer dereference警告:

  • 使SC::h()内联
  • 使CCD_ 5成为非虚拟的
  • 将优化级别从-O1更改为-O0
  • 正在删除-fPIC选项

那么,是否存在GCC错误,或者代码中仍然存在UB,或者非nullptr的static_cast会导致nullptr?

链接到导螺杆。

如果使用-fPIC而不为h使用inline函数,则编译器无法对h的行为做出任何假设,因为GCC的默认语义是允许任何共享库使用替代语义覆盖该函数。您还可以指定-fno-semantic-interposition,以允许GCC在假设从共享库加载的函数的其他实现不会有不同行为的情况下进行优化。

据我所知,-Wnull-dereference并不能保证只在存在明确的空指针取消引用时发出警告,只有在存在潜在的空指针时才会发出警告(尽管文档似乎有点不清楚,另请参阅https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86172)。由于上述原因,编译器无法确定r_->h()不会修改r_,因此空指针检查无法证明static_cast<IF*>(r_)->get();不会取消引用空指针。

-O0不会出现警告,因为有文档表明,只有在启用-fdelete-null-pointer-checks时,该警告才起作用,而只有在启用了优化的情况下,该警告才会起作用。

我想,如果get不是virtual,就不会出现警告,这可能是故意的,因为编译器可以确保函数调用在实际意义上不会实际导致null解引用,即使对象指针是null指针(尽管根据标准,它仍然是UB),或者函数在执行null指针检查之前内联。(如果函数是virtual,编译器可以再次对该调用不做任何假设,因为它可能会调用派生类重写。)

相关内容

最新更新