我为一个核心设置了一个gdb会话,它表明在读取一个指针的成员时,指针的取消引用中存在一个分段错误。指针的值为非空。我假设这意味着进程无法访问内存地址。如何从核心的死后gdb会话中获取这些信息?
例如,给定以下程序:
#include <iostream>
using namespace std;
int
main(int argc, char* argv[])
{
int *ptr = new int(5);
cout << "I can access it here: " << *ptr << endl;
delete ptr;
cout << "But I shouldn't do so here: " << *ptr << endl;
return 0;
}
如果我用gdb调试这个程序:
$ g++ -g -Wall test.cc -o test
$ gdb ./test
(gdb) b 13
...
Breakpoint 1 at 0x400943: file test.cc, line 13.
(gdb) run
Starting program: /usr/home/nfs/bneradt/test/test
I can access it here: 5
Breakpoint 1, main (argc=1, argv=0x7fffffffe348) at test.cc:13
13 cout << "But I shouldn't do so here: " << *ptr << endl;
(gdb)
我可以从ptr获得什么样的记忆信息?我能确定ptr指向释放的内存吗?由于在内核中我正在调试(不是在上面的玩具测试二进制程序中),我得到了一个seg错误取消引用--也就是说,从指针读取,而不是写入指针,我想原来的内存位置被分页了,因此不是进程访问内存吗?我可以从gdb会话中确定这一点吗?
发布于 2016-12-13 22:19:00
gdb没有动态分配的概念,也不知道释放的内存。它可以判断地址是否映射到进程地址空间:
gdb> info files
gdb> maintenance info sections
但是,由于您的程序已经与SIGSEGV崩溃,您已经知道它试图访问未映射的地址。
其他工具可以检测对已释放内存的访问。valgrind
通常是您的朋友,但不是用于死后调试的。您需要在valgrind
下运行该程序,以了解其行为。
当取消引用指针时,分段错误很少意味着指针指向已释放的内存。通常情况下,被重用和重写的是驻留在释放内存中的指针本身。所以
int** ptrarr = new int*[5];
ptrarr[3] = new int(5);
// later
delete [] ptrarr;
// later still after many memory allocations
int* ptr = ptrarr[3]; // ptrarr points to freed memory; UB but no segfault
// ptr contains a seemingly random value
int num = *ptr; // possible segfault
从非仪器可执行文件的死后转储中提取此类信息是非常困难的。您需要熟悉malloc
和new
的内部工作,能够跟踪它们的内部数据结构,并手动绘制它们的领域图。这不是一项琐碎的任务。使用标准库的版本和保留的调试符号将有帮助。
否则,您可以尝试映射程序的内存,包括静态/全局变量、堆栈变量、上面所指向的所有分配的数据结构以及其他分配数据结构中的指针指向的所有分配的数据结构。我知道没有任何工具能够在死后转储中自动完成这个任务,尽管理论上这样的工具是可能的。
在映射了程序内存,或者程序内存的某些部分之后,您可以尝试找出不同类型的无关对象是否位于无效指针所在的地址。如果是这样的话,您可能会得出结论,这两个对象中的一个可能是被释放后被非法访问的内存。
https://stackoverflow.com/questions/41130332
复制相似问题