不可重复释放资源
2.12 ID_doubleFree
重复释放资源会导致标准未定义的行为。
由于多种原因,动态资源管理机制可能难以甚至无法预先判断资源是否已被回收,一旦重复释放资源,会直接破坏程序结构,导致不可预期的错误。
在特殊情况下,重复释放内存或写入已被释放的内存会为攻击者构造的恶意指令提供执行机会,严重威胁系统安全。
示例:
void* p = malloc(n);
free(p);
void* q = malloc(n);
free(p); // Non-compliant, double free, undefined behavior
例中指针 p 被连续释放两次,导致未定义的行为,这是一种复制粘贴错误,另一种导致这种问题的常见原因是资源在异常处理流程中被释放,而在正常处理流程中被再次释放。
规则 ID_missingResetNull 提供了一种解决方法。在 C++ 代码中,应使资源接受类对象的管理,避免分散地分配回收操作,可以更有效地解决这种问题,可参见 ID_ownerlessResource 的进一步介绍。
又如:
class T {
char* p;
public:
T(const char* s): p(strdup(s)) {}
~T() { free(p); }
};
例中类 T 在构造函数中分配资源,在析构函数中释放资源,但缺少合理的拷贝构造函数和复制赋值运算符,复制对象仍然会导致重复释放:
void foo() {
T a("xyz");
T b = a; // Shallow copy
....
} // Double free
例中对象 b 由对象 a 复制而成,a 和 b 在析构时会重复释放同一成员指针,所以存在任一拷贝、移动、析构相关的函数时,应定义所有相关函数,可参见 ID_violateRuleOfFive 的进一步讨论。
相关
ID_missingResetNull
ID_ownerlessResource
ID_missingCopyConstructor
ID_missingCopyAssignOperator
ID_violateRuleOfFive
依据
ISO/IEC 9899:1999 7.20.3.2(2)-undefined
ISO/IEC 9899:2011 7.22.3.3(2)-undefined
ISO/IEC 14882:2003 3.7.3.2(4)-undefined
ISO/IEC 14882:2011 3.7.4.2(4)-undefined