You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调试含递归指针的FileSystemNode结构体GDB递归溢出问题

解决rust-gdb调试循环引用节点时的递归溢出问题

问题描述

实现了带父子循环引用的文件系统树形节点结构(Rc<RefCell<FileSystemNode>>),用rust-gdb调试时,gdb会递归遍历父指针和子节点,触发递归溢出错误:

Python Exception <class 'RecursionError'>: maximum recursion depth exceeded while calling a Python object
Python Exception <class 'RecursionError'>: maximum recursion depth exceeded while getting the str of an object

需要避免这种递归,打印节点时只显示关键信息(路径、名称、大小)或仅显示引用地址。

解决方案

1. 自定义gdb打印格式(推荐)

通过gdb的Python脚本自定义FileSystemNode的打印逻辑,跳过循环引用的字段遍历:

  • 在项目根目录创建.gdbinit文件,写入以下内容:
python
import gdb.printing

class FileSystemNodePrinter:
    def __init__(self, val):
        self.val = val

    def to_string(self):
        path = self.val['current_directory_path'].string()
        name = self.val['current_directory_name'].string()
        size = self.val['size']
        return f"FileSystemNode(path: '{path}', name: '{name}', size: {size})"

    def children(self):
        # 不返回parent和children字段,彻底避免递归遍历
        return []

def build_pretty_printer():
    pp = gdb.printing.RegexpCollectionPrettyPrinter("FileSystemNode")
    pp.add_printer('FileSystemNode', '^FileSystemNode$', FileSystemNodePrinter)
    return pp

gdb.printing.register_pretty_printer(gdb.current_objfile(), build_pretty_printer())
end
  • 启动rust-gdb时会自动加载该脚本,直接打印节点(如p root)就会使用自定义格式,不会触发递归。

2. 手动指定打印字段

调试时不打印整个节点,只打印需要的单个字段,避免触发递归遍历:

# 打印root节点的路径
p (*root.borrow()).current_directory_path

# 打印第一个子节点的名称
p (*(*root.borrow()).children[0].borrow()).current_directory_name

# 打印子节点的父引用地址
p (*node.borrow()).parent_directory

3. 临时添加自定义Debug实现

给FileSystemNode实现Debug trait,自定义输出格式,简化或忽略循环引用的字段:

use std::fmt;

impl fmt::Debug for FileSystemNode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FileSystemNode")
            .field("path", &self.current_directory_path)
            .field("name", &self.current_directory_name)
            .field("size", &self.size)
            // 只显示父引用的地址,不展开
            .field("parent", &self.parent_directory.as_ref().map(|rc| format!("Rc<RefCell<..>> @ {:p}", rc)))
            // 只显示子节点的地址列表,不展开
            .field("children", &self.children.iter().map(|rc| format!("Rc<RefCell<..>> @ {:p}", rc)).collect::<Vec<_>>())
            .finish()
    }
}

添加后,无论是代码里用println!("{:?}", root.borrow())输出,还是gdb里执行p root.borrow(),都会使用这个安全的格式,不会递归溢出。

内容的提问来源于stack exchange,提问作者Tare

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 06:15:36