Skip to content

Commit

Permalink
Handle set where internalSetter and Proxy are both true
Browse files Browse the repository at this point in the history
Summary:
If putComputed is called on a proxy whose target's prototype
is an array with a propname of 'length', then internalSetter will be
true, and the receiver will be a proxy.  In that case, proxy needs to
win; the behavior may assert or be UB otherwise.

Reviewed By: tmikov

Differential Revision: D23916279

fbshipit-source-id: c760356d48a02ece565fb4bc1acdafd7ccad7c68
  • Loading branch information
mhorowitz authored and facebook-github-bot committed Sep 26, 2020
1 parent 2201966 commit 8cb935c
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 15 deletions.
35 changes: 20 additions & 15 deletions lib/VM/JSObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1699,6 +1699,24 @@ CallResult<bool> JSObject::putComputedWithReceiver_RJS(
if (LLVM_UNLIKELY(
desc.flags.internalSetter || receiverHandle->isHostObject() ||
receiverHandle->isProxyObject())) {
// If putComputed is called on a proxy whose target's prototype
// is an array with a propname of 'length', then internalSetter
// will be true, and the receiver will be a proxy. In that case,
// proxy wins.
if (receiverHandle->isProxyObject()) {
if (*descDefinedRes) {
dpf.setValue = 1;
} else {
dpf = DefinePropertyFlags::getDefaultNewPropertyFlags();
}
return JSProxy::defineOwnProperty(
receiverHandle,
runtime,
nameValPrimitiveHandle,
dpf,
valueHandle,
opFlags);
}
SymbolID id{};
LAZY_TO_IDENTIFIER(runtime, nameValPrimitiveHandle, id);
if (desc.flags.internalSetter) {
Expand All @@ -1709,23 +1727,10 @@ CallResult<bool> JSObject::putComputedWithReceiver_RJS(
desc.castToNamedPropertyDescriptorRef(),
valueHandle,
opFlags);
} else if (receiverHandle->isHostObject()) {
return vmcast<HostObject>(receiverHandle.get())->set(id, *valueHandle);
}
assert(
receiverHandle->isProxyObject() && "descriptor flags are impossible");
if (*descDefinedRes) {
dpf.setValue = 1;
} else {
dpf = DefinePropertyFlags::getDefaultNewPropertyFlags();
}
return JSProxy::defineOwnProperty(
receiverHandle,
runtime,
nameValPrimitiveHandle,
dpf,
valueHandle,
opFlags);
receiverHandle->isHostObject() && "descriptor flags are impossible");
return vmcast<HostObject>(receiverHandle.get())->set(id, *valueHandle);
}
}

Expand Down
9 changes: 9 additions & 0 deletions test/hermes/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -2125,5 +2125,14 @@ checkDeep({...f})(_ => ({a:1, b:2}))
// uses fast array access (this will trip an assert otherwise)
new Proxy([], {}).unshift(0);

// If putComputed is called on a proxy whose target's prototype is an
// array with a propname of 'length', then internalSetter will be
// true, and the receiver will be a proxy. In that case, proxy needs
// to win; the behavior may assert or be UB otherwise.
var p = new Proxy(Object.create([]), {});
// using String() forces putComputed
p[String('length')] = 0x123;
p[0xABC] = 1111;

print('done');
// CHECK-LABEL: done

0 comments on commit 8cb935c

Please sign in to comment.