我们正在使用 DevPartners boundchecker 来检测内存泄漏问题。它做得很好,虽然它没有发现字符串溢出,如下所示
char szTest [1] = "";
for (i = 0; i < 100; i ++) {
strcat (szTest, "hi");
}
问题 1:他们有什么办法,我可以让 BoundsChecker 检测到这一点吗?
问题 2:他们是否有任何其他工具可以检测到此类问题?
我们正在使用 DevPartners boundchecker 来检测内存泄漏问题。它做得很好,虽然它没有发现字符串溢出,如下所示
char szTest [1] = "";
for (i = 0; i < 100; i ++) {
strcat (szTest, "hi");
}
问题 1:他们有什么办法,我可以让 BoundsChecker 检测到这一点吗?
问题 2:他们是否有任何其他工具可以检测到此类问题?
一种选择是简单地禁止使用没有关于目标缓冲区信息的字符串函数。通用包含的标题中的一组如下宏可能会有所帮助:
#define strcpy strcpy_is_banned_use_strlcpy
#define strcat strcat_is_banned_use_strlcat
#define strncpy strncpy_is_banned_use_strlcpy
#define strncat strncat_is_banned_use_strlcat
#define sprintf sprintf_is_banned_use_snprintf
因此,任何尝试使用“禁止”例程都会导致链接器错误,该错误还会告诉您应该改用什么。MSVC 做了类似的事情,可以使用宏来控制,比如_CRT_SECURE_NO_DEPRECATE
.
这种技术的缺点是,如果您有大量现有代码,那么将事情转移到使用新的、更安全的例程可能是一项巨大的苦差事。在你摆脱被认为是危险的功能之前,它会让你发疯。
valgrind
将检测写入过去动态分配的数据,但我认为它不能像您的示例中那样对自动数组执行此操作。如果您使用strcat
,strcpy
等,则必须确保目标足够大。
编辑:关于 valgrind我是对的,但有一些希望:
不幸的是,Memcheck 不对静态或堆栈数组进行边界检查。我们愿意,但不可能以符合 Memcheck 工作方式的合理方式进行。对不起。
但是,实验工具 Ptrcheck 可以检测到这样的错误。运行 Valgrind 并
--tool=exp-ptrcheck
选择尝试它,但要注意它不如 Memcheck 强大。
我没有使用过 Ptrcheck。
我在我的 devpartner (msvc6.6) (devpartner 7.2.0.372) 中尝试过
我确认您观察到的行为。在循环大约 63 次后,我遇到了访问冲突。
compuware 对这个问题有什么看法?
CppCheck将检测到此问题。
您可能会发现您的编译器可以提供帮助。例如,在 Visual Studio 2008 中,检查项目属性 - C/C++ - 代码生成页面。有一个“缓冲区安全检查”选项。
我的猜测是它保留了一些额外的内存并在其中写入了一个已知序列。如果该序列被修改,则假定缓冲区溢出。不过,我不确定——我记得在某处读过这个,但我不确定它是否是关于 VC++ 的。
既然你已经标记了这个 C++,为什么还要使用指向 char 的指针呢?
std::stringstream test;
std::fill_n(std::ostream_iterator<std::string>(test), 100, "hi");
如果您启用/RTCs 编译器开关,它可能有助于发现此类问题。启用此开关后,测试strcat
仅在运行一次时会导致访问冲突。
另一个有助于解决此类问题的有用实用程序(比堆栈更面向堆但非常有用)是应用程序验证器。它是免费的,可以解决很多与堆溢出相关的问题。
另一种选择:我们的内存安全检查器。我想它会处理这个案子。
问题是默认情况下,API Validation 子系统未启用,您感兴趣的消息来自那里。
我不能代表旧版本的 BoundsChecker,但 10.5 版的这个测试没有特别的问题。它报告正确的结果并且 BoundsChecker 本身不会崩溃。然而,测试应用程序确实如此,因为这个特定的测试用例完全破坏了调用堆栈,该调用堆栈导致了测试代码所在的函数,并且一旦该函数终止,应用程序也会这样做。
结果:100 条关于局部变量写入溢出的消息,以及 99 条关于目标字符串未以空值终止的消息。从技术上讲,第二条消息是不正确的,但 BoundsChecker 仅在目标字符串本身的范围内搜索空终止,并且在第一次 strcat 调用之后,它不再在其范围内包含零字节。
免责声明:我在 MicroFocus 作为 BoundsChecker 的开发人员工作。