aboutsummaryrefslogtreecommitdiffstats
path: root/askama_parser/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--askama_parser/src/expr.rs12
-rw-r--r--askama_parser/src/tests.rs6
2 files changed, 15 insertions, 3 deletions
diff --git a/askama_parser/src/expr.rs b/askama_parser/src/expr.rs
index 65a7835..4aa778a 100644
--- a/askama_parser/src/expr.rs
+++ b/askama_parser/src/expr.rs
@@ -214,14 +214,20 @@ impl<'a> Expr<'a> {
Ok((i, res))
}
- fn prefix(i: &'a str, level: Level) -> ParseResult<'a, Self> {
- let (_, level) = level.nest(i)?;
+ fn prefix(i: &'a str, mut level: Level) -> ParseResult<'a, Self> {
+ let (_, nested) = level.nest(i)?;
let (i, (ops, mut expr)) = pair(many0(ws(alt((tag("!"), tag("-"))))), |i| {
- Suffix::parse(i, level)
+ Suffix::parse(i, nested)
})(i)?;
+
for op in ops.iter().rev() {
+ // This is a rare place where we create recursion in the parsed AST
+ // without recursing the parser call stack. However, this can lead
+ // to stack overflows in drop glue when the AST is very deep.
+ level = level.nest(i)?.1;
expr = Self::Unary(op, Box::new(expr));
}
+
Ok((i, expr))
}
diff --git a/askama_parser/src/tests.rs b/askama_parser/src/tests.rs
index 703dd6a..742f0f3 100644
--- a/askama_parser/src/tests.rs
+++ b/askama_parser/src/tests.rs
@@ -807,3 +807,9 @@ fn fuzzed_target_recursion() {
const TEMPLATE: &str = include_str!("../tests/target-recursion.txt");
assert!(Ast::from_str(TEMPLATE, &Syntax::default()).is_err());
}
+
+#[test]
+fn fuzzed_unary_recursion() {
+ const TEMPLATE: &str = include_str!("../tests/unary-recursion.txt");
+ assert!(Ast::from_str(TEMPLATE, &Syntax::default()).is_err());
+}