2016-12-02 39 views
8

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 
+5

[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

+1

'-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

+0

@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 –

Odpowiedz

0

wyszukuj tekstowy na ZERO. Następnie uruchom kompilator w trybie ostrzegawczym i wydrukuj wszystkie ostrzeżenia na papierze (jeśli nadal masz taką technologię). Teraz dla każdej wartości zerowej jest to problematyczny pusty lub dobry? Jeśli problematyczne, zmień nazwę na XNULL.

Teraz jest prawdopodobne, że kontrole C++ mogą zawieść w małym systemie z zainstalowanym, powiedzmy 640k, ponieważ 640k jest wystarczający dla każdego, ale nie w nowoczesnym systemie z wieloma GB. Więc po prostu je rozebraj, po ponownym oznakowaniu. Jeśli tak nie jest. uczyń XNULL "obiektem obojętnym" z poprawnym adresem w oczach C++.

(Z przykładu wygląda na to, że kod to interpreter Lispa, Lisp potrzebuje zarówno wskaźnika zerowego, jak i manekina, nie ma innego prostego sposobu na zapisanie interpretera).

+0

To nie jest rozwiązanie –