
2.5.9 strlen()
strlen()函数没有特别的缺陷,但由于底层字符串表示的弱点,它的操作可能被破坏。strlen()函数接受一个指向一个字符数组的指针,并返回终止空字符之前的字符数量。如果字符数组不是正确地以空字符结尾的,strlen()函数可能会返回一个错误的超大的数值,使用它时,就可能会导致漏洞。此外,如果传入一个非以空字符结尾的字符串,strlen()函数可以越过动态分配的数组的边界读取,并导致程序停止运行。
C99。C99没有定义strlen()的替代函数。因此,在开发严格符合C99的程序时,在将字符串传递给strlen()函数之前,有必要确保它们是正确地以空值结尾的,从而使函数的结果在预期范围内。
C11附录K边界检查接口。C11提供了一种替代strlen()的函数—带边界检查的strnlen_s()函数。另外,对于一个字符指针,strnlen_s()函数接受一个最大大小。如果字符串的长度超过指定的最大大小,那么返回最大大小,而不是字符串的实际长度。strnlen_s()函数没有运行时约束。这种运行时约束的缺乏,以及以一个空指针或一个未终止字符串参数返回的值,使得strnlen_s()在优雅地处理这些异常数据的算法中非常有用。
有一种误解,认为带边界检查的函数总是天生就比相应的传统函数更安全且传统的函数不应该被使用。教条地把对C99函数的调用替换为对带边界检查的函数的调用,这会导致令人费解的代码,而不比使用传统的函数更安全,并且效率低下,难以阅读。例如,要获得一个字符串字面值的长度,教条地使用带边界检查的函数会导致下面这样的愚蠢代码。
#define S "foo" size_t n = strnlen_s(S, sizeof S);
在处理可能缺乏结尾的空字符的字符串时,strnlen_s()函数很有用。该函数返回不含空终止字符的数组中的元素的数量,致使许多计算更直接。
因为C11附录K中定义的带边界检查的函数,不产生不带结束符的字符串,所以在大多数情况下,把对strlen()函数的调用替换为对strnlen_s()的调用是不必要的。
strnlen_s()函数与POSIX的函数strnlen()是相同的。