我有一个非常古老的(和巨大的)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
和-O1
,something
keeps the null check,以及代码&#34;工作&#34;:
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
答案 0 :(得分:0)
对NULL进行基于文本的搜索。 然后在警告模式下运行编译器并在纸上打印出所有警告(如果您仍有此类技术)。 现在对于每个null,它是一个有问题的null还是一个好的?如果有问题,请将其重命名为XNULL。
现在很可能C ++检查在安装了640k的小型系统上可能会失败,因为对于任何人来说640k都足够了,但对于没有GB的现代系统来说却不行。所以只要重新标记就把它们剥掉。如果不是这样的话。使XNULL成为一个虚拟对象&#34;在C ++眼中使用有效地址。
(从示例中,看起来代码是一个Lisp解释器.Lisp需要一个空指针和一个虚拟指针,没有其他简单的方法来编写解释器。)