私は、逆参照されたポインタをポインタにキャストすることによって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コンパイラにそのような逆参照を許可することができますか?
UPDATE。問題を確認する実際の動作例。
//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に関係しているかどうかは分かりませんが、Apple LLVM 8.0でこれを見てきました。 –