From 3f84d7fe704275b9ec40552b8d601ecb4cc6c909 Mon Sep 17 00:00:00 2001 From: "igor%mir2.org" Date: Fri, 16 May 2003 14:25:57 +0000 Subject: [PATCH] Resolving http://bugzilla.mozilla.org/show_bug.cgi?id=203013 : Changing behavior of sealed objects to throw an exception on any attempt to modify them including changing values of existing properties. In the same time making object sealed does not affect read-only status of its properties which allows to override properties of objects with a sealed object as a prototype. Rhino shell now accepts -sealedlib option to seal all standard objects. --- .../org/mozilla/javascript/IdScriptable.java | 6 +++- .../mozilla/javascript/ImporterTopLevel.java | 6 +++- .../org/mozilla/javascript/NativeArray.java | 30 +++++++++-------- .../mozilla/javascript/ScriptableObject.java | 32 +++++++++++++++---- .../javascript/resources/Messages.properties | 7 ++-- .../javascript/tools/shell/Global.java | 2 +- .../mozilla/javascript/tools/shell/Main.java | 15 +++++++++ 7 files changed, 73 insertions(+), 25 deletions(-) diff --git a/js/rhino/src/org/mozilla/javascript/IdScriptable.java b/js/rhino/src/org/mozilla/javascript/IdScriptable.java index b09ddb3e2329..43c349573545 100644 --- a/js/rhino/src/org/mozilla/javascript/IdScriptable.java +++ b/js/rhino/src/org/mozilla/javascript/IdScriptable.java @@ -99,8 +99,12 @@ public abstract class IdScriptable extends ScriptableObject if (maxId != 0) { int id = mapNameToId_cached(name); if (id != 0) { + if (start == this && isSealed()) { + throw Context.reportRuntimeError1("msg.modify.sealed", + name); + } int attr = getIdAttributes(id); - if ((attr & READONLY) == 0 && !isSealed()) { + if ((attr & READONLY) == 0) { if (start == this) { setIdValue(id, value); } diff --git a/js/rhino/src/org/mozilla/javascript/ImporterTopLevel.java b/js/rhino/src/org/mozilla/javascript/ImporterTopLevel.java index ad20f3f2a03e..d2467d049648 100644 --- a/js/rhino/src/org/mozilla/javascript/ImporterTopLevel.java +++ b/js/rhino/src/org/mozilla/javascript/ImporterTopLevel.java @@ -80,7 +80,11 @@ public class ImporterTopLevel extends ScriptableObject { } public ImporterTopLevel(Context cx) { - cx.initStandardObjects(this); + this(cx, false); + } + + public ImporterTopLevel(Context cx, boolean sealed) { + cx.initStandardObjects(this, sealed); init(); } diff --git a/js/rhino/src/org/mozilla/javascript/NativeArray.java b/js/rhino/src/org/mozilla/javascript/NativeArray.java index a798e00c7424..87a2daa478be 100644 --- a/js/rhino/src/org/mozilla/javascript/NativeArray.java +++ b/js/rhino/src/org/mozilla/javascript/NativeArray.java @@ -231,41 +231,45 @@ public class NativeArray extends IdScriptable { public void put(String id, Scriptable start, Object value) { + super.put(id, start, value); if (start == this) { + // If the object is sealed, super will throw exception long index = toArrayIndex(id); if (index >= length) { length = index + 1; } } - super.put(id, start, value); } public void put(int index, Scriptable start, Object value) { + if (start == this && !isSealed() + && dense != null && 0 <= index && index < dense.length) + { + // If start == this && sealed, super will throw exception + dense[index] = value; + } else { + super.put(index, start, value); + } if (start == this) { // only set the array length if given an array index (ECMA 15.4.0) if (this.length <= index) { // avoid overflowing index! this.length = (long)index + 1; } - - if (dense != null && 0 <= index && index < dense.length) { - dense[index] = value; - return; - } } - super.put(index, start, value); + } public void delete(int index) { - if (!isSealed()) { - if (dense != null && 0 <= index && index < dense.length) { - dense[index] = NOT_FOUND; - return; - } + if (!isSealed() + && dense != null && 0 <= index && index < dense.length) + { + dense[index] = NOT_FOUND; + } else { + super.delete(index); } - super.delete(index); } public Object[] getIds() diff --git a/js/rhino/src/org/mozilla/javascript/ScriptableObject.java b/js/rhino/src/org/mozilla/javascript/ScriptableObject.java index aad9c864a32e..eea9df3b0e35 100644 --- a/js/rhino/src/org/mozilla/javascript/ScriptableObject.java +++ b/js/rhino/src/org/mozilla/javascript/ScriptableObject.java @@ -256,8 +256,10 @@ public abstract class ScriptableObject implements Scriptable, Serializable, } // Note: cache is not updated in put } - - if ((slot.attributes & ScriptableObject.READONLY) != 0 || isSealed()) { + if (start == this && isSealed()) { + throw Context.reportRuntimeError1("msg.modify.sealed", name); + } + if ((slot.attributes & ScriptableObject.READONLY) != 0) { return; } if ((slot.flags & Slot.HAS_SETTER) != 0) { @@ -293,9 +295,16 @@ public abstract class ScriptableObject implements Scriptable, Serializable, setterThis = start; args = new Object[] { actualArg }; } else { + if (start != this) Context.codeBug(); setterThis = slot.delegateTo; args = new Object[] { this, actualArg }; } + // Check start is sealed: start is always instance of ScriptableObject + // due to logic in if (start != this) above + if (((ScriptableObject)start).isSealed()) { + throw Context.reportRuntimeError1("msg.modify.sealed", + slot.stringKey); + } try { setterResult = slot.setter.invoke(setterThis, args); @@ -343,8 +352,13 @@ public abstract class ScriptableObject implements Scriptable, Serializable, } slot = getSlotToSet(null, index); } - if ((slot.attributes & ScriptableObject.READONLY) != 0 || isSealed()) + if (start == this && isSealed()) { + throw Context.reportRuntimeError1("msg.modify.sealed", + Integer.toString(index)); + } + if ((slot.attributes & ScriptableObject.READONLY) != 0) { return; + } if (this == start) { slot.value = value; } else { @@ -1571,8 +1585,10 @@ public abstract class ScriptableObject implements Scriptable, Serializable, * caused the table to grow while this thread was searching. */ private synchronized Slot addSlot(String id, int index, Slot newSlot) { - if (isSealed()) - throw Context.reportRuntimeError0("msg.add.sealed"); + if (isSealed()) { + String str = (id != null) ? id : Integer.toString(index); + throw Context.reportRuntimeError1("msg.add.sealed", str); + } if (slots == null) { slots = new Slot[5]; } @@ -1619,8 +1635,10 @@ public abstract class ScriptableObject implements Scriptable, Serializable, * deletes are not common. */ private synchronized void removeSlot(String name, int index) { - if (isSealed()) - throw Context.reportRuntimeError0("msg.remove.sealed"); + if (isSealed()) { + String str = (name != null) ? name : Integer.toString(index); + throw Context.reportRuntimeError1("msg.remove.sealed", str); + } int i = getSlotPosition(slots, name, index); if (i >= 0) { diff --git a/js/rhino/src/org/mozilla/javascript/resources/Messages.properties b/js/rhino/src/org/mozilla/javascript/resources/Messages.properties index caa3bd5178ba..ab56e682f59d 100644 --- a/js/rhino/src/org/mozilla/javascript/resources/Messages.properties +++ b/js/rhino/src/org/mozilla/javascript/resources/Messages.properties @@ -430,10 +430,13 @@ msg.setter.parms =\ Expected either one or two parameters for setter. msg.add.sealed =\ - Cannot add a property to a sealed object. + Cannot add a property to a sealed object: {0}. msg.remove.sealed =\ - Cannot remove a property from a sealed object. + Cannot remove a property from a sealed object: {0}. + +msg.modify.sealed =\ + Cannot modify a property of a sealed object: {0}. # TokenStream msg.missing.exponent =\ diff --git a/js/rhino/toolsrc/org/mozilla/javascript/tools/shell/Global.java b/js/rhino/toolsrc/org/mozilla/javascript/tools/shell/Global.java index b1736343c19d..657c4ec17bec 100644 --- a/js/rhino/toolsrc/org/mozilla/javascript/tools/shell/Global.java +++ b/js/rhino/toolsrc/org/mozilla/javascript/tools/shell/Global.java @@ -58,7 +58,7 @@ public class Global extends ImporterTopLevel { { // Define some global functions particular to the shell. Note // that these functions are not part of ECMA. - super(cx); + super(cx, Main.sealedStdLib); String[] names = { "print", "quit", "version", "load", "help", "loadClass", "defineClass", "spawn", "sync", "serialize", "deserialize", "runCommand" }; diff --git a/js/rhino/toolsrc/org/mozilla/javascript/tools/shell/Main.java b/js/rhino/toolsrc/org/mozilla/javascript/tools/shell/Main.java index f1b1ee79692a..52ac707332b1 100644 --- a/js/rhino/toolsrc/org/mozilla/javascript/tools/shell/Main.java +++ b/js/rhino/toolsrc/org/mozilla/javascript/tools/shell/Main.java @@ -82,6 +82,15 @@ public class Main { * Execute the given arguments, but don't System.exit at the end. */ public static int exec(String args[]) { + + for (int i=0; i < args.length; i++) { + String arg = args[i]; + if (arg.equals("-sealedlib")) { + sealedStdLib = true; + break; + } + } + Context cx = enterContext(); // Create the top-level scope object. global = getGlobal(); @@ -177,6 +186,11 @@ public class Main { fileList.addElement(args[i].equals("-") ? null : args[i]); continue; } + if (arg.equals("-sealedlib")) { + // Should already be processed + if (!sealedStdLib) Context.codeBug(); + continue; + } usage(arg); } return new String[0]; @@ -447,6 +461,7 @@ public class Main { static private final int EXITCODE_FILE_NOT_FOUND = 4; //static private DebugShell debugShell; static boolean processStdin = true; + static boolean sealedStdLib = false; static Vector fileList = new Vector(5); private static SecurityProxy securityImpl; }