CL.MLK.ASSIGN

代入演算子のメモリ リーク

これは演算子 = のメモリリークの可能性を通知するクラスレベル (CL) のチェッカーです。Klocwork は、コンストラクタで動的メモリ割り当てを行うクラスが演算子 = の対応するポインターを上書きし、前のメモリを解放せず、および/または適切なリファレンスカウンターを減分しない場合に、CL.MLK.ASSIGN をレポートします。これはメモリリークにつながる可能性があります。

脆弱性とリスク

メモリリークは、アプリケーションで余分なメモリを消費させます。これによって他のアプリケーションが使用できるメモリ量が減り、結果的に、オペレーティングシステムにページングを開始させ、システム速度を低下させます。重大な場合、アプリケーションがメモリ制限に達して、クラッシュする可能性があります。

脆弱コード例 1

コピー
    class C {
    public
        C() { ip = new int; }
        ~C() { delete ip; }
        C& operator=(const C& rhs) {
            if (this == &rhs) return *this;
            ip = new int;      // memory pointed by ip is leaked
            *ip = *rhs.ip;
            return *this;
        }
   private
       C(const C&);
       int* ip;
   };

この例では、ip がポイントするメモリは上書きされる前に解放されません。コンストラクタでこのポインターにメモリが割り当てられるため、この代入はメモリリークにつながる可能性があり、これは Klocwork によって CL.MLK.ASSIGN とレポートされます。

修正コード例 1

コピー
    class C {
    public
        C() { ip = new int; }
        ~C() { delete ip; }
        C& operator=(const C& rhs) {
            if (this == &rhs) return *this;
            delete ip;
            ip = new int;
            *ip = *rhs.ip;
           return *this;
       }
   private
       C(const C&);
       int* ip;
   };

修正例 1 では、ip がポイントする動的メモリは新しい値に割り当てられる前に行 7 で解放されます。

脆弱コード例 2

コピー
    class counted {
    public
        counted() { counter = 1; }
        void addRef() { counter++; }
        void decRef() { counter--; if (counter == 0) delete this; }
        /* other methods */
    private
        int counter;
        /* other members */
   };

   class C {
   public
       C() { cp = new counted; }
       ~C() { cp->decRef(); }
       C& operator=(const C& rhs) {
           if (this == &rhs) return *this;
           cp = rhs.cp;    // CL.MLK.ASSIGN reported
           cp->addRef();
           return *this;
       }
   private
       C(const C&);
       counted* cp;
   };

この例では、cp がポイントするメモリのリファレンスカウンターは上書きする前に減分されません。その結果メモリリークにつながる可能性があり、Klocwork によって CL.MLK.ASSIGN とレポートされます。

修正コード例 2

コピー
    class counted {
    public
        counted() { counter = 1; }
        void addRef() { counter++; }
        void decRef() { counter--; if (counter == 0) delete this; }
        /* other methods */
    private
        int counter;
        /* other members */
   };

   class C {
   public
       C() { cp = new counted(); }
       ~C() { cp->decRef(); }
       C& operator=(const C& rhs) {
           if (this == &rhs) return *this;
           cp->decRef();
           cp = rhs.cp;
           cp->addRef();
           return *this;
       }
   private
       C(const C&);
       counted* cp;
   }; 

これでリファレンスカウンターは減分され、欠陥のレポートはありません。

拡張機能

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