通过检查核心和调用堆栈来了解使用GDB的C指针

Bha*_*kar 5 c stack gdb pointers

我已经用C语言进行了一段时间的专业编程,但是仍然对一些与指针相关的问题感到困惑。我非常感谢SO社区对理解以下问题的帮助。

以下代码崩溃并生成了核心文件。

void func1()    // Frame 1 in GDB stack trace.  
{ 
    UTYPE  *ptr;  // pointer to user defined type  
    ...

    // data is of type UTYPE and has valid contents.
    // lets say its address is 0x100 
    ptr = &data;     --- (1)  
    ...

    func2(ptr);      --- (2) 
    ...
} 

void func2(UTYPE *inp)    // Frame 0 in GDB stack trace.  
{
    if(!inp)         --- (3) 
        return; 
    ...

    // another_ptr is of UTYPE * which is a NULL.  
    inp = another_ptr;   ---- (4)  

    /* Did not check for NULL and dereference inp and CRASH */    ---- (5) 
} 
Run Code Online (Sandbox Code Playgroud)

来自GDB的简化回溯:

Frame 0: 
    func2(inp = 0x0) 
    // crash at line (5) due to dereference 

Frame 1: 
    func1: func2(0x0)  
    // `ptr` at line (2) is 0x0. Why is this so? 
Run Code Online (Sandbox Code Playgroud)

为什么ptr显示为第0x0 (NULL)1帧?

func2()被调用时,其调用堆栈如下所示:

  | //local vars  | 
  |               | 
  | another_ptr = |
  |      NULL     |
  +---------------+
  | return addr   |
  +---------------+
  | input args    |
  | copy of ptr   |
  |   contents    |
  |     0x100     |
Run Code Online (Sandbox Code Playgroud)

对于func1(),其调用堆栈应如下所示:

  |               | 
  | ptr = 0x100   |
  |               |
  +---------------+
  | return addr   |
  +---------------+
  | input args    |
  |  none in this |
  |  func         |
Run Code Online (Sandbox Code Playgroud)

inp成为NULLfunc2()管线(4),它是如何反映在func1的()?

Mar*_*ick 2

当在 C 中调用函数时,参数被复制到寄存器或压入堆栈。被调用的函数可以出于任何目的重用这些寄存器和堆栈位置。通常(但并非总是),参数在函数调用的整个生命周期中都保存在相同的寄存器或堆栈位置中。

在 32 位系统上,函数的第一个参数(在您的情况下inp)通常位于堆栈上,距堆栈帧基指针指向的位置 12 个字节。请参阅stackoverflow.com:程序堆栈的增长方向到底是什么

gdb进行回溯时,编译器提供的唯一指导类似于“第一个参数已func2命名,并且是位于 %ebp 寄存器 12 字节偏移处的inp4 字节类型值”。*UTYPE

如果在 中的某个位置func2,您更改了inp,就像在位置 (4) 处所做的那样,那么从该点开始的任何回溯很可能会显示 的更改值(在您的情况下为 0)。输入时所具有的inp值将永远丢失,除非编译器足够聪明,包含诸如“第一个参数被命名并且是类型的4字节值,并且可以通过将堆栈展开到前一帧并查看值来找到它在进入时的值”的指导,它位于距 %ebp 寄存器 -4 字节的偏移处。” 我相信,较新版本的 DWARF 调试格式可以指定类似的内容。inpfunc2func2inp*UTYPEfunc2ptr

我无法解释为什么你的gdb回溯ptrfunc1's 框架中显示为具有值 0。设置为 NULL 应该对 's 值和 gdb 显示's 值的能力inp没有影响。ptrptr