Fix #3090: let binding in command leaks when error occurs (#4022)

This commit is contained in:
Tom Panton 2021-09-19 03:57:20 +01:00 committed by GitHub
parent 1297499d7a
commit f7043bf690
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -101,17 +101,14 @@ fn if_command(args: CommandArgs) -> Result<OutputStream, ShellError> {
//FIXME: should we use the scope that's brought in as well? //FIXME: should we use the scope that's brought in as well?
let condition = evaluate_baseline_expr(cond, &context); let condition = evaluate_baseline_expr(cond, &context);
match condition { let result = match condition {
Ok(condition) => match condition.as_bool() { Ok(condition) => match condition.as_bool() {
Ok(b) => { Ok(b) => {
let result = if b { if b {
run_block(&then_case.block, &context, input, external_redirection) run_block(&then_case.block, &context, input, external_redirection)
} else { } else {
run_block(&else_case.block, &context, input, external_redirection) run_block(&else_case.block, &context, input, external_redirection)
}; }
context.scope.exit_scope();
result
} }
Err(e) => Ok(OutputStream::from_stream( Err(e) => Ok(OutputStream::from_stream(
vec![UntaggedValue::Error(e).into_untagged_value()].into_iter(), vec![UntaggedValue::Error(e).into_untagged_value()].into_iter(),
@ -120,13 +117,16 @@ fn if_command(args: CommandArgs) -> Result<OutputStream, ShellError> {
Err(e) => Ok(OutputStream::from_stream( Err(e) => Ok(OutputStream::from_stream(
vec![UntaggedValue::Error(e).into_untagged_value()].into_iter(), vec![UntaggedValue::Error(e).into_untagged_value()].into_iter(),
)), )),
} };
context.scope.exit_scope();
result
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::If; use super::If;
use super::ShellError; use super::ShellError;
use nu_test_support::nu;
#[test] #[test]
fn examples_work_as_expected() -> Result<(), ShellError> { fn examples_work_as_expected() -> Result<(), ShellError> {
@ -134,4 +134,21 @@ mod tests {
test_examples(If {}) test_examples(If {})
} }
#[test]
fn if_doesnt_leak_on_error() {
let actual = nu!(
".",
r#"
def test-leak [] {
let var = "hello"
if 0 == "" {echo ok} {echo not}
}
test-leak
echo $var
"#
);
assert!(actual.err.contains("unknown variable"));
}
} }