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++ 分析。