C++ 如果strncpy将随机数据复制到缓冲区中会发生什么?

C++ 如果strncpy将随机数据复制到缓冲区中会发生什么?,c++,C++,假设您有一个char缓冲区,要将std::string复制到该缓冲区中。即使缓冲区有足够的大小,在字符串范围之外将额外数据复制到缓冲区是否会产生后果 范例 std::string my_string = "hello"; char my_buffer[128]; memset(my_buffer, 0, 128); strncpy(my_buffer, my_string.c_str(), 128); 因此,“hello”会被复制到my\u buffer,但my\u string之后的123

假设您有一个
char
缓冲区,要将
std::string
复制到该缓冲区中。即使缓冲区有足够的大小,在字符串范围之外将额外数据复制到缓冲区是否会产生后果

范例

std::string my_string = "hello";
char my_buffer[128];
memset(my_buffer, 0, 128);

strncpy(my_buffer, my_string.c_str(), 128);
因此,“hello”会被复制到
my\u buffer
,但
my\u string
之后的123个其他字节的数据也会被复制。这有什么后果吗?缓冲区保存其他数据是否有害

但是在
my_string

这种假设是不正确的:
strncpy
注意源字符串的空终止,从不读取空终止符。剩余的数据将设置为
'\0'
字符:

目标用零填充,直到总共写入num个字符


这与
memcpy
相反,后者要求源和目标都具有足够的大小,以避免未定义的行为。

好的,让我们假设您想要的是:

strncpy(my_buffer, my_string.c_str(), 128);
根据定义,Thsi始终是以0结尾的字符串,因此考虑:

将src指向的字符数组(包括终止的空字符,但不包括空字符后面的任何字符)的最多个计数字符复制到dest指向的字符数组

在原始字符串的“hello”之后,您将不会得到任何复制内容,其余内容将是
0
s:

如果从src复制终止的空字符后,未达到计数,则会将其他空字符写入dest,直到写入计数字符总数为止


假设您的意思是复制该数据,因为您当前的代码将以空终止符结尾

从本质上说,没有。那里的任何数据都将仅用作字符串数据,因此,除非您随后尝试对该备用数据执行一些奇怪的操作(尝试将函数指针指向它并执行它等等),否则它基本上是安全的


问题在于最初将随机数据复制到原始字符串的末尾,这可能会溢出到您无权访问的受保护数据中,并引发segfault(不可访问内存异常)

根据此处的strncpy()说明,复制的长度将达到您提供的长度,对于以null结尾的字符串,因此,当字符串的结尾出现在前面时,就像在本例中一样,复制到它上面,不再复制,因此其余的“123字节”不会被复制,复制循环终止。

这个问题的其他答案已经解决了使用
strncpy()时会发生什么。
(也就是说,它将正确地复制字符串,因为它在0-终止符字节处停止),因此,可能更符合问题的意图的是,如果改为使用这个怎么办

memcpy(my_buffer, my_string.c_str(), 128);
在这种情况下,函数(
memcpy()
)不知道以0结尾的字符串语义,总是盲目地将128个字节(从
my_string.c_str()
返回的地址开始)复制到地址
my_buffer
。前6个字节(大约6个)这些字节中的一个将来自
my_string
的内部缓冲区,其余字节将来自此后内存中的任何内容

所以问题是,接下来会发生什么?这个
memcpy()
调用从“神秘内存”中读取,而您不知道它的用途,因此您这样做是在调用未定义的行为,因此原则上任何事情都可能发生。实际上,可能的结果是,您的缓冲区将包含读取的任何字节的副本(尽管您可能不会注意到它们,因为您将使用的字符串函数看起来无论如何都不会超过数组中的0/终止符字节)

不过,读取
memcpy()
的“额外”内存字节很可能是标记为禁止访问的内存页的一部分,在这种情况下,尝试从该页读取可能会导致分段错误


最后,有一个未定义的行为的真正的BugBoO,即C++编译器的优化器被允许对程序的逻辑进行各种疯狂的修改,以使程序更有效——并且(假设优化器不是BGGY)所有这些优化仍然会导致程序按预期运行——只要程序遵循规则并且不调用未定义的行为。也就是说,如果您的程序以任何方式调用未定义的行为,则可能会以某种方式应用优化,从而导致程序中出现奇怪/意外的行为。So一般规则是,避免像瘟疫这样未定义的行为,因为即使你认为它“应该是无害的”,很有可能它最终会做一些你不希望它做的事情,然后在你试图弄清楚发生了什么的过程中,你会经历一个漫长而痛苦的调试过程。

函数
strncpy
将所有内容复制到NUL字符或指定的
大小。就是这样

除了其他答案,请记住当
src
字符串长度(不包括NUL)等于给定缓冲区的
大小时,
strncpy
不会终止
dst
缓冲区。您应该始终执行类似
my_buffer[127]=0
以防止以后处理字符串时缓冲区溢出。在
libbsd
中定义了
strlcpy
始终NUL终止缓冲区

查看此代码段:

#include <string.h>

int main(int argc, char ** argv)
{
    char buf[8];
    char *str = "deadbeef";

    strlcpy(buf, str, sizeof(buf));
    printf("%s\n", buf);

    strncpy(buf, str, sizeof(buf));
    printf("%s\n", buf);
    return 0;
}
#包括
int main(int argc,字符**argv)
{
char-buf[8];
char*str=“死牛肉”;
strlcpy(buf,str,sizeof(buf));
printf(“%s\n”,buf);
strncpy(buf,str,sizeof(buf));
printf(“%s\n”,buf);
返回0;
}
若要查看问题,请使用标志
-fsanitize=address
编译它。第二个缓冲区不是NUL终止的!

s