繁体   English   中英

为什么在执行memcpy时会检测到堆栈粉碎?

[英]Why am I getting stack smashing detected when doing memcpy?

    char test[]={"abcde"};
    char* test1={"xyz"};
    memcpy(test+5,test1,3);
    printf("%s",test);

我试图了解memcpy的工作原理,这是我到目前为止编写的示例。 这将输出作为abcdexyz&vjunkcharacters

和以下消息。

*** stack smashing detected ***: ./testcode terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb7656dd5]
/lib/i386-linux-gnu/libc.so.6(+0xffd8a)[0xb7656d8a]
./testcode[0x8048797]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75704d3]
./testcode[0x80483a1]

这种情况背后的原因是什么?

根本原因:

char test[]={"abcde"};

分配足够的内存空间以仅存储5字符。

memcpy(test+5,test1,3);  

test1指向的数据复制到分配的内存空间之外。
从技术上讲,以这种方式写超出已分配内存的边界是Undefined Behavior ,这意味着可能发生任何事情。

实际发生了什么?

实际发生的是memcpy字符复制到分配的内存之外,从而覆盖了NULL终止符,该终止符标志着字符数组test结束。
此外, printftest起始地址读取内容,直到遇到随机NULL从而打印出垃圾字符。

解:
在执行memcpy之前,应确保目标缓冲区已分配足够的内存。 由于您打算复制3字符,因此目标缓冲区test应至少:

5 + 3 + 1 byte for NULL terminator = 9 bytes

您可以简单地使用:

char test[9]="abcde";

您的memcpy调用确实粉碎了堆栈,这就是为什么您看到该消息的原因。 您正在复制test数组末尾的数据,这是不允许的。

无需额外的缓冲

实际上,最直接的方法是避免复制:

#include <string.h>
#include <stdio.h>

int main() {
  char a[] = "abcde";
  char b[] = "xyz";
  printf("%s%s\n", a, b);
  return 0;
}

用memcpy做

memcpy将src n个字节复制到dest 您需要自己正确跟踪复制字符串的空终止字节。

#include <string.h>
#include <stdio.h>

int main() {
  char a[] = "abcde";
  char b[] = "xyz";

  /* note that both strings add a '\0' termination */
  char c[sizeof(a) + sizeof(b) - 1];

  /* copy the content of a to c */
  memcpy(c, a, sizeof(a));

  /* copy the content of b to where a ends (concatenate the strings) */
  memcpy(c + sizeof(a) - 1, b, sizeof(b));

  /* note that the '\0' termination of the string is necessary to let
   * functions like printf know where the string is over 
   */
  printf(c);

  return 0;
}

用strcpy和strcat来做

请注意,使用memcpy时,有很多陷阱可以正确处理字符串的空终止。 为了简化字符串的此过程,您应该执行以下操作。

如果这些确实是字符串而不是随机字节,则应使用标准库的字符串函数。 这是完成的方式。

#include <string.h>
#include <stdio.h>

int main() {
  char a[] = "abcde";
  char b[] = "xyz";

  /* note that both strings add a '\0' termination */
  char c[sizeof(a) + sizeof(b) - 1];

  /* copy the content of a to c */
  strcpy(c, a);

  /* copy the content of b to where a ends (concatenate the strings) */
  strcat(c, b);

  /* note that the '\0' termination of the string is necessary to let
   * functions like printf know where the string is over 
   */
  printf(c);

  return 0;
}

知道琴弦的大小

关于知道缓冲区的大小,请注意,通常不能简单地执行sizeof(a_string) 如果将字符数组传递给函数,则它会衰减为指针,并且此操作不再返回数组的预期大小,而是返回指针的大小。

对于字符串,您需要发出strlen(a_string)来扫描空终止符的出现并返回字符串的长度(不包括终止符)。

对于包含随机数据的字符缓冲区(或需要写入的空缓冲区),此方法也不起作用。 您始终需要将缓冲区的大小作为附加参数传递。

memcpy(test+5,test1,3); 用简单的话做以下事情:

“从数组“ test”的最后一个元素开始,然后从数组“ test1”复制3个字符到那里”,这基本上写了2个字符,超出了数组“ test”的长度。

因此,如果您只想玩'memcpy',请定义第三个数组:

char test[]="abcde";
char test1[]="xyz";
char output[sizeof(test) + sizeof(test1)];
memset(output, 0, sizeof(output));
memcpy(&output[0],test,5);
memcpy(&output[5],test1,3);
printf("%s",output);

变量test1在内存中为4个字符,3个加上结束字符串终止符。 尝试这个:

char test[9]={"abcde"};
char* test1={"xyz"};
memcpy(test+5,test1,4);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM