Misc. bug: Stack overflow in GBNF grammar via nested repetition

该报错通常发生在 llama.cpp 加载或初始化含嵌套重复结构(如 ("a"*)* )的 GBNF 语法文件时, llama_grammar_advance_stack 递归过深导致栈溢出,优先排查 GBNF 规则中是否存在嵌套重复或间接递归。

快速结论:该报错通常发生在 llama.cpp 加载或初始化含嵌套重复结构(如 ("a"*)*)的 GBNF 语法文件时,llama_grammar_advance_stack 递归过深导致栈溢出,优先排查 GBNF 规则中是否存在嵌套重复或间接递归。

适用环境:llama.cpp master 分支 commit 55abc393552f3f2097f168cb6db4dc495a514d56;Linux;使用 AddressSanitizer 构建;涉及 test-gbnf-validator 与 llama-server。

最快修复方案:暂无确认的一步修复方案。Issue 讨论中报告称该 POC 在较新 master(b3fa69955e)上已不再复现,可优先尝试升级到包含相关语法改动的 llama.cpp 版本;这一点尚未经维护者正式确认。

注意事项:Issue 关闭原因是标记 stale 后 14 天无活动,并非已确认修复;CVE-2026-2069 已被分配,但修复归属的提交未在讨论中明确。自行修改 GBNF 规避只能绕过当前 POC,不能证明其他嵌套递归规则安全。

问题场景

在 Linux 上使用 llama.cpp(commit 55abc393552f3f2097f168cb6db4dc495a514d56,master)加载 GBNF 语法文件 poc.gbnf 时触发崩溃。程序进入 llama_grammar_init_impl 解析语法,在构建初始栈阶段调用 llama_grammar_advance_stack,遇到嵌套重复规则 ("a⏎aaab"*)* 后不断递归,最终耗尽栈空间,由 AddressSanitizer 报告栈溢出并终止进程。

报错原文

AddressSanitizer:DEADLYSIGNAL
...

Issue 标题中的核心描述为:Misc. bug: Stack overflow in GBNF grammar via nested repetition。涉及函数 llama_grammar_advance_stack,位置 llama.cpp/src/llama-grammar.cpp:858:17;递归调用位于该函数约第 858 行,每次递归新建 llama_grammar_stack 对象(约第 849 行)。

原因分析

可能原因:根据 Issue 的触发流程分析,llama_grammar_advance_stack 只以 stack.empty() 作为终止条件,没有递归深度限制,也没有对循环引用做通用检测。初始化阶段虽有左递归检测(约 1096–1108 行),但无法覆盖嵌套重复((...*)*)、间接递归、右递归等形式。对于 root ::= ("a⏎aaab"*)* 这类规则,外层 * 与内层 * 都可零次或多次展开,处理时不断生成新的栈状态并递归调用,最终栈溢出。该分析来自 Issue 正文,属于对缺陷机制的推断,未在讨论中由维护者逐条确认。

环境排查

  • 确认 llama.cpp 版本/commit:Issue 原始复现为 55abc393552f3f2097f168cb6db4dc495a514d56;后续报告在 b3fa69955e 上未复现,版本差异是关键变量。
  • 确认是否为 AddressSanitizer 构建,以及崩溃输出是否与 AddressSanitizer:DEADLYSIGNAL 一致。
  • 检查所用 GBNF 语法中是否存在 ("..."*)* 形式的嵌套重复、间接自引用或右递归规则。
  • Issue 未提供 Python、CUDA、PyTorch、显卡型号等环境信息,这些不作为排查前提。
  • 确认触发路径是 test-gbnf-validator 还是 llama-server 加载语法;两者在讨论中均被提及。

解决步骤

  1. 保留原始崩溃信息,尤其是 llama_grammar_advance_stack 的递归栈帧,用于确认崩溃点是否在语法初始化阶段。
  2. 用 test-gbnf-validator 单独加载出问题的 GBNF 文件(例如 Issue 附带 poc.zip 中的 poc.gbnf),缩小问题范围,排除模型加载和推理过程的影响。
  3. 检查语法中的嵌套重复与递归引用,确认是否存在 (...*)* 等结构;在旧版本上这是可稳定触发溢出的输入。
  4. 可优先尝试:将 llama.cpp 升级到较新的 master(讨论中验证为 b3fa69955e),重新用同一 GBNF 文件运行 test-gbnf-validator 与 llama-server。该版本上的未复现属于讨论中用户的报告,尚非官方确认的修复结论。
  5. 若升级后仍崩溃,保留当前 commit、GBNF 文件和 ASan 输出,回到 Issue 或新开 Issue 反馈;可同时参考讨论中提到的 #18993 以及 CVE-2026-2069 跟踪信息。
  6. 无法升级时,可优先尝试改写 GBNF 规避嵌套重复形式;这只是临时绕过,不能证明修复了递归处理缺陷。

验证方法

升级后使用同一份 poc.gbnf,分别运行 test-gbnf-validator 对输入进行接受/拒绝校验,并通过 llama-server 加载该语法完成一段生成(讨论中提到 200 token 生成)。若不再出现 AddressSanitizer:DEADLYSIGNAL,且语法校验结果正确,说明该 POC 不再触发问题;但这只能证明该样例未复现,不能推断所有嵌套递归语法均已安全。

参考来源

ggml-org/llama.cpp #18988

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 30763

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注