8015969: Needs to enforce and document that global "context" and "engine" can't be modified when running via jsr223

Reviewed-by: hannesw, jlaskey
This commit is contained in:
Athijegannathan Sundararajan 2013-06-25 17:31:19 +05:30
parent 02e0b5c3f1
commit 249d0ae5b4
6 changed files with 102 additions and 10 deletions

@ -227,6 +227,16 @@ access the variable - for example, it can call public methods on
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>

@ -71,6 +71,9 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
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 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
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 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
// 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;

@ -288,7 +288,7 @@ public class AccessorProperty extends Property {
}
@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 @@ public class AccessorProperty extends Property {
}
@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()];
}

@ -363,7 +363,7 @@ public abstract class Property {
* @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 @@ public abstract class Property {
* @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

@ -158,12 +158,12 @@ public final class UserAccessorProperty extends Property {
}
@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);
}

@ -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);