【缺陷周话】第22期:错误的内存释放对象
字数 1936 2025-08-18 11:37:57

错误的内存释放对象缺陷分析与防护指南

1. 缺陷概述

错误的内存释放对象(CWE-590: Free of Memory not on the Heap)是指程序尝试释放非动态分配的内存,导致内存数据结构损坏的安全缺陷。这种缺陷可能导致程序崩溃、拒绝服务攻击,在某些情况下甚至可能被利用来修改关键程序变量或执行恶意代码。

2. C/C++内存分配方式

C/C++程序内存分配主要有三种方式:

  1. 静态存储区域分配

    • 存放全局变量和static变量
    • 内存在程序编译时分配
    • 程序运行期间不会被回收
  2. 栈上分配

    • 由编译器自动分配
    • 存放函数参数值和局部变量
    • 函数执行结束时自动释放
    • 注意:alloca()函数是向栈申请内存的
  3. 堆上分配(动态分配)

    • 由程序员手动分配和释放
    • 使用malloc/calloc/realloc分配,free释放
    • 或使用new/new[]分配,delete/delete[]释放

关键点:只有第三种堆上分配的内存需要程序员手动释放,对前两种内存进行手动释放会导致错误的内存释放对象问题。

3. 缺陷危害

错误的内存释放对象可能导致:

  • 程序内存数据结构损坏
  • 程序崩溃
  • 拒绝服务攻击(DoS)
  • 可能被利用修改关键程序变量
  • 可能被利用执行恶意代码

CVE案例(2018-2019):

  • CVE-2018-7554:sam2p中的ReadImage函数无效释放导致DoS
  • CVE-2018-7552:sam2p中的Mapping::DoubleHash::clear函数无效释放导致DoS
  • CVE-2018-7551:sam2p中的MiniPS::delete0函数无效释放导致DoS
  • CVE-2018-15857:xkbcommon中的ExprAppendMultiKeysymList函数无效释放导致解析器崩溃

4. 缺陷代码示例

// 缺陷代码示例
void bad()
{
    char * data;
    data = (char *)alloca(100*sizeof(char)); // 栈上分配内存
    // ... 使用data的代码 ...
    delete [] data; // 错误:尝试释放栈内存
}

问题分析

  • 第2行使用alloca()函数在栈上申请内存
  • 第5行错误地使用delete[]尝试释放栈内存
  • 这会导致"错误的内存释放对象"问题

5. 修复方案

5.1 正确修复代码

// 修复后的代码
void good()
{
    char * data;
    data = new char[100]; // 堆上动态分配内存
    // ... 使用data的代码 ...
    delete [] data; // 正确:释放动态分配的内存
}

