Skip to content

Commit 0728265

Browse files
committed
[PR: 5556] Proxy : ownKeys trap.
Returning duplicates from ownKeys trap will lead to type error.
1 parent 7149247 commit 0728265

File tree

6 files changed

+22
-13
lines changed

6 files changed

+22
-13
lines changed

lib/Common/DataStructures/BaseDictionary.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ namespace JsUtil
250250
return Insert<Insert_Add>(key, value);
251251
}
252252

253+
// Returns -1 if the key is already in the dictionary
253254
int AddNew(const TKey& key, const TValue& value)
254255
{
255256
return Insert<Insert_AddNew>(key, value);

lib/Parser/rterrors.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ RT_ERROR_MSG(JSERR_RegExpInvalidEscape, 5674, "", "Invalid regular expression: i
367367
RT_ERROR_MSG(JSERR_RegExpTooManyCapturingGroups, 5675, "", "Regular expression cannot have more than 32,767 capturing groups", kjstRangeError, 0)
368368
RT_ERROR_MSG(JSERR_ProxyHandlerReturnedFalse, 5676, "Proxy %s handler returned false", "Proxy handler returned false", kjstTypeError, 0)
369369
RT_ERROR_MSG(JSERR_UnicodeRegExpRangeContainsCharClass, 5677, "%s", "Character classes not allowed in a RegExp class range.", kjstSyntaxError, 0)
370+
RT_ERROR_MSG(JSERR_DuplicateKeysFromOwnPropertyKeys, 5678, "%s", "Proxy's ownKeys trap returned duplicate keys", kjstTypeError, 0)
370371

371372
//Host errors
372373
RT_ERROR_MSG(JSERR_HostMaybeMissingPromiseContinuationCallback, 5700, "", "Host may not have set any promise continuation callback. Promises may not be executed.", kjstTypeError, 0)

lib/Runtime/Library/JavascriptProxy.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2342,10 +2342,6 @@ namespace Js
23422342
}
23432343
RecyclableObject* trapResultArray = RecyclableObject::FromVar(ownKeysResult);
23442344

2345-
BOOL isTargetExtensible = targetObj->IsExtensible();
2346-
2347-
targetKeys = JavascriptOperators::GetOwnPropertyKeys(targetObj, requestContext);
2348-
23492345
//15. Assert: targetKeys is a List containing only String and Symbol values.
23502346
//16. Let targetConfigurableKeys be an empty List.
23512347
//17. Let targetNonconfigurableKeys be an empty List.
@@ -2427,6 +2423,7 @@ namespace Js
24272423
Var element;
24282424
PropertyId propertyId;
24292425
const PropertyRecord* propertyRecord = nullptr;
2426+
BOOL isTargetExtensible = FALSE;
24302427

24312428
BEGIN_TEMP_ALLOCATOR(tempAllocator, requestContext, _u("Runtime"))
24322429
{
@@ -2465,6 +2462,9 @@ namespace Js
24652462
break;
24662463
}
24672464

2465+
isTargetExtensible = targetObj->IsExtensible();
2466+
targetKeys = JavascriptOperators::GetOwnPropertyKeys(targetObj, requestContext);
2467+
24682468
for (uint32 i = 0; i < targetKeys->GetLength(); i++)
24692469
{
24702470
element = targetKeys->DirectGetItem(i);

lib/Runtime/Library/JavascriptProxy.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,16 +176,14 @@ namespace Js
176176
JavascriptConversion::ToPropertyKey(element, scriptContext, &propertyRecord, nullptr);
177177
propertyId = propertyRecord->GetPropertyId();
178178

179-
if (!targetToTrapResultMap.ContainsKey(propertyId))
179+
if (propertyId != Constants::NoProperty)
180180
{
181-
if (propertyId != Constants::NoProperty)
181+
if (targetToTrapResultMap.AddNew(propertyId, true) == -1)
182182
{
183-
targetToTrapResultMap.Add(propertyId, true);
183+
JavascriptError::ThrowTypeError(scriptContext, JSERR_DuplicateKeysFromOwnPropertyKeys);
184184
}
185185
}
186186

187-
// We explicitly allow duplicates in the results. A map is sufficient since the spec steps that remove entries
188-
// remove ALL of them at the same time.
189187
if (fn(propertyRecord))
190188
{
191189
trapResult->DirectSetItemAt(trapResultIndex++, element);

test/es6/proxybugs.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,17 @@ var tests = [
484484
var obj2 = Reflect.construct(proxy2, [20]);
485485
assert.areEqual(20, obj2.x);
486486
}
487+
},
488+
{
489+
name: "Proxy's ownKeys is returning duplicate keys should throw",
490+
body() {
491+
var proxy = new Proxy({}, {
492+
ownKeys: function (t) {
493+
return ["a", "a"];
494+
}
495+
});
496+
assert.throws(()=> { Object.keys(proxy);}, TypeError, "proxy's ownKeys is returning duplicate keys", "Proxy's ownKeys trap returned duplicate keys");
497+
}
487498
}
488499
];
489500

test/es6/proxyenumremoval.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,18 +86,16 @@ passed &= keys==="a";
8686

8787
// check property descriptor trap
8888
var keys=""
89-
var already_non_enmerable = false;
9089
var getPrototypeOfCalled = 0;
9190
var proxy = new Proxy({}, {
9291
ownKeys: function() {
93-
return ['a','b','a']; // make first a non-enumerable, and second a enumerable, second a won't show up in for-in
92+
return ['a','b']; // make a non-enumerable and b enumerable
9493
},
9594
getOwnPropertyDescriptor: function(target, key){
9695
var enumerable = true;
97-
if(key === "a" && !already_non_enmerable)
96+
if(key === "a")
9897
{
9998
enumerable=false;
100-
already_non_enmerable = true;
10199
}
102100
return {
103101
configurable: true,

0 commit comments

Comments
 (0)