我需要注意哪些strtok
不安全的功能(就缓冲区溢出而言)?
对我来说有点奇怪的是strtok_s
Visual C++ 中的(这是“安全的”)有一个额外的“上下文”参数,但它看起来在其他方面是相同的......是相同的,还是实际上不同?
根据本文档的 strtok_s 部分:
6.7.3.1 strtok_s 函数 strtok_s 函数修复了 strtok 函数中的两个问题:
- 新参数 s1max 可防止 strtok_s 存储在被标记的字符串之外。(被划分为标记的字符串既是函数的输入也是函数的输出,因为 strtok_s 将空字符存储到字符串中。)
- 一个新参数 ptr 消除了阻止 strtok 重入的静态内部状态(子条款 1.1.12)。(ISO/IEC 9899 函数 wcstok 和 ISO/IEC 9945 (POSIX) 函数 strtok_r 相同地解决了这个问题。)
没有什么不安全的。您只需要了解它是如何工作的以及如何使用它。编写代码和单元测试后,只需多花几分钟时间即可使用 valgrind 重新运行单元测试,以确保您在内存范围内运行。手册页说明了一切:
错误
使用这些功能时要小心。如果您确实使用它们,请注意:
- 这些函数修改它们的第一个参数。
- 这些函数不能用于常量字符串。
- 定界字符的标识丢失。
- 该
strtok()
函数在解析时使用静态缓冲区,因此它不是线程安全的。strtok_r()
如果这对您很重要,请使用。
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 变得可重入。
如果您没有正确以 null 结尾的字符串;你最终会出现缓冲区溢出。另请注意(这是我很难学到的东西) strtok 似乎并不关心内部字符串。具有“hello”/“world”的 IE 将解析“hello”/“world”,而“hello/world”将解析为“hello world”。请注意,它在 / 上拆分并忽略了它在括号内的事实。