У меня есть очень старый (и огромный) проект 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
[Соответствующий отчет об ошибке] (https://llvm.org/bugs/show_bug.cgi?id=9251). Это не обещает: на данный момент флаг действительно игнорируется (сначала он был непризнан). – Quentin
'-fno-delete-null-pointer-checks' не должно влиять на' & * (int *) x', это все равно должно быть разрешено «NULL». Проверка с помощью clag на http://gcc.godbolt.org/, с помощью просто 'bool b (short * p) {return 0 == & * (int *) p; } ', clang генерирует правильный код. Пожалуйста, опубликуйте минимальную полную программу, в которой ваш компилятор генерирует неправильный код. – hvd
@hvd Я написал настоящий пример. Я не уверен, связана ли эта проблема с GCC, я видел это только в Apple LLVM 8.0 –