8015969: Needs to enforce and document that global "context" and "engine" can't be modified when running via jsr223
authorsundar
Tue, 25 Jun 2013 17:31:19 +0530
changeset 18615 3f6e6adcbc1a
parent 18614 addca7a10167
child 18616 05a084e63f71
8015969: Needs to enforce and document that global "context" and "engine" can't be modified when running via jsr223 Reviewed-by: hannesw, jlaskey
nashorn/docs/JavaScriptingProgrammersGuide.html
nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java
nashorn/src/jdk/nashorn/internal/runtime/Property.java
nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
nashorn/test/script/basic/JDK-8015969.js
--- a/nashorn/docs/JavaScriptingProgrammersGuide.html	Mon Jun 24 19:06:01 2013 +0530
+++ b/nashorn/docs/JavaScriptingProgrammersGuide.html	Tue Jun 25 17:31:19 2013 +0530
@@ -227,6 +227,16 @@
 it. Note that the syntax to access Java objects, methods and fields
 is dependent on the scripting language. JavaScript supports the
 most "natural" Java-like syntax.</p>
+<p>
+Nashorn script engine pre-defines two global variables named "context"
+and "engine". The "context" variable is of type javax.script.ScriptContext
+and refers to the current ScriptContext instance passed to script engine's
+eval method. The "engine" variable is of type javax.script.ScriptEngine and
+refers to the current nashorn script engine instance evaluating the script.
+Both of these variables are non-writable, non-enumerable and non-configurable
+- which implies script code can not write overwrite the value, for..loop iteration
+on global object will not iterate these variables and these variables can not be
+deleted by script.
 <pre><code>
 // <a href="source/ScriptVars.java">ScriptVars.java</a>
 
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Mon Jun 24 19:06:01 2013 +0530
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Tue Jun 25 17:31:19 2013 +0530
@@ -71,6 +71,9 @@
     private final ScriptEngineFactory factory;
     private final Context             nashornContext;
     private final ScriptObject        global;
+    // initialized bit late to be made 'final'. Property object for "context"
+    // property of global object
+    private Property                  contextProperty;
 
     // default options passed to Nashorn Options object
     private static final String[] DEFAULT_OPTIONS = new String[] { "-scripting", "-doe" };
@@ -281,13 +284,16 @@
 
         nashornContext.initGlobal(newGlobal);
 
+        final int NON_ENUMERABLE_CONSTANT = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE;
         // current ScriptContext exposed as "context"
-        newGlobal.addOwnProperty("context", Property.NOT_ENUMERABLE, UNDEFINED);
+        // "context" is non-writable from script - but script engine still
+        // needs to set it and so save the context Property object
+        contextProperty = newGlobal.addOwnProperty("context", NON_ENUMERABLE_CONSTANT, UNDEFINED);
         // current ScriptEngine instance exposed as "engine". We added @SuppressWarnings("LeakingThisInConstructor") as
         // NetBeans identifies this assignment as such a leak - this is a false positive as we're setting this property
         // in the Global of a Context we just created - both the Context and the Global were just created and can not be
         // seen from another thread outside of this constructor.
-        newGlobal.addOwnProperty("engine", Property.NOT_ENUMERABLE, this);
+        newGlobal.addOwnProperty("engine", NON_ENUMERABLE_CONSTANT, this);
         // global script arguments with undefined value
         newGlobal.addOwnProperty("arguments", Property.NOT_ENUMERABLE, UNDEFINED);
         // file name default is null
@@ -322,9 +328,10 @@
 
     // scripts should see "context" and "engine" as variables
     private void setContextVariables(final ScriptContext ctxt) {
-        ctxt.setAttribute("context", ctxt, ScriptContext.ENGINE_SCOPE);
         final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
-        ctxtGlobal.set("context", ctxt, false);
+        // set "context" global variable via contextProperty - because this
+        // property is non-writable
+        contextProperty.setObjectValue(ctxtGlobal, ctxtGlobal, ctxt, false);
         Object args = ScriptObjectMirror.unwrap(ctxt.getAttribute("arguments"), ctxtGlobal);
         if (args == null || args == UNDEFINED) {
             args = ScriptRuntime.EMPTY_ARRAY;
--- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Mon Jun 24 19:06:01 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Tue Jun 25 17:31:19 2013 +0530
@@ -288,7 +288,7 @@
     }
 
     @Override
-    protected void setObjectValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict)  {
+    public void setObjectValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict)  {
         if (isSpill()) {
             self.spill[getSlot()] = value;
         } else {
@@ -303,7 +303,7 @@
     }
 
     @Override
-    protected Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
+    public Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
         if (isSpill()) {
             return self.spill[getSlot()];
         }
--- a/nashorn/src/jdk/nashorn/internal/runtime/Property.java	Mon Jun 24 19:06:01 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Property.java	Tue Jun 25 17:31:19 2013 +0530
@@ -363,7 +363,7 @@
      * @param value the new property value
      * @param strict is this a strict setter?
      */
-    protected abstract void setObjectValue(ScriptObject self, ScriptObject owner, Object value, boolean strict);
+    public abstract void setObjectValue(ScriptObject self, ScriptObject owner, Object value, boolean strict);
 
     /**
      * Set the Object value of this property from {@code owner}. This allows to bypass creation of the
@@ -373,7 +373,7 @@
      * @param owner the owner object
      * @return  the property value
      */
-    protected abstract Object getObjectValue(ScriptObject self, ScriptObject owner);
+    public abstract Object getObjectValue(ScriptObject self, ScriptObject owner);
 
     /**
      * Abstract method for retrieving the setter for the property. We do not know
--- a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Mon Jun 24 19:06:01 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Tue Jun 25 17:31:19 2013 +0530
@@ -158,12 +158,12 @@
     }
 
     @Override
-    protected Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
+    public Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
         return userAccessorGetter(owner, getGetterSlot(), self);
     }
 
     @Override
-    protected void setObjectValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
+    public void setObjectValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
         userAccessorSetter(owner, getSetterSlot(), strict ? getKey() : null, self, value);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8015969.js	Tue Jun 25 17:31:19 2013 +0530
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2010, 2013, 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-8015969: Needs to enforce and document that global "context" and "engine" can't be modified when running via jsr223
+ *
+ * @test
+ * @option -scripting
+ * @run
+ */
+
+var m = new javax.script.ScriptEngineManager();
+var e = m.getEngineByName("nashorn");
+
+e.eval(<<EOF
+
+'use strict';
+
+try {
+    context = 444;
+    print("FAILED!! context write should have thrown error");
+} catch (e) {
+    if (! (e instanceof TypeError)) {
+        print("TypeError expected but got " + e);
+    }
+}
+
+try {
+    engine = "hello";
+    print("FAILED!! engine write should have thrown error");
+} catch (e) {
+    if (! (e instanceof TypeError)) {
+        print("TypeError expected but got " + e);
+    }
+}
+
+try {
+    delete context;
+    print("FAILED!! context delete should have thrown error");
+} catch (e) {
+    if (! (e instanceof SyntaxError)) {
+        print("SyntaxError expected but got " + e);
+    }
+}
+
+try {
+    delete engine;
+    print("FAILED!! engine delete should have thrown error");
+} catch (e) {
+    if (! (e instanceof SyntaxError)) {
+        print("SyntaxError expected but got " + e);
+    }
+}
+
+EOF);