【问题标题】:Force allow dereference of NULL pointer强制允许取消引用 NULL 指针
【发布时间】:2017-04-17 02:41:27
【问题描述】:

我有一个非常古老(而且很大)的 Win32 项目,它通过将取消引用的指针转换为指针来使用 NULL 指针进行大量检查。像这样:

int* x = NULL; //somewhere
//... code
if (NULL == &(*(int*)x) //somewhere else
    return;

是的,我知道这段代码很愚蠢,需要重构。但由于代码量很大,这是不可能的。现在我需要在 Xcode 中的 MacOS Sierra 下编译这个项目,这会导致很大的问题......事实证明,在发布模式(使用代码优化)中,条件以不正确的行为执行(由于取消引用 NULL,因此称为未定义行为指针)。

根据this document for GCC 有一个选项-fno-delete-null-pointer-checks,但是当启用 O1、O2 或 O3 优化时,它似乎不适用于 LLVM。所以问题是:如何强制 LLVM 8.0 编译器允许此类取消引用?

更新。检查问题的真实工作示例。

//somewhere 1
class carr
{
public:
    carr(int length)
    {
        xarr = new void*[length];

        for (int i = 0; i < length; i++)
            xarr[i] = NULL;
    }

    //some other fields and methods

    void** xarr;
    int& operator[](int i)
    {
        return *(int*)xarr[i];
    }
};

//somewhere 2
carr m(5);

bool something(int i)
{
    int* el = &m[i];
    if (el == NULL)
        return FALSE; //executes in debug mode (no optimization)

    //other code
    return TRUE; //executes in release mode (optimization enabled)
}

-O0-O1something keeps the null check 和代码“有效”:

something(int):                          # @something(int)
    pushq   %rax
    movl    %edi, %eax
    movl    $m, %edi
    movl    %eax, %esi
    callq   carr::operator[](int)
    movb    $1, %al
    popq    %rcx
    retq

但是-O2及以上,the check is optimized out

something(int):                          # @something(int)
    movb    $1, %al
    retq

【问题讨论】:

  • Corresponding bug report。这并不乐观:该标志现在确实被忽略了(起初它无法识别)。
  • -fno-delete-null-pointer-checks 不应该影响&amp;*(int*)x,它仍然应该被允许为NULL。在gcc.godbolt.org 上使用clang 检查,只需使用bool b(short *p) { return 0 == &amp;*(int*)p; },clang 会生成正确的代码。请发布一个最小的完整程序,您的编译器会生成不正确的代码。
  • @hvd 我已经发布了真实的例子。我不确定这个问题是否与 GCC 有关,我只在 Apple LLVM 8.0 中看到过这个
  • @hvd &amp; 返回的东西不应该为空——它是某物的地址。取消引用空指针会触发 UB,因此 bool b(short *p) { return true; } 将是根据标准对您的函数进行的有效优化。
  • @Quentin 对于 C,即使 pNULL,也明确表示允许 &amp;*p,对于 C++,意图已被声明为相同,这就是编译器所做的.对于参考来说,这是一个不同的故事,但这里没有参考。请参阅open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232 编辑:编辑后的问题中现在有 are 引用。这就解释了。

标签: c++ undefined-behavior clang++ dereference null-pointer


【解决方案1】:

对 NULL 进行基于文本的搜索。 然后在警告模式下运行编译器并在纸上打印出所有警告(如果你还有这样的技术)。 现在对于每个空值,它是一个有问题的空值还是一个好的空值?如果有问题,将其重命名为 XNULL。

现在,在安装了 640k 的小型系统上,C++ 检查可能会失败,因为 640k 对任何人来说都足够了,但在具有许多 GB 的现代系统上却不行。所以一旦重新贴标签就把它们去掉。如果不是这样。使 XNULL 成为在 C++ 眼中具有有效地址的“虚拟对象”。

(从示例中,代码看起来是一个 Lisp 解释器。Lisp 需要一个空指针和一个虚拟指针,没有其他简单的方法来编写解释器)。

【讨论】:

  • 那不是解决方案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-05
  • 2011-02-13
  • 2020-07-14
  • 1970-01-01
  • 2017-01-29
相关资源
最近更新 更多