-
-
Notifications
You must be signed in to change notification settings - Fork 407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Functions seem to have access to their caller's scope #989
Comments
I think you're mixing 2 different bugs together, the expeted behaviour would be for a ReferenceError to be thrown when executing
|
Hmm, maybe I had an |
I started digging deeper into the problem and I think the root cause is how lexical environments are implemented. When function environment records are created, they seem to be using the right outer environment, but when they're pushed to the LexicalEnvironment stack, that environment gets overwritten. Then, even if that's fixed, the issue will still persist because of the way the environment stack is used in the rest of the lexical environment implementation, for example in Here's a proof of concept (so excuse the excessive cloning) that fixes the first problem and changes --- a/boa/src/environment/lexical_environment.rs
+++ b/boa/src/environment/lexical_environment.rs
@@ -94,7 +94,7 @@ impl LexicalEnvironment {
pub fn push(&mut self, env: Environment) {
let current_env: Environment = self.get_current_environment().clone();
- env.borrow_mut().set_outer_environment(current_env);
+ //env.borrow_mut().set_outer_environment(current_env);
self.environment_stack.push_back(env);
}
@@ -239,15 +239,21 @@ impl LexicalEnvironment {
}
pub fn get_binding_value(&self, name: &str) -> Result<Value, ErrorKind> {
- self.environments()
- .find(|env| env.borrow().has_binding(name))
- .map(|env| env.borrow().get_binding_value(name, false))
- .unwrap_or_else(|| {
- Err(ErrorKind::new_reference_error(format!(
- "{} is not defined",
- name
- )))
- })
+ println!("!! {}", name);
+ let mut env: Environment = self.get_current_environment_ref().clone();
+ while !env.borrow().has_binding(name) {
+ println!("env: {:?}", env.borrow().get_environment_type());
+ env = env
+ .clone()
+ .borrow()
+ .get_outer_environment()
+ .ok_or_else(|| {
+ ErrorKind::new_reference_error(format!("{} is not defined", name))
+ })?;
+ }
+ println!("last env: {:?}", env.borrow().get_environment_type());
+
+ return env.clone().borrow().get_binding_value(name, false);
} With this change, the snippet in my initial report starts to correctly raise a ReferenceError. |
Alternate implementation which replaces the diff --git a/boa/src/environment/lexical_environment.rs b/boa/src/environment/lexical_environment.rs
index 8bdd9cd3f..46fdb8ae5 100644
--- a/boa/src/environment/lexical_environment.rs
+++ b/boa/src/environment/lexical_environment.rs
@@ -93,8 +93,6 @@ impl LexicalEnvironment {
}
pub fn push(&mut self, env: Environment) {
- let current_env: Environment = self.get_current_environment().clone();
- env.borrow_mut().set_outer_environment(current_env);
self.environment_stack.push_back(env);
}
@@ -102,8 +100,10 @@ impl LexicalEnvironment {
self.environment_stack.pop_back()
}
- pub fn environments(&self) -> impl Iterator<Item = &Environment> {
- self.environment_stack.iter().rev()
+ fn environments(&self) -> impl Iterator<Item = Environment> {
+ std::iter::successors(Some(self.get_current_environment_ref().clone()), |env| {
+ env.borrow().get_outer_environment()
+ })
}
pub fn get_global_object(&self) -> Option<Value> {
@@ -134,17 +134,15 @@ impl LexicalEnvironment {
.create_mutable_binding(name, deletion, false),
VariableScope::Function => {
// Find the first function or global environment (from the top of the stack)
- let env = self
- .environments()
+ self.environments()
.find(|env| {
matches!(
env.borrow().get_environment_type(),
EnvironmentType::Function | EnvironmentType::Global
)
})
- .expect("No function or global environment");
-
- env.borrow_mut()
+ .expect("No function or global environment")
+ .borrow_mut()
.create_mutable_binding(name, deletion, false)
}
}
@@ -163,17 +161,16 @@ impl LexicalEnvironment {
.create_immutable_binding(name, deletion),
VariableScope::Function => {
// Find the first function or global environment (from the top of the stack)
- let env = self
- .environments()
+ self.environments()
.find(|env| {
matches!(
env.borrow().get_environment_type(),
EnvironmentType::Function | EnvironmentType::Global
)
})
- .expect("No function or global environment");
-
- env.borrow_mut().create_immutable_binding(name, deletion)
+ .expect("No function or global environment")
+ .borrow_mut()
+ .create_immutable_binding(name, deletion)
}
}
}
@@ -189,15 +186,17 @@ impl LexicalEnvironment {
.environments()
.find(|env| env.borrow().has_binding(name));
- let env = if let Some(env) = env {
+ if let Some(ref env) = env {
env
} else {
// global_env doesn't need has_binding to be satisfied in non strict mode
self.environment_stack
.get(0)
.expect("Environment stack underflow")
- };
- env.borrow_mut().set_mutable_binding(name, value, strict)
+ }
+ .borrow_mut()
+ .set_mutable_binding(name, value, strict)?;
+ Ok(())
}
pub fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> {
@@ -206,15 +205,17 @@ impl LexicalEnvironment {
.environments()
.find(|env| env.borrow().has_binding(name));
- let env = if let Some(env) = env {
+ if let Some(ref env) = env {
env
} else {
// global_env doesn't need has_binding to be satisfied in non strict mode
self.environment_stack
.get(0)
.expect("Environment stack underflow")
- };
- env.borrow_mut().initialize_binding(name, value)
+ }
+ .borrow_mut()
+ .initialize_binding(name, value)?;
+ Ok(())
}
/// get_current_environment_ref is used when you only need to borrow the environment Not a fan of doing it this way though. I think I want to modify |
When calling a function, it appears to be able to access variables defined in the context it was called in, even if it's not supposed to be able to.
To Reproduce
f2()
appears to return 1 instead of raising aReferenceError
.Expected behavior
ReferenceError
is raisedBuild environment (please complete the following information):
I also observed this issue in Boa Playground.
The text was updated successfully, but these errors were encountered: