我正在执行我的a.out文件。执行后,程序运行一段时间,然后带着消息退出:
**** stack smashing detected ***: ./a.out terminated*
*======= Backtrace: =========*
*/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)Aborted*
可能的原因是什么?我该如何纠正?
我正在执行我的a.out文件。执行后,程序运行一段时间,然后带着消息退出:
**** stack smashing detected ***: ./a.out terminated*
*======= Backtrace: =========*
*/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)Aborted*
可能的原因是什么?我该如何纠正?
当前回答
堆栈损坏通常是由缓冲区溢出引起的。 你可以通过防御性的编程来防御它们。
无论何时访问数组,都要在数组前面加上断言,以确保访问没有越界。例如:
assert(i + 1 < N);
assert(i < N);
a[i + 1] = a[i];
这使您考虑数组边界,并使您考虑在可能的情况下添加测试来触发它们。如果其中一些断言在正常使用期间失败,则将它们转换为常规If。
其他回答
我得到了这个错误,而使用malloc()分配一些内存到一个结构*后,花了一些这个调试代码,我最终使用free()函数来释放分配的内存,随后错误消息消失了:)
可能的原因是什么?我该如何纠正?
一个场景是下面的例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void swap ( char *a , char *b );
void revSTR ( char *const src );
int main ( void ){
char arr[] = "A-B-C-D-E";
revSTR( arr );
printf("ARR = %s\n", arr );
}
void swap ( char *a , char *b ){
char tmp = *a;
*a = *b;
*b = tmp;
}
void revSTR ( char *const src ){
char *start = src;
char *end = start + ( strlen( src ) - 1 );
while ( start < end ){
swap( &( *start ) , &( *end ) );
start++;
end--;
}
}
在这个程序中,你可以反向一个字符串或字符串的一部分,如果你调用reverse()像这样:
reverse( arr + 2 );
如果你决定像这样传递数组的长度:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void swap ( char *a , char *b );
void revSTR ( char *const src, size_t len );
int main ( void ){
char arr[] = "A-B-C-D-E";
size_t len = strlen( arr );
revSTR( arr, len );
printf("ARR = %s\n", arr );
}
void swap ( char *a , char *b ){
char tmp = *a;
*a = *b;
*b = tmp;
}
void revSTR ( char *const src, size_t len ){
char *start = src;
char *end = start + ( len - 1 );
while ( start < end ){
swap( &( *start ) , &( *end ) );
start++;
end--;
}
}
工作也很好。
但是当你这样做的时候:
revSTR( arr + 2, len );
你会得到:
==7125== Command: ./program
==7125==
ARR = A-
*** stack smashing detected ***: ./program terminated
==7125==
==7125== Process terminating with default action of signal 6 (SIGABRT)
==7125== at 0x4E6F428: raise (raise.c:54)
==7125== by 0x4E71029: abort (abort.c:89)
==7125== by 0x4EB17E9: __libc_message (libc_fatal.c:175)
==7125== by 0x4F5311B: __fortify_fail (fortify_fail.c:37)
==7125== by 0x4F530BF: __stack_chk_fail (stack_chk_fail.c:28)
==7125== by 0x400637: main (program.c:14)
这是因为在第一个代码中,arr的长度是在revSTR()中检查的,这很好,但在第二个代码中,你传递的长度:
revSTR( arr + 2, len );
长度现在比你说arr + 2时传递的实际长度要长。
strlen的长度(arr + 2) != strlen (arr)。
这里的Stack Smashing实际上是由gcc用于检测缓冲区溢出错误的保护机制引起的。例如,在下面的代码片段中:
#include <stdio.h>
void func()
{
char array[10];
gets(array);
}
int main(int argc, char **argv)
{
func();
}
编译器(在本例中为gcc)添加了具有已知值的保护变量(称为canaries)。大小大于10的输入字符串会导致该变量损坏,从而导致SIGABRT终止程序。
你可以尝试在编译时使用option -fno-stack-protector禁用gcc的这种保护。在这种情况下,你会得到一个不同的错误,最有可能的分割错误,因为你试图访问一个非法的内存位置。注意-fstack-protector应该在发布版本中始终打开,因为它是一个安全特性。
您可以通过使用调试器运行程序来获得有关溢出点的一些信息。Valgrind不能很好地处理与堆栈相关的错误,但像调试器一样,它可以帮助您确定崩溃的位置和原因。
这意味着您以非法的方式写入堆栈上的某些变量,很可能是缓冲区溢出的结果。
您可以尝试使用valgrind调试问题:
Valgrind发行版 包括六个生产质量工具: 一个内存错误检测器,两个线程 错误检测器,缓存和 分支预测分析器,a 调用图生成缓存分析器, 和一个堆分析器。它还包括 两种实验工具:a 堆/堆栈/全局数组溢出 检测器和SimPoint基本块 向量生成器。它运行在 X86/Linux、 AMD64/Linux、PPC32/Linux、PPC64/Linux、 X86/Darwin (Mac OS X)。