我被要求维护一个充满内存泄漏的大型C++代码库。在研究时,我发现我们有很多导致内存泄漏的缓冲区溢出(我不想知道它是如何变得如此糟糕的)。
我已经决定首先消除缓冲区溢出,从危险函数开始。哪些C/C++函数最容易被不正确使用并可能导致缓冲区溢出?
对于编译器和/或用于帮助查找缓冲区溢出的工具,我创建了另一个问题来处理这个问题
我被要求维护一个充满内存泄漏的大型C++代码库。在研究时,我发现我们有很多导致内存泄漏的缓冲区溢出(我不想知道它是如何变得如此糟糕的)。
我已经决定首先消除缓冲区溢出,从危险函数开始。哪些C/C++函数最容易被不正确使用并可能导致缓冲区溢出?
对于编译器和/或用于帮助查找缓冲区溢出的工具,我创建了另一个问题来处理这个问题
一般来说,任何不检查参数边界的函数都有风险。以下是其中一些
应该使用带有大小限制版本的函数,例如stncpy、strncat、fgets等。在给出大小限制时要小心,考虑字符串末尾的'\0'。
C或C++中也没有对数组进行边界检查。下面这个例子会导致错误。请参见off by one error
int foo[3];
foo[3] = WALKED_OFF_END_OF_ARRAY;
编辑:复制了@MrValdez和@Denton Gentry的答案。
Valgrind是你的新朋友。
valgrind --tool=memcheck --leak-check=full ./a.out
(注:该命令用于检查内存泄漏和其他内存错误)恐怕问题的开始就错了。它假设缓冲区溢出发生在其他函数中。根据我的经验,最常见的原因是operator ++,或者缺少operator !=。
找到一批这样的问题的最佳解决方案是在Visual Studio 2005/8中使用/GS。它不会找到所有问题,但这是一种减少手动工作量的廉价方法。
下面是一些我发现的危险函数:
不幸的是,任何数组都可能导致缓冲区溢出:
uint32_t foo[3];
foo[3] = WALKED_OFF_END_OF_ARRAY;
就功能而言,sprintf 可能会超出缓冲区的末尾。可以用 snprintf 替代。
Memcpy()是另一个危险的函数。
任何访问数组的循环都是一个危险点,因为没有停止越过数组末端的机制。
内存泄漏是由于分配内存后未释放造成的。构造函数和析构函数应该是另一个强烈审核点,后者确保任何分配的内存都被释放。
strncpy
是不安全的?此外,strtok
也是线程不安全和有风险的。+1 - legends2k