CL.FMM

使用不相符的函数释放内存

类级别检查器会根据 Scott Meyer 的高效 C++ 规则类构造来生成建议。

CL.FMM 基于 Scott Meyer 的第 5 项:使用 new和 delete 的相应用法中的相同形式。此检查器可查找使用一种机制分配并使用另一种机制释放的内存;例如,将 C 和 C++ 内存管理函数混合,或将标量和矢量内存管理函数混合。

漏洞与风险

当内存使用 C++ new 运算符进行分配,并使用 C 运行时函数 free() 解除分配时,此检查器将暴露出最典型的问题。在这种情况下,无论该内存中可能驻留有何种对象,都不会调用 C++ 析构函数,因此尽管完全可以解除分配该内存,但执行此操作时将不包含程序员的预期语义。

此外,如果不同的 C 和 C++ 实现使用不同的底层堆,混用函数很容易导致内存泄漏和堆损坏。

漏洞代码示例

复制
    class C{
      Data *data;
    public
      C(){  data = new Data[2];}
      ~C(){  delete data;}
    };

在此示例中,构造函数使用数组版本的运算符 new,析构函数使用标量 delete。即使构造函数中分配的所有内存都将在析构函数中释放,也只会调用 Data 的一个析构函数。在本例中,对于使用一种机制 (new) 分配并使用另一种机制 (delete) 释放的内存,CL.FMM 已找到一个典型示例。

修正代码示例

复制
    #include <iostream>
    using namespace std;
    class Data{
    public
      Data(){ cout << "Constructing Data at " << (void *)this << endl;}
      ~Data() {cout << "Destroying Data at " << (void *)this << endl;}
    };
//...
    int main(){
      C c;
      return 1;
    }
Output: 

Constructing Data at 0x602018
Constructing Data at 0x602019
Destroying Data at 0x602019

此外,new/delete 的某些实现可能导致运行时错误。要解决此问题,请使用以下释放对象的相应方法:

复制
    class C{
//...
      ~C(){  delete[] data;}
//...
    };

扩展

此检查器可通过 Klocwork 知识库进行扩展。有关详情,请参阅调整 C/C++ 分析。