提交 5436b77c 编写于 作者: S sundar

8098578: Global scope is not accessible with indirect load call

Reviewed-by: attila, hannesw
上级 013314f6
......@@ -1502,26 +1502,53 @@ public final class Global extends ScriptObject implements Scope {
}
/**
* Global load implementation - Nashorn extension
* Global load implementation - Nashorn extension.
*
* <p>
* load builtin loads the given script. Script source can be a URL or a File
* or a script object with name and script properties. Evaluated code gets
* global object "this" and uses global object as scope for evaluation.
* </p>
* <p>
* If self is undefined or null or global, then global object is used
* as scope as well as "this" for the evaluated code. If self is any other
* object, then it is indirect load call. With indirect load call, the
* properties of scope are available to evaluated script as variables. Also,
* global scope properties are accessible. Any var, function definition in
* evaluated script goes into an object that is not accessible to user scripts.
* </p>
* Thus the indirect load call is equivalent to the following:
* <pre>
* <code>
* (function (scope, source) {
* with(scope) {
* eval(&lt;script_from_source&gt;);
* }
* })(self, source);
* </code>
* </pre>
*
* @param self scope
* @param source source to load
* @param self scope to use for the script evaluation
* @param source script source
*
* @return result of load (undefined)
* @return result of load (may be undefined)
*
* @throws IOException if source could not be read
*/
public static Object load(final Object self, final Object source) throws IOException {
final Global global = Global.instanceFrom(self);
final ScriptObject scope = self instanceof ScriptObject ? (ScriptObject)self : global;
return global.getContext().load(scope, source);
return global.getContext().load(self, source);
}
/**
* Global loadWithNewGlobal implementation - Nashorn extension
* Global loadWithNewGlobal implementation - Nashorn extension.
*
* loadWithNewGlobal builtin loads the given script from a URL or a File
* or a script object with name and script properties. Evaluated code gets
* new global object "this" and uses that new global object as scope for evaluation.
*
* @param self scope
* @param args from plus (optional) arguments to be passed to the loaded script
* @param self self This value is ignored by this function
* @param args optional arguments to be passed to the loaded script
*
* @return result of load (may be undefined)
*
......
......@@ -777,7 +777,7 @@ public final class Context {
*
* @throws IOException if source cannot be found or loaded
*/
public Object load(final ScriptObject scope, final Object from) throws IOException {
public Object load(final Object scope, final Object from) throws IOException {
final Object src = from instanceof ConsString ? from.toString() : from;
Source source = null;
......@@ -829,7 +829,42 @@ public final class Context {
}
if (source != null) {
return evaluateSource(source, scope, scope);
if (scope instanceof ScriptObject && ((ScriptObject)scope).isScope()) {
final ScriptObject sobj = (ScriptObject)scope;
// passed object is a script object
// Global is the only user accessible scope ScriptObject
assert sobj.isGlobal() : "non-Global scope object!!";
return evaluateSource(source, sobj, sobj);
} else if (scope == null || scope == UNDEFINED) {
// undefined or null scope. Use current global instance.
final Global global = getGlobal();
return evaluateSource(source, global, global);
} else {
/*
* Arbitrary object passed for scope.
* Indirect load that is equivalent to:
*
* (function(scope, source) {
* with (scope) {
* eval(<script_from_source>);
* }
* })(scope, source);
*/
final Global global = getGlobal();
// Create a new object. This is where all declarations
// (var, function) from the evaluated code go.
// make global to be its __proto__ so that global
// definitions are accessible to the evaluated code.
final ScriptObject evalScope = newScope(global);
// finally, make a WithObject around user supplied scope object
// so that it's properties are accessible as variables.
final ScriptObject withObj = ScriptRuntime.openWith(evalScope, scope);
// evaluate given source with 'withObj' as scope
// but use global object as "this".
return evaluateSource(source, withObj, global);
}
}
throw typeError("cant.load.script", ScriptRuntime.safeToString(from));
......
/*
* 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-8098578: Global scope is not accessible with indirect load call
*
* @test
* @run
*/
var obj = { foo: 343 };
var global = this;
var x = 434;
// indirect load call
var res = load.call(obj, {
name: "t.js",
// global is accessible. All declarations go into
// intermediate inaccessible scope. "this" is global
// User's passed object's properties are accessible
// as variables.
script: "foo -= 300; var bar = x; Assert.assertTrue(bar == 434); function func() {}; this"
})
// 'this' for the evaluated code is global
Assert.assertTrue(res === global);
// properties of passed object are accessible in evaluated code
Assert.assertTrue(obj.foo == 43);
// vars, functions definined in evaluated code don't go into passed object
Assert.assertTrue(typeof obj.bar == "undefined");
Assert.assertTrue(typeof obj.func == "undefined");
// vars, functions definined in evaluated code don't go leak into global
Assert.assertTrue(typeof bar == "undefined");
Assert.assertTrue(typeof func == "undefined");
Assert.assertTrue(typeof foo == "undefined");
var res = load.call(undefined, {
name: "t1.js",
// still global is accessible and 'this' is global
script: "Assert.assertTrue(x == 434); this"
});
// indirect load with 'undefined' this is same as as direct load
// or load on global itself.
Assert.assertTrue(res === global);
// indirect load with 'undefined' this is same as as direct load
// or load on global itself.
var res = load.call(null, {
name: "t2.js",
// still global is accessible and 'this' is global
script: "Assert.assertTrue(x == 434); this"
});
Assert.assertTrue(res === global);
// indirect load with mirror object
var mirror = loadWithNewGlobal({
name: "t3.js",
script: "({ foo: 'hello', x: Math.PI })"
});
var res = load.call(mirror, {
name: "t4.js",
script: "Assert.assertTrue(foo == 'hello'); Assert.assertTrue(x == Math.PI); this"
});
Assert.assertTrue(res === global);
// indirect load on non-script object, non-mirror results in TypeError
function tryLoad(obj) {
try {
load.call(obj, {
name: "t5.js", script: "this"
});
throw new Error("should thrown TypeError for: " + obj);
} catch (e if TypeError) {}
}
tryLoad("hello");
tryLoad(Math.E);
tryLoad(true);
tryLoad(false);
// indirect load of a large script
load.call({}, __DIR__ + "JDK-8098807-payload.js");
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册