Skip to content

Commit

Permalink
Fix Object.getOwnPropertyDescriptors by fixing missing scope definiti…
Browse files Browse the repository at this point in the history
…ons at some places

Fix handling of the parent scope in a number of places.

Fixes #934, which was re-opened due to a bug in the original implementation.
  • Loading branch information
rbri authored May 27, 2022
1 parent 50ae46c commit 7a94441
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/org/mozilla/javascript/ArrowFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public ArrowFunction(

Function thrower = ScriptRuntime.typeErrorThrower(cx);
NativeObject throwing = new NativeObject();
ScriptRuntime.setBuiltinProtoAndParent(throwing, scope, TopLevel.Builtins.Object);
throwing.put("get", throwing, thrower);
throwing.put("set", throwing, thrower);
throwing.put("enumerable", throwing, Boolean.FALSE);
Expand Down
5 changes: 4 additions & 1 deletion src/org/mozilla/javascript/BaseFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,8 @@ protected synchronized Object setupDefaultPrototype() {
return prototypeProperty;
}
NativeObject obj = new NativeObject();
obj.defineProperty("constructor", this, DONTENUM);
obj.setParentScope(getParentScope());

// put the prototype property into the object now, then in the
// wacky case of a user defining a function Object(), we don't
// get an infinite loop trying to find the prototype.
Expand All @@ -519,6 +520,8 @@ protected synchronized Object setupDefaultPrototype() {
// not the one we just made, it must remain grounded
obj.setPrototype(proto);
}

obj.defineProperty("constructor", this, DONTENUM);
return obj;
}

Expand Down
1 change: 1 addition & 0 deletions src/org/mozilla/javascript/BoundFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public BoundFunction(

Function thrower = ScriptRuntime.typeErrorThrower(cx);
NativeObject throwing = new NativeObject();
ScriptRuntime.setBuiltinProtoAndParent(throwing, scope, TopLevel.Builtins.Object);
throwing.put("get", throwing, thrower);
throwing.put("set", throwing, thrower);
throwing.put("enumerable", throwing, Boolean.FALSE);
Expand Down
4 changes: 2 additions & 2 deletions src/org/mozilla/javascript/Delegator.java
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] ar

/**
* Note that if the <code>delegee</code> is <code>null</code>, this method creates a new
* instance of the Delegator itself rathert than forwarding the call to the <code>delegee</code>
* instance of the Delegator itself rather than forwarding the call to the <code>delegee</code>
* . This permits the use of Delegator prototypes.
*
* @param cx the current Context for this thread
Expand All @@ -243,7 +243,7 @@ public Scriptable construct(Context cx, Scriptable scope, Object[] args) {
Delegator n = newInstance();
Scriptable delegee;
if (args.length == 0) {
delegee = new NativeObject();
delegee = cx.newObject(scope);
} else {
delegee = ScriptRuntime.toObject(cx, scope, args[0]);
}
Expand Down
2 changes: 1 addition & 1 deletion src/org/mozilla/javascript/NativeObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public Object execIdCall(
return f.construct(cx, scope, args);
}
if (args.length == 0 || args[0] == null || Undefined.isUndefined(args[0])) {
return new NativeObject();
return cx.newObject(scope);
}
return ScriptRuntime.toObject(cx, scope, args[0]);
}
Expand Down
3 changes: 1 addition & 2 deletions src/org/mozilla/javascript/ScriptableObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -2654,8 +2654,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE
protected ScriptableObject getOwnPropertyDescriptor(Context cx, Object id) {
Slot slot = querySlot(cx, id);
if (slot == null) return null;
Scriptable scope = getParentScope();
return slot.getPropertyDescriptor(cx, (scope == null ? this : scope));
return slot.getPropertyDescriptor(cx, this);
}

protected Slot querySlot(Context cx, Object id) {
Expand Down
38 changes: 36 additions & 2 deletions testsrc/org/mozilla/javascript/tests/es6/NativeObjectTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.Map;
import org.junit.Test;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.tests.Utils;

Expand All @@ -38,7 +39,8 @@ public void testAssignPropertyGetter() {

@Test
public void testAssignOneParameter() {
evaluateAndAssert("var obj = {};" + "res = Object.assign(obj);" + "res === obj;", true);
evaluateAndAssert(
"var obj = {};" + "res = Object.assign(obj);" + "res === obj;", Boolean.TRUE);
}

@Test
Expand Down Expand Up @@ -264,7 +266,39 @@ public void testFromEntriesOnArray() {
evaluateAndAssert("Object.fromEntries(Object.entries(['x','y','z']))", map);
}

private void evaluateAndAssert(final String script, final Object expected) {
@Test
public void issue943() {
evaluateAndAssert(
"var foo = function e() {}\n"
+ "var fooProto = foo.prototype;\n"
+ "var descProp = Object.getOwnPropertyDescriptor(fooProto, 'constructor');"
+ "descProp.hasOwnProperty('value');\n",
Boolean.TRUE);
}

@Test
public void issue943Realm() {
final String script =
"realm.Object.getOwnPropertyDescriptor(realm.Object, 'getOwnPropertyDescriptor').__proto__ === ({}).__proto__;";

String[] prefixes = {"", "'use strict;'\n"};
for (final String prefix : prefixes) {
Utils.runWithAllOptimizationLevels(
cx -> {
cx.setLanguageVersion(Context.VERSION_ES6);
ScriptableObject scope = cx.initStandardObjects();

Scriptable realm = cx.initStandardObjects();
scope.put("realm", scope, realm);

Object result = cx.evaluateString(scope, prefix + script, "test", 1, null);
assertEquals(Boolean.FALSE, result);
return null;
});
}
}

private static void evaluateAndAssert(final String script, final Object expected) {
String[] prefixes = {"", "'use strict;'\n"};
for (final String prefix : prefixes) {
Utils.runWithAllOptimizationLevels(
Expand Down

0 comments on commit 7a94441

Please sign in to comment.