Skip to content

Commit 95c1c89

Browse files
committed
- Do not re-fetch proxy.target after invoking handler.getOwnPropertyDescriptor since the call may have revoked the proxy. Use the cached targetObj instead.
Found by OSS-Fuzz - Do not consider the case a `TypeError`. Arguably the proxy was valid at the time of the entry. (also consistent with other JS runtimes).
1 parent 3eb4f0e commit 95c1c89

File tree

3 files changed

+32
-12
lines changed

3 files changed

+32
-12
lines changed

lib/Runtime/Library/JavascriptProxy.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ namespace Js
195195
target = nullptr;
196196
}
197197

198-
template <class Fn, class GetPropertyIdFunc>
199-
BOOL JavascriptProxy::GetPropertyDescriptorTrap(Var originalInstance, Fn fn, GetPropertyIdFunc getPropertyId, PropertyDescriptor* resultDescriptor, ScriptContext* requestContext)
198+
template <class Fn>
199+
BOOL JavascriptProxy::GetPropertyDescriptorTrap(Var originalInstance, Fn fn, PropertyId propertyId, PropertyDescriptor* resultDescriptor, ScriptContext* requestContext)
200200
{
201201
PROBE_STACK(GetScriptContext(), Js::Constants::MinStackDefault);
202202

@@ -233,7 +233,6 @@ namespace Js
233233
return fn(targetObj);
234234
}
235235

236-
PropertyId propertyId = getPropertyId();
237236
Var propertyName = GetName(requestContext, propertyId);
238237

239238
Assert(JavascriptString::Is(propertyName) || JavascriptSymbol::Is(propertyName));
@@ -254,9 +253,8 @@ namespace Js
254253
//11. Let targetDesc be the result of calling the[[GetOwnProperty]] internal method of target with argument P.
255254
//12. ReturnIfAbrupt(targetDesc).
256255
PropertyDescriptor targetDescriptor;
257-
BOOL hasProperty;
256+
BOOL hasProperty = JavascriptOperators::GetOwnPropertyDescriptor(targetObj, propertyId, requestContext, &targetDescriptor);
258257

259-
hasProperty = JavascriptOperators::GetOwnPropertyDescriptor(targetObj, getPropertyId(), requestContext, &targetDescriptor);
260258
//13. If trapResultObj is undefined, then
261259
//a.If targetDesc is undefined, then return undefined.
262260
//b.If targetDesc.[[Configurable]] is false, then throw a TypeError exception.
@@ -274,7 +272,7 @@ namespace Js
274272
{
275273
JavascriptError::ThrowTypeError(requestContext, JSERR_InconsistentTrapResult, _u("getOwnPropertyDescriptor"));
276274
}
277-
if (!target->IsExtensible())
275+
if (!targetObj->IsExtensible())
278276
{
279277
JavascriptError::ThrowTypeError(requestContext, JSERR_InconsistentTrapResult, _u("getOwnPropertyDescriptor"));
280278
}
@@ -1250,7 +1248,10 @@ namespace Js
12501248
{
12511249
if (target == nullptr)
12521250
{
1253-
JavascriptError::ThrowTypeError(GetScriptContext(), JSERR_ErrorOnRevokedProxy, _u(""));
1251+
// We only can get here through GetOwnPropertyDescriptor, which would check that proxy is not revoked and throw if necessary.
1252+
// It may still be possible for the `target` to become null after the validation, for example if a trap handler revokes the proxy.
1253+
// Just return FALSE in such cases.
1254+
return FALSE;
12541255
}
12551256

12561257
return target->GetDefaultPropertyDescriptor(descriptor);
@@ -1675,8 +1676,8 @@ namespace Js
16751676
auto fn = [&](RecyclableObject *targetObj)-> BOOL {
16761677
return JavascriptOperators::GetOwnPropertyDescriptor(targetObj, propertyId, requestContext, propertyDescriptor);
16771678
};
1678-
auto getPropertyId = [&]() -> PropertyId {return propertyId; };
1679-
BOOL foundProperty = proxy->GetPropertyDescriptorTrap(obj, fn, getPropertyId, propertyDescriptor, requestContext);
1679+
1680+
BOOL foundProperty = proxy->GetPropertyDescriptorTrap(obj, fn, propertyId, propertyDescriptor, requestContext);
16801681
return foundProperty;
16811682
}
16821683

lib/Runtime/Library/JavascriptProxy.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,8 @@ namespace Js
231231
template <class Fn, class GetPropertyIdFunc>
232232
BOOL GetPropertyTrap(Var instance, PropertyDescriptor* propertyDescriptor, Fn fn, GetPropertyIdFunc getPropertyId, ScriptContext* requestContext);
233233

234-
template <class Fn, class GetPropertyIdFunc>
235-
BOOL GetPropertyDescriptorTrap(Var originalInstance, Fn fn, GetPropertyIdFunc getPropertyId, PropertyDescriptor* resultDescriptor, ScriptContext* requestContext);
234+
template <class Fn>
235+
BOOL GetPropertyDescriptorTrap(Var originalInstance, Fn fn, PropertyId propertyId, PropertyDescriptor* resultDescriptor, ScriptContext* requestContext);
236236

237237
#if ENABLE_TTD
238238
public:

test/es6/proxybugs.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,26 @@ var tests = [
230230
};
231231

232232
var obj = Proxy.revocable({}, handler);
233-
assert.throws( () => { Object.getOwnPropertyDescriptor(obj.proxy, 'a'); }, TypeError);
233+
Object.getOwnPropertyDescriptor(obj.proxy, 'a');
234+
assert.isTrue(trapCalled);
235+
}
236+
},
237+
{
238+
name: "Assertion validation : revoking the proxy in getOwnPropertyDescriptor trap, undefined argument",
239+
body() {
240+
var trapCalled = false;
241+
var handler = {
242+
getOwnPropertyDescriptor: function (a, b, c) {
243+
trapCalled = true;
244+
obj.revoke();
245+
246+
// used to cause AV
247+
a[undefined] = new String();
248+
}
249+
};
250+
251+
var obj = Proxy.revocable({}, handler);
252+
Object.getOwnPropertyDescriptor(obj.proxy);
234253
assert.isTrue(trapCalled);
235254
}
236255
},

0 commit comments

Comments
 (0)