Description
An FT.SEARCH (or FT.AGGREGATE) query whose OR operator | has an empty right-hand side crashes the server with a SIGSEGV (null-pointer dereference) in the filter parser. No indexed data is required — the crash happens at query-parse time. Reachable by any client that can run FT.SEARCH (a @read command).
Steps to reproduce
FT.CREATE idx ON HASH PREFIX 1 doc: SCHEMA n NUMERIC t TEXT
FT.SEARCH idx '@n:[0 10]|' # trailing '|', empty OR right-hand side
FT.SEARCH idx 'hello|the' # OR where the right operand is a stopword ('the')
Each drops the connection (Error: Server closed the connection). docker inspect ExitCode 139.
The general shape is any valid predicate immediately followed by an unescaped | whose right-hand side resolves to nothing: end-of-input, only whitespace, a closing ), or a stop word (the tokenizer drops stop words, yielding a null token). '@n:[0 10]||' does NOT crash — the inner recursion hits the second | with a null left operand and returns a graceful "Missing OR term" error, so the crash specifically requires the RHS to terminate empty.
Crash output
valkey ... crashed by signal: 11, si_code: 1
libsearch.so(_ZN13valkey_search12FilterParser13WrapPredicate...+0x286)
at src/commands/filter_parser.cc:536
<- FilterParser::ParseExpression
<- FilterParser::Parse
<- query::ParsePreFilter at src/query/search.cc
Root cause
src/commands/filter_parser.cc, ParseExpression, the '|' branch: it parses the right operand into predicate, then guards only the LEFT operand (if (result.prev_predicate) ... else return "Missing OR term"). It never checks that the right operand is non-null. A trailing | (RHS recursion returns null) or a stop-word RHS (ParseUnquotedTextToken returns a null token) passes a null new_predicate into WrapPredicate. There (around filter_parser.cc:487), the OR-flatten path dereferences new_predicate->GetType() on the null pointer, and a sibling path builds a ComposedPredicate owning a null child that crashes on destruction.
Suggested fix
After obtaining the RHS in the | branch, return InvalidArgumentError("Missing OR term") if it is null (mirror the existing left-operand guard), and/or null-check new_predicate in WrapPredicate.
Environment
- valkey-search
origin/main (8c260db); also reproduces on valkey/valkey-bundle:unstable
- Confirmed live on current
main: filter_parser.cc is untouched by the recent expr.cc crash fixes.
This issue was generated by AI but verified, with love, by a human.
Description
An
FT.SEARCH(orFT.AGGREGATE) query whose OR operator|has an empty right-hand side crashes the server with a SIGSEGV (null-pointer dereference) in the filter parser. No indexed data is required — the crash happens at query-parse time. Reachable by any client that can runFT.SEARCH(a@readcommand).Steps to reproduce
Each drops the connection (
Error: Server closed the connection).docker inspectExitCode 139.The general shape is any valid predicate immediately followed by an unescaped
|whose right-hand side resolves to nothing: end-of-input, only whitespace, a closing), or a stop word (the tokenizer drops stop words, yielding a null token).'@n:[0 10]||'does NOT crash — the inner recursion hits the second|with a null left operand and returns a graceful "Missing OR term" error, so the crash specifically requires the RHS to terminate empty.Crash output
Root cause
src/commands/filter_parser.cc,ParseExpression, the'|'branch: it parses the right operand intopredicate, then guards only the LEFT operand (if (result.prev_predicate) ... else return "Missing OR term"). It never checks that the right operand is non-null. A trailing|(RHS recursion returns null) or a stop-word RHS (ParseUnquotedTextTokenreturns a null token) passes a nullnew_predicateintoWrapPredicate. There (aroundfilter_parser.cc:487), the OR-flatten path dereferencesnew_predicate->GetType()on the null pointer, and a sibling path builds aComposedPredicateowning a null child that crashes on destruction.Suggested fix
After obtaining the RHS in the
|branch, returnInvalidArgumentError("Missing OR term")if it is null (mirror the existing left-operand guard), and/or null-checknew_predicateinWrapPredicate.Environment
origin/main(8c260db); also reproduces onvalkey/valkey-bundle:unstablemain:filter_parser.ccis untouched by the recent expr.cc crash fixes.This issue was generated by AI but verified, with love, by a human.