问题在这里:
strncpy(buffer,str,strlen(str));
^^^^^^^^^^^
如果字符串大于目标缓冲区的长度,strncpy仍将其复制过来。您将字符串的字符数作为要复制的数字而不是缓冲区的大小。正确的方法如下:
strncpy(buffer,str, sizeof(buff) - 1);
buffer[sizeof(buff) - 1] = '\0';
这是将复制的数据量限制为缓冲区的实际大小减去空终止符的数量。然后,我们将缓冲区中的最后一个字节设置为空字符,以此作为附加保护措施。原因是因为strncpy将复制最多n个字节,包括终止空值,如果strlen(str)<len-1。串。
希望这可以帮助。
编辑:经过进一步检查并从其他人输入,该函数的可能编码如下:
int func (char *str)
{
char buffer[100];
unsigned short size = sizeof(buffer);
unsigned short len = strlen(str);
if (len > size - 1) return(-1);
memcpy(buffer, str, len + 1);
buffer[size - 1] = '\0';
return(0);
}
由于我们已经知道了字符串的长度,因此可以使用memcpy将字符串从str引用的位置复制到缓冲区中。请注意,在strlen(3)的手册页上(在FreeBSD 9.3系统上),声明如下:
The strlen() function returns the number of characters that precede the
terminating NUL character. The strnlen() function returns either the
same result as strlen() or maxlen, whichever is smaller.
我将其解释为字符串的长度不包含null。这就是为什么我复制len + 1个字节以包含null的原因,并且测试检查以确保长度<缓冲区的大小-2。减去1,因为缓冲区从位置0开始,然后减去另一个,以确保有空间为空。
编辑:事实证明,某些东西的大小以1开头,而访问以0开头,所以之前的-2是不正确的,因为它对于大于98字节的任何内容都会返回错误,但应该大于99字节。
编辑:尽管关于无符号短路的答案通常是正确的,因为可以表示的最大长度为65,535个字符,但这并不重要,因为如果字符串长于该长度,则该值将环绕。就像拿了75,231(即0x000125DF)并屏蔽掉了前16位一样,您得到了9695(0x000025DF)。我看到的唯一问题是长度超过65,535的前100个字符,因为长度检查将允许复制,但是在所有情况下,它最多只能复制字符串的前100个字符,并且null终止字符串。因此,即使存在环绕问题,缓冲区仍然不会溢出。
这本身可能会或可能不会带来安全风险,具体取决于字符串的内容及其用途。如果只是可读的纯文本,那么通常就没有问题。您只会得到一个截断的字符串。但是,如果它是URL或SQL命令序列之类的内容,则可能会出现问题。