I have the very old (and huge) Win32 project which uses massive checks with NULL pointer by casting to pointer the dereferenced pointer. Like this:
int* x = NULL; //somewhere
//... code
if (NULL == &(*(int*)x) //somewhere else
return;
And yes, I know that this code is stupid and need to be refactored. But it is impossible due to huge amount of code. Right now I need to compile this project under MacOS Sierra in Xcode, which leads to big problems... It turns out that in release mode (with code optimization) the condition executes with incorrect behaviour (so called undefined behaviour because of dereferencing of NULL pointer).
According to this document for GCC there is an option -fno-delete-null-pointer-checks, but it seems not working for LLVM when O1, O2 or O3 optimization enabled. So the question is: how can I force LLVM 8.0 compiler to allow such dereferences?
UPDATE. The real working example to check the problem.
//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)
}
At -O0 and -O1, something keeps the null check, and the code "works":
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
But at -O2 and above, the check is optimized out:
something(int): # @something(int)
movb $1, %al
retq
-fno-delete-null-pointer-checksisn't supposed to affect&*(int*)x, that's still supposed to be allowed to beNULL. Checking with clang on gcc.godbolt.org, with simplybool b(short *p) { return 0 == &*(int*)p; }, clang generates correct code. Please post a minimal complete program where your compiler generates incorrect code.&returns should not possibly be null -- it's the address of something. Dereferencing a null pointer triggers UB, sobool b(short *p) { return true; }would be a valid optimisation of your function according to the standard.&*pis allowed even ifpisNULL, and for C++, the intent has been stated to be the same and that's what compilers do. It's a different story for references, but there are no references here. See open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232 Edit: there are now references in the edited question. That explains it.