2016-12-02 14 views
8

私は、逆参照されたポインタをポインタにキャストすることによって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-O1something 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'が許されているはずです。 http://gcc.godbolt.org/のclangで、単に 'bool b(short * p){return 0 ==&*(int *)p; } '、clangは正しいコードを生成します。あなたのコンパイラが間違ったコードを生成する最小限の完全なプログラムを投稿してください。 – hvd

+0

@hvd私は実際の例を掲載しました。私はこの問題がGCCに関係しているかどうかは分かりませんが、Apple LLVM 8.0でこれを見てきました。 –

答えて

0

上のテキストベースの検索を行うとヌル。 その後、警告モードでコンパイラを実行し、紙にすべての警告を出力します(まだそのような技術がある場合)。 それぞれのヌルについて、問題のあるヌルかいいですか?問題がある場合は、名前をXNULLに変更します。

これで、640kがインストールされている小さなシステムでは、640kで十分ですが、多くのGBを搭載した現代のシステムではうまくいかない可能性があります。だから、一度ラベルをつけ直すだけでそれらを取り除く。そうでない場合。 XNULLをC++の目では有効なアドレスを持つ「ダミーオブジェクト」にします。

(この例では、codeがLispインタプリタのように見えますが、Lispにはヌルポインタとダミーポインタの両方が必要ですが、他に簡単なインタープリタを書く方法はありません)。

+0

これは解決策ではありません –

関連する問題