strtok
中哪些特性是不安全的(涉及缓冲区溢出),我需要注意什么?
对我来说有点奇怪的是,Visual C++中“安全”的strtok_s
有一个额外的“context”参数,但在其他方面它看起来是相同的... 它是相同的吗,还是实际上有所不同?
strtok
中哪些特性是不安全的(涉及缓冲区溢出),我需要注意什么?
对我来说有点奇怪的是,Visual C++中“安全”的strtok_s
有一个额外的“context”参数,但在其他方面它看起来是相同的... 它是相同的吗,还是实际上有所不同?
6.7.3.1 strtok_s 函数解决了 strtok 函数中的两个问题:
- 新增参数 s1max,防止 strtok_s 在令牌化的字符串外部存储。(被划分为标记的字符串既是函数的输入又是输出,因为 strtok_s 将空字符存储到该字符串中。)
- 新增参数 ptr,消除了静态内部状态,防止 strtok 不可重入(子条款 1.1.12)。 (ISO/IEC 9899 函数 wcstok 和 ISO/IEC 9945(POSIX)函数 strtok_r 以相同方式解决此问题。)
strtok_s()
的此规范来自 ISO/IEC 9899:2011 的(可选)K附录,并且其定义与 Microsoft 的 strtok_s()
规范不同。 - Jonathan Leffler这并不会有任何安全隐患。您只需要了解它的工作原理以及如何使用它。在编写代码和单元测试之后,只需要额外几分钟时间就可以使用 valgrind 重新运行单元测试,以确保您在内存边界内操作。man 手册已经说明了一切:
漏洞
在使用这些函数时要小心。如果您确实要使用它们,请注意以下事项:
- 这些函数会修改它们的第一个参数。
- 这些函数不能用于常量字符串。
- 定界字符的标识丢失了。
strtok()
函数在解析时使用静态缓冲区,因此不是线程安全的。如果这很重要,请使用strtok_r()
。
strtok_s
进行了一些小的编辑... 你知道它和普通的 strtok
有什么不同吗? - user541686strtok
。这可能是由你的插件引起的。或者你的代码被用于在另一个线程中运行 strtok
的库中,而主应用程序也使用了该库。或者某天你决定将你的代码改为多线程,在那之后你已经忘记了其中有一个 strtok
调用。 - Gabestrtok在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 );
}
为什么 strtok 不适用 - 因为每个线程只能在线程本地存储中保存单个状态,而这里需要两个状态 - 一个是第一个字符串的状态,另一个是第二个字符串的状态。因此,尽管 VC++ 中的 strtok 是线程安全的,但它不是可重入的。
strtok_s(或其他任何地方的 strtok_r)提供了一个显式状态,因此 strtok 变得可重入。