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