Skip to content

Variable leakage across eval invocations #5332

@ivankra

Description

@ivankra

Describe the bug

$ cat a.js
function f(s) { return eval(s); };
console.log(f("eval('var x = 1;'); typeof x"));  // should be: number
console.log(f("typeof x"));                      // should be: undefined
$ ./boa a.js
number
Uncaught Error: ReferenceError: x is not defined (a.js:3:14)
    at <eval> (eval at :?:?)
    at f (a.js:1:28)
    at <main> (a.js:3:14)

Build environment (please complete the following information):

  • OS: Linux
  • Version: 352ec3d
  • Target triple: aarch64-unknown-linux-gnu
  • Rustc version: rustc 1.94.1 (e408947bf 2026-03-25)

Additional context

Potential fix that codex came up with - add a deep clone of scope to FunctionEnvironment

Details
diff --git a/core/ast/src/scope.rs b/core/ast/src/scope.rs
index c1728774..7c98df8a 100644
--- a/core/ast/src/scope.rs
+++ b/core/ast/src/scope.rs
@@ -110,6 +110,28 @@ pub(crate) struct Inner {
 }
 
 impl Scope {
+    /// Creates a deep clone of this scope chain, preserving indices, unique IDs and bindings,
+    /// but without sharing the underlying `Rc` storage.
+    #[must_use]
+    pub fn deep_clone(&self) -> Self {
+        fn clone_inner(scope: &Scope) -> Scope {
+            let outer = scope.inner.outer.as_ref().map(clone_inner);
+            Scope {
+                inner: Rc::new(Inner {
+                    unique_id: scope.inner.unique_id,
+                    outer,
+                    index: Cell::new(scope.inner.index.get()),
+                    bindings: RefCell::new(scope.inner.bindings.borrow().clone()),
+                    function: scope.inner.function,
+                    this_escaped: Cell::new(scope.inner.this_escaped.get()),
+                    context: scope.inner.context.clone(),
+                }),
+            }
+        }
+
+        clone_inner(self)
+    }
+
     /// Creates a new global scope.
     #[must_use]
     pub fn new_global() -> Self {
diff --git a/core/engine/src/environments/runtime/declarative/function.rs b/core/engine/src/environments/runtime/declarative/function.rs
index 9e198882..38aba0b6 100644
--- a/core/engine/src/environments/runtime/declarative/function.rs
+++ b/core/engine/src/environments/runtime/declarative/function.rs
@@ -19,7 +19,7 @@ impl FunctionEnvironment {
         Self {
             bindings: GcRefCell::new(vec![None; bindings_count as usize]),
             slots: Box::new(slots),
-            scope,
+            scope: scope.deep_clone(),
         }
     }

Affects some ~15 tests in test262's test/staging/sm/

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions