[英]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
结束。
此外, printf
从test
起始地址读取内容,直到遇到随机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.