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 知识库进行扩展。有关详情,请参阅调整 C/C++ 分析。