C 无效读/写有时会造成分段错误,有时则不会
示例代码:C 无效读/写有时会造成分段错误,有时则不会,c,linux,segmentation-fault,C,Linux,Segmentation Fault,示例代码: int main () { char b[] = {"abcd"}; char *c = NULL; printf("\nsize: %d\n",sizeof(b)); c = (char *)malloc(sizeof(char) * 3); memcpy(c,b,10); // here invalid read and invalid write printf("\nb: %s\n",b); printf("\nc: %s\n",c); r
int main ()
{
char b[] = {"abcd"};
char *c = NULL;
printf("\nsize: %d\n",sizeof(b));
c = (char *)malloc(sizeof(char) * 3);
memcpy(c,b,10); // here invalid read and invalid write
printf("\nb: %s\n",b);
printf("\nc: %s\n",c);
return 0;
}
在代码中,我做了一些无效读取和无效写入,但这个小程序运行良好,不会创建核心转储
但在我的大库中,每当我进行1字节无效读或无效写时,它总是创建核心转储
问题:
int main ()
{
char b[] = {"abcd"};
char *c = NULL;
printf("\nsize: %d\n",sizeof(b));
c = (char *)malloc(sizeof(char) * 3);
memcpy(c,b,10); // here invalid read and invalid write
printf("\nb: %s\n",b);
printf("\nc: %s\n",c);
return 0;
}
为什么有时我会从无效读/写中获取核心转储,有时我不会获取核心转储?这完全取决于执行无效读/写时覆盖或取消引用的内容。具体地说,如果您覆盖某个被取消引用的指针,例如,一个指针的最高有效字节,那么最终可能会导致某个指针被取消引用到完全不同(并且完全无效)的内存区域
因此,例如,如果堆栈的排列方式使memcpy超过c
的结尾将覆盖b
的一部分,那么当您尝试使用b
作为参数调用printf()
时,它将尝试使用该指针并取消引用以打印字符串。因为它不再是有效的指针,这将导致segfault。但是,由于堆栈排列之类的事情依赖于平台(可能还有编译器),因此在不同的程序中,类似的示例可能看不到相同的行为。您创建了一个3个字符的字符串c
,但您在其上复制了10个字符。这是一个错误
这称为缓冲区溢出:您在不属于您的内存中写入。因此,行为是未定义的。它可能是一个崩溃,它可以正常工作,或者它可以修改您创建的另一个变量
所以最好的办法是为c分配足够的内存来包含b的内容:
c = (char *)malloc(sizeof(char) * (sizeof(b)+1)); // +1 is for the '\0' char that ends every string in c.
2-当您在c
中复制b
时,不要忘了在字符串的末尾加上字符:'\0'
。这在c标准中是强制性的。
所以printf(“%s”,c)代码>知道字符串在哪里结束
3-您将10个字符从b
复制到c
,但b
仅包含5个字符(a、b、c、d和'\0'),因此memcpy
的行为未定义(例如:memcpy可以尝试读取无法读取的内存,…)
您只能复制自己拥有的内存:b
的5个字符
4-我认为定义b
的好方法是:char b=“abcd”代码>或字符b={'a','b','c','d',0}代码>您试图做的基本上是缓冲区溢出&在您的代码示例中更具体地说。只有在某些时候才会看到崩溃的原因取决于您正在访问的内存区域&您是否有访问/写入它的权限(Dan Fego对此做了很好的解释)。我认为Dan Fego提供的示例更多地是关于堆栈溢出的(欢迎更正!)。gcc具有与堆栈上的缓冲区溢出(堆栈崩溃)相关的保护。您可以在以下示例中看到这一点(基于堆栈的溢出):
#include <stdio.h>
#include <string.h>
int main (void)
{
char b[] = { "abcdefghijk"};
char c [8];
memcpy (c, b, sizeof c + 1); // here invalid read and invalid write
printf ("\nsize: %d\n", sizeof b);
printf ("\nc: %s\n", c);
return 0;
}
可以使用gcc中的-fno stack protector
选项禁用此保护。
缓冲区溢出是造成安全漏洞的主要原因之一。不幸的是,像memcpy
这样的函数不会检查这些类型的问题,但是有很多方法可以防止这些类型的问题。
希望这有帮助 +1,你说得对;位于c
的内存位于堆上,而b
位于堆栈上。因此,在这种情况下,你是溢出堆。接得好