2011-05-14 46 views
25

strtok的哪些功能是不安全的(就缓冲区溢出而言),我需要注意什么?为什么strtok()被认为是不安全的?

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

+1

也许是因为strtok的两个参数都是指向char的指针,所以strtok可能不会达到溢出任何本地缓冲区的任何终结符字符? – Heisenbug 2011-05-14 02:21:41

+0

@ 0verbose:嗯......但是对于所有的C字符串都不是这样吗? – Mehrdad 2011-05-14 02:22:58

+0

你可以看看实现:http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/string/strtok.c?rev=1.6&content-type=text/x-cvsweb-markup 。我也看看。 – Heisenbug 2011-05-14 02:28:03

回答

23

this document的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相同的解决这个问题 )
+0

+1我没有看到该文档,似乎正好解释了答案。 :) – Mehrdad 2011-05-14 02:37:35

+1

请注意,这个'strtok_s()'的规范来自ISO/IEC 9899:2011附录K(可选),其定义与['strtok_s()'](https:// msdn.microsoft.com/en-us/library/ftsafwz3.aspx)。 – 2017-09-30 21:20:45

11

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

BUGS

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

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

我做了一个未成年人编辑关于'strtok_s' ......你碰巧知道它有什么不同吗? – Mehrdad 2011-05-14 02:25:23

+0

我不熟悉那个,但听起来像strtok_r。如果你同时标记两个或更多的字符串,那么你需要其中的一个。如果你只处理一个,那么就没有必要使用它。 – Bob 2011-05-14 02:35:44

+0

啊好的,+1谢谢! – Mehrdad 2011-05-14 02:38:45

0

如果你没有正确空结尾的字符串;你会以缓冲区溢出结束。另外请注意(这是我学到了很难的东西)strtok似乎并不关心内部字符串。 I.E.有“你好”/“世界”将解析“你好”/“世界”,而“你好/世界”将解析为“你好世界”。请注意,它在/上分裂并且忽略它在括号内的事实。

4

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变为可重入。

相关问题