Skip to content

Commit f8f2b0b

Browse files
committed
In strict mode throw type error when set/deleteProperty trap handler return falsy value.
1 parent bb8eb71 commit f8f2b0b

File tree

5 files changed

+29
-10
lines changed

5 files changed

+29
-10
lines changed

lib/Parser/rterrors.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ RT_ERROR_MSG(JSERR_InvalidIteratorObject, 5672, "%s : Invalid iterator object",
365365
RT_ERROR_MSG(JSERR_NoAccessors, 5673, "Invalid property descriptor: accessors not supported on this object", "", kjstTypeError, 0)
366366
RT_ERROR_MSG(JSERR_RegExpInvalidEscape, 5674, "", "Invalid regular expression: invalid escape in unicode pattern", kjstSyntaxError, 0)
367367
RT_ERROR_MSG(JSERR_RegExpTooManyCapturingGroups, 5675, "", "Regular expression cannot have more than 32,767 capturing groups", kjstRangeError, 0)
368+
RT_ERROR_MSG(JSERR_ProxyHandlerReturnedFalse, 5676, "Proxy %s handler returned false", "Proxy handler returned false", kjstTypeError, 0)
368369

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

lib/Runtime/Language/JavascriptOperators.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2326,7 +2326,7 @@ using namespace Js;
23262326
PropertyValueInfo::SetNoCache(info, proxy);
23272327
PropertyValueInfo::DisablePrototypeCache(info, proxy);
23282328
}
2329-
return proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetPropertyWPCacheKind, propertyKey, newValue, requestContext);
2329+
return proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetPropertyWPCacheKind, propertyKey, newValue, requestContext, propertyOperationFlags);
23302330
}
23312331
else
23322332
{
@@ -2410,7 +2410,7 @@ using namespace Js;
24102410
JavascriptProxy* proxy = JavascriptProxy::FromVar(setterValueOrProxy);
24112411
const PropertyRecord* propertyRecord = nullptr;
24122412
proxy->PropertyIdFromInt(index, &propertyRecord);
2413-
return proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetItemOnTaggedNumberKind, propertyRecord->GetPropertyId(), newValue, requestContext);
2413+
return proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetItemOnTaggedNumberKind, propertyRecord->GetPropertyId(), newValue, requestContext, propertyOperationFlags);
24142414
}
24152415
else
24162416
{
@@ -2458,7 +2458,7 @@ using namespace Js;
24582458
{
24592459
Assert(JavascriptProxy::Is(setterValueOrProxy));
24602460
JavascriptProxy* proxy = JavascriptProxy::FromVar(setterValueOrProxy);
2461-
return proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetPropertyOnTaggedNumberKind, propertyId, newValue, requestContext);
2461+
return proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetPropertyOnTaggedNumberKind, propertyId, newValue, requestContext, propertyOperationFlags);
24622462
}
24632463
else
24642464
{
@@ -2549,7 +2549,7 @@ using namespace Js;
25492549
PropertyValueInfo::SetNoCache(info, proxy);
25502550
PropertyValueInfo::DisablePrototypeCache(info, proxy); // We can't cache prototype property either
25512551

2552-
*result = proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetPropertyKind, propertyId, newValue, requestContext);
2552+
*result = proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetPropertyKind, propertyId, newValue, requestContext, propertyOperationFlags);
25532553
return true;
25542554
}
25552555
else
@@ -3305,7 +3305,7 @@ using namespace Js;
33053305
JavascriptProxy* proxy = JavascriptProxy::FromVar(setterValueOrProxy);
33063306
const PropertyRecord* propertyRecord = nullptr;
33073307
proxy->PropertyIdFromInt(index, &propertyRecord);
3308-
return proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetItemKind, propertyRecord->GetPropertyId(), value, scriptContext, skipPrototypeCheck);
3308+
return proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetItemKind, propertyRecord->GetPropertyId(), value, scriptContext, propertyOperationFlags, skipPrototypeCheck);
33093309
}
33103310
else
33113311
{

lib/Runtime/Library/JavascriptProxy.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,10 @@ namespace Js
827827
BOOL trapResult = JavascriptConversion::ToBoolean(deletePropertyResult, requestContext);
828828
if (!trapResult)
829829
{
830+
if (flags & PropertyOperation_StrictMode)
831+
{
832+
JavascriptError::ThrowTypeError(requestContext, JSERR_ProxyHandlerReturnedFalse, _u("deleteProperty"));
833+
}
830834
return trapResult;
831835
}
832836

@@ -1775,15 +1779,15 @@ namespace Js
17751779
}
17761780

17771781

