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

标签 c pointers gdb stack

我已经专业地使用 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) 
} 

来自 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? 

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

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

  | //local vars  | 
  |               | 
  | another_ptr = |
  |      NULL     |
  +---------------+
  | return addr   |
  +---------------+
  | input args    |
  | copy of ptr   |
  |   contents    |
  |     0x100     |

对于func1(),它的调用栈应该是这样的:

  |               | 
  | ptr = 0x100   |
  |               |
  +---------------+
  | return addr   |
  +---------------+
  | input args    |
  |  none in this |
  |  func         |

当第(4)行func2()中的inp变为NULL时,在func1()中是如何体现的呢?

最佳答案

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

在 32 位系统上,函数的第一个参数 - 在您的例子中是 inp - 通常位于堆栈上,距离堆栈帧的基指针指向的位置 12 个字节到。参见 stackoverflow.com: what exactly is program stack's growth direction .

gdb 执行回溯时,它从编译器获得的唯一指导是类似“func2 的第一个参数被命名为 inp并且是 *UTYPE 类型的 4 字节值,位于距 %ebp 寄存器 12 字节的偏移量处。

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

我无法解释为什么你的 gdb 的回溯在 func1 的框架中显示 ptr 的值为 0。设置 inp 到 NULL 应该对 ptr 的值和 gdb 显示 ptr 的值的能力没有影响。

关于c - 通过检查核心和调用堆栈了解使用 GDB 的 C 指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21466160/

相关文章:

C - 无法找出此错误 : "C2106: ' =' : left operand must be l-value"

c - C 中 main 的参数

c - 程序输出错误

c++ - 关于 GDB 和 CRC 不匹配

python - 如何使用 GDB 的新 python 支持将变量分配给 python?

c - 插入到哈希表中

c - 数组元素取消引用和寻址 - &buffer[index] - 在 Swift 中有效吗?

c++ - 在列表中调用子对象

c - char的返回链 - C中的getgrouplist

c - gdb 调试器最棘手/有用的命令