Stack overflow when dropping a flat operator chain AST (parse succeeds)
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 58/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- rust
- Área
- backend-api-design
Línea de trabajo
Start with src/ast/mod.rs and the parse_subexpr precedence loop mentioned in the issue; trace how operator chains are folded and how recursion limits are counted. Reproduce with the supplied Rust example, then check the existing recursion-limit tests. Done means dropping a long flat operator chain no longer overflows and the behavior respects the recursion limit (or safely drops the AST).
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary
Parser::parse_sql accepts a flat left-associative operator chain and returns successfully, but dropping the returned Vec<Statement> then overflows the stack: the derived drop glue for the left-deep Box<Expr> tree recurses once per level with no guard. The process aborts (rc=134), and abort cannot be caught by the caller.
On a 2 MB stack (the default for spawned threads, including tokio workers) roughly 35,000 + operators — about 70 KB of input — is enough:
| stack | operators | input | result |
|---|---|---|---|
| 8 MB (main) | 130,625 | 261,258 B | parses and drops, rc=0 |
| 8 MB (main) | 132,000 | 264,008 B | prints parsed 1 statement(s) then aborts |
| 2 MB (thread) | 30,000 | 60,008 B | parses and drops, rc=0 |
| 2 MB (thread) | 35,000 | 70,008 B | prints parsed 1 statement(s) then aborts |
The parsed ... line is printed before the abort, so the overflow is in drop, not in parsing.
thread 'main' has overflowed its stack
fatal runtime error: stack overflow, aborting
Root cause
Expr and the rest of the AST derive Drop (src/ast/mod.rs). The only recursion guard on these types is
#[cfg_attr(feature = "recursive-protection", recursive::recursive)]
impl Display for Expr
at src/ast/mod.rs:1795; there is no impl Drop and no ManuallyDrop.
A flat chain such as SELECT 1+1+1... is built by the iterative precedence-climbing loop in parse_subexpr, so the recursion counter never fires, and the result is a left-deep BinaryOp { left: Box<Expr>, .. } spine. Dropping it walks that spine recursively, one stack frame per operator. Parser::with_recursion_limit does not help because parsing never recursed.
Reproduction
[dependencies]
sqlparser = "=0.63.0"
fn main() {
let n: usize = std::env::args().nth(1).and_then(|s| s.parse().ok()).unwrap_or(132_000);
let mut sql = String::from("SELECT 1");
for _ in 0..n { sql.push_str("+1"); }
let dialect = sqlparser::dialect::GenericDialect {};
let stmts = sqlparser::parser::Parser::parse_sql(&dialect, &sql).expect("parse");
println!("parsed {} statement(s), {} bytes", stmts.len(), sql.len());
drop(stmts);
println!("dropped ok");
}
$ cargo run --release -- 130625
parsed 1 statement(s), 261258 bytes
dropped ok
$ cargo run --release -- 132000
parsed 1 statement(s), 264008 bytes
thread 'main' has overflowed its stack
fatal runtime error: stack overflow, aborting # rc=134
SELECT 1=1 AND 1=1 ... shows the same behaviour.
Suggested fix
Count the chain length against the existing recursion accounting: when the precedence loop folds another operator onto the same chain, add it to RecursionCounter and return RecursionLimitExceeded past the limit, matching what deeply nested parentheses already do. Alternatively, implement an iterative Drop for Expr with an explicit work stack, which also covers trees built programmatically.
- Lenguaje dominante
- Rust
- Estrellas
- 3.5k
- Forks
- 805
- Merge medio
- 2 d 3 h
- PR fusionados (30 d)
- 116
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Sin guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de apache/datafusion-sqlparser-rs
-
Redshift
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
apache/datafusion-sqlparser-rs#2959 ·
Los mantenedores suelen responder en 1 día
-
Redshift
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
apache/datafusion-sqlparser-rs#2958 ·
Los mantenedores suelen responder en 1 día
-
PostgreSQL
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
apache/datafusion-sqlparser-rs#2862 ·
Los mantenedores suelen responder en 1 día
-
PostgreSQL
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
apache/datafusion-sqlparser-rs#2861 ·
Los mantenedores suelen responder en 1 día
-
PostgreSQL
Dificultad 2/5 1-3 horas Aptitud para principiantes 77/100
apache/datafusion-sqlparser-rs#2858 ·
Los mantenedores suelen responder en 1 día
Todos los issues de apache/datafusion-sqlparser-rs
Issues similares
-
area:schema documentation
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
ElectronicWave/Elemental#252 ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
dekobon/big-code-analysis#1887 ·
Los mantenedores suelen responder en 1 día
-
Shell中文符号输入异常Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 82/100
Los mantenedores suelen responder en 1 día