我正在尝试了解使用strnlen
的正确方法是什么,以便即使考虑到边缘情况也可以安全地使用它。
例如,以非空终止的字符串作为输入。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
void* data = malloc(5);
size_t len = strnlen((const char*)data, 10);
printf("len = %zu\n", len);
return 0;
}
如果我期望一个最大大小为10
的字符串,但是该字符串在这10个字符中不包含空字符,strnlen
将读取越界字节(输入指针可能指向分配的堆)数据)。这种行为是不确定的吗?如果是,是否有一种方法可以安全地使用strnlen
计算字符串的长度,而这种长度考虑了这种情况,并且不会导致未定义的行为?
答案 0 :(得分:5)
为了安全地使用strnlen
,您需要
自己跟踪输入缓冲区的大小(在您的情况下为5),并传递 that 作为第二个参数, not 大于该数字
确保输入的指针不是NULL
。
确保另一个线程未将其写入缓冲区。
从形式上讲,您不需要初始化缓冲区的内容,因为从概念上讲,该函数将读取缓冲区,就好像它们是char
类型一样。
答案 1 :(得分:1)
此代码很可能会调用undefined behavior。
malloc
返回的字节具有不确定的值。如果在返回的5个字节中没有空字节,则strnlen
将读取超过这些字节的值,因为它最多传递了10个字节,读取超过分配的内存末尾将引发未定义的行为。
仅读取返回的字节,但是应该 not 未定义。尽管不确定的值可以包含陷阱表示,但是strnlen
使用char *
读取字节,并且字符类型 not 没有陷阱表示,因此这些值只是未指定并读取它们是安全的。
如果传递给strnlen
的值不大于分配的内存大小,则使用它是安全的。
答案 2 :(得分:0)
由于数据的实际长度为5,并且您很可能没有在其中的'\ 0',它将开始读取未分配的内存(从data [5]开始),这可能有点不愉快。 / p>