Ignore:
Timestamp:
Feb 29, 2016, 7:48:36 PM (9 years ago)
Author:
Yusuke Suzuki
Message:

[JSC] Private symbols should not be trapped by proxy handler
https://bugs.webkit.org/show_bug.cgi?id=154817

Reviewed by Mark Lam.

Since the runtime has some assumptions on the properties associated with the private symbols, ES6 Proxy should not trap these property operations.
For example, in ArrayIteratorPrototype.js

var itemKind = this.@arrayIterationKind;
if (itemKind === @undefined)

throw new @TypeError("%ArrayIteratorPrototype%.next requires that |this| be an Array Iterator instance");

Here, we assume that only the array iterator has the @arrayIterationKind property that value is non-undefined.
But If we implement Proxy with the get handler, that returns a non-undefined value for every operations, we accidentally assumes that the given value is an array iterator.

To avoid these situation, we perform the default operations onto property operations with private symbols.

  • runtime/ProxyObject.cpp:

(JSC::performProxyGet):
(JSC::ProxyObject::performInternalMethodGetOwnProperty):
(JSC::ProxyObject::performHasProperty):
(JSC::ProxyObject::performPut):
(JSC::ProxyObject::performDelete):
(JSC::ProxyObject::deleteProperty):
(JSC::ProxyObject::deletePropertyByIndex):

  • tests/stress/proxy-basic.js:
  • tests/stress/proxy-with-private-symbols.js: Added.

(assert):
(let.handler.getOwnPropertyDescriptor):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp

    r197295 r197383  
    9696
    9797    ProxyObject* proxyObject = jsCast<ProxyObject*>(proxyObjectAsObject);
     98    JSObject* target = proxyObject->target();
     99
     100    auto performDefaultGet = [&] {
     101        return JSValue::encode(target->get(exec, propertyName));
     102    };
     103
     104    if (vm.propertyNames->isPrivateName(Identifier::fromUid(&vm, propertyName.uid())))
     105        return performDefaultGet();
     106
    98107    JSValue handlerValue = proxyObject->handler();
    99108    if (handlerValue.isNull())
     
    107116        return JSValue::encode(jsUndefined());
    108117
    109     JSObject* target = proxyObject->target();
    110118    if (getHandler.isUndefined())
    111         return JSValue::encode(target->get(exec, propertyName));
     119        return performDefaultGet();
    112120
    113121    MarkedArgumentBuffer arguments;
     
    139147{
    140148    VM& vm = exec->vm();
     149    JSObject* target = this->target();
     150
     151    auto performDefaultGetOwnProperty = [&] {
     152        return target->methodTable(vm)->getOwnPropertySlot(target, exec, propertyName, slot);
     153    };
     154
     155    if (vm.propertyNames->isPrivateName(Identifier::fromUid(&vm, propertyName.uid())))
     156        return performDefaultGetOwnProperty();
     157
    141158    JSValue handlerValue = this->handler();
    142159    if (handlerValue.isNull()) {
     
    151168    if (exec->hadException())
    152169        return false;
    153     JSObject* target = this->target();
    154170    if (getOwnPropertyDescriptorMethod.isUndefined())
    155         return target->methodTable(vm)->getOwnPropertySlot(target, exec, propertyName, slot);
     171        return performDefaultGetOwnProperty();
    156172
    157173    MarkedArgumentBuffer arguments;
     
    227243{
    228244    VM& vm = exec->vm();
     245    JSObject* target = this->target();
    229246    slot.setValue(this, None, jsUndefined()); // Nobody should rely on our value, but be safe and protect against any bad actors reading our value.
    230    
     247
     248    auto performDefaultHasProperty = [&] {
     249        return target->methodTable(vm)->getOwnPropertySlot(target, exec, propertyName, slot);
     250    };
     251
     252    if (vm.propertyNames->isPrivateName(Identifier::fromUid(&vm, propertyName.uid())))
     253        return performDefaultHasProperty();
     254
    231255    JSValue handlerValue = this->handler();
    232256    if (handlerValue.isNull()) {
     
    241265    if (exec->hadException())
    242266        return false;
    243     JSObject* target = this->target();
    244267    if (hasMethod.isUndefined())
    245         return target->methodTable(vm)->getOwnPropertySlot(target, exec, propertyName, slot);
     268        return performDefaultHasProperty();
    246269
    247270    MarkedArgumentBuffer arguments;
     
    311334
    312335template <typename PerformDefaultPutFunction>
    313 void ProxyObject::performPut(ExecState* exec, JSValue putValue, JSValue thisValue, PropertyName propertyName, PerformDefaultPutFunction performDefaultPutFunction)
    314 {
    315     VM& vm = exec->vm();
     336void ProxyObject::performPut(ExecState* exec, JSValue putValue, JSValue thisValue, PropertyName propertyName, PerformDefaultPutFunction performDefaultPut)
     337{
     338    VM& vm = exec->vm();
     339
     340    if (vm.propertyNames->isPrivateName(Identifier::fromUid(&vm, propertyName.uid())))
     341        return performDefaultPut();
     342
    316343    JSValue handlerValue = this->handler();
    317344    if (handlerValue.isNull()) {
     
    328355    JSObject* target = this->target();
    329356    if (setMethod.isUndefined()) {
    330         performDefaultPutFunction();
     357        performDefaultPut();
    331358        return;
    332359    }
     
    488515
    489516template <typename DefaultDeleteFunction>
    490 bool ProxyObject::performDelete(ExecState* exec, PropertyName propertyName, DefaultDeleteFunction defaultDeleteFunction)
    491 {
    492     VM& vm = exec->vm();
     517bool ProxyObject::performDelete(ExecState* exec, PropertyName propertyName, DefaultDeleteFunction performDefaultDelete)
     518{
     519    VM& vm = exec->vm();
     520
     521    if (vm.propertyNames->isPrivateName(Identifier::fromUid(&vm, propertyName.uid())))
     522        return performDefaultDelete();
     523
    493524    JSValue handlerValue = this->handler();
    494525    if (handlerValue.isNull()) {
     
    505536    JSObject* target = this->target();
    506537    if (deletePropertyMethod.isUndefined())
    507         return defaultDeleteFunction();
     538        return performDefaultDelete();
    508539
    509540    MarkedArgumentBuffer arguments;
     
    538569{
    539570    ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
    540     auto defaultDelete = [&] () -> bool {
     571    auto performDefaultDelete = [&] () -> bool {
    541572        JSObject* target = jsCast<JSObject*>(thisObject->target());
    542573        return target->methodTable(exec->vm())->deleteProperty(target, exec, propertyName);
    543574    };
    544     return thisObject->performDelete(exec, propertyName, defaultDelete);
     575    return thisObject->performDelete(exec, propertyName, performDefaultDelete);
    545576}
    546577
     
    551582    if (exec->hadException())
    552583        return false;
    553     auto defaultDelete = [&] () -> bool {
     584    auto performDefaultDelete = [&] () -> bool {
    554585        JSObject* target = jsCast<JSObject*>(thisObject->target());
    555586        return target->methodTable(exec->vm())->deletePropertyByIndex(target, exec, propertyName);
    556587    };
    557     return thisObject->performDelete(exec, ident.impl(), defaultDelete);
     588    return thisObject->performDelete(exec, ident.impl(), performDefaultDelete);
    558589}
    559590
Note: See TracChangeset for help on using the changeset viewer.