From 1d2851465ff908bc29b1f62feb00eb1497b05fd1 Mon Sep 17 00:00:00 2001 From: Addison Crump Date: Mon, 21 Feb 2022 15:50:29 +0000 Subject: [PATCH] Add assertion to check that a break label is identified at compile-time (#1852) This PR changes the following: - Adds a check at compile time for the existence of a break label (this should be a syntax error in the future; refactor from panics to results in compile should be a separate PR) - Adds a test for break label existence in boa/tests 262 misses some fairly important JS parity issues and not performing this check eagerly can lead to other more severe issues during VM execution. --- boa/src/bytecompiler.rs | 23 +++++++++++++++-------- boa/src/tests.rs | 12 ++++++++++++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/boa/src/bytecompiler.rs b/boa/src/bytecompiler.rs index 7a88a6a9dbf..7d4ad25d787 100644 --- a/boa/src/bytecompiler.rs +++ b/boa/src/bytecompiler.rs @@ -1471,19 +1471,26 @@ impl<'b> ByteCompiler<'b> { self.emit(Opcode::FinallySetJump, &[u32::MAX]); } let label = self.jump(); - if node.label().is_none() { - self.jump_info - .last_mut() - .expect("no jump information found") - .breaks - .push(label); - } else { + if let Some(label_name) = node.label() { + let mut found = false; for info in self.jump_info.iter_mut().rev() { - if info.label == node.label() { + if info.label == Some(label_name) { info.breaks.push(label); + found = true; break; } } + assert!( + found, + "Undefined label '{}'", + self.interner().resolve_expect(label_name) + ); + } else { + self.jump_info + .last_mut() + .expect("no jump information found") + .breaks + .push(label); } } Node::Block(block) => { diff --git a/boa/src/tests.rs b/boa/src/tests.rs index 10ad9d0a4fa..1d8176012a0 100644 --- a/boa/src/tests.rs +++ b/boa/src/tests.rs @@ -430,6 +430,18 @@ fn for_loop_iteration_variable_does_not_leak() { assert_eq!(&exec(inner_scope), "\"i is not defined\""); } +#[test] +#[should_panic] +fn test_invalid_break_target() { + let src = r#" + while (false) { + break nonexistent; + } + "#; + + let _ = &exec(src); +} + #[test] fn unary_pre() { let unary_inc = r#"