我实现了一个递归算法,该算法运行大约1730次递归,然后使用神秘的SIGSEGV崩溃。我尝试了我的gdb并获得了以下输出:
Program received signal SIGSEGV, Segmentation fault.
0x000000000040b7da in Town::get_cur_capacity (this=0x61efe0) at ./solver/Darstellung.cpp:54
54 return left_over_capacity;
(gdb) print 0x61efe0
$1 = 6418400
(gdb) print *0x61efe0
Cannot access memory at address 0x61efe0
(gdb) print this
$2 = (const Town * const) 0x61efe0
(gdb)
如何调试器确实知道它应该是const Town指针但是无法访问内存以给我转储?我非常确定此方法中没有错误,因为它在崩溃前使用了几千次,就像程序中的其他所有功能一样。这是否与操作系统相关的问题有可能吗?我使用的是Linux Ubuntu 64-Bit。
我的简化算法:
bool solveproblem(ptr_to_model) {
if( way_one(ptr_to_model) )
return true;
if(way_two(ptr_to_model) )
return true;
if( check_if_solved)
return true;
return false;
}
bool way_one(ptr_to_model) {
for(go_through_current_problem_configuration) {
if(check_stuff) {
ptr_to_model->execute_partial_solution(...); //adds another problem configuration to the stack within the model
if(solveproblem(ptr_to_model))
return true;
ptr_to_model->redo_last_step();
}
}
return false;
}
bool way_two(...) {
/*basicly the same as way one*/
}
bool check_if_solve(...) {
if(problem_solved)
return true;
else
return false;
}
该模型与名称类似,它表示算法通过在其堆栈上推送一个新的“层”时所做的所有步骤,这是一个由旧版本构成的修改(快速简化)问题,考虑到部分算法评估的解决方案。希望我把它缩小到可以理解的范围。
答案 0 :(得分:4)
如果你的递归深度为1700级,那么你就会超越堆栈并破坏一个很容易导致这种崩溃的调用参数,这并不令人难以置信。
如果您使用g ++,请尝试添加-fstack-protector-all
以查看它是否有助于您获得更好的诊断。
编辑:另一个指标是,如果你在gdb中的回溯变成圆形或者没有导致任何地方:这是一个强烈的指示,表明堆栈已经损坏。
在回应评论时,没有一种可靠的方法可以确定某些内容是堆栈溢出还是“更正常”的堆损坏。显然,如果可用,valgrind总是一个可靠的内存错误选项。您可以在shell中使用ulimit
或以编程方式(我相信)setrlimit
来配置堆栈限制。请注意,存在硬上限,并且通常最好将递归更改为更少堆栈滥用而不是增加堆栈大小。
答案 1 :(得分:0)
你在堆栈上传递的参数有多大?在那个深度,如果你为8M堆栈传递大约5k,你可能会溢出。这对堆栈变量来说相当大,但可能。或者,您可能通过写入堆栈中存储的缓冲区的末尾(通常是字符串缓冲区)来粉碎堆栈。你在return
崩溃的事实表明这是一种可能性。