【问题标题】:string overflow detection in CC中的字符串溢出检测
【发布时间】:2010-02-24 01:15:12
【问题描述】:

我们正在使用 DevPartners boundchecker 来检测内存泄漏问题。它做得很好,虽然它没有发现像下面这样的字符串溢出

char szTest [1] = "";

for (i = 0; i < 100; i ++) {

    strcat (szTest, "hi");
}

问题 1:他们有什么办法,我可以让 BoundsChecker 检测到这一点吗?

问题 2:他们是否还有其他工具可以检测到此类问题?

【问题讨论】:

    标签: c string memory buffer-overflow memory-corruption


    【解决方案1】:

    我在我的 devpartner (msvc6.6) (devpartner 7.2.0.372) 中尝试过

    我确认您观察到的行为。 在循环大约 63 次后,我遇到了访问冲突。

    compuware 对此问题有什么看法?

    CppCheck 会检测到这个问题。

    【讨论】:

    • 你联系compuware了吗?
    【解决方案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 这样的宏来控制。

    这种技术的缺点是,如果您有大量现有代码,那么将事情转移到使用新的、更安全的例程可能会是一项繁重的工作。在你摆脱那些被认为是危险的功能之前,它会让你发疯。

    【讨论】:

    • @Michael - 虽然我喜欢这个想法,但一个问题是你不能总是用对 strlX 的调用替换对 strnX 的调用。问题是当源不是 0 终止时可以使用 strn 函数,但 strl 函数无法处理这种情况。
    • 我同意这不是一个完整的解决方案,但总体而言,它对于我参与的一些项目来说效果很好。有几次无法使用 strlX() 函数,但可以使用其他替代方法(通常是 memcpy())。 strlX() 函数并不完美(我已经讨厌目标缓冲区大小不在目标指针之后的事实),但它们通常比不知道大小的函数好目的地是。如果你不喜欢strlX(),那么想出你自己的并不难(就像 MSVC 所做的那样)。
    • 如果你知道缓冲区大小并且它不是大得离谱,那么固定长度的 memcpy 可以比任何 str* 函数快三倍。
    【解决方案3】:

    valgrind 将检测写入过去动态分配的数据,但我认为它不能像您的示例中那样对自动数组执行此操作。如果你使用strcatstrcpy等,你要确保目的地足够大。

    编辑:我是right about valgrind,但有一些希望:

    不幸的是,Memcheck 不对静态或堆栈数组进行边界检查。我们愿意,但不可能以符合 Memcheck 工作方式的合理方式进行。对不起。

    但是,实验工具 Ptrcheck 可以检测到这样的错误。使用 --tool=exp-ptrcheck 选项运行 Valgrind 以尝试它,但请注意它不如 Memcheck 强大。

    我没用过 Ptrcheck。

    【讨论】:

    【解决方案4】:

    您可能会发现您的编译器可以提供帮助。例如,在 Visual Studio 2008 中,检查项目属性 - C/C++ - 代码生成页面。有一个“缓冲区安全检查”选项。

    我的猜测是它保留了一些额外的内存并在其中写入了一个已知序列。如果该序列被修改,则假定缓冲区溢出。不过我不确定——我记得在某处读过这篇文章,但我不确定它是否是关于 VC++ 的。

    【讨论】:

      【解决方案5】:

      鉴于您已经标记了这个 C++,为什么还要使用指向 char 的指针?

      std::stringstream test;
      std::fill_n(std::ostream_iterator<std::string>(test), 100, "hi");
      

      【讨论】:

      • STL 并非在所有平台上都可移植
      • @YeenFei:完全不清楚你所说的“STL”是什么意思。我上面的内容是标准库的必需部分。如果你的编译器有一个糟糕的标准库,以至于这个简单的代码不起作用,你需要找到一个新的(Comeau 做了他们编译器的自定义端口)。
      • @Jerry - 它可能不那么“糟糕”而且更老了。例如VC++ 6 仍在世界的某些角落使用(可能用于与 VB 6 的互操作,可能在世界上无法负担每隔一天升级所有内容的地方,等等)。此外,他可能并不担心“他的编译器”。也许他是在卖给仍在使用 VC++ 6 的人?
      • @Steve314:VC++ 6 将毫无问题地处理该代码。我很确定它会失败,你必须回到 VC++ 4.1 左右——在 VC++ 4.2b 之前,我经常做这样的简单 STL 事情。
      • @Steve314:是的,它确实有字符串流。它肯定有一些错误(尤其是早期,但六个服务包有很大帮助)。我已经用得够多了,最近够了,可以肯定上面的代码可以很好地使用它。
      【解决方案6】:

      如果您启用/RTCs compiler switch,它可能有助于发现此类问题。开启此开关后,测试仅在运行一次strcat 时导致访问冲突。

      另一个有助于解决此类问题的有用实用程序(比堆栈更面向堆但非常有用)是application verifier。它是免费的,可以解决很多与堆溢出相关的问题。

      【讨论】:

      • @Mark Wilkins:感谢您的回答。我正在使用 MSVC 6.0;我启用了 RTCs 标志,但它没有检测到错误。无论如何,我会朝这个方向努力。谢谢。
      【解决方案7】:

      另一种选择:我们的Memory Safety Checker。 我认为它会处理这种情况。

      【讨论】:

        【解决方案8】:

        问题在于,默认情况下,API Validation 子系统未启用,您感兴趣的消息来自那里。

        我不能代表旧版本的 BoundsChecker,但 10.5 版的这个测试没有特别的问题。它报告正确的结果并且 BoundsChecker 本身不会崩溃。然而,测试应用程序确实如此,因为这个特定的测试用例完全破坏了调用堆栈,该调用堆栈导致了测试代码所在的函数,并且一旦该函数终止,应用程序也会这样做。

        结果:1​​00 条关于局部变量写入溢出的消息,以及 99 条关于目标字符串未以空值终止的消息。从技术上讲,第二条消息是不正确的,但 BoundsChecker 仅在目标字符串本身的范围内搜索空终止符,并且在第一次 strcat 调用之后,它的范围内不再包含零字节。

        免责声明:我在 MicroFocus 工作,是一名开发 BoundsChecker 的开发人员。

        【讨论】:

          猜你喜欢
          • 2015-02-09
          • 2013-05-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-10
          • 2022-11-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多