1778-
BOOL JavascriptProxy::SetPropertyTrap(Var receiver, SetPropertyTrapKind setPropertyTrapKind, Js::JavascriptString * propertyNameString, Var newValue, ScriptContext* requestContext)
1782+
BOOL JavascriptProxy::SetPropertyTrap(Var receiver, SetPropertyTrapKind setPropertyTrapKind, Js::JavascriptString * propertyNameString, Var newValue, ScriptContext* requestContext, PropertyOperationFlags propertyOperationFlags)
17791783
{
17801784
const PropertyRecord* propertyRecord;
17811785
requestContext->GetOrAddPropertyRecord(propertyNameString, &propertyRecord);
1782-
return SetPropertyTrap(receiver, setPropertyTrapKind, propertyRecord->GetPropertyId(), newValue, requestContext);
1786+
return SetPropertyTrap(receiver, setPropertyTrapKind, propertyRecord->GetPropertyId(), newValue, requestContext, propertyOperationFlags);
17831787

17841788
}
17851789

1786-
BOOL JavascriptProxy::SetPropertyTrap(Var receiver, SetPropertyTrapKind setPropertyTrapKind, PropertyId propertyId, Var newValue, ScriptContext* requestContext, BOOL skipPrototypeCheck)
1790+
BOOL JavascriptProxy::SetPropertyTrap(Var receiver, SetPropertyTrapKind setPropertyTrapKind, PropertyId propertyId, Var newValue, ScriptContext* requestContext, PropertyOperationFlags propertyOperationFlags, BOOL skipPrototypeCheck)
17871791
{
17881792
PROBE_STACK(GetScriptContext(), Js::Constants::MinStackDefault);
17891793

@@ -1865,6 +1869,11 @@ namespace Js
18651869
BOOL setResult = JavascriptConversion::ToBoolean(setPropertyResult, requestContext);
18661870
if (!setResult)
18671871
{
1872+
if (propertyOperationFlags & PropertyOperation_StrictMode)
1873+
{
1874+
JavascriptError::ThrowTypeError(requestContext, JSERR_ProxyHandlerReturnedFalse, _u("set"));
1875+
}
1876+
18681877
return setResult;
18691878
}
18701879

lib/Runtime/Library/JavascriptProxy.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ namespace Js
154154
virtual Var GetTypeOfString(ScriptContext* requestContext) override;
155155

156156
bool IsRevoked() const;
157-
BOOL SetPropertyTrap(Var receiver, SetPropertyTrapKind setPropertyTrapKind, PropertyId propertyId, Var newValue, ScriptContext* requestContext, BOOL skipPrototypeCheck = FALSE);
158-
BOOL SetPropertyTrap(Var receiver, SetPropertyTrapKind setPropertyTrapKind, Js::JavascriptString * propertyString, Var newValue, ScriptContext* requestContext);
157+
BOOL SetPropertyTrap(Var receiver, SetPropertyTrapKind setPropertyTrapKind, PropertyId propertyId, Var newValue, ScriptContext* requestContext, PropertyOperationFlags propertyOperationFlags, BOOL skipPrototypeCheck = FALSE);
158+
BOOL SetPropertyTrap(Var receiver, SetPropertyTrapKind setPropertyTrapKind, Js::JavascriptString * propertyString, Var newValue, ScriptContext* requestContext, PropertyOperationFlags propertyOperationFlags);
159159

160160
void PropertyIdFromInt(uint32 index, PropertyRecord const** propertyRecord);
161161

test/Bugs/misc_bugs.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,15 @@ var tests = [
165165
assert.areEqual([1], eval("let {x} = {}; [x] = [1]"));
166166
}
167167
},
168+
{
169+
name: "Strict Mode : throw type error when the handler returns falsy value",
170+
body: function () {
171+
assert.throws(() => {"use strict"; let p1 = new Proxy({}, { set() {}}); p1.foo = 1;}, TypeError, "returning undefined on set handler is return false which will throw type error", "Proxy set handler returned false");
172+
assert.throws(() => {"use strict"; let p1 = new Proxy({}, { deleteProperty() {}}); delete p1.foo;}, TypeError, "returning undefined on deleteProperty handler is return false which will throw type error", "Proxy deleteProperty handler returned false");
173+
assert.throws(() => {"use strict"; let p1 = new Proxy({}, { set() {return false;}}); p1.foo = 1;}, TypeError, "set handler is returning false which will throw type error", "Proxy set handler returned false");
174+
assert.throws(() => {"use strict"; let p1 = new Proxy({}, { deleteProperty() {return false;}}); delete p1.foo;}, TypeError, "deleteProperty handler is returning false which will throw type error", "Proxy deleteProperty handler returned false");
175+
}
176+
},
168177

169178
];
170179

0 commit comments

Comments
 (0)