我正在调试崩溃,我看到以下行为 -
当我将 GDB 附加到进程并执行信息寄存器时,我看到 esp 的以下值 -
esp 0xfd2475d0 0xfd2475d0
在对崩溃的代码进行反汇编时,我发现它正在存储到堆栈指针指向的内存中 -
81c886a: c7 04 24 2c f9 8a 0c movl $0xc8af92c,(%esp)
如果我在
/proc/<PID>/maps
中查看映射文件,我会看到堆栈地址范围为 -
fff39000-fff59000 rwxp 7ffffffde000 00:00 0 [stack]
显然,GDB中
ESP 0xfd2475d0
的值与maps文件中的堆栈地址不同步。
这可能是崩溃的原因吗?我认为这应该是因为我收到 SIGSEGV。另外,我该如何解决这个问题?
是的,这显然是分段错误的原因。不抛出它实际上是非常不明智的,因为英特尔架构支持分配单独的代码、数据和堆栈段——并且所有内存访问(基址寄存器== ebp或esp)都隐式地通过堆栈段。
因为编译器将使用不同的基址寄存器(以及不同的隐式段寄存器)来读取任何其他任意指针,这缩小了堆栈寄存器损坏的搜索范围。
更罕见的可能性是堆栈粉碎,即。访问当前函数作用域中局部变量以外的其他堆栈元素——在这种特殊情况下会破坏调用者的堆栈/帧指针。
void foo(int *p) {
int a[2];
a[4] = p;
}
更有可能的选择是过度分配。
void foo() {
double too_big[6000000]; // this would be located at 0xfd......
int a; // this would be located at 0xfff3f000 ...
}