8098546: eval within a 'with' leaks definitions into global scope
authorhannesw
Mon, 15 Jun 2015 15:49:14 +0200
changeset 31194 f00cb8259826
parent 31193 f019295fdeb3
child 31195 4ff0587b9ed1
8098546: eval within a 'with' leaks definitions into global scope Reviewed-by: sundar, attila
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java
nashorn/test/script/basic/JDK-8098546.js
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java	Mon Jun 15 15:37:01 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java	Mon Jun 15 15:49:14 2015 +0200
@@ -373,9 +373,9 @@
      * @return prototype object after merge
      */
     public static ScriptObject mergeScope(final ScriptObject scope) {
-        final ScriptObject global = scope.getProto();
-        global.addBoundProperties(scope);
-        return global;
+        final ScriptObject parentScope = scope.getProto();
+        parentScope.addBoundProperties(scope);
+        return parentScope;
     }
 
     /**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java	Mon Jun 15 15:37:01 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java	Mon Jun 15 15:49:14 2015 +0200
@@ -224,29 +224,33 @@
 
     @Override
     public void setSplitState(final int state) {
-        getNonWithParent().setSplitState(state);
+        ((Scope) getNonWithParent()).setSplitState(state);
     }
 
     @Override
     public int getSplitState() {
-        return getNonWithParent().getSplitState();
+        return ((Scope) getNonWithParent()).getSplitState();
+    }
+
+    @Override
+    public void addBoundProperties(final ScriptObject source, final Property[] properties) {
+        // Declared variables in nested eval go to first normal (non-with) parent scope.
+        getNonWithParent().addBoundProperties(source, properties);
     }
 
     /**
      * Get first parent scope that is not an instance of WithObject.
      */
-    private Scope getNonWithParent() {
-        ScriptObject proto = getParentScope();
+    private ScriptObject getNonWithParent() {
+        ScriptObject proto = getProto();
 
         while (proto != null && proto instanceof WithObject) {
-            proto = ((WithObject)proto).getParentScope();
+            proto = proto.getProto();
         }
 
-        assert proto instanceof Scope : "with scope without parent scope";
-        return (Scope) proto;
+        return proto;
     }
 
-
     private static GuardedInvocation fixReceiverType(final GuardedInvocation link, final MethodHandle filter) {
         // The receiver may be an Object or a ScriptObject.
         final MethodType invType = link.getInvocation().type();
@@ -380,14 +384,6 @@
         return expression;
     }
 
-    /**
-     * Get the parent scope for this {@code WithObject}
-     * @return the parent scope
-     */
-    public ScriptObject getParentScope() {
-        return getProto();
-    }
-
     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
         return MH.findStatic(MethodHandles.lookup(), WithObject.class, name, MH.type(rtype, types));
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8098546.js	Mon Jun 15 15:49:14 2015 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8098546: eval within a 'with' leaks definitions into global scope
+ *
+ * @test
+ * @run
+ */
+
+function func() {
+    var obj = { foo: 344 };
+    with (obj) {
+       eval("var x = foo + 3");
+    }
+    Assert.assertTrue(obj.x === undefined);
+    Assert.assertTrue(x === 347);
+}
+
+func();
+
+// x should be undefined here
+Assert.assertTrue(typeof x === "undefined");
+