如果strncpy将随机数据复制到缓冲区中会怎样?

时间:2019-01-23 16:30:03

标签: 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_buffer中,但是my_string之后的其他123个数据字节也将被复制。这有什么后果吗?缓冲区保留其他数据是否有害?

6 个答案:

答案 0 :(得分:3)

  

但是my_string之后的其他123个字节的数据也会如此

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

  

目标用零填充,直到总共写入了num个字符。 [reference]

这与memcpy相反,后者SELECT EXTRACT(YEAR FROM COMMAND_DATE) AS year, SUM(PRODUCT_PRICE*PRODUCT_QUANTITY) AS gain FROM PRODUCT JOIN COMMAND ON PRODUCT.PRODUCT_ID=COMMAND.PRODUCT_ID GROUP BY year ORDER BY year 要求源和目标都具有足够的大小,以避免未定义的行为。

答案 1 :(得分:3)

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

strncpy(my_buffer, my_string.c_str(), 128);

根据定义,Thsi始终是0终止的字符串,因此请考虑:

  

最多将src指向的字符数组的字符(包括终止的空字符,但不包括跟随空字符的任何字符)复制到dest指向的字符数组。

"hello"之后,您不会从原始字符串中复制任何内容,其余的将是0 s:

  

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

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:2)

根据此处1的strncpy()描述,将以您提供的长度完成复制(对于以null终止的字符串),这样,当字符串的末尾在此位置之前(如本例所示),就完成了复制到此为止,并且不再执行任何复制操作,因此不会复制其余的“ 123字节”,并且复制循环终止

答案 4 :(得分:2)

该问题的其他答案已经解决了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()读取的“额外”内存字节有可能是标记为禁止访问的内存页面的一部分,在这种情况下,尝试从该页面读取可能会导致细分错误。

最后,确实存在不确定行为的错误,那就是您的C ++编译器的优化器被允许以使程序更高效的名义对代码的逻辑进行各种疯狂的修改-和(假设优化程序不是错误的),所有这些优化仍将导致程序按预期运行-只要程序遵守规则并且不调用未定义的行为。也就是说,如果您的程序以任何方式调用未定义的行为,则优化可能会以very difficult to predict or understand的方式应用,从而导致程序中出现异常/意外的行为。因此,通常的规则是,避免像瘟疫这样的不确定行为,因为即使您认为它“应该无害”,也很有可能最终会完成您意想不到的事情要做,然后您将花费很长时间进行痛苦的调试,以尝试了解正在发生的事情。

答案 5 :(得分:0)

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

除了其他答案,请记住,当strncpy字符串长度(不包括NUL)等于给定的缓冲区dst时,src不会NUL终止size缓冲区。以后处理字符串时,应始终执行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;
}

要查看该问题,请使用标志-fsanitize=address进行编译。第二个缓冲区没有被NUL终止!