【问题标题】:what is stack smashing (C)?什么是堆栈粉碎(C)?
【发布时间】:2016-11-04 06:23:13
【问题描述】:

代码:

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

输出:

string-1 长度 = 7, char *a = StringA StringB

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

中止(核心转储)

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

【问题讨论】:

标签: c gcc stack-overflow stack-smash


【解决方案1】:

嗯,堆栈粉碎堆栈缓冲区溢出是一个比较详细的话题要在这里讨论,您可以参考this wiki article了解更多信息。

来到这里显示的代码,问题是,您的数组a 不够大,无法容纳最终的连接结果。

因此,通过说

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

您实际上是在访问调用undefined behavior 的越界内存。这就是您遇到“堆栈粉碎”问题的原因,因为您尝试访问不属于您的进程的内存。

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

【讨论】:

    【解决方案2】:

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

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

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

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

    解决方案归结为需要明确告诉您的代码为您的组合字符串提供足够的内存。您可以通过显式指定“a”数组的长度来做到这一点,使其对两个字符串都足够长,但这通常仅适用于您事先知道需要多少空间的简单用途。对于通用解决方案,您可以使用malloc 之类的函数从操作系统中获取指向新内存块的指针,该内存块具有您需要/想要的大小,一旦您计算出完整大小将如何成为(只要记住在你从 malloc 获得的指针上调用 free 以及完成它们后的类似函数)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-18
      • 1970-01-01
      相关资源
      最近更新 更多