简体   繁体   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);

I'm trying to grasp how exactly memcpy works and this is the example I've written so far. 我试图了解memcpy的工作原理,这是我到目前为止编写的示例。 This gives output as abcdexyz&vjunkcharacters 这将输出作为abcdexyz&vjunkcharacters

and the following message. 和以下消息。

*** 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]

What are the reasons behind this situation? 这种情况背后的原因是什么?

Root Cause: 根本原因:

char test[]={"abcde"};

Allocates enough memory space to store 5 characters only. 分配足够的内存空间以仅存储5字符。

memcpy(test+5,test1,3);  

Copies the data pointed by test1 beyond the allocated memory space. test1指向的数据复制到分配的内存空间之外。
Technically, writing beyond the bounds of an allocated memory in this fashion is Undefined Behavior , which means anything can happen. 从技术上讲,以这种方式写超出已分配内存的边界是Undefined Behavior ,这意味着可能发生任何事情。

What actually happens? 实际发生了什么?

What actually happens here is memcpy copies characters beyond the allocated memory thus overwritting the NULL terminator which marks ends of your character array test . 实际发生的是memcpy字符复制到分配的内存之外,从而覆盖了NULL终止符,该终止符标志着字符数组test结束。
Further, printf reads the contents from starting address of test till it encounters a random NULL thus printing out junk characters. 此外, printftest起始地址读取内容,直到遇到随机NULL从而打印出垃圾字符。

Solution: 解:
You should ensure that destination buffer has enough memory allocated before you perform the memcpy . 在执行memcpy之前,应确保目标缓冲区已分配足够的内存。 Since you intend to copy 3 characters, Your destination buffer test should be atleast: 由于您打算复制3字符,因此目标缓冲区test应至少:

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

You can simply use: 您可以简单地使用:

char test[9]="abcde";

Your memcpy call does smash the stack, which is why you see that message. 您的memcpy调用确实粉碎了堆栈,这就是为什么您看到该消息的原因。 You're copying data past the end of your test array, which isn't allowed. 您正在复制test数组末尾的数据,这是不允许的。

Doing it without an additional buffer 无需额外的缓冲

The most straight-forward approach, indeed, would be to avoid the copy: 实际上,最直接的方法是避免复制:

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

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

Doing it with memcpy 用memcpy做

memcpy copies n bytes from src to dest . memcpy将src n个字节复制到dest You need to keep track of copying null termination bytes of the strings correctly yourself. 您需要自己正确跟踪复制字符串的空终止字节。

#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;
}

Doing it with strcpy and strcat 用strcpy和strcat来做

Note that there's a lot of pitfalls dealing correctly with the null termination of the strings when using memcpy. 请注意,使用memcpy时,有很多陷阱可以正确处理字符串的空终止。 To simplify this procedure for strings you should do the following. 为了简化字符串的此过程,您应该执行以下操作。

If these are indeed strings and not random bytes you should stick to the string functions of the standard library. 如果这些确实是字符串而不是随机字节,则应使用标准库的字符串函数。 This is how it's done. 这是完成的方式。

#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;
}

On knowing the size of the strings 知道琴弦的大小

Concerning knowing the size of the buffer, note that you can usually not simply do sizeof(a_string) . 关于知道缓冲区的大小,请注意,通常不能简单地执行sizeof(a_string) If you pass a character array to a function it decays to a pointer and this operation no longer returns the expected size of the array but the size of the pointer. 如果将字符数组传递给函数,则它会衰减为指针,并且此操作不再返回数组的预期大小,而是返回指针的大小。

For strings you need to issue strlen(a_string) which scans for the occurance of the null termination and returns the length of the string (not including the termination). 对于字符串,您需要发出strlen(a_string)来扫描空终止符的出现并返回字符串的长度(不包括终止符)。

As for character buffers containing random data (or empty buffers that need to be written to) this approach doesn't work either. 对于包含随机数据的字符缓冲区(或需要写入的空缓冲区),此方法也不起作用。 You always need to pass the size of the buffer as an additional parameter. 您始终需要将缓冲区的大小作为附加参数传递。

The line memcpy(test+5,test1,3); memcpy(test+5,test1,3); does the following in plain words: 用简单的话做以下事情:

"start at the last element of array "test" and copy 3 characters from array "test1" to there", which basically writes 2 characters beyond the length of the array 'test'. “从数组“ test”的最后一个元素开始,然后从数组“ test1”复制3个字符到那里”,这基本上写了2个字符,超出了数组“ test”的长度。

So if you just want to play around with 'memcpy' define a 3rd array: 因此,如果您只想玩'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);

Variable test1 is in memory 4 chars, 3 plus the ending string terminator. 变量test1在内存中为4个字符,3个加上结束字符串终止符。 Try this: 尝试这个:

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