私は大きなc++コードベースを継承しており、コードベースで発生する可能性のあるnullポインター例外を回避するタスクがあります。利用可能な静的分析ツールはありますか、私はあなたがうまく使用したことを考えています。
他に何に気をつけていますか?
私は大きなc++コードベースを継承しており、コードベースで発生する可能性のあるnullポインター例外を回避するタスクがあります。利用可能な静的分析ツールはありますか、私はあなたがうまく使用したことを考えています。
他に何に気をつけていますか?
NULL のソースを排除することから始めることができます。
変化する
if (error) {
return NULL;
}
の中へ
if (error) {
return DefaultObject; // Ex: an empty vector
}
デフォルト オブジェクトを返すことが適用されず、コード ベースで既に例外が使用されている場合は、次のようにします。
if (error) {
throw BadThingHappenedException;
}
次に、適切な場所で処理を追加します。
レガシー コードを使用している場合は、いくつかのラッパー関数/クラスを作成できます。
ResultType *new_function() {
ResultType *result = legacy_function();
if (result) {
return result;
} else {
throw BadThingHappenedException;
}
}
新しい機能は、新しい関数を使用して開始し、適切な例外処理を行う必要があります。
Joelのような賢い人を含め、一部のプログラマーは例外を取得しないことを知っています。しかし、NULL を返すことによって最終的に起こるのは、この NULL が狂ったように渡されてしまうということです。誰もがそれを処理して黙って返すことは自分たちの仕事ではないと考えるからです。一部の関数はエラー コードを返す場合がありますが、これは問題ありませんが、呼び出し元はエラーに応答してさらに別の NULL を返すことがよくあります。次に、関数がどれほど些細なものであっても、すべての関数で多くの NULL チェックが行われます。そして、NULL をチェックしない 1 つの場所だけでプログラムがクラッシュします。例外により、エラーについて慎重に検討し、どこでどのように処理する必要があるかを正確に決定する必要があります。
静的分析ツール (常に使用する必要があります) などの簡単なソリューションを探しているようです。ポインターを参照に変更することも優れたソリューションです。ただし、C++ には RAII の優れた点があり、どこでも「{} を最後に {} を試す」必要がなくなるため、真剣に検討する価値があると思います。
主にコードベースを維持している場合、実行できる最も低いレベルの労力と最も高いリターンの1つは、カウントされたポインターを参照するためにベアポインターのリファクタリングを開始することです。
また、メモリの破損を検出するためにコードをインストルメント化するPurifyのようなものも検討します。
コードを変更したくない場合は、いくつかのツールを使用する必要があります (他の回答を参照)。しかし、問題の特別な部分 (関数にポインターを置いて使用する場所) には、小さなバガーを見つけるために使用できる素敵な小さなマクロ定義があります: (リリースモードで時間のオーバーヘッドがなく、目に見えるコードへの条件)
#ifdef NDEBUG
#define NotNull(X) X
#else // in Debug-Mode
template<typename T> class NotNull;
template<typename T> // template specialization only for pointer-types
class NotNull<T*> {
public:
NotNull(T* object)
: _object(object) {
assert(object);
}
operator T*() const {
return _object;
}
T* operator->() const {
return _object;
}
private:
T *_object;
};
#define NotNull(X) NotNull<X>
#endif // in Debug-Mode
これからすべての関数を変更するだけです:
void increase(int* counter)
{ .. }
これに
void increase(NotNull(int*) counter)
{ .. }
ps : ここで最初に見つかり、さらに微調整できます
まず、技術的な点として、C++ には NULL ポインター例外がありません。NULL ポインターを逆参照すると動作が未定義になり、ほとんどのシステムでプログラムが突然終了 (「クラッシュ」) します。
ツールに関しては、私も次の質問をお勧めします。
特に NULL ポインターの逆参照に関しては、NULL ポインターの逆参照には 3 つの主要な要素があることを考慮してください。
静的分析ツールの難しい部分はもちろんステップ 2 であり、ツールはどれだけ複雑な経路を正確に追跡できるか (つまり、誤検知が多すぎないか) によって区別されます。どのような種類のツールが最も効果的かについてより適切にアドバイスするために、キャッチしたいバグの具体的な例をいくつか見ることが役立つ場合があります。
免責事項: 私はコベリティで働いています。
補足質問ですが、顧客にクラッシュを見せたくないので、これらを回避する目的はありますか? 多くの場合、null ポインターは予期しない状況であり、すぐに対処する必要がありますが、非常に頻繁にシステムを通過してしまいます。
私はかつて、関数へのエントリ時に習慣があったコードベースで作業し、最初にヌルポインターをチェックし、そうであればリターンしました。これに関する問題は、ツールがクラッシュすることはありませんでしたが、最終的に不正なデータが静かに生成されたことです。また、これらの問題をデバッグしようとするのは困難でした。結果が耐えられなくなったり、最終的に明らかになる前に、多くの関数を介して長い間不正に null ポインターが渡されていた可能性があるためです。
理想的には、少なくとも開発期間中は適切なアサーションが必要なので、本番ビルド用にアサートを非表示または再定義するマクロを検討してください