diff --git a/rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java b/rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java index 27e2c188d4..aad5f3f51f 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java +++ b/rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java @@ -150,15 +150,11 @@ public static ScriptableObject initSafeStandardObjects( scope.associateValue(LIBRARY_SCOPE_KEY, scope); new ClassCache().associate(scope); - BaseFunction.init(cx, scope, sealed); NativeObject.init(scope, sealed); + BaseFunction.init(cx, scope, sealed); Scriptable objectProto = ScriptableObject.getObjectPrototype(scope); - // Function.prototype.__proto__ should be Object.prototype - Scriptable functionProto = ScriptableObject.getClassPrototype(scope, "Function"); - functionProto.setPrototype(objectProto); - // Set the prototype of the object passed in if need be if (scope.getPrototype() == null) scope.setPrototype(objectProto); diff --git a/rhino/src/main/java/org/mozilla/javascript/ScriptableObject.java b/rhino/src/main/java/org/mozilla/javascript/ScriptableObject.java index ed72aa6cfd..436cbab2d1 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ScriptableObject.java +++ b/rhino/src/main/java/org/mozilla/javascript/ScriptableObject.java @@ -710,6 +710,7 @@ public Scriptable getPrototype() { /** Sets the prototype of the object. */ @Override public void setPrototype(Scriptable m) { + checkNotSealed("__proto__", 0); prototypeObject = m; } @@ -722,6 +723,7 @@ public Scriptable getParentScope() { /** Sets the parent (enclosing) scope of the object. */ @Override public void setParentScope(Scriptable m) { + checkNotSealed("__parent__", 0); parentScopeObject = m; } diff --git a/tests/src/test/java/org/mozilla/javascript/tests/SealedSharedScopeTest.java b/tests/src/test/java/org/mozilla/javascript/tests/SealedSharedScopeTest.java index d801bf130e..9c8b10399c 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/SealedSharedScopeTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/SealedSharedScopeTest.java @@ -22,6 +22,7 @@ import org.mozilla.javascript.IdFunctionObject; import org.mozilla.javascript.ImporterTopLevel; import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.Wrapper; @RunWith(BlockJUnit4ClassRunner.class) @@ -36,6 +37,19 @@ public class SealedSharedScopeTest { public void setUp() throws Exception { try (Context tmpCtx = Context.enter()) { sharedScope = new ImporterTopLevel(tmpCtx, true); + tmpCtx.evaluateString( + sharedScope, + "jsObj = {'bar': 42};\n" + // Some tests... + // + "Object.defineProperties(jsObj, { baz : { writable: true, value: 'aaa' + // }});\n" + // + "Object.seal(jsObj);" + , + "init", + 1, + null); + // Note: Object.seal != ScriptableObject.sealObject + ((ScriptableObject) sharedScope.get("jsObj", sharedScope)).sealObject(); sharedScope.sealObject(); } @@ -177,4 +191,56 @@ public void importClassSucceedsOnScope() throws Exception { assertEquals("ReferenceError: \"Locale\" is not defined. (test#1)", e.getMessage()); } } + + @Test + public void testSealedJsModifyProp() { + String s = evaluateString(scope1, "jsObj").toString(); + assertEquals("[object Object]", s); + + try { + evaluateString(scope1, "'use strict';jsObj.bar = 3"); + fail("EvaluatorException expected"); + } catch (EvaluatorException e) { + assertEquals( + "Cannot modify a property of a sealed object: bar. (test#1)", e.getMessage()); + } + } + + @Test + public void testSealedJsAddProp() { + String s = evaluateString(scope1, "jsObj").toString(); + assertEquals("[object Object]", s); + + try { + evaluateString(scope1, "'use strict';jsObj.foo = 3"); + fail("EvaluatorException expected"); + } catch (EvaluatorException e) { + assertEquals( + "Cannot modify a property of a sealed object: foo. (test#1)", e.getMessage()); + } + } + + @Test + public void testSealedJsModifyProto() { + try { + evaluateString(scope1, "jsObj.__proto__ = {}"); + fail("EvaluatorException expected"); + } catch (EvaluatorException e) { + assertEquals( + "Cannot modify a property of a sealed object: __proto__. (test#1)", + e.getMessage()); + } + } + + @Test + public void testSealedJsModifyParent() { + try { + evaluateString(scope1, "jsObj.__parent__ = {}"); + fail("EvaluatorException expected"); + } catch (EvaluatorException e) { + assertEquals( + "Cannot modify a property of a sealed object: __parent__. (test#1)", + e.getMessage()); + } + } }