Mam bardzo stary (i ogromny) projekt Win32, który używa masywnych sprawdzeń z NULL wskaźnikiem przez rzutowanie na wskaźnik dereferencji. Tak:Siła pozwala na dereferencję wskaźnika NULL
int* x = NULL; //somewhere
//... code
if (NULL == &(*(int*)x) //somewhere else
return;
i tak, wiem, że ten kod jest głupi i muszą być refactored. Ale jest to niemożliwe z powodu ogromnej ilości kodu. W tej chwili muszę skompilować ten projekt pod MacOS Sierra w Xcode, co prowadzi do dużych problemów ... Okazuje się, że w trybie zwolnienia (z optymalizacją kodu) warunek jest wykonywany z nieprawidłowym zachowaniem (tak zwane niezdefiniowane zachowanie z powodu dereferencji NULL wskaźnik).
Według this document for GCC istnieje opcja -fno-delete-null pointer kontrole, ale nie wydaje się pracować dla LLVM gdy O1, O2 lub O3 optymalizacji włączona. Pytanie brzmi: jak mogę wymusić kompilator LLVM 8.0, aby zezwolić na takie dereferencje?
AKTUALIZACJA. Prawdziwy przykład pracy, aby sprawdzić 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)
}
Na -O0
i -O1
, something
keeps the null check, a kod "działa":
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
ale w -O2
i wyżej the check is optimized out:
something(int): # @something(int)
movb $1, %al
retq
[Odpowiedni raport o błędzie] (https://llvm.org/bugs/show_bug.cgi?id=9251). To nie jest obiecujące: flaga jest na razie ignorowana (początkowo nie była rozpoznawana). – Quentin
'-fno-delete-null-pointer-checks' nie powinno wpływać na' & * (int *) x', to wciąż powinno mieć wartość 'NULL'. Sprawdzanie z clang na http://gcc.godbolt.org/, z prostym 'bool b (short * p) {return 0 == & * (int *) p; } ', clang generuje poprawny kod. Opublikuj minimalny kompletny program, w którym twój kompilator generuje niepoprawny kod. – hvd
@hvd zamieściłem prawdziwy przykład. Nie jestem pewien, czy ten problem związany z GCC, widziałem tylko w Apple LLVM 8.0 –