调试含递归指针的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
相关产品推荐
相关产品推荐

