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

时间:2011-05-14 02:18:24

标签: c security strtok

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

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

4 个答案:

答案 0 :(得分:24)

根据this document的strtok_s部分:

  

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

     
      
  1. 新参数s1max阻止strtok_s存储在   字符串被标记化。 (字符串   分为代币是一种   输入和输出函数,因为   strtok_s将空字符存储到   字符串。)
  2.   
  3. 新参数ptr消除了静态内部状态   防止strtok重入   (第1.1.12条)。 (ISO / IEC 9899   功能wcstok和ISO / IEC 9945   (POSIX)函数strtok_r解决了这个问题   问题完全相同。)
  4.   

答案 1 :(得分:12)

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

  

<强> BUGS

     

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

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

答案 2 :(得分:5)

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

然而即使在VC ++中,strtok是线程安全的,它仍然有点奇怪 - 你不能同时在同一个线程中的不同字符串上使用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 );
     }

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

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

答案 3 :(得分:0)

如果没有正确的空终止字符串;你将最终陷入缓冲区溢出。还要注意(这是我学到的东西)strtok似乎并不关心内部字符串。 I.E.拥有“hello”/“world”将解析“hello”/“world”,而“hello / world”将解析为“hello world”。请注意,它会拆分/并忽略它在括号内的事实。