seg-Vで次のクラッシュが発生します。
// my code
int* ipt;
int bool set = false;
void Set(int* i) {
ASSERT(i);
ipt = i;
set = true;
}
int Get() {
return set ? *ipt : 0;
}
// code that I don't control.
struct S { int I, int J; }
int main() {
S* ip = NULL;
// code that, as a bug, forgets to set ip...
Set(&ip->J);
// gobs of code
return Get();
}
これは、そうでi
はないがNULL
、それでも有効ではないためです。NULL
呼び出し元のコードがポインタから配列インデックス操作のアドレスを取得する場合にも、同じ問題が発生する可能性があります。
これに対する1つの解決策は、下位ビットをトリミングすることです。
void Set(int* i) {
ASSERT((reinterpret_cast<size_t>(i))>>10);
ipt = i;
set = true;
}
しかし、いくつのビットを取り除く必要がありますか?
編集、とにかくその場合は中止するので(ただし、seg-vよりもクリーンに)、未定義の動作については心配していません。
FWIW:これは半仮想的な状況です。これを考えさせられたバグは、投稿する前に修正されましたが、以前に遭遇したことがあり、将来どのように処理するかを考えています。
議論のために想定できること:
- Setがseg-vになるもので呼び出された場合、それはバグです
- Setは、修正するのが私の仕事ではないコードによって呼び出される可能性があります。(たとえば、バグを報告します)
- Setは、修正しようとしているコードによって呼び出される可能性があります。(たとえば、デバッグ作業の一部として健全性チェックを追加しています。)
- Setが呼び出された場所に関する情報を提供しない方法で呼び出されます。(つまり、Get to seg-vを許可することは、何かをデバッグするための効果的な方法ではありません。)
- コードは移植可能である必要はなく、不正なポインターを100%キャッチする必要もありません。現在のシステムで十分な頻度で動作するだけで、どこで問題が発生しているのかを見つけることができます。