Skip to content

Commit

Permalink
Prevent unbounded recursion when parsing expressions (#1248)
Browse files Browse the repository at this point in the history
  • Loading branch information
evanrichter authored Jun 22, 2022
1 parent 0e4b443 commit bfceb8f
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 5 deletions.
3 changes: 3 additions & 0 deletions src/compile_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ impl Display for CompileError<'_> {
parameter
)?;
}
ParsingRecursionDepthExceeded => {
write!(f, "Parsing recursion depth exceeded")?;
}
RequiredParameterFollowsDefaultParameter { parameter } => {
write!(
f,
Expand Down
1 change: 1 addition & 0 deletions src/compile_error_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ pub(crate) enum CompileErrorKind<'src> {
ParameterShadowsVariable {
parameter: &'src str,
},
ParsingRecursionDepthExceeded,
RequiredParameterFollowsDefaultParameter {
parameter: &'src str,
},
Expand Down
25 changes: 20 additions & 5 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub(crate) struct Parser<'tokens, 'src> {
next: usize,
/// Current expected tokens
expected: BTreeSet<TokenKind>,
/// Current recursion depth
depth: u8,
}

impl<'tokens, 'src> Parser<'tokens, 'src> {
Expand All @@ -46,6 +48,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
next: 0,
expected: BTreeSet::new(),
tokens,
depth: 0,
}
}

Expand Down Expand Up @@ -391,19 +394,31 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {

/// Parse an expression, e.g. `1 + 2`
fn parse_expression(&mut self) -> CompileResult<'src, Expression<'src>> {
if self.accepted_keyword(Keyword::If)? {
self.parse_conditional()
if self.depth == if cfg!(windows) { 64 } else { 255 } {
return Err(CompileError {
token: self.next()?,
kind: CompileErrorKind::ParsingRecursionDepthExceeded,
});
}

self.depth += 1;

let expression = if self.accepted_keyword(Keyword::If)? {
self.parse_conditional()?
} else {
let value = self.parse_value()?;

if self.accepted(Plus)? {
let lhs = Box::new(value);
let rhs = Box::new(self.parse_expression()?);
Ok(Expression::Concatenation { lhs, rhs })
Expression::Concatenation { lhs, rhs }
} else {
Ok(value)
value
}
}
};

self.depth -= 1;
Ok(expression)
}

/// Parse a conditional, e.g. `if a == b { "foo" } else { "bar" }`
Expand Down
1 change: 1 addition & 0 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ mod positional_arguments;
mod quiet;
mod quote;
mod readme;
mod recursion_limit;
mod regexes;
mod run;
mod search;
Expand Down
30 changes: 30 additions & 0 deletions tests/recursion_limit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use super::*;

#[test]
fn bugfix() {
let mut justfile = String::from("foo: (x ");
for _ in 0..500 {
justfile.push('(');
}
Test::new()
.justfile(&justfile)
.stderr(RECURSION_LIMIT_REACHED)
.status(EXIT_FAILURE)
.run();
}

#[cfg(not(windows))]
const RECURSION_LIMIT_REACHED: &str = "
error: Parsing recursion depth exceeded
|
1 | foo: (x ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
| ^
";

#[cfg(windows)]
const RECURSION_LIMIT_REACHED: &str = "
error: Parsing recursion depth exceeded
|
1 | foo: (x ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
| ^
";

0 comments on commit bfceb8f

Please sign in to comment.