为什么strtok()被认为是不安全的?
strtok
什么特性是不安全的(就缓冲区溢出而言)我需要注意的是什么?
对我来说strtok_s
是,在Visual C ++中的strtok_s
(这是“安全的”)有一个额外的“上下文”参数,但它看起来在其他方面是相同的…是一样的,还是实际上是不同的?
根据本文档的strtok_s部分:
6.7.3.1 strtok_s函数strtok_s函数修复了strtok函数中的两个问题:
- 一个新的参数s1max防止strtok_s被存储在被标记化的string之外。 (被分成标记的string既是函数的input又是输出,因为strtok_s将空字符存储到string中。)
- 一个新的参数ptr消除了静态内部状态,防止strtok被重入(子条款1.1.12)。 (ISO / IEC 9899函数wcstok和ISO / IEC 9945(POSIX)函数strtok_r同样解决了这个问题。)
没有什么不安全的。 你只需要了解它是如何工作的,以及如何使用它。 在编写代码和unit testing之后,用valgrind重新运行unit testing只需要几分钟的时间,以确保您正在使用内存边界。 手册页说明了一切:
BUGS
使用这些function时要小心。 如果你确实使用它们,请注意:
- 这些函数修改他们的第一个参数
- 这些函数不能用于常量string。
- 划界angular色的身份已经丢失。
strtok()
函数在parsing时使用了一个静态缓冲区,所以它不是线程安全的。 使用strtok_r()
如果这对你很重要。
strtok在Visual C ++中是安全的(但没有其他地方),因为它使用线程本地存储来保存其调用之间的状态。 在其他地方,全局variables用于保存strtok()状态。
但是,即使在VC ++中,strtok也是线程安全的,但它仍然有点奇怪 – 你不能同时在同一个线程的不同string中使用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个状态 – 第一个string和第二个string。 所以虽然strtok是VC ++线程安全的,但它不是可重入的。
什么strtok_s(或其他地方的strtok_r)提供 – 一个明确的状态,并与该strtok成为可重入。
如果你没有一个正确的空string终止; 你将最终在缓冲区溢出。 另外请注意(这是我学到了很难的东西)strtok似乎并不关心内部string。 具有“hello”/“world”的IE将parsing“hello”/“world”,而“hello / world”parsing为“hello world”。 请注意,它在/上分裂,忽略了它在括号内的事实。