我被要求维护一个充满内存泄漏的大型 C++ 代码库。在四处寻找时,我发现我们有很多导致泄漏的缓冲区溢出(它是如何变得如此糟糕,我不想知道)。
我决定先删除缓冲区溢出,从危险函数开始。哪些 C/C++ 函数最常被错误使用并可能导致缓冲区溢出?
对于用于帮助查找缓冲区溢出的编译器和/或工具,我创建了另一个处理此问题的问题
我被要求维护一个充满内存泄漏的大型 C++ 代码库。在四处寻找时,我发现我们有很多导致泄漏的缓冲区溢出(它是如何变得如此糟糕,我不想知道)。
我决定先删除缓冲区溢出,从危险函数开始。哪些 C/C++ 函数最常被错误使用并可能导致缓冲区溢出?
对于用于帮助查找缓冲区溢出的编译器和/或工具,我创建了另一个处理此问题的问题
通常,任何不检查参数边界的函数。一个列表将是
您应该使用大小有限的版本,如 stncpy、strncat、fgets 等。然后在给出大小限制时要小心;考虑到 '\0' 终止字符串。
此外,数组未在 C 或 C++ 中进行绑定检查。以下示例将导致错误。一错就走
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。它不会找到所有这些,但它是一种减少所需手动工作量的廉价方法。
以下是我发现的一些危险功能:
以下链接应让您全面了解 C++ 中的安全功能(后置“_s”以解决溢出等问题的安全功能):http: //msdn.microsoft.com/en-us/library/8ef0s5kh( VS.80).aspx
编辑:此链接包含已被替换的特定功能:http: //msdn.microsoft.com/en-us/library/wd3wzwts (VS.80).aspx
编辑:我应该提到这些是 Microsoft 方法,但该链接对于识别被视为危险信号的功能仍然很有用。
不幸的是,任何数组都可能导致缓冲区溢出:
uint32_t foo[3];
foo[3] = WALKED_OFF_END_OF_ARRAY;
就功能而言, sprintf 将愉快地离开缓冲区的末端。可以用 snprintf 代替。
Memcpy() 是另一个危险的。
任何访问数组的循环都是一个危险点,因为超出数组末尾没有停止。
内存泄漏是由分配内存而不是释放它引起的。构造函数和析构函数应该是另一个重要的审查点,后者确保释放任何分配的内存。
您使用的是哪个版本的视觉工作室?在 2008 年启用所有警告的情况下,您提到的所有功能(以及更多)都会警告您它们已被弃用。
也许您可以检查所有警告是否已打开并让编译器为您完成繁重的工作?
附带说明一下,出色的编写安全代码很好地解释了一些旧功能的不同缺陷。
在我工作的代码库上,我遇到了同样的问题。我的建议:警惕任何看起来像 str*() 和 mem*() 的 C 函数。还要警惕任何带有指向缓冲区的指针的东西,没有长度。因为看起来你有机会使用 C++,所以在最糟糕的情况下,我会尝试使用 C++ 容器来做一些事情:向量、字符串、地图等。这些让你的生活变得更轻松。
此外,自动化问题检测工具也很棒。如果你可以使用 valgrind,我会推荐它。此外,Rational Purify 非常强大,虽然并不便宜。
C 中的另一个问题是“strncpy()”函数。许多人没有意识到返回一个非空终止的字符串是免费的。
基本上,任何接受指针并写入它的东西,而不检查长度。所以像 strcpy()、sprintf() 等。