构建深度嵌套递归安全模型的关键是用基本类型承载轻量状态,栈上仅存int/enum/小数组,深度硬限制+静态校验,重数据移至堆或静态缓冲区,终止前置、类型驱动跳转。
直接利用基本类型(如 int、char、enum)在栈上固定、小尺寸、无动态分配的特性,是构建深度嵌套递归安全模型的关键突破口。核心思路不是“避免递归”,而是让每一层递归调用只压入极轻量的状态,把内存压力从栈空间转移到可控的堆或静态缓冲区。
用基本类型承载关键状态,不传指针或结构体
递归函数参数和局部变量尽量只使用整数、枚举、小数组(如 char key_buf[32]),杜绝传递 struct json_node* 或 char* 这类可能引发间接访问与生命周期风险的类型。例如解析 JSON 对象成员时:
- 传入当前层级深度
int depth而非整个节点指针 - 用
enum json_type_t type标识当前待处理类型,而非携带完整类型信息结构 - 键名长度用
uint8_t key_len记录,配合预分配的栈缓冲区读取,不 malloc 字符串
栈空间显式预留 + 深度硬限制
编译期或启动时确定最大允许嵌套深度(如 64 层),据此计算单次调用所需栈空间上限(例如每层 64 字节 × 64 层 = 4KB),并在入口处做静态校验:
- 函数开头检查
if (depth >= MAX_DEPTH) return PARSE_ERROR_DEPTH_EXCEEDED; - 结合编译器扩展(如 GCC 的
__builtin_frame_address)粗略估算剩余栈空间,触发提前退出 - 禁用编译器尾递归优化(
-fno-optimize-sibling-calls),确保深度控制逻辑始终生效
将重负载移出栈:值存储委托给外部缓冲区
字符串内容、数字字面量、子节点列表等“重”数据,一律不放在递归栈帧内。改为:
- 使用全局或线程局部的静态 token 缓冲池,解析时只记录起始偏移和长度(两个
size_t) - 节点树结构采用 arena 分配或环形缓冲区管理,递归过程只写入索引(
uint16_t child_idx)而非指针 - 布尔/数字等原子值直接解析为
int或double存入栈,但不保存原始字符串形式
终止条件前置 + 类型驱动跳转
每层递归开始就判断是否该结束,不依赖深层返回后统一清理。用 switch 基于当前字符或类型快速分发,避免冗余分支:
- 遇到
'{'→ 进入对象解析,depth + 1,跳转至对象处理逻辑 - 遇到
'['→ 进入数组解析,同样 depth + 1,但切换为数组状态机 - 遇到
'"'、数字首字符、't'/'f'/'n'→ 直接进入对应原子类型解析,depth 不变

















