CL.MLK.VIRTUAL
虚拟内存泄漏
这是一个类级别 (CL) 检查器,可告知用户可能发生的内存泄漏情况。如果相应类至少包含一个虚拟方法(意味着旨在作为基类进行继承),某个派生类的析构函数执行内存解除分配,但是基类析构函数未声明为虚拟,这时将报告 CL.MLK.VIRTUAL。在这种情况下,如果程序损坏了某个指针,且该指针指向某个派生类型对象的向上转换的基本类型,则将不会调用该派生类型的析构函数。
漏洞与风险
在这种情况下,与派生类型相关的动态内存不会得到正确销毁;也就是说,不会调用任何所需析构函数,因此这将导致意外的程序行为。
漏洞代码示例
复制
#define TEXTURE_DATA char
#define TEXTURE_SIZE 512
class Shape {
public:
Shape() {}
~Shape() {}
void setArea(double a) { area = a; }
virtual void Draw();
private:
double area;
};
class Circle: public Shape {
public:
Circle() { texture = (TEXTURE_DATA*)malloc(TEXTURE_SIZE); }
~Circle() { free(texture); }
bool operator!=(Circle &r);
private:
TEXTURE_DATA *texture;
Circle(Circle &r) { texture = strdup(r.texture); }
Circle& operator=(Circle &r) { if (r != *this) texture = strdup(r.texture); return *this; }
};
void foo() {
Shape *newObj = new Circle;
// ... some code ...
delete newObj;
}
“texture”引用的内存不可以在析构函数中解除分配。基类 Shape 中的析构函数未定义为虚拟函数,因此当通过向上转换的基类删除时,不会调用派生类的析构函数,并将导致内存泄漏。
修正代码示例
复制
#define TEXTURE_DATA char
#define TEXTURE_SIZE 512
class Shape {
public:
Shape() {}
virtual ~Shape() {}
void setArea(double a) { area = a; }
virtual void Draw();
private:
double area;
};
class Circle: public Shape {
public:
Circle() { texture = (TEXTURE_DATA*)malloc(TEXTURE_SIZE); }
~Circle() { free(texture); }
bool operator!=(Circle &r);
private:
TEXTURE_DATA *texture;
Circle(Circle &r) { texture = strdup(r.texture); }
Circle& operator=(Circle &r) { if (r != *this) texture = strdup(r.texture); return *this; }
};
void foo() {
Shape *newObj = new Circle;
// ... some code ...
delete newObj;
}
在该修正代码中,第 7 行包含虚拟析构函数。
相关检查器
扩展
此检查器可通过 Klocwork 知识库进行扩展。有关详情,请参阅调整 C/C++ 分析。