8098546: eval within a 'with' leaks definitions into global scope
Reviewed-by: sundar, attila
--- 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");
+