【缺陷周话】第31期:错误的内存释放
字数 1615 2025-08-18 11:38:28
错误的内存释放方法 - 代码安全缺陷详解
1. 错误的内存释放方法概述
在C/C++编程中,内存管理是一个核心且容易出错的部分。错误的内存释放方法指的是内存申请和释放方式不匹配的情况,主要包括:
- C语言中:使用
malloc()/calloc()/realloc()申请但用delete释放 - C++中:使用
new申请但用free()释放 - C++中:使用
new[]申请但用delete释放(或相反)
这种不匹配会导致未定义行为,可能引发内存泄漏、程序崩溃或更严重的安全问题。
2. 危害分析
错误的内存释放方法可能导致:
- 内存泄漏:部分内存无法被正确释放
- 堆损坏:破坏堆管理数据结构
- 程序崩溃:立即或延迟性的程序异常终止
- 安全漏洞:可能被利用进行攻击
根据《Effective C++(第二版)》条目5指出:"如果错误地释放对象中的元素,可能造成整个对象、甚至整个堆上的内存结构都发生损坏"。
3. 实际漏洞案例
2018-2019年CVE中记录的相关漏洞:
| CVE编号 | 受影响软件 | 问题描述 |
|---|---|---|
| CVE-2018-14948 | dilawar sound(2017-11-27及之前版本) | wav-file.cc文件中存在new[]/delete不匹配 |
| CVE-2018-14947 | PDF2JSON 0.69 | XmlFonts.cc文件中XmlFontAccu::CSStyle函数存在new[]/delete不匹配 |
| CVE-2018-14946 | PDF2JSON 0.69 | ImgOutputDev.cc文件中HtmlString类存在malloc/delete不匹配 |
4. 示例代码分析
4.1 缺陷代码示例
// 源自Samate Juliet Test Suite for C/C++ v1.3
// 文件名: CWE762_Mismatched_Memory_Management_Routines__new_array_delete_char_01.cpp
void bad()
{
char * data;
/* 使用new[]分配内存 */
data = new char[100];
/* 错误: 使用delete而非delete[]释放 */
delete data;
}
问题分析:
- 第5行使用
new[]分配了字符数组 - 第7行错误地使用
delete而非delete[]释放 - 这种不匹配会导致未定义行为
4.2 修复代码
void good()
{
char * data;
/* 使用new[]分配内存 */
data = new char[100];
/* 正确: 使用匹配的delete[]释放 */
delete [] data;
}
修复要点:
- 保持分配(
new[])和释放(delete[])方法一致 - 使用正确的数组释放语法
5. 检测方法
使用静态代码分析工具可以有效地检测这类问题:
-
代码卫士检测结果:
- 缺陷代码:检测出"错误的内存释放方法",等级为"中"
- 修复代码:不再报告该缺陷
-
人工检查要点:
- 检查所有内存分配点
- 跟踪对应的释放操作
- 验证分配和释放方法是否匹配
6. 最佳实践建议
为避免错误的内存释放方法,建议:
-
编码规范:
- 明确团队的内存管理规范
- 对每个
new/new[]立即编写对应的delete/delete[]
-
代码审查:
- 将内存分配/释放匹配性作为代码审查重点
- 特别关注跨函数/跨文件的内存管理
-
工具辅助:
- 使用静态分析工具进行自动化检测
- 在CI/CD流程中加入内存检查环节
-
现代C++实践:
- 优先使用智能指针(
unique_ptr,shared_ptr) - 使用容器类而非裸指针管理数组
- 尽量减少显式的
new/delete操作
- 优先使用智能指针(
7. 扩展知识
-
内存管理函数对应关系:
分配函数 释放函数 malloc/calloc/realloc free new delete new[] delete[] -
底层机制差异:
new/delete会调用构造函数/析构函数new[]会存储数组大小信息供delete[]使用- 混用会导致内存布局解释错误
-
跨语言问题:
- 避免在C++中使用C的内存管理函数
- 模块接口处明确内存管理责任
通过遵循这些原则和实践,可以显著减少因内存释放方法错误导致的问题,提高代码的健壮性和安全性。