2016-12-02 8 views
8

У меня есть очень старый (и огромный) проект Win32, который использует массивные проверки с помощью указателя NULL путем нажатия на указатель разыменованного указателя. Как это:Сила позволяет разыменовать NULL-указатель

int* x = NULL; //somewhere 
//... code 
if (NULL == &(*(int*)x) //somewhere else 
    return; 

И да, я знаю, что этот код глуп и нужно быть переработан. Но это невозможно из-за огромного количества кода. Прямо сейчас мне нужно скомпилировать этот проект под MacOS Sierra в Xcode, что приводит к большим проблемам ... Оказывается, что в режиме выпуска (с оптимизацией кода) условие выполняется с неправильным поведением (так называемое неопределенное поведение из-за разыменования NULL указатель).

По this document for GCC есть вариант -fno-удаление-нуль-указатель проверка, но это, кажется, не работает на LLVM, когда O1, O2 или оптимизации O3 включены. Поэтому возникает вопрос: как я могу заставить компилятор 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, а код "работает":

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

[Соответствующий отчет об ошибке] (https://llvm.org/bugs/show_bug.cgi?id=9251). Это не обещает: на данный момент флаг действительно игнорируется (сначала он был непризнан). – Quentin

+1

'-fno-delete-null-pointer-checks' не должно влиять на' & * (int *) x', это все равно должно быть разрешено «NULL». Проверка с помощью clag на http://gcc.godbolt.org/, с помощью просто 'bool b (short * p) {return 0 == & * (int *) p; } ', clang генерирует правильный код. Пожалуйста, опубликуйте минимальную полную программу, в которой ваш компилятор генерирует неправильный код. – hvd

+0

@hvd Я написал настоящий пример. Я не уверен, связана ли эта проблема с GCC, я видел это только в Apple LLVM 8.0 –

ответ

0

сделать текстовый поиск по НОЛЬ. Затем запустите компилятор в режиме предупреждения и распечатайте все предупреждения на бумаге (если у вас все еще есть такая технология). Теперь для каждого нуля это проблематичный нуль или хороший? Если проблема, переименуйте ее XNULL.

Теперь вполне вероятно, что проверки C++ могут завершиться неудачно в небольшой системе с, скажем, 640k, потому что 640k достаточно для кого-то, но не для вашей современной системы со многими ГБ. Так что просто разделите их, как только перемаркированы. Если это не так. сделайте XNULL «фиктивным объектом» с действительным адресом в глазах C++.

(Из примера видно, что код является интерпретатором Lisp. Для Lisp нужны как нулевой указатель, так и фиктивный указатель, нет другого простого способа написать интерпретатор).

+0

Это не решение –

 Смежные вопросы

  • Нет связанных вопросов^_^