为什么strtok()被认为是不安全的?

Meh*_*dad 28 c security strtok

strtok我需要注意哪些特性是不安全的(在缓冲区溢出方面)?

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

Hei*_*bug 24

根据本文档的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完全解决了这个问题.)

  • 请注意,`strtok_s()`的这个规范来自ISO/IEC 9899:2011的(可选)附件K,其定义不同于[`strtok_s()`的Microsoft规范(https://msdn.microsoft) .COM/EN-US /库/ ftsafwz3.aspx). (2认同)

Bob*_*Bob 13

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

BUGS

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

  • 这些函数修改了第一个参数.
  • 这些函数不能用于常量字符串.
  • 分隔字符的标识丢失了.
  • strtok()函数在解析时使用静态缓冲区,因此它不是线程安全的.使用strtok_r(),如果这对你很重要.

  • 它可能不是*你*谁在另一个线程中运行`strtok`.它可能是你的插件.或者,您的代码可能会在一个库中使用,该库在主应用程序的另一个线程中运行,该应用程序也使用`strtok`.或者你可能只是在你忘记那里有一个'strtok`电话后的某一天决定让你的代码多线程化. (6认同)

Vla*_*oub 5

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

但是,即使在strtok是线程安全的VC ++中,它仍然有点怪异-您不能同时在同一线程中的不同字符串上使用strtok()。例如,这不能很好地工作:

     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 );
     }
Run Code Online (Sandbox Code Playgroud)

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

strtok_s(或其他任何地方的strtok_r)提供的内容-显式状态,并且该strtok成为可重入的。