From 9b07c852633952eb321880580e45fa247e106bb7 Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Sat, 4 Sep 2021 02:35:06 +0200 Subject: [PATCH] Handle non-strict functions in strict functions --- boa/src/context.rs | 49 +++++++++++++++++-- .../syntax/ast/node/operator/unary_op/mod.rs | 2 +- boa/src/syntax/ast/node/statement_list/mod.rs | 23 ++++++--- .../syntax/ast/node/statement_list/tests.rs | 22 +++++++++ boa/src/syntax/parser/function/mod.rs | 2 +- boa/src/syntax/parser/mod.rs | 2 +- boa_tester/src/exec/mod.rs | 8 ++- 7 files changed, 94 insertions(+), 14 deletions(-) diff --git a/boa/src/context.rs b/boa/src/context.rs index 7c43c753988..2cd30888c5a 100644 --- a/boa/src/context.rs +++ b/boa/src/context.rs @@ -212,6 +212,14 @@ impl StandardObjects { } } +/// Internal representation of the strict mode types. +#[derive(Debug, Copy, Clone)] +pub(crate) enum StrictType { + Off, + Global, + Function, +} + /// Javascript context. It is the primary way to interact with the runtime. /// /// `Context`s constructed in a thread share the same runtime, therefore it @@ -275,7 +283,7 @@ pub struct Context { pub trace: bool, /// Whether or not strict mode is active. - pub strict: bool, + strict: StrictType, } impl Default for Context { @@ -290,7 +298,7 @@ impl Default for Context { iterator_prototypes: IteratorPrototypes::default(), standard_objects: Default::default(), trace: false, - strict: false, + strict: StrictType::Off, }; // Add new builtIns to Context Realm @@ -327,6 +335,36 @@ impl Context { &mut self.console } + /// Returns if strict mode is currently active. + #[inline] + pub fn strict(&self) -> bool { + matches!(self.strict, StrictType::Global | StrictType::Function) + } + + /// Returns the strict mode type. + #[inline] + pub(crate) fn strict_type(&self) -> StrictType { + self.strict + } + + /// Set strict type. + #[inline] + pub(crate) fn set_strict(&mut self, strict: StrictType) { + self.strict = strict; + } + + /// Disable the strict mode. + #[inline] + pub fn set_strict_mode_off(&mut self) { + self.strict = StrictType::Off; + } + + /// Enable the global strict mode. + #[inline] + pub fn set_strict_mode_global(&mut self) { + self.strict = StrictType::Global; + } + /// Sets up the default global objects within Global #[inline] fn create_intrinsics(&mut self) { @@ -793,7 +831,12 @@ impl Context { .map_err(|e| e.to_string()); let execution_result = match parsing_result { - Ok(statement_list) => statement_list.run(self), + Ok(statement_list) => { + if statement_list.strict() { + self.set_strict_mode_global(); + } + statement_list.run(self) + } Err(e) => self.throw_syntax_error(e), }; diff --git a/boa/src/syntax/ast/node/operator/unary_op/mod.rs b/boa/src/syntax/ast/node/operator/unary_op/mod.rs index d10a8f4ae24..0153025f300 100644 --- a/boa/src/syntax/ast/node/operator/unary_op/mod.rs +++ b/boa/src/syntax/ast/node/operator/unary_op/mod.rs @@ -97,7 +97,7 @@ impl Executable for UnaryOp { .to_object(context)? .__delete__(&get_const_field.field().into(), context)?; - if !delete_status && context.strict { + if !delete_status && context.strict() { return context.throw_type_error("Cannot delete property"); } else { JsValue::new(delete_status) diff --git a/boa/src/syntax/ast/node/statement_list/mod.rs b/boa/src/syntax/ast/node/statement_list/mod.rs index 2b1b865a7e5..5d9c138d736 100644 --- a/boa/src/syntax/ast/node/statement_list/mod.rs +++ b/boa/src/syntax/ast/node/statement_list/mod.rs @@ -1,6 +1,7 @@ //! Statement list node. use crate::{ + context::StrictType, exec::{Executable, InterpreterState}, gc::{empty_trace, Finalize, Trace}, syntax::ast::node::{Declaration, Node}, @@ -32,12 +33,20 @@ pub struct StatementList { impl StatementList { /// Gets the list of items. + #[inline] pub fn items(&self) -> &[Node] { &self.items } + /// Get the strict mode. + #[inline] + pub fn strict(&self) -> bool { + self.strict + } + /// Set the strict mode. - pub fn set_strict_mode(&mut self, strict: bool) { + #[inline] + pub fn set_strict(&mut self, strict: bool) { self.strict = strict; } @@ -131,17 +140,19 @@ impl Executable for StatementList { .executor() .set_current_state(InterpreterState::Executing); - let strict_before = context.strict; + let strict_before = context.strict_type(); - if !context.strict && self.strict { - context.strict = true; + match context.strict_type() { + StrictType::Off if self.strict => context.set_strict(StrictType::Function), + StrictType::Function if !self.strict => context.set_strict_mode_off(), + _ => {} } for (i, item) in self.items().iter().enumerate() { let val = match item.run(context) { Ok(val) => val, Err(e) => { - context.strict = strict_before; + context.set_strict(strict_before); return Err(e); } }; @@ -167,7 +178,7 @@ impl Executable for StatementList { } } - context.strict = strict_before; + context.set_strict(strict_before); Ok(obj) } diff --git a/boa/src/syntax/ast/node/statement_list/tests.rs b/boa/src/syntax/ast/node/statement_list/tests.rs index c2697cd0ed2..f39b57b9186 100644 --- a/boa/src/syntax/ast/node/statement_list/tests.rs +++ b/boa/src/syntax/ast/node/statement_list/tests.rs @@ -72,3 +72,25 @@ fn strict_mode_global_active_in_function() { assert_eq!(&exec(scenario), "true"); } + +#[test] +fn strict_mode_function_in_function() { + let scenario = r#" + let throws = false; + function a(){ + try { + delete Boolean.prototype; + } catch (e) { + throws = true; + } + } + function b(){ + 'use strict'; + a(); + } + b(); + throws + "#; + + assert_eq!(&exec(scenario), "false"); +} diff --git a/boa/src/syntax/parser/function/mod.rs b/boa/src/syntax/parser/function/mod.rs index b6790d21b5a..7367f6dbd9d 100644 --- a/boa/src/syntax/parser/function/mod.rs +++ b/boa/src/syntax/parser/function/mod.rs @@ -295,7 +295,7 @@ where cursor.set_strict_mode(global_strict_mode); let mut statement_list = statement_list?; - statement_list.set_strict_mode(strict); + statement_list.set_strict(strict); Ok(statement_list) } } diff --git a/boa/src/syntax/parser/mod.rs b/boa/src/syntax/parser/mod.rs index 8475699c7fb..2a06f7afdde 100644 --- a/boa/src/syntax/parser/mod.rs +++ b/boa/src/syntax/parser/mod.rs @@ -133,7 +133,7 @@ where _ => {} } let mut statement_list = ScriptBody.parse(cursor)?; - statement_list.set_strict_mode(strict); + statement_list.set_strict(strict); Ok(statement_list) } None => Ok(StatementList::from(Vec::new())), diff --git a/boa_tester/src/exec/mod.rs b/boa_tester/src/exec/mod.rs index a4021b91373..b77b6176781 100644 --- a/boa_tester/src/exec/mod.rs +++ b/boa_tester/src/exec/mod.rs @@ -139,7 +139,9 @@ impl Test { match self.set_up_env(harness, strict) { Ok(mut context) => { - context.strict = strict; + if strict { + context.set_strict_mode_global(); + } let res = context.eval(&self.content.as_ref()); let passed = res.is_ok(); @@ -186,7 +188,9 @@ impl Test { } else { match self.set_up_env(harness, strict) { Ok(mut context) => { - context.strict = strict; + if strict { + context.set_strict_mode_global(); + } match context.eval(&self.content.as_ref()) { Ok(res) => (false, format!("{}", res.display())), Err(e) => {