0%

【安全编码】内存管理

本章总结《C和C++安全编码》中内存管理相关的内容。

常见的C++内存管理错误

1 未能正确检查分配失败

下面是一个错误的检测分配内存是否成功的例子:

1
2
3
4
5
6
7
int *ip = new int;
if(ip) {
...
}
else {
...
}

由于 new 在内存分配失败时会抛出异常,因此上面的检验条件总为真,else 分支不会被执行,可以使用 std::nothrow 来使 new 在分配失败时不抛出异常,而是返回一个空指针:

1
T* p2 = new(std::nothrow) T;

2 不正确配对的内存管理函数

不要混合使用 C 和 C++ 的内存分配运算符,比如使用 free() 来释放 new 分配的内存,因为这样会导致内存泄露。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void test_memory_new_delete_unpaired()
{
int* ip = new int(12);
free(ip); // 错误,应使用delete ip

int* ip2 = static_cast<int*>(malloc(sizeof(int)));
*ip2 = 12;
delete ip2; // 错误,应使用free(ip2)

// new和delete操作符用于分配和释放单个对象
Widget* w = new Widget();
delete w;

// new[]和delete[]操作符用于分配和释放数组
Widget* w2 = new Widget[10];
delete [] w2;

// operator new()分配原始内存,但不调用构造函数
std::string* sp = static_cast<std::string*>(operator new(sizeof(std::string)));
//delete sp; // 错误
operator delete (sp); // 正确
}

更多关于 new、delete 和内存泄漏的内容可以查看之前的笔记:【知识汇总】C++ 相关

3 多次释放内存

为了防止多次释放内存或内存泄漏,在存放指针的容器中使用智能指针,更多关于内存泄漏、野指针和智能指针的内容可以查看之前的笔记:【知识汇总】C++ 相关

4 释放函数抛出异常

如果释放函数通过抛出一个异常终止,那么该行为是未定义的。释放函数,包括全局的operator delete()函数,它的数组形式与其用户定义的重载,经常在销毁类类型的对象时被调用,其中包括作为某个异常结果的栈解开。允许栈解开期间抛出异常导致逃避了调用std::terminate,而导致std::abort函数调用的默认效果。这种情况可能被利用为一种拒绝服务攻击的机会。因此,释放函数必须避免抛出异常

---- 本文结束 知识又增加了亿点点!----

文章版权声明 1、博客名称:LycTechStack
2、博客网址:https://lz328.github.io/LycTechStack.github.io/
3、本博客的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系博主进行删除处理。
4、本博客所有文章版权归博主所有,如需转载请标明出处。