Title: [240465] trunk/Source/_javascript_Core
Revision
240465
Author
[email protected]
Date
2019-01-24 18:47:58 -0800 (Thu, 24 Jan 2019)

Log Message

[JSC] ErrorConstructor should not have own IsoSubspace
https://bugs.webkit.org/show_bug.cgi?id=193800

Reviewed by Saam Barati.

Similar to r240456, sizeof(ErrorConstructor) != sizeof(InternalFunction), and that is why we have
IsoSubspace errorConstructorSpace in VM. But it is allocated only one-per-JSGlobalObject, and it is
too costly to have IsoSubspace which allocates 16KB. Since stackTraceLimit information is per
JSGlobalObject information, we should have m_stackTraceLimit in JSGlobalObject instead and put
ErrorConstructor in InternalFunction's IsoSubspace. As r230813 (moving InternalFunction and subclasses
into IsoSubspaces) described,

    "subclasses that are the same size as InternalFunction share its subspace. I did this because the subclasses
    appear to just override methods, which are called dynamically via the structure or class of the object.
    So, I don't see a type confusion risk if UAF is used to allocate one kind of InternalFunction over another."

Then, putting ErrorConstructor in InternalFunction IsoSubspace is fine since it meets the above condition.
This patch removes m_stackTraceLimit in ErrorConstructor, and drops IsoSubspace for errorConstructorSpace.
This reduces the memory usage.

* interpreter/Interpreter.h:
* runtime/Error.cpp:
(JSC::getStackTrace):
* runtime/ErrorConstructor.cpp:
(JSC::ErrorConstructor::ErrorConstructor):
(JSC::ErrorConstructor::finishCreation):
(JSC::constructErrorConstructor):
(JSC::callErrorConstructor):
(JSC::ErrorConstructor::put):
(JSC::ErrorConstructor::deleteProperty):
(JSC::Interpreter::constructWithErrorConstructor): Deleted.
(JSC::Interpreter::callErrorConstructor): Deleted.
* runtime/ErrorConstructor.h:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::JSGlobalObject):
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::stackTraceLimit const):
(JSC::JSGlobalObject::setStackTraceLimit):
(JSC::JSGlobalObject::errorConstructor const): Deleted.
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (240464 => 240465)


--- trunk/Source/_javascript_Core/ChangeLog	2019-01-25 02:30:03 UTC (rev 240464)
+++ trunk/Source/_javascript_Core/ChangeLog	2019-01-25 02:47:58 UTC (rev 240465)
@@ -1,3 +1,50 @@
+2019-01-24  Yusuke Suzuki  <[email protected]>
+
+        [JSC] ErrorConstructor should not have own IsoSubspace
+        https://bugs.webkit.org/show_bug.cgi?id=193800
+
+        Reviewed by Saam Barati.
+
+        Similar to r240456, sizeof(ErrorConstructor) != sizeof(InternalFunction), and that is why we have
+        IsoSubspace errorConstructorSpace in VM. But it is allocated only one-per-JSGlobalObject, and it is
+        too costly to have IsoSubspace which allocates 16KB. Since stackTraceLimit information is per
+        JSGlobalObject information, we should have m_stackTraceLimit in JSGlobalObject instead and put
+        ErrorConstructor in InternalFunction's IsoSubspace. As r230813 (moving InternalFunction and subclasses
+        into IsoSubspaces) described,
+
+            "subclasses that are the same size as InternalFunction share its subspace. I did this because the subclasses
+            appear to just override methods, which are called dynamically via the structure or class of the object.
+            So, I don't see a type confusion risk if UAF is used to allocate one kind of InternalFunction over another."
+
+        Then, putting ErrorConstructor in InternalFunction IsoSubspace is fine since it meets the above condition.
+        This patch removes m_stackTraceLimit in ErrorConstructor, and drops IsoSubspace for errorConstructorSpace.
+        This reduces the memory usage.
+
+        * interpreter/Interpreter.h:
+        * runtime/Error.cpp:
+        (JSC::getStackTrace):
+        * runtime/ErrorConstructor.cpp:
+        (JSC::ErrorConstructor::ErrorConstructor):
+        (JSC::ErrorConstructor::finishCreation):
+        (JSC::constructErrorConstructor):
+        (JSC::callErrorConstructor):
+        (JSC::ErrorConstructor::put):
+        (JSC::ErrorConstructor::deleteProperty):
+        (JSC::Interpreter::constructWithErrorConstructor): Deleted.
+        (JSC::Interpreter::callErrorConstructor): Deleted.
+        * runtime/ErrorConstructor.h:
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::JSGlobalObject):
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::stackTraceLimit const):
+        (JSC::JSGlobalObject::setStackTraceLimit):
+        (JSC::JSGlobalObject::errorConstructor const): Deleted.
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        * runtime/VM.h:
+
 2019-01-24  Joseph Pecoraro  <[email protected]>
 
         Web Inspector: CPU Usage Timeline

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.h (240464 => 240465)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.h	2019-01-25 02:30:03 UTC (rev 240464)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.h	2019-01-25 02:47:58 UTC (rev 240465)
@@ -117,8 +117,6 @@
         NEVER_INLINE void debug(CallFrame*, DebugHookType);
         static String stackTraceAsString(VM&, const Vector<StackFrame>&);
 
-        static EncodedJSValue JSC_HOST_CALL constructWithErrorConstructor(ExecState*);
-        static EncodedJSValue JSC_HOST_CALL callErrorConstructor(ExecState*);
         static EncodedJSValue JSC_HOST_CALL constructWithNativeErrorConstructor(ExecState*);
         static EncodedJSValue JSC_HOST_CALL callNativeErrorConstructor(ExecState*);
 

Modified: trunk/Source/_javascript_Core/runtime/Error.cpp (240464 => 240465)


--- trunk/Source/_javascript_Core/runtime/Error.cpp	2019-01-25 02:30:03 UTC (rev 240464)
+++ trunk/Source/_javascript_Core/runtime/Error.cpp	2019-01-25 02:47:58 UTC (rev 240465)
@@ -161,13 +161,12 @@
 std::unique_ptr<Vector<StackFrame>> getStackTrace(ExecState* exec, VM& vm, JSObject* obj, bool useCurrentFrame)
 {
     JSGlobalObject* globalObject = obj->globalObject(vm);
-    ErrorConstructor* errorConstructor = globalObject->errorConstructor();
-    if (!errorConstructor->stackTraceLimit())
+    if (!globalObject->stackTraceLimit())
         return nullptr;
 
     size_t framesToSkip = useCurrentFrame ? 0 : 1;
     std::unique_ptr<Vector<StackFrame>> stackTrace = std::make_unique<Vector<StackFrame>>();
-    vm.interpreter->getStackTrace(obj, *stackTrace, framesToSkip, errorConstructor->stackTraceLimit().value());
+    vm.interpreter->getStackTrace(obj, *stackTrace, framesToSkip, globalObject->stackTraceLimit().value());
     if (!stackTrace->isEmpty())
         ASSERT_UNUSED(exec, exec == vm.topCallFrame || exec->isGlobalExec());
     return stackTrace;

Modified: trunk/Source/_javascript_Core/runtime/ErrorConstructor.cpp (240464 => 240465)


--- trunk/Source/_javascript_Core/runtime/ErrorConstructor.cpp	2019-01-25 02:30:03 UTC (rev 240464)
+++ trunk/Source/_javascript_Core/runtime/ErrorConstructor.cpp	2019-01-25 02:47:58 UTC (rev 240465)
@@ -33,8 +33,11 @@
 
 const ClassInfo ErrorConstructor::s_info = { "Function", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ErrorConstructor) };
 
+static EncodedJSValue JSC_HOST_CALL callErrorConstructor(ExecState*);
+static EncodedJSValue JSC_HOST_CALL constructErrorConstructor(ExecState*);
+
 ErrorConstructor::ErrorConstructor(VM& vm, Structure* structure)
-    : InternalFunction(vm, structure, Interpreter::callErrorConstructor, Interpreter::constructWithErrorConstructor)
+    : InternalFunction(vm, structure, callErrorConstructor, constructErrorConstructor)
 {
 }
 
@@ -44,15 +47,12 @@
     // ECMA 15.11.3.1 Error.prototype
     putDirectWithoutTransition(vm, vm.propertyNames->prototype, errorPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
-
-    unsigned defaultStackTraceLimit = Options::defaultErrorStackTraceLimit();
-    m_stackTraceLimit = defaultStackTraceLimit;
-    putDirectWithoutTransition(vm, vm.propertyNames->stackTraceLimit, jsNumber(defaultStackTraceLimit), static_cast<unsigned>(PropertyAttribute::None));
+    putDirectWithoutTransition(vm, vm.propertyNames->stackTraceLimit, jsNumber(globalObject(vm)->stackTraceLimit().valueOr(Options::defaultErrorStackTraceLimit())), static_cast<unsigned>(PropertyAttribute::None));
 }
 
 // ECMA 15.9.3
 
-EncodedJSValue JSC_HOST_CALL Interpreter::constructWithErrorConstructor(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL constructErrorConstructor(ExecState* exec)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -62,7 +62,7 @@
     RELEASE_AND_RETURN(scope, JSValue::encode(ErrorInstance::create(exec, errorStructure, message, nullptr, TypeNothing, false)));
 }
 
-EncodedJSValue JSC_HOST_CALL Interpreter::callErrorConstructor(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL callErrorConstructor(ExecState* exec)
 {
     JSValue message = exec->argument(0);
     Structure* errorStructure = jsCast<InternalFunction*>(exec->jsCallee())->globalObject(exec->vm())->errorStructure();
@@ -79,9 +79,9 @@
             double effectiveLimit = value.asNumber();
             effectiveLimit = std::max(0., effectiveLimit);
             effectiveLimit = std::min(effectiveLimit, static_cast<double>(std::numeric_limits<unsigned>::max()));
-            thisObject->m_stackTraceLimit = static_cast<unsigned>(effectiveLimit);
+            thisObject->globalObject(vm)->setStackTraceLimit(static_cast<unsigned>(effectiveLimit));
         } else
-            thisObject->m_stackTraceLimit = { };
+            thisObject->globalObject(vm)->setStackTraceLimit(WTF::nullopt);
     }
 
     return Base::put(thisObject, exec, propertyName, value, slot);
@@ -93,7 +93,7 @@
     ErrorConstructor* thisObject = jsCast<ErrorConstructor*>(cell);
 
     if (propertyName == vm.propertyNames->stackTraceLimit)
-        thisObject->m_stackTraceLimit = { };
+        thisObject->globalObject(vm)->setStackTraceLimit(WTF::nullopt);
 
     return Base::deleteProperty(thisObject, exec, propertyName);
 }

Modified: trunk/Source/_javascript_Core/runtime/ErrorConstructor.h (240464 => 240465)


--- trunk/Source/_javascript_Core/runtime/ErrorConstructor.h	2019-01-25 02:30:03 UTC (rev 240464)
+++ trunk/Source/_javascript_Core/runtime/ErrorConstructor.h	2019-01-25 02:47:58 UTC (rev 240465)
@@ -29,14 +29,8 @@
 
 class ErrorConstructor final : public InternalFunction {
 public:
-    typedef InternalFunction Base;
+    using Base = InternalFunction;
 
-    template<typename CellType>
-    static IsoSubspace* subspaceFor(VM& vm)
-    {
-        return &vm.errorConstructorSpace;
-    }
-
     static ErrorConstructor* create(VM& vm, Structure* structure, ErrorPrototype* errorPrototype, GetterSetter*)
     {
         ErrorConstructor* constructor = new (NotNull, allocateCell<ErrorConstructor>(vm.heap)) ErrorConstructor(vm, structure);
@@ -51,8 +45,6 @@
         return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info()); 
     }
 
-    Optional<unsigned> stackTraceLimit() const { return m_stackTraceLimit; }
-
 protected:
     void finishCreation(VM&, ErrorPrototype*);
 
@@ -62,7 +54,8 @@
 private:
     ErrorConstructor(VM&, Structure*);
 
-    Optional<unsigned> m_stackTraceLimit;
 };
 
+static_assert(sizeof(ErrorConstructor) == sizeof(InternalFunction), "");
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (240464 => 240465)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2019-01-25 02:30:03 UTC (rev 240464)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2019-01-25 02:47:58 UTC (rev 240465)
@@ -360,6 +360,7 @@
     , m_arraySpeciesWatchpoint(ClearWatchpoint)
     , m_numberToStringWatchpoint(IsWatched)
     , m_runtimeFlags()
+    , m_stackTraceLimit(Options::defaultErrorStackTraceLimit())
     , m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable)
 {
 }
@@ -700,7 +701,6 @@
     
 #undef CREATE_CONSTRUCTOR_FOR_SIMPLE_TYPE
 
-    m_errorConstructor.set(vm, this, errorConstructor);
     m_promiseConstructor.set(vm, this, promiseConstructor);
     m_internalPromiseConstructor.set(vm, this, internalPromiseConstructor);
     
@@ -878,7 +878,7 @@
         GlobalPropertyInfo(vm.propertyNames->builtinNames().propertyIsEnumerablePrivateName(), privateFuncPropertyIsEnumerable, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().importModulePrivateName(), privateFuncImportModule, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().enqueueJobPrivateName(), JSFunction::create(vm, this, 0, String(), enqueueJob), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
-        GlobalPropertyInfo(vm.propertyNames->builtinNames().ErrorPrivateName(), m_errorConstructor.get(), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
+        GlobalPropertyInfo(vm.propertyNames->builtinNames().ErrorPrivateName(), errorConstructor, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().RangeErrorPrivateName(), m_rangeErrorConstructor.get(), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().TypeErrorPrivateName(), m_typeErrorConstructor.get(), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().typedArrayLengthPrivateName(), privateFuncTypedArrayLength, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
@@ -1548,7 +1548,6 @@
     visitor.append(thisObject->m_globalCallee);
     visitor.append(thisObject->m_stackOverflowFrameCallee);
     visitor.append(thisObject->m_regExpConstructor);
-    visitor.append(thisObject->m_errorConstructor);
     visitor.append(thisObject->m_nativeErrorPrototypeStructure);
     visitor.append(thisObject->m_nativeErrorStructure);
     thisObject->m_evalErrorConstructor.visit(visitor);

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (240464 => 240465)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2019-01-25 02:30:03 UTC (rev 240464)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2019-01-25 02:47:58 UTC (rev 240465)
@@ -259,7 +259,6 @@
     WriteBarrier<JSCallee> m_globalCallee;
     WriteBarrier<JSCallee> m_stackOverflowFrameCallee;
     WriteBarrier<RegExpConstructor> m_regExpConstructor;
-    WriteBarrier<ErrorConstructor> m_errorConstructor;
     WriteBarrier<Structure> m_nativeErrorPrototypeStructure;
     WriteBarrier<Structure> m_nativeErrorStructure;
     LazyProperty<JSGlobalObject, NativeErrorConstructor> m_evalErrorConstructor;
@@ -498,6 +497,7 @@
     String m_webAssemblyDisabledErrorMessage;
     RuntimeFlags m_runtimeFlags;
     ConsoleClient* m_consoleClient { nullptr };
+    Optional<unsigned> m_stackTraceLimit;
 
 #if !ASSERT_DISABLED
     const ExecState* m_callFrameAtDebuggerEntry { nullptr };
@@ -530,6 +530,9 @@
     WatchpointSet& ensureReferencedPropertyWatchpointSet(UniquedStringImpl*);
 #endif
 
+    Optional<unsigned> stackTraceLimit() const { return m_stackTraceLimit; }
+    void setStackTraceLimit(Optional<unsigned> value) { m_stackTraceLimit = value; }
+
 protected:
     JS_EXPORT_PRIVATE explicit JSGlobalObject(VM&, Structure*, const GlobalObjectMethodTable* = nullptr);
 
@@ -573,7 +576,6 @@
 
     RegExpConstructor* regExpConstructor() const { return m_regExpConstructor.get(); }
 
-    ErrorConstructor* errorConstructor() const { return m_errorConstructor.get(); }
     ArrayConstructor* arrayConstructor() const { return m_arrayConstructor.get(); }
     ObjectConstructor* objectConstructor() const { return m_objectConstructor.get(); }
     JSPromiseConstructor* promiseConstructor() const { return m_promiseConstructor.get(); }

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (240464 => 240465)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2019-01-25 02:30:03 UTC (rev 240464)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2019-01-25 02:47:58 UTC (rev 240465)
@@ -297,7 +297,6 @@
     , boundFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSBoundFunction)
     , callbackFunctionSpace ISO_SUBSPACE_INIT(heap, destructibleObjectHeapCellType.get(), JSCallbackFunction)
     , customGetterSetterFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSCustomGetterSetterFunction)
-    , errorConstructorSpace ISO_SUBSPACE_INIT(heap, destructibleObjectHeapCellType.get(), ErrorConstructor)
     , executableToCodeBlockEdgeSpace ISO_SUBSPACE_INIT(heap, cellDangerousBitsHeapCellType.get(), ExecutableToCodeBlockEdge)
     , functionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSFunction)
     , generatorFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSGeneratorFunction)

Modified: trunk/Source/_javascript_Core/runtime/VM.h (240464 => 240465)


--- trunk/Source/_javascript_Core/runtime/VM.h	2019-01-25 02:30:03 UTC (rev 240464)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2019-01-25 02:47:58 UTC (rev 240465)
@@ -372,7 +372,6 @@
     IsoSubspace boundFunctionSpace;
     IsoSubspace callbackFunctionSpace;
     IsoSubspace customGetterSetterFunctionSpace;
-    IsoSubspace errorConstructorSpace;
     IsoSubspace executableToCodeBlockEdgeSpace;
     IsoSubspace functionSpace;
     IsoSubspace generatorFunctionSpace;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to