역 참조 포인터를 포인터로 캐스팅하여 NULL 포인터로 대규모 검사를 사용하는 매우 오래된 (거대한) Win32 프로젝트가 있습니다. 이처럼 :강제로 NULL 포인터의 역 참조 허용
int* x = NULL; //somewhere
//... code
if (NULL == &(*(int*)x) //somewhere else
return;
그리고 네, 이 코드는 바보임을 알고을 리팩토링 할 필요가있다. 그러나 엄청난 양의 코드로 인해 불가능합니다. 바로 지금 Xcode의 MacOS Sierra에서이 프로젝트를 컴파일해야합니다. 문제가 발생합니다 ... 릴리스 모드 (코드 최적화)에서는 조건이 잘못된 동작으로 실행됩니다. 따라서 NULL을 참조 해제하기 때문에 정의되지 않은 동작이 발생합니다 바늘).
는 this document for GCC에 따르면 옵션 -fno-삭제 - 널 포인터 검사이 있지만, O1, O2 또는 O3 최적화가 활성화 된 경우는 LLVM 작동하지 않는 것 같다. 그래서 질문은 : 어떻게 그러한 역 참조를 허용하도록 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'이 될 수 있습니다. http://gcc.godbolt.org/에서 clang으로 확인하면 간단히 'bool b (short * p) {return 0 == & * (int *) p; }', clang은 올바른 코드를 생성합니다. 컴파일러가 잘못된 코드를 생성하는 최소한의 완전한 프로그램을 게시하십시오. – hvd
@hvd 실제 사례를 게시했습니다. 나는이 문제가 GCC와 관련이 있는지 확신 할 수 없다. 애플 LLVM 8.0에서 이것을 보았을 뿐이다. –