什么是堆栈粉碎(C)?

Gon*_*lez 5 c stack-overflow gcc stack-smash

码:

int str_join(char *a,  const char *b) {
   int sz =0; 
   while(*a++) sz++;  
   char *st = a -1, c;  
   *st = (char) 32;
   while((c = *b++)) *++st = c;  
   *++st = 0;
   return sz;
}

....

char a[] = "StringA"; 
printf("string-1 length = %d, String a = %s\n", str_join(&a[0],"StringB"), a);
Run Code Online (Sandbox Code Playgroud)

输出:

string-1 length = 7,char*a = StringA StringB

***堆栈粉碎检测****:/ T02终止

中止(核心倾倒)

我不明白为什么它会显示堆栈粉碎?什么是*堆栈粉碎?或者是我编译器的错误?

mtr*_*eur 11

堆栈粉碎意味着您已经在函数的存储空间之外写入(“粉碎”过去/通过)局部变量(在大多数系统和编程语言中,该区域称为“堆栈”)。您还可能会发现这种类型的错误称为“堆栈溢出”和/或“堆栈下溢”。

在您的代码中,C 可能会将 指向的字符串a放入堆栈中。在你的情况下,导致堆栈“崩溃”的地方是当你增加st超出原始a指针并写入它指向的位置时,你正在C编译器保证为分配给的原始字符串保留的区域之外写入a

每当你在 C 中已经正确“保留”的内存区域之外写入时,这就是“未定义的行为”(这只是意味着 C 语言/标准没有说明会发生什么):通常,你最终会覆盖其他内容您的程序的内存(程序通常将其他信息放在堆栈上的变量旁边,例如返回地址和其他内部详细信息),或者您的程序尝试在操作系统“允许”它使用的内存之外进行写入。无论哪种方式,程序通常都会中断,有时会立即且明显地中断(例如,出现“分段错误”错误),有时会以非常隐蔽的方式中断,直到很久以后才变得明显。

在这种情况下,您的编译器正在构建具有特殊保护的程序来检测此问题,因此您的程序会退出并显示错误消息。如果编译器没有这样做,您的程序将尝试继续运行,除非它最终可能会做错误的事情和/或崩溃。

解决方案归结为需要明确告诉您的代码为组合字符串提供足够的内存。您可以通过显式指定“a”数组的长度足以容纳两个字符串来实现此目的,但这通常仅足以满足您提前知道需要多少空间的简单用途。对于通用解决方案,您可以使用一个函数,例如在malloc计算出完整大小后,从操作系统获取指向新内存块的指针,该内存块具有您需要/想要的大小(只需记住在完成后调用free从中获得的指针和类似的函数即可)。malloc


Sou*_*osh 7

好吧,堆栈粉碎堆栈缓冲区溢出是一个相当详细的主题,这里要讨论,你可以参考这篇wiki文章了解更多信息.

来到这里显示的代码,问题是,你的数组a不够大,无法保存最终的连接结果.

因此,通过说

 while((c = *b++)) *++st = c;
Run Code Online (Sandbox Code Playgroud)

你本质上是访问绑定内存,调用未定义的行为.这就是你得到"堆栈粉碎"问题的原因,因为你试图访问不属于你的进程的内存.

要解决此问题,您需要确保该数组a包含足够的空间来容纳第一个和第二个字符串连接在一起.简而言之,您必须提供更大的目标阵列.