У меня есть очень старый (и огромный) проект Win32, который использует массовые проверки с указателем NULL путем преобразования указателя разыменования. Нравится:
int* x = NULL; //somewhere
//... code
if (NULL == &(*(int*)x) //somewhere else
return;
И да, я знаю, что этот код глупый и требует рефакторинга. Но это невозможно из-за огромного количества кода. Прямо сейчас мне нужно скомпилировать этот проект под MacOS Sierra в Xcode, что приводит к большим проблемам ... Оказывается, в режиме выпуска (с оптимизацией кода) условие выполняется с некорректным поведением (так называемое поведение undefined из-за разыменования NULL указатель).
Согласно в этом документе для GCC есть опция -fno -delete-null-pointer-tests, но кажется, что он не работает для 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
сохраняет нулевую проверку, и код "работает":
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
и выше оптимизирована проверка:
something(int): # @something(int)
movb $1, %al
retq
-fno-delete-null-pointer-checks
не должен влиять на&*(int*)x
, это должно быть разрешеноNULL
. Проверка с помощью clang на gcc.godbolt.org с помощью простогоbool b(short *p) { return 0 == &*(int*)p; }
, clang генерирует правильный код. Пожалуйста, опубликуйте минимально полную программу, в которой ваш компилятор генерирует неправильный код. - person   schedule 02.12.2016&
, не должно быть нулевым - это адрес чего-то. Разыменование нулевого указателя запускает UB, поэтомуbool b(short *p) { return true; }
будет допустимой оптимизацией вашей функции в соответствии со стандартом. - person Quentin   schedule 02.12.2016&*p
разрешено, даже еслиp
равноNULL
, а для C ++ заявлено, что намерение совпадает с тем, что делают компиляторы. Другое дело со ссылками, но здесь ссылок нет. См. open-std.org/jtc1/sc22/wg21 /docs/cwg_active.html#232 Изменить: теперь в отредактированном вопросе есть ссылки. Что объясняет его. - person   schedule 02.12.2016m[i]
вернет прокси, который перегружаетoperator&
. - person M.M   schedule 02.12.2016