EN JP CN

CL.SHALLOW.ASSIGN

CL.SHALLOW.ASSIGN

代入演算子での形式的なコピーによる解放されたメモリの解放

これは、演算子 = での形式的なコピーに起因するクラスデストラクタによるヒープメモリの二重解放の可能性を通知するクラスレベル (CL) のチェッカーです。Klocwork は、クラスデストラクタが 1 つ以上のデータメンバーによってポイントされる動的メモリの解放を実行し、代入演算子でこれらのポインターの形式的なコピーのみを実行する場合に、CL.SHALLOW.ASSIGN をレポートします。

脆弱性とリスク

形式的なコピーの場合、代入演算子の呼び出しにより、同じ動的メモリをポイントするデータメンバーを持つ 2 つのオブジェクトが作成されます。適切なリファレンスカウンターデバイスがない場合、最初のオブジェクトが範囲外になると、クラスデストラクタは 2 つのオブジェクト間で共有されるメモリを解放します。2 番目のオブジェクトの該当するデータメンバーは、この場合、削除されたメモリ場所をポイントします。2 番目のオブジェクトが範囲外になると、そのデストラクタはこのメモリを再度解放しようとします。これはアプリケーションのクラッシュやヒープメモリの破壊といった問題につながる可能性があります。

脆弱コード例 1

1    struct D {
2        /* omitted for brevity */
3    };
4
5    class C {
6    public:
7        C();
8        ~C() {
9            delete d;
10       }
11       C& operator=(const C& rhs) {
12           d = rhs.d;    // shallow copy
13           return *this;
14       }
15   private:
16       C(const C&);
17       D* d;
18   };                 

この例では、メンバーポインター d の形式的なコピーが演算子 = にて実行されます。対応するヒープメモリはデストラクタ ~C() で解放されます。Klocwork はこの潜在的に危険な状況に対して CL.SHALLOW.ASSIGN のフラグを立てます。

修正コード例 1

1    struct D {
2       /* omitted for brevity */
3       D(const D&);
4    };
5
6    class C {
7    public:
8        C();
9        ~C() {
10           delete d;
11       }
12       C& operator=(const C& rhs) {
13           d = new D(*rsh.d);
14           return *this;
15       }
16   private:
17       C(const C&);
18       D* d;
19   };         

修正例 1 では演算子 = で実質的なコピーが実行されます。この結果、2 つのオブジェクトのデストラクタが呼び出される場合に二重解放は起こりません。

拡張機能

このチェッカーは、Klocwork knowledge base (ナレッジベース) を利用して拡張できます。詳細については、C/C++ 解析のチューニングを参照してください。