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

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions