Changeset 240456 in webkit


Ignore:
Timestamp:
Jan 24, 2019 4:49:44 PM (5 years ago)
Author:
ysuzuki@apple.com
Message:

[JSC] SharedArrayBufferConstructor and ArrayBufferConstructor should not have their own IsoSubspace
https://bugs.webkit.org/show_bug.cgi?id=193774

Reviewed by Mark Lam.

We put all the instances of InternalFunction and its subclasses in IsoSubspace to make safer from UAF.
But since IsoSubspace requires the memory layout of instances is the same, we created different IsoSubspace
for subclasses of InternalFunction if sizeof(subclass) != sizeof(InternalFunction). One example is
ArrayBufferConstructor and SharedArrayBufferConstructor. But it is too costly to allocate 16KB page just
for these two constructor instances. They are only two instances per JSGlobalObject.

This patch makes sizeof(ArrayBufferConstructor) == sizeof(InternalFunction) so that they can use IsoSubspace
of InternalFunction. We introduce JSGenericArrayBufferConstructor, and it takes ArrayBufferSharingMode as
its template parameter. We define JSArrayBufferConstructor as JSGenericArrayBufferConstructor<ArrayBufferSharingMode::Default>
and JSSharedArrayBufferConstructor as JSGenericArrayBufferConstructor<ArrayBufferSharingMode::Shared> so that
we do not need to hold ArrayBufferSharingMode in the field of the constructor. This change removes IsoSubspace
for ArrayBufferConstructors, and reduces the memory usage.

  • runtime/JSArrayBufferConstructor.cpp:

(JSC::JSGenericArrayBufferConstructor<sharingMode>::JSGenericArrayBufferConstructor):
(JSC::JSGenericArrayBufferConstructor<sharingMode>::finishCreation):
(JSC::JSGenericArrayBufferConstructor<sharingMode>::constructArrayBuffer):
(JSC::JSGenericArrayBufferConstructor<sharingMode>::createStructure):
(JSC::JSGenericArrayBufferConstructor<sharingMode>::info):
(JSC::JSArrayBufferConstructor::JSArrayBufferConstructor): Deleted.
(JSC::JSArrayBufferConstructor::finishCreation): Deleted.
(JSC::JSArrayBufferConstructor::create): Deleted.
(JSC::JSArrayBufferConstructor::createStructure): Deleted.
(JSC::constructArrayBuffer): Deleted.

  • runtime/JSArrayBufferConstructor.h:
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):

  • runtime/JSGlobalObject.h:
  • runtime/VM.cpp:

(JSC::VM::VM):

  • runtime/VM.h:
Location:
trunk/Source/JavaScriptCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r240449 r240456  
     12019-01-24  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] SharedArrayBufferConstructor and ArrayBufferConstructor should not have their own IsoSubspace
     4        https://bugs.webkit.org/show_bug.cgi?id=193774
     5
     6        Reviewed by Mark Lam.
     7
     8        We put all the instances of InternalFunction and its subclasses in IsoSubspace to make safer from UAF.
     9        But since IsoSubspace requires the memory layout of instances is the same, we created different IsoSubspace
     10        for subclasses of InternalFunction if sizeof(subclass) != sizeof(InternalFunction). One example is
     11        ArrayBufferConstructor and SharedArrayBufferConstructor. But it is too costly to allocate 16KB page just
     12        for these two constructor instances. They are only two instances per JSGlobalObject.
     13
     14        This patch makes sizeof(ArrayBufferConstructor) == sizeof(InternalFunction) so that they can use IsoSubspace
     15        of InternalFunction. We introduce JSGenericArrayBufferConstructor, and it takes ArrayBufferSharingMode as
     16        its template parameter. We define JSArrayBufferConstructor as JSGenericArrayBufferConstructor<ArrayBufferSharingMode::Default>
     17        and JSSharedArrayBufferConstructor as JSGenericArrayBufferConstructor<ArrayBufferSharingMode::Shared> so that
     18        we do not need to hold ArrayBufferSharingMode in the field of the constructor. This change removes IsoSubspace
     19        for ArrayBufferConstructors, and reduces the memory usage.
     20
     21        * runtime/JSArrayBufferConstructor.cpp:
     22        (JSC::JSGenericArrayBufferConstructor<sharingMode>::JSGenericArrayBufferConstructor):
     23        (JSC::JSGenericArrayBufferConstructor<sharingMode>::finishCreation):
     24        (JSC::JSGenericArrayBufferConstructor<sharingMode>::constructArrayBuffer):
     25        (JSC::JSGenericArrayBufferConstructor<sharingMode>::createStructure):
     26        (JSC::JSGenericArrayBufferConstructor<sharingMode>::info):
     27        (JSC::JSArrayBufferConstructor::JSArrayBufferConstructor): Deleted.
     28        (JSC::JSArrayBufferConstructor::finishCreation): Deleted.
     29        (JSC::JSArrayBufferConstructor::create): Deleted.
     30        (JSC::JSArrayBufferConstructor::createStructure): Deleted.
     31        (JSC::constructArrayBuffer): Deleted.
     32        * runtime/JSArrayBufferConstructor.h:
     33        * runtime/JSGlobalObject.cpp:
     34        (JSC::JSGlobalObject::init):
     35        * runtime/JSGlobalObject.h:
     36        * runtime/VM.cpp:
     37        (JSC::VM::VM):
     38        * runtime/VM.h:
     39
    1402019-01-24  Yusuke Suzuki  <ysuzuki@apple.com>
    241
  • trunk/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.cpp

    r233122 r240456  
    3939
    4040static EncodedJSValue JSC_HOST_CALL arrayBufferFuncIsView(ExecState*);
     41static EncodedJSValue JSC_HOST_CALL callArrayBuffer(ExecState*);
    4142
     43template<>
    4244const ClassInfo JSArrayBufferConstructor::s_info = {
    4345    "Function", &Base::s_info, nullptr, nullptr,
     
    4547};
    4648
    47 static EncodedJSValue JSC_HOST_CALL callArrayBuffer(ExecState*);
    48 static EncodedJSValue JSC_HOST_CALL constructArrayBuffer(ExecState*);
     49template<>
     50const ClassInfo JSSharedArrayBufferConstructor::s_info = {
     51    "Function", &Base::s_info, nullptr, nullptr,
     52    CREATE_METHOD_TABLE(JSSharedArrayBufferConstructor)
     53};
    4954
    50 JSArrayBufferConstructor::JSArrayBufferConstructor(VM& vm, Structure* structure, ArrayBufferSharingMode sharingMode)
    51     : Base(vm, structure, callArrayBuffer, constructArrayBuffer)
    52     , m_sharingMode(sharingMode)
     55template<ArrayBufferSharingMode sharingMode>
     56JSGenericArrayBufferConstructor<sharingMode>::JSGenericArrayBufferConstructor(VM& vm, Structure* structure)
     57    : Base(vm, structure, callArrayBuffer, JSGenericArrayBufferConstructor<sharingMode>::constructArrayBuffer)
    5358{
    5459}
    5560
    56 void JSArrayBufferConstructor::finishCreation(VM& vm, JSArrayBufferPrototype* prototype, GetterSetter* speciesSymbol)
     61template<ArrayBufferSharingMode sharingMode>
     62void JSGenericArrayBufferConstructor<sharingMode>::finishCreation(VM& vm, JSArrayBufferPrototype* prototype, GetterSetter* speciesSymbol)
    5763{
    58     Base::finishCreation(vm, arrayBufferSharingModeName(m_sharingMode));
     64    Base::finishCreation(vm, arrayBufferSharingModeName(sharingMode));
    5965    putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
    6066    putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
    6167    putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, PropertyAttribute::Accessor | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
    6268
    63     if (m_sharingMode == ArrayBufferSharingMode::Default) {
     69    if (sharingMode == ArrayBufferSharingMode::Default) {
    6470        JSGlobalObject* globalObject = this->globalObject(vm);
    6571        JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->isView, arrayBufferFuncIsView, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
     
    6874}
    6975
    70 JSArrayBufferConstructor* JSArrayBufferConstructor::create(VM& vm, Structure* structure, JSArrayBufferPrototype* prototype, GetterSetter* speciesSymbol, ArrayBufferSharingMode sharingMode)
    71 {
    72     JSArrayBufferConstructor* result =
    73         new (NotNull, allocateCell<JSArrayBufferConstructor>(vm.heap))
    74         JSArrayBufferConstructor(vm, structure, sharingMode);
    75     result->finishCreation(vm, prototype, speciesSymbol);
    76     return result;
    77 }
    78 
    79 Structure* JSArrayBufferConstructor::createStructure(
    80     VM& vm, JSGlobalObject* globalObject, JSValue prototype)
    81 {
    82     return Structure::create(
    83         vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info());
    84 }
    85 
    86 static EncodedJSValue JSC_HOST_CALL constructArrayBuffer(ExecState* exec)
     76template<ArrayBufferSharingMode sharingMode>
     77EncodedJSValue JSC_HOST_CALL JSGenericArrayBufferConstructor<sharingMode>::constructArrayBuffer(ExecState* exec)
    8778{
    8879    VM& vm = exec->vm();
    8980    auto scope = DECLARE_THROW_SCOPE(vm);
    9081
    91     JSArrayBufferConstructor* constructor =
    92         jsCast<JSArrayBufferConstructor*>(exec->jsCallee());
     82    JSGenericArrayBufferConstructor* constructor = jsCast<JSGenericArrayBufferConstructor*>(exec->jsCallee());
    9383
    94     Structure* arrayBufferStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), constructor->globalObject(vm)->arrayBufferStructure(constructor->sharingMode()));
     84    Structure* arrayBufferStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), constructor->globalObject(vm)->arrayBufferStructure(sharingMode));
    9585    RETURN_IF_EXCEPTION(scope, { });
    9686
     
    110100        return JSValue::encode(throwOutOfMemoryError(exec, scope));
    111101   
    112     if (constructor->sharingMode() == ArrayBufferSharingMode::Shared)
     102    if (sharingMode == ArrayBufferSharingMode::Shared)
    113103        buffer->makeShared();
    114     ASSERT(constructor->sharingMode() == buffer->sharingMode());
     104    ASSERT(sharingMode == buffer->sharingMode());
    115105
    116106    JSArrayBuffer* result = JSArrayBuffer::create(vm, arrayBufferStructure, WTFMove(buffer));
    117107    return JSValue::encode(result);
     108}
     109
     110template<ArrayBufferSharingMode sharingMode>
     111Structure* JSGenericArrayBufferConstructor<sharingMode>::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     112{
     113    return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info());
     114}
     115
     116template<ArrayBufferSharingMode sharingMode>
     117const ClassInfo* JSGenericArrayBufferConstructor<sharingMode>::info()
     118{
     119    return &JSGenericArrayBufferConstructor<sharingMode>::s_info;
    118120}
    119121
     
    132134    return JSValue::encode(jsBoolean(jsDynamicCast<JSArrayBufferView*>(exec->vm(), exec->argument(0))));
    133135}
    134    
     136
     137// Instantiate JSGenericArrayBufferConstructors.
     138template class JSGenericArrayBufferConstructor<ArrayBufferSharingMode::Shared>;
     139template class JSGenericArrayBufferConstructor<ArrayBufferSharingMode::Default>;
    135140
    136141} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.h

    r230813 r240456  
    3434class GetterSetter;
    3535
    36 class JSArrayBufferConstructor final : public InternalFunction {
     36template<ArrayBufferSharingMode sharingMode>
     37class JSGenericArrayBufferConstructor final : public InternalFunction {
    3738public:
    38     typedef InternalFunction Base;
     39    using Base = InternalFunction;
    3940
    40     template<typename CellType>
    41     static IsoSubspace* subspaceFor(VM& vm)
     41protected:
     42    JSGenericArrayBufferConstructor(VM&, Structure*);
     43    void finishCreation(VM&, JSArrayBufferPrototype*, GetterSetter* speciesSymbol);
     44
     45    static EncodedJSValue JSC_HOST_CALL constructArrayBuffer(ExecState*);
     46
     47public:
     48    static JSGenericArrayBufferConstructor* create(VM& vm, Structure* structure, JSArrayBufferPrototype* prototype, GetterSetter* speciesSymbol)
    4249    {
    43         return &vm.arrayBufferConstructorSpace;
     50        JSGenericArrayBufferConstructor* result =
     51            new (NotNull, allocateCell<JSGenericArrayBufferConstructor>(vm.heap)) JSGenericArrayBufferConstructor(vm, structure);
     52        result->finishCreation(vm, prototype, speciesSymbol);
     53        return result;
    4454    }
    4555
    46 protected:
    47     JSArrayBufferConstructor(VM&, Structure*, ArrayBufferSharingMode);
    48     void finishCreation(VM&, JSArrayBufferPrototype*, GetterSetter* speciesSymbol);
    49 
    50 public:
    51     static JSArrayBufferConstructor* create(VM&, Structure*, JSArrayBufferPrototype*, GetterSetter* speciesSymbol, ArrayBufferSharingMode);
    52    
    53     DECLARE_INFO;
    54    
    5556    static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
    5657   
    57     ArrayBufferSharingMode sharingMode() const { return m_sharingMode; }
    58 
    59 private:
    60     ArrayBufferSharingMode m_sharingMode;
     58    static const ClassInfo s_info; // This is never accessed directly, since that would break linkage on some compilers.
     59    static const ClassInfo* info();
    6160};
    6261
     62using JSArrayBufferConstructor = JSGenericArrayBufferConstructor<ArrayBufferSharingMode::Default>;
     63using JSSharedArrayBufferConstructor = JSGenericArrayBufferConstructor<ArrayBufferSharingMode::Shared>;
     64static_assert(sizeof(JSArrayBufferConstructor::Base) == sizeof(JSArrayBufferConstructor), "");
     65static_assert(sizeof(JSSharedArrayBufferConstructor::Base) == sizeof(JSSharedArrayBufferConstructor), "");
     66
    6367} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r240273 r240456  
    677677    m_regExpConstructor.set(vm, this, RegExpConstructor::create(vm, RegExpConstructor::createStructure(vm, this, m_functionPrototype.get()), m_regExpPrototype.get(), m_speciesGetterSetter.get()));
    678678   
    679     JSArrayBufferConstructor* arrayBufferConstructor = JSArrayBufferConstructor::create(vm, JSArrayBufferConstructor::createStructure(vm, this, m_functionPrototype.get()), m_arrayBufferPrototype.get(), m_speciesGetterSetter.get(), ArrayBufferSharingMode::Default);
     679    JSArrayBufferConstructor* arrayBufferConstructor = JSArrayBufferConstructor::create(vm, JSArrayBufferConstructor::createStructure(vm, this, m_functionPrototype.get()), m_arrayBufferPrototype.get(), m_speciesGetterSetter.get());
    680680    m_arrayBufferPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, arrayBufferConstructor, static_cast<unsigned>(PropertyAttribute::DontEnum));
    681681
    682682#if ENABLE(SHARED_ARRAY_BUFFER)
    683     JSArrayBufferConstructor* sharedArrayBufferConstructor = nullptr;
    684     sharedArrayBufferConstructor = JSArrayBufferConstructor::create(vm, JSArrayBufferConstructor::createStructure(vm, this, m_functionPrototype.get()), m_sharedArrayBufferPrototype.get(), m_speciesGetterSetter.get(), ArrayBufferSharingMode::Shared);
     683    JSSharedArrayBufferConstructor* sharedArrayBufferConstructor = nullptr;
     684    sharedArrayBufferConstructor = JSSharedArrayBufferConstructor::create(vm, JSSharedArrayBufferConstructor::createStructure(vm, this, m_functionPrototype.get()), m_sharedArrayBufferPrototype.get(), m_speciesGetterSetter.get());
    685685    m_sharedArrayBufferPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, sharedArrayBufferConstructor, static_cast<unsigned>(PropertyAttribute::DontEnum));
    686686
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h

    r240273 r240456  
    8383class IntlObject;
    8484class JSArrayBuffer;
    85 class JSArrayBufferConstructor;
    8685class JSArrayBufferPrototype;
    8786class JSCallee;
     
    9493class JSPromisePrototype;
    9594class JSSharedArrayBuffer;
    96 class JSSharedArrayBufferConstructor;
    9795class JSSharedArrayBufferPrototype;
    9896class JSTypedArrayViewConstructor;
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r240273 r240456  
    293293    , eagerlySweptDestructibleObjectSpace("Eagerly Swept JSDestructibleObject", heap, destructibleObjectHeapCellType.get(), fastMallocAllocator.get())
    294294    , segmentedVariableObjectSpace("JSSegmentedVariableObjectSpace", heap, segmentedVariableObjectHeapCellType.get(), fastMallocAllocator.get())
    295     , arrayBufferConstructorSpace ISO_SUBSPACE_INIT(heap, destructibleObjectHeapCellType.get(), JSArrayBufferConstructor)
    296295    , asyncFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSAsyncFunction)
    297296    , asyncGeneratorFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSAsyncGeneratorFunction)
  • trunk/Source/JavaScriptCore/runtime/VM.h

    r240273 r240456  
    368368    CompleteSubspace segmentedVariableObjectSpace;
    369369   
    370     IsoSubspace arrayBufferConstructorSpace;
    371370    IsoSubspace asyncFunctionSpace;
    372371    IsoSubspace asyncGeneratorFunctionSpace;
Note: See TracChangeset for help on using the changeset viewer.