32

我需要注意哪些strtok不安全的功能(就缓冲区溢出而言)?

对我来说有点奇怪的是strtok_sVisual C++ 中的(这是“安全的”)有一个额外的“上下文”参数,但它看起来在其他方面是相同的......是相同的,还是实际上不同?

4

4 回答 4

30

根据本文档的 strtok_s 部分:

6.7.3.1 strtok_s 函数 strtok_s 函数修复了 strtok 函数中的两个问题:

  1. 新参数 s1max 可防止 strtok_s 存储在被标记的字符串之外。(被划分为标记的字符串既是函数的输入也是函数的输出,因为 strtok_s 将空字符存储到字符串中。)
  2. 一个新参数 ptr 消除了阻止 strtok 重入的静态内部状态(子条款 1.1.12)。(ISO/IEC 9899 函数 wcstok 和 ISO/IEC 9945 (POSIX) 函数 strtok_r 相同地解决了这个问题。)
于 2011-05-14T02:33:00.547 回答
14

没有什么不安全的。您只需要了解它是如何工作的以及如何使用它。编写代码和单元测试后,只需多花几分钟时间即可使用 valgrind 重新运行单元测试,以确保您在内存范围内运行。手册页说明了一切:

错误

使用这些功能时要小心。如果您确实使用它们,请注意:

  • 这些函数修改它们的第一个参数。
  • 这些函数不能用于常量字符串。
  • 定界字符的标识丢失。
  • strtok()函数在解析时使用静态缓冲区,因此它不是线程安全的。strtok_r()如果这对您很重要,请使用。
于 2011-05-14T02:22:48.120 回答
8

strtok 在 Visual C++ 中是安全的(但在其他地方没有),因为它使用线程本地存储来保存调用之间的状态。在其他任何地方,全局变量都用于保存 strtok() 状态。

然而,即使在 VC++ 中,strtok 是线程安全的,它仍然有点奇怪——你不能同时在同一个线程中的不同字符串上使用 strtok()s。例如,这不会很好地工作:

     token = strtok( string, seps );
     while(token)
     {
        printf("token=%s\n", token)
        token2 = strtok(string2, seps);
        while(token2)  
        {
            printf("token2=%s", token2);
            token2 = strtok( NULL, seps );
        }
        token = strtok( NULL, seps );
     }

它无法正常工作的原因 - 对于每个线程,只有单个状态可以保存在线程本地存储中,这里需要 2 个状态 - 第一个字符串和第二个字符串。因此,虽然 strtok 在 VC++ 中是线程安全的,但它不是可重入的。

strtok_s (或其他地方的 strtok_r )提供了什么 - 一个明确的状态,并且 strtok 变得可重入。

于 2011-05-14T02:52:14.147 回答
0

如果您没有正确以 null 结尾的字符串;你最终会出现缓冲区溢出。另请注意(这是我很难学到的东西) strtok 似乎并不关心内部字符串。具有“hello”/“world”的 IE 将解析“hello”/“world”,而“hello/world”将解析为“hello world”。请注意,它在 / 上拆分并忽略了它在括号内的事实。

于 2011-05-14T02:36:50.437 回答