gcc 什么是堆栈粉碎(C)?

ecbunoof  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(256)

编码:

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);

输出量:
字符串-1长度= 7,字符串 *a =字符串A字符串B

侦测到堆栈毁损*:/T02已终止

已中止(核心转储)
我不明白为什么它会显示 stack smashing?什么是 *stack smashing?或者是我的编译器的错误?

7cwmlq89

7cwmlq891#

好的,堆栈粉碎堆栈缓冲区溢出是这里要讨论的一个相当详细的主题,您可以参考this wiki article了解更多信息。
回到这里显示的代码,问题是,数组a不够大,无法容纳最终的连接结果。
因此,通过说

while((c = *b++)) *++st = c;

你实际上是在访问超出内存范围的内存,这会调用undefined behavior。这就是你遇到“堆栈崩溃”问题的原因,因为你试图访问的内存不属于你的进程。
要解决这个问题,你需要确保数组a包含足够的空间来容纳第一个和第二个串接在一起的 string

ngynwnxp

ngynwnxp2#

堆栈破坏意味着你在函数的局部变量存储空间之外(在大多数系统和编程语言中,这个区域被称为“堆栈”)写了东西(“破坏”过去/通过)。你也可能发现这种类型的错误被称为“堆栈溢出”和/或“堆栈下溢”。
在你的代码中,C可能是把a指向的字符串放到堆栈上。在你的例子中,导致堆栈“粉碎”的地方是当你把st递增到原来的a指针之外,并写到它所指向的地方时,你正在写的地方超出了C编译器保证为分配给a的原始字符串保留的区域。
无论何时,只要你在C语言中已经正确“保留”的内存区域之外进行写入,那就是“未定义的行为”(这只是意味着C语言/标准没有说明会发生什么):通常,你最终会覆盖程序内存中的其他内容(程序通常会将其他信息放在堆栈中变量的旁边,比如返回地址和其他内部细节),或者你的程序试图在操作系统“允许”它使用的内存之外进行写入。无论哪种方式,程序通常都会中断,有时会立即中断,而且很明显(例如,具有“分段错误”错误),有时以非常隐蔽的方式直到很久以后才变得明显。
在这种情况下,编译器会在编译程序时使用特殊的保护机制来检测这个问题,因此程序会退出并显示错误信息。如果编译器没有这样做,程序会尝试继续运行,但可能会以做错误的事情和/或崩溃而告终。
解决方案可以归结为需要显式告诉代码有足够的内存来存储组合后的字符串。可以通过显式指定“a”数组的长度,使其对两个字符串都足够长来实现这一点,但这通常只足以满足简单的使用,即您事先知道需要多少空间。对于通用的解决方案,计算出完整的内存大小后,您可以使用malloc之类的函数从操作系统中获取指向新内存块的指针,该内存块具有您需要的大小(只要记住在从malloc和类似的函数中获得的指针上调用free,一旦完成了它们)。

相关问题