Prevent unbounded recursion when parsing expressions (#1248)
This commit is contained in:
parent
0e4b443742
commit
bfceb8f9c9
@ -198,6 +198,9 @@ impl Display for CompileError<'_> {
|
||||
parameter
|
||||
)?;
|
||||
}
|
||||
ParsingRecursionDepthExceeded => {
|
||||
write!(f, "Parsing recursion depth exceeded")?;
|
||||
}
|
||||
RequiredParameterFollowsDefaultParameter { parameter } => {
|
||||
write!(
|
||||
f,
|
||||
|
@ -74,6 +74,7 @@ pub(crate) enum CompileErrorKind<'src> {
|
||||
ParameterShadowsVariable {
|
||||
parameter: &'src str,
|
||||
},
|
||||
ParsingRecursionDepthExceeded,
|
||||
RequiredParameterFollowsDefaultParameter {
|
||||
parameter: &'src str,
|
||||
},
|
||||
|
@ -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> {
|
||||
@ -46,6 +48,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
||||
next: 0,
|
||||
expected: BTreeSet::new(),
|
||||
tokens,
|
||||
depth: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -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" }`
|
||||
|
@ -62,6 +62,7 @@ mod positional_arguments;
|
||||
mod quiet;
|
||||
mod quote;
|
||||
mod readme;
|
||||
mod recursion_limit;
|
||||
mod regexes;
|
||||
mod run;
|
||||
mod search;
|
||||
|
30
tests/recursion_limit.rs
Normal file
30
tests/recursion_limit.rs
Normal file
@ -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 ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
|
||||
| ^
|
||||
";
|
Loading…
Reference in New Issue
Block a user