b8467
common/grammar: fix grammar parsing issues to prevent stack overflow and hangs (#18604)
- grammar: add test case for nullable symbol loop
Reproduce stack overflow (or OOM) with ( [x]* )* found while adding GBNF support to ripgrep-edit.
llama-server reproducer:
curl
-X POST
-d '{
"messages": [{ "role": "user", "content": "write yes" }],
"grammar": "root ::= ( [x]* )*"
}'
-H "Content-Type: application/json"
http://localhost:8811/v1/chat/completions
- grammar: prevent stack overflow with nullable symbol loop
Fix a potential stack overflow in llama_grammar_advance_stack that could occur when processing grammars with nullable symbols that lead to infinite derivations of empty strings. The fix introduces cycle detection by tracking visited stacks to prevent infinite recursion.
rg-edit regexp: llama_grammar_advance_stack rg-edit extra-args: -A20 rg-edit directive: """Rewrite: fix the following segfault:
[..] ⚫ Testing segfault. Grammar: root ::= ( [x]* )*
root ::= ( [x]* )*
Segmentation fault build/bin/test-grammar-integration"""
gptel-context: (("/llama.cpp/src/llama-grammar.cpp") ("/llama.cpp/tests/test-grammar-integration.cpp") ("/llama.cpp/grammars/./list.gbnf") ("/llama.cpp/grammars/./json_arr.gbnf") ("/llama.cpp/grammars/./json.gbnf") ("/llama.cpp/grammars/./japanese.gbnf") ("/llama.cpp/grammars/./english.gbnf") ("/llama.cpp/grammars/./chess.gbnf") ("/llama.cpp/grammars/./c.gbnf") ("/llama.cpp/grammars/./arithmetic.gbnf") ("~/llama.cpp/grammars/./README.md"))
- grammar: convert recursive llama_grammar_advance_stack to iterative
This change converts the function to an iterative approach using explicit stacks, which prevents deep recursion and eliminates the risk of stack overflow.
rg-edit regexp: llama_grammar_advance_stack rg-edit extra-args: -A30 rg-edit directive: """Rewrite: fix the following segfault:
[..] ⚫ Testing segfault. Grammar: root ::= ( [x]* )*
root ::= ( [x]* )*
Segmentation fault build/bin/test-grammar-integration
convert from recursive to interactive"""
gptel-context: (("/llama.cpp/src/llama-grammar.cpp") ("/llama.cpp/tests/test-grammar-integration.cpp") ("/llama.cpp/grammars/./list.gbnf") ("/llama.cpp/grammars/./json_arr.gbnf") ("/llama.cpp/grammars/./json.gbnf") ("/llama.cpp/grammars/./japanese.gbnf") ("/llama.cpp/grammars/./english.gbnf") ("/llama.cpp/grammars/./chess.gbnf") ("/llama.cpp/grammars/./c.gbnf") ("/llama.cpp/grammars/./arithmetic.gbnf") ("~/llama.cpp/grammars/./README.md"))
v2: Added a std::set to perform tree-based lookups with O(N log N)
complexity. Testing with a parallel run of test-grammar-integration
shows a double-digit percentage increase in runtime. An
unordered_set with O(1) hashing was also evaluated, but the overhead
of constructing hash keys from pointers made it significantly slower
than the rbtree implementation that only requires an ordering
operator. The performance regression in the test suite appears
justified by the overall reduction in algorithmic complexity.
Co-developed-by: Piotr Wilkin (ilintar) piotr.wilkin@syndatis.com
- grammar: add test case for hang in repetition grammar processing
This commit adds a new test case to the grammar integration tests that specifically targets a hang scenario in the repetition grammar parser found while adding GBNF support to ripgrep-edit.
llama-server reproducer:
curl
-X POST
-d '{
"messages": [{ "role": "user", "content": "write yes" }],
"grammar": "root ::= (([^x]*){0,99}){0,99}"
}'
-H "Content-Type: application/json"
http://localhost:8811/v1/chat/completions
- grammar: add repetition threshold check
The change introduces a maximum repetition threshold to avoid excessive rule expansion during grammar parsing. When parsing repetition patterns like {m,n}, the parser now calculates the potential number of rules that would be generated and throws an error if the product of previous rules and new rules exceeds the threshold.
A test case was added to verify the threshold is properly enforced for deeply nested repetition patterns that would otherwise cause hangs.
macOS/iOS:
Linux:
Windows:
- Windows x64 (CPU)
- Windows arm64 (CPU)
- Windows x64 (CUDA 12) - CUDA 12.4 DLLs
- Windows x64 (CUDA 13) - CUDA 13.1 DLLs
- Windows x64 (Vulkan)
- Windows x64 (SYCL)
- Windows x64 (HIP)
openEuler: