mirror of
https://github.com/nushell/nushell.git
synced 2025-03-13 15:08:43 +01:00
Fix unterminated loop in parse_record (#15246)
Fixes #15243 # Description As noted in #15243, a record with more characters after it (e.g., `{a:b}/`) will cause an OOM due to an infinite loop, introduced by #15023. This happens because the entire string `{a:b}/` is lexed as one token and passed to `parse_record`, where it repeatedly lexes until it hits the closing `}`. This PR detects such extra characters and reports an error. # User-Facing Changes `{a:b}/` and other such constructions will no longer cause infinite loops. Before #15023, you would've seen an "Unclosed delimiter" error message, but this PR changes that to "Invalid characters." ``` Error: nu::parser::extra_token_after_closing_delimiter × Invalid characters after closing delimiter ╭─[entry #5:1:7] 1 │ {a:b}/ · ┬ · ╰── invalid characters ╰──── help: Try removing them. ``` # Tests + Formatting # After Submitting
This commit is contained in:
parent
122bcff356
commit
b1e591f84c
@ -5995,10 +5995,12 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression
|
||||
return garbage(working_set, span);
|
||||
}
|
||||
|
||||
let mut unclosed = false;
|
||||
let mut extra_tokens = false;
|
||||
if bytes.ends_with(b"}") {
|
||||
end -= 1;
|
||||
} else {
|
||||
working_set.error(ParseError::Unclosed("}".into(), Span::new(end, end)));
|
||||
unclosed = true;
|
||||
}
|
||||
|
||||
let inner_span = Span::new(start, end);
|
||||
@ -6009,7 +6011,12 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression
|
||||
error: None,
|
||||
span_offset: start,
|
||||
};
|
||||
loop {
|
||||
while !lex_state.input.is_empty() {
|
||||
if lex_state.input[0] == b'}' {
|
||||
extra_tokens = true;
|
||||
unclosed = false;
|
||||
break;
|
||||
}
|
||||
let additional_whitespace = &[b'\n', b'\r', b','];
|
||||
if lex_n_tokens(&mut lex_state, additional_whitespace, &[b':'], true, 1) < 1 {
|
||||
break;
|
||||
@ -6038,6 +6045,15 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression
|
||||
}
|
||||
let (tokens, err) = (lex_state.output, lex_state.error);
|
||||
|
||||
if unclosed {
|
||||
working_set.error(ParseError::Unclosed("}".into(), Span::new(end, end)));
|
||||
} else if extra_tokens {
|
||||
working_set.error(ParseError::ExtraTokensAfterClosingDelimiter(Span::new(
|
||||
lex_state.span_offset + 1,
|
||||
end,
|
||||
)));
|
||||
}
|
||||
|
||||
if let Some(err) = err {
|
||||
working_set.error(err);
|
||||
}
|
||||
|
@ -2818,4 +2818,16 @@ mod record {
|
||||
_ => panic!("Expected full cell path"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Regression test for https://github.com/nushell/nushell/issues/15243
|
||||
#[test]
|
||||
fn record_terminate_loop() {
|
||||
let engine_state = EngineState::new();
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
parse(&mut working_set, None, b"{a:b}/", false);
|
||||
assert_eq!(
|
||||
working_set.parse_errors.first().map(|e| e.to_string()),
|
||||
Some("Invalid characters after closing delimiter".to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user