修复要点

  • 使用new[]在堆上动态分配内存
  • 使用delete[]正确释放动态分配的内存
  • 确保分配和释放方式匹配(new对应deletenew[]对应delete[]

5.2 其他修复建议

  1. 对于栈内存(如局部变量、alloca分配的内存):

    • 不要手动释放
    • 让编译器自动管理其生命周期
  2. 对于静态存储区域内存(如全局变量、static变量):

    • 不要手动释放
    • 其生命周期与程序相同
  3. 对于动态分配的内存:

    • 确保分配和释放配对使用
    • 使用malloc/calloc/realloc分配的内存使用free释放
    • 使用new分配的内存使用delete释放
    • 使用new[]分配的内存使用delete[]释放

6. 防护最佳实践

  1. 明确内存来源

    • 在释放内存前,确认内存是通过动态分配方式获得的
    • 对于复杂程序结构(如多条件分支),确保释放路径正确
  2. 了解特殊函数行为

    • alloca():在栈上分配内存,不要手动释放
    • realloc():只能用于重新分配由malloc/calloc/realloc分配的内存
      • 错误示例:realloc()的第一个参数指向非动态分配的内存
  3. 代码审查要点

    • 检查所有free/delete/delete[]操作
    • 确认被释放的内存确实来自动态分配
    • 特别注意条件分支中的内存释放操作
  4. 使用静态分析工具

    • 使用如360代码卫士等工具进行自动化检测
    • 配置工具规则检测潜在的错误内存释放
  5. 编码规范建议

    • 统一内存管理策略(如使用RAII、智能指针)
    • 避免混合使用不同内存分配/释放方式
    • 对动态分配的内存添加明确的注释说明

7. 相关CWE条目

  • CWE-590: Free of Memory not on the Heap
  • 相关缺陷:
    • CWE-415: Double Free(双重释放)
    • CWE-416: Use After Free(释放后使用)
    • CWE-762: Mismatched Memory Management Routines(内存管理例程不匹配)

8. 总结

错误的内存释放对象是C/C++程序中常见的内存管理错误,可能导致严重的安全问题。开发人员应当:

  1. 清楚区分不同类型的内存分配方式
  2. 只释放动态分配的内存
  3. 确保分配和释放方式正确匹配
  4. 使用工具辅助检测潜在问题
  5. 遵循良好的内存管理实践

通过遵循这些原则,可以有效避免错误的内存释放对象缺陷,提高程序的稳定性和安全性。

错误的内存释放对象缺陷分析与防护指南 1. 缺陷概述 错误的内存释放对象(CWE-590: Free of Memory not on the Heap)是指程序尝试释放非动态分配的内存,导致内存数据结构损坏的安全缺陷。这种缺陷可能导致程序崩溃、拒绝服务攻击,在某些情况下甚至可能被利用来修改关键程序变量或执行恶意代码。 2. C/C++内存分配方式 C/C++程序内存分配主要有三种方式: 静态存储区域分配 存放全局变量和static变量 内存在程序编译时分配 程序运行期间不会被回收 栈上分配 由编译器自动分配 存放函数参数值和局部变量 函数执行结束时自动释放 注意: alloca() 函数是向栈申请内存的 堆上分配(动态分配) 由程序员手动分配和释放 使用 malloc / calloc / realloc 分配, free 释放 或使用 new / new[] 分配, delete / delete[] 释放 关键点 :只有第三种堆上分配的内存需要程序员手动释放,对前两种内存进行手动释放会导致错误的内存释放对象问题。 3. 缺陷危害 错误的内存释放对象可能导致: 程序内存数据结构损坏 程序崩溃 拒绝服务攻击(DoS) 可能被利用修改关键程序变量 可能被利用执行恶意代码 CVE案例 (2018-2019): CVE-2018-7554:sam2p中的 ReadImage 函数无效释放导致DoS CVE-2018-7552:sam2p中的 Mapping::DoubleHash::clear 函数无效释放导致DoS CVE-2018-7551:sam2p中的 MiniPS::delete0 函数无效释放导致DoS CVE-2018-15857:xkbcommon中的 ExprAppendMultiKeysymList 函数无效释放导致解析器崩溃 4. 缺陷代码示例 问题分析 : 第2行使用 alloca() 函数在栈上申请内存 第5行错误地使用 delete[] 尝试释放栈内存 这会导致"错误的内存释放对象"问题 5. 修复方案 5.1 正确修复代码 修复要点 : 使用 new[] 在堆上动态分配内存 使用 delete[] 正确释放动态分配的内存 确保分配和释放方式匹配( new 对应 delete , new[] 对应 delete[] ) 5.2 其他修复建议 对于栈内存(如局部变量、 alloca 分配的内存): 不要手动释放 让编译器自动管理其生命周期 对于静态存储区域内存(如全局变量、static变量): 不要手动释放 其生命周期与程序相同 对于动态分配的内存: 确保分配和释放配对使用 使用 malloc / calloc / realloc 分配的内存使用 free 释放 使用 new 分配的内存使用 delete 释放 使用 new[] 分配的内存使用 delete[] 释放 6. 防护最佳实践 明确内存来源 : 在释放内存前,确认内存是通过动态分配方式获得的 对于复杂程序结构(如多条件分支),确保释放路径正确 了解特殊函数行为 : alloca() :在栈上分配内存,不要手动释放 realloc() :只能用于重新分配由 malloc / calloc / realloc 分配的内存 错误示例: realloc() 的第一个参数指向非动态分配的内存 代码审查要点 : 检查所有 free / delete / delete[] 操作 确认被释放的内存确实来自动态分配 特别注意条件分支中的内存释放操作 使用静态分析工具 : 使用如360代码卫士等工具进行自动化检测 配置工具规则检测潜在的错误内存释放 编码规范建议 : 统一内存管理策略(如使用RAII、智能指针) 避免混合使用不同内存分配/释放方式 对动态分配的内存添加明确的注释说明 7. 相关CWE条目 CWE-590: Free of Memory not on the Heap 相关缺陷: CWE-415: Double Free(双重释放) CWE-416: Use After Free(释放后使用) CWE-762: Mismatched Memory Management Routines(内存管理例程不匹配) 8. 总结 错误的内存释放对象是C/C++程序中常见的内存管理错误,可能导致严重的安全问题。开发人员应当: 清楚区分不同类型的内存分配方式 只释放动态分配的内存 确保分配和释放方式正确匹配 使用工具辅助检测潜在问题 遵循良好的内存管理实践 通过遵循这些原则,可以有效避免错误的内存释放对象缺陷,提高程序的稳定性和安全性。