Regression(r196145): Crash in getOwnPropertyDescriptor on http://www.history.com...
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 4 Apr 2016 20:01:38 +0000 (20:01 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 4 Apr 2016 20:01:38 +0000 (20:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=156136
<rdar://problem/25410767>

Reviewed by Ryosuke Niwa.

Source/JavaScriptCore:

Add a few more identifiers for using in the generated bindings.

* runtime/CommonIdentifiers.h:

Source/WebCore:

The page was crashing when doing the following:
Object.getOwnPropertyDescriptor(window, "indexedDB")

getOwnPropertyDescriptor() expected getDirect() to return a CustomGetterSetter for
CustomAccessors but it was not the case for window.indexedDB. The reason was that
window.indexedDB was a special property, which is not part of the static table but
returned by GetOwnPropertySlot() if IndexedDB feature is enabled. This weirdness
was due to our bindings generator not having proper support for [EnabledAtRuntime]
properties on Window.

This patch adds support for [EnabledAtRuntime] properties on Window by omitting
these properties from the static property table and then setting them at runtime
in JSDOMWindow::finishCreation() if the corresponding feature is enabled.
window.indexedDB now looks like a regular property when IndexedDB is enabled
and getOwnPropertyDescriptor() works as expected for this property.

Test: storage/indexeddb/indexeddb-getownpropertyDescriptor.html

* Modules/indexeddb/DOMWindowIndexedDatabase.cpp:
(WebCore::DOMWindowIndexedDatabase::indexedDB):
* Modules/indexeddb/DOMWindowIndexedDatabase.h:
The generated bindings pass DOMWindow by reference instead of pointer so update
the implementation accordingly.

* Modules/indexeddb/DOMWindowIndexedDatabase.idl:
Add 'indexedDB' and 'webkitIndexedDB' properties and mark them as
[EnabledAtRuntime]. Now that the bindings generator correctly handles
[EnabledAtRuntime] properties on the Window, there is no need to
custom-handle them in JSDOMWindowCustom.

* bindings/js/JSDOMWindowCustom.cpp:
Drop custom handling for 'indexedDB' and 'webkitIndexedDB' properties
in getOwnPropertySlot(). The generated bindings code now makes sure to
only set those properties on the Window if IndexedDB is enabled so we
can let the regular code path look up those properties.

* bindings/scripts/CodeGeneratorJS.pm:
(GetJSCAttributesForAttribute):
(GenerateHeader):
(GeneratePropertiesHashTable):
(GenerateImplementation):
Add support for [EnabledAtRuntime] properties on DOMWindow. For such
properties, we do the following:
1. Omit them from the static property table
2. In JSDOMWindow::finishCreation(), dynamically add those properties
   at runtime if the corresponding feature is enabled.

Note that this works for constructors as well.

* inspector/InspectorIndexedDBAgent.cpp:
(WebCore::assertIDBFactory):
Pass Window by reference instead of pointer.

LayoutTests:

Add a layout test to confirm that calling Object.getOwnPropertyDescriptor(window, "indexedDB")
does not crash and works as expected.

* storage/indexeddb/indexeddb-getownpropertyDescriptor-expected.txt: Added.
* storage/indexeddb/indexeddb-getownpropertyDescriptor.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@199017 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
LayoutTests/ChangeLog
LayoutTests/storage/indexeddb/indexeddb-getownpropertyDescriptor-expected.txt [new file with mode: 0644]
LayoutTests/storage/indexeddb/indexeddb-getownpropertyDescriptor.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.cpp
Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.h
Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.idl
Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/inspector/InspectorIndexedDBAgent.cpp

index 9dc1df0..2f033f2 100644 (file)
@@ -1,3 +1,17 @@
+2016-04-04  Chris Dumez  <cdumez@apple.com>
+
+        Regression(r196145): Crash in getOwnPropertyDescriptor on http://www.history.com/shows/vikings
+        https://bugs.webkit.org/show_bug.cgi?id=156136
+        <rdar://problem/25410767>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add a layout test to confirm that calling Object.getOwnPropertyDescriptor(window, "indexedDB")
+        does not crash and works as expected.
+
+        * storage/indexeddb/indexeddb-getownpropertyDescriptor-expected.txt: Added.
+        * storage/indexeddb/indexeddb-getownpropertyDescriptor.html: Added.
+
 2016-04-04  Ryan Haddad  <ryanhaddad@apple.com>
 
         Marking plugins/focus.html as flaky on mac
diff --git a/LayoutTests/storage/indexeddb/indexeddb-getownpropertyDescriptor-expected.txt b/LayoutTests/storage/indexeddb/indexeddb-getownpropertyDescriptor-expected.txt
new file mode 100644 (file)
index 0000000..5fa19e7
--- /dev/null
@@ -0,0 +1,14 @@
+Tests using getOwnPropertyDescriptor() on window.indexedDB
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+desc = Object.getOwnPropertyDescriptor(window, 'indexedDB')
+PASS desc.get is an instance of Function
+PASS desc.set is undefined.
+PASS desc.enumerable is true
+PASS desc.configurable is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/storage/indexeddb/indexeddb-getownpropertyDescriptor.html b/LayoutTests/storage/indexeddb/indexeddb-getownpropertyDescriptor.html
new file mode 100644 (file)
index 0000000..0787999
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<body>
+<script src="../../resources/js-test.js"></script>
+<script>
+description("Tests using getOwnPropertyDescriptor() on window.indexedDB");
+
+evalAndLog("desc = Object.getOwnPropertyDescriptor(window, 'indexedDB')");
+shouldBeType("desc.get", "Function");
+shouldBeUndefined("desc.set");
+shouldBeTrue("desc.enumerable");
+shouldBeTrue("desc.configurable");
+</script>
+</body>
index 2a7dae3..d4f0620 100644 (file)
@@ -1,3 +1,15 @@
+2016-04-04  Chris Dumez  <cdumez@apple.com>
+
+        Regression(r196145): Crash in getOwnPropertyDescriptor on http://www.history.com/shows/vikings
+        https://bugs.webkit.org/show_bug.cgi?id=156136
+        <rdar://problem/25410767>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add a few more identifiers for using in the generated bindings.
+
+        * runtime/CommonIdentifiers.h:
+
 2016-04-04  Geoffrey Garen  <ggaren@apple.com>
 
         CopiedBlock should be 16kB
index 9dea78c..e8ba446 100644 (file)
 // MarkedArgumentBuffer of property names, passed to a macro so we can do set them up various
 // ways without repeating the list.
 #define JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(macro) \
+    macro(AnimationTimeline) \
     macro(Array) \
     macro(ArrayBuffer) \
     macro(ArrayIterator) \
+    macro(Audio) \
     macro(BYTES_PER_ELEMENT) \
     macro(Boolean) \
     macro(Collator) \
     macro(Date) \
     macro(DateTimeFormat) \
+    macro(DocumentTimeline) \
     macro(Error) \
     macro(EvalError) \
     macro(Function) \
+    macro(Gamepad) \
+    macro(GamepadButton) \
+    macro(GamepadEvent) \
     macro(GeneratorFunction) \
+    macro(HTMLAudioElement) \
+    macro(HTMLSlotElement) \
+    macro(IDBCursor) \
+    macro(IDBCursorWithValue) \
+    macro(IDBDatabase) \
+    macro(IDBFactory) \
+    macro(IDBIndex) \
+    macro(IDBKeyRange) \
+    macro(IDBObjectStore) \
+    macro(IDBOpenDBRequest) \
+    macro(IDBRequest) \
+    macro(IDBTransaction) \
+    macro(IDBVersionChangeEvent) \
     macro(Infinity) \
     macro(Intl) \
     macro(JSON) \
@@ -59,6 +78,7 @@
     macro(RegExp) \
     macro(Set)\
     macro(SetIterator)\
+    macro(ShadowRoot) \
     macro(String) \
     macro(Symbol) \
     macro(SyntaxError) \
@@ -67,6 +87,7 @@
     macro(UTC) \
     macro(WeakMap)\
     macro(WeakSet)\
+    macro(WebSocket) \
     macro(__defineGetter__) \
     macro(__defineSetter__) \
     macro(__lookupGetter__) \
     macro(valueOf) \
     macro(values) \
     macro(webkit) \
+    macro(webkitIDBCursor) \
+    macro(webkitIDBDatabase) \
+    macro(webkitIDBFactory) \
+    macro(webkitIDBIndex) \
+    macro(webkitIDBKeyRange) \
+    macro(webkitIDBObjectStore) \
+    macro(webkitIDBRequest) \
+    macro(webkitIDBTransaction) \
     macro(webkitIndexedDB) \
     macro(weekday) \
     macro(window) \
index 594f2a2..83e88ed 100644 (file)
@@ -1,3 +1,64 @@
+2016-04-04  Chris Dumez  <cdumez@apple.com>
+
+        Regression(r196145): Crash in getOwnPropertyDescriptor on http://www.history.com/shows/vikings
+        https://bugs.webkit.org/show_bug.cgi?id=156136
+        <rdar://problem/25410767>
+
+        Reviewed by Ryosuke Niwa.
+
+        The page was crashing when doing the following:
+        Object.getOwnPropertyDescriptor(window, "indexedDB")
+
+        getOwnPropertyDescriptor() expected getDirect() to return a CustomGetterSetter for
+        CustomAccessors but it was not the case for window.indexedDB. The reason was that
+        window.indexedDB was a special property, which is not part of the static table but
+        returned by GetOwnPropertySlot() if IndexedDB feature is enabled. This weirdness
+        was due to our bindings generator not having proper support for [EnabledAtRuntime]
+        properties on Window.
+
+        This patch adds support for [EnabledAtRuntime] properties on Window by omitting
+        these properties from the static property table and then setting them at runtime
+        in JSDOMWindow::finishCreation() if the corresponding feature is enabled.
+        window.indexedDB now looks like a regular property when IndexedDB is enabled
+        and getOwnPropertyDescriptor() works as expected for this property.
+
+        Test: storage/indexeddb/indexeddb-getownpropertyDescriptor.html
+
+        * Modules/indexeddb/DOMWindowIndexedDatabase.cpp:
+        (WebCore::DOMWindowIndexedDatabase::indexedDB):
+        * Modules/indexeddb/DOMWindowIndexedDatabase.h:
+        The generated bindings pass DOMWindow by reference instead of pointer so update
+        the implementation accordingly.
+
+        * Modules/indexeddb/DOMWindowIndexedDatabase.idl:
+        Add 'indexedDB' and 'webkitIndexedDB' properties and mark them as
+        [EnabledAtRuntime]. Now that the bindings generator correctly handles
+        [EnabledAtRuntime] properties on the Window, there is no need to
+        custom-handle them in JSDOMWindowCustom.
+
+        * bindings/js/JSDOMWindowCustom.cpp:
+        Drop custom handling for 'indexedDB' and 'webkitIndexedDB' properties
+        in getOwnPropertySlot(). The generated bindings code now makes sure to
+        only set those properties on the Window if IndexedDB is enabled so we
+        can let the regular code path look up those properties.
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GetJSCAttributesForAttribute):
+        (GenerateHeader):
+        (GeneratePropertiesHashTable):
+        (GenerateImplementation):
+        Add support for [EnabledAtRuntime] properties on DOMWindow. For such
+        properties, we do the following:
+        1. Omit them from the static property table
+        2. In JSDOMWindow::finishCreation(), dynamically add those properties
+           at runtime if the corresponding feature is enabled.
+
+        Note that this works for constructors as well.
+
+        * inspector/InspectorIndexedDBAgent.cpp:
+        (WebCore::assertIDBFactory):
+        Pass Window by reference instead of pointer.
+
 2016-04-04  Myles C. Maxfield  <mmaxfield@apple.com>
 
         Addressing post-review feedback on r198970
index 87d626e..ab24707 100644 (file)
@@ -93,9 +93,9 @@ void DOMWindowIndexedDatabase::willDetachGlobalObjectFromFrame()
     DOMWindowProperty::willDetachGlobalObjectFromFrame();
 }
 
-IDBFactory* DOMWindowIndexedDatabase::indexedDB(DOMWindow* window)
+IDBFactory* DOMWindowIndexedDatabase::indexedDB(DOMWindow& window)
 {
-    return from(window)->indexedDB();
+    return from(&window)->indexedDB();
 }
 
 IDBFactory* DOMWindowIndexedDatabase::indexedDB()
index de65ac9..073b593 100644 (file)
@@ -44,7 +44,7 @@ public:
 
     static DOMWindowIndexedDatabase* from(DOMWindow*);
 
-    static IDBFactory* indexedDB(DOMWindow*);
+    static IDBFactory* indexedDB(DOMWindow&);
 
     void disconnectFrameForDocumentSuspension() override;
     void reconnectFrameFromDocumentSuspension(Frame*) override;
index d1b0203..72b7b27 100644 (file)
@@ -27,6 +27,7 @@
 [
     Conditional=INDEXED_DATABASE,
 ] partial interface DOMWindow {
-    // This space is intentionally left blank.
+    [EnabledAtRuntime=IndexedDB] readonly attribute IDBFactory indexedDB;
+    [EnabledAtRuntime=IndexedDB, ImplementedAs=indexedDB] readonly attribute IDBFactory webkitIndexedDB;
 };
 
index 22ea1df..5b5da95 100644 (file)
@@ -76,21 +76,6 @@ static EncodedJSValue jsDOMWindowWebKit(ExecState* exec, EncodedJSValue thisValu
 }
 #endif
 
-#if ENABLE(INDEXED_DATABASE)
-static EncodedJSValue jsDOMWindowIndexedDB(ExecState* exec, EncodedJSValue thisValue, PropertyName)
-{
-    UNUSED_PARAM(exec);
-    auto* castedThis = toJSDOMWindow(JSValue::decode(thisValue));
-    if (!RuntimeEnabledFeatures::sharedFeatures().indexedDBEnabled())
-        return JSValue::encode(jsUndefined());
-    if (!castedThis || !BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->wrapped()))
-        return JSValue::encode(jsUndefined());
-    auto& impl = castedThis->wrapped();
-    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(DOMWindowIndexedDatabase::indexedDB(&impl)));
-    return JSValue::encode(result);
-}
-#endif
-
 static bool jsDOMWindowGetOwnPropertySlotRestrictedAccess(JSDOMWindow* thisObject, Frame* frame, ExecState* exec, PropertyName propertyName, PropertySlot& slot, String& errorMessage)
 {
     // Allow access to toString() cross-domain, but always Object.prototype.toString.
@@ -287,16 +272,6 @@ bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* exec, Property
     if (getStaticPropertySlot<JSDOMWindow, Base>(exec, *JSDOMWindow::info()->staticPropHashTable, thisObject, propertyName, slot))
         return true;
 
-#if ENABLE(INDEXED_DATABASE)
-    // FIXME: With generated JS bindings built on static property tables there is no way to
-    // completely remove a generated property at runtime. So to completely disable IndexedDB
-    // at runtime we have to not generate these accessors and have to handle them specially here.
-    // Once https://webkit.org/b/145669 is resolved, they can once again be auto generated.
-    if (RuntimeEnabledFeatures::sharedFeatures().indexedDBEnabled() && (propertyName == exec->propertyNames().indexedDB || propertyName == exec->propertyNames().webkitIndexedDB)) {
-        slot.setCustom(thisObject, DontDelete | ReadOnly | CustomAccessor, jsDOMWindowIndexedDB);
-        return true;
-    }
-#endif
 #if ENABLE(USER_MESSAGE_HANDLERS)
     if (propertyName == exec->propertyNames().webkit && thisObject->wrapped().shouldHaveWebKitNamespaceForWorld(thisObject->world())) {
         slot.setCacheableCustom(thisObject, DontDelete | ReadOnly, jsDOMWindowWebKit);
index 1eb2004..185ba68 100644 (file)
@@ -733,6 +733,23 @@ sub OperationShouldBeOnInstance
     return 0;
 }
 
+sub GetJSCAttributesForAttribute
+{
+    my $interface = shift;
+    my $attribute = shift;
+
+    my @specials = ();
+    push(@specials, "DontDelete") if IsUnforgeable($interface, $attribute);
+
+    # As per Web IDL specification, constructor properties on the ECMAScript global object should not be enumerable.
+    my $is_global_constructor = $attribute->signature->type =~ /Constructor$/;
+    push(@specials, "DontEnum") if ($attribute->signature->extendedAttributes->{"NotEnumerable"} || $is_global_constructor);
+    push(@specials, "ReadOnly") if IsReadonly($attribute);
+    push(@specials, "CustomAccessor") unless $is_global_constructor or IsJSBuiltin($interface, $attribute);
+    push(@specials, "Accessor | Builtin") if  IsJSBuiltin($interface, $attribute);
+    return (@specials > 0) ? join(" | ", @specials) : "0";
+}
+
 sub GetIndexedGetterFunction
 {
     my $interface = shift;
@@ -1230,6 +1247,7 @@ sub GenerateHeader
     # Constructor
     if ($interfaceName eq "DOMWindow") {
         push(@headerContent, "    $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&, JSDOMWindowShell*);\n");
+        push(@headerContent, "    void finishCreation(JSC::VM&, JSDOMWindowShell*);\n");
     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
         push(@headerContent, "    $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&);\n");
     } elsif (!NeedsImplementationClass($interface)) {
@@ -1392,19 +1410,17 @@ sub GeneratePropertiesHashTable
     foreach my $attribute (@{$interface->attributes}) {
         next if ($attribute->isStatic);
         next if AttributeShouldBeOnInstance($interface, $attribute) != $isInstance;
+
+        # DOMWindow adds RuntimeEnabled attributes after creation so do not add them to the static table.
+        if ($interfaceName eq "DOMWindow" && $attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) {
+            $propertyCount -= 1;
+            next;
+        }
+
         my $name = $attribute->signature->name;
         push(@$hashKeys, $name);
 
-        my @specials = ();
-        push(@specials, "DontDelete") if IsUnforgeable($interface, $attribute);
-
-        # As per Web IDL specification, constructor properties on the ECMAScript global object should not be enumerable.
-        my $is_global_constructor = $attribute->signature->type =~ /Constructor$/;
-        push(@specials, "DontEnum") if ($attribute->signature->extendedAttributes->{"NotEnumerable"} || $is_global_constructor);
-        push(@specials, "ReadOnly") if IsReadonly($attribute);
-        push(@specials, "CustomAccessor") unless $is_global_constructor or IsJSBuiltin($interface, $attribute);
-        push(@specials, "Accessor | Builtin") if  IsJSBuiltin($interface, $attribute);
-        my $special = (@specials > 0) ? join(" | ", @specials) : "0";
+        my $special = GetJSCAttributesForAttribute($interface, $attribute);
         push(@$hashSpecials, $special);
 
         my $getter = GetAttributeGetterName($interfaceName, $className, $interface, $attribute);
@@ -2175,6 +2191,29 @@ sub GenerateImplementation
         push(@implContent, "    : $parentClassName(vm, structure, WTFMove(impl), shell)\n");
         push(@implContent, "{\n");
         push(@implContent, "}\n\n");
+
+        push(@implContent, "void ${className}::finishCreation(VM& vm, JSDOMWindowShell* shell)\n");
+        push(@implContent, "{\n");
+        push(@implContent, "    Base::finishCreation(vm, shell);\n\n");
+        # Support for RuntimeEnabled attributes on DOMWindow.
+        foreach my $attribute (@{$interface->attributes}) {
+            next unless $attribute->signature->extendedAttributes->{"EnabledAtRuntime"};
+
+            AddToImplIncludes("RuntimeEnabledFeatures.h");
+            my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
+            push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+            my $enable_function = GetRuntimeEnableFunctionName($attribute->signature);
+            my $attributeName = $attribute->signature->name;
+            push(@implContent, "    if (${enable_function}()) {\n");
+            my $getter = GetAttributeGetterName($interfaceName, $className, $interface, $attribute);
+            my $setter = IsReadonly($attribute) ? "nullptr" : GetAttributeSetterName($interfaceName, $className, $interface, $attribute);
+            push(@implContent, "        auto* customGetterSetter = CustomGetterSetter::create(vm, $getter, $setter);\n");
+            my $jscAttributes = GetJSCAttributesForAttribute($interface, $attribute);
+            push(@implContent, "        putDirectCustomAccessor(vm, vm.propertyNames->$attributeName, customGetterSetter, attributesForStructure($jscAttributes));\n");
+            push(@implContent, "    }\n");
+            push(@implContent, "#endif\n") if $conditionalString;
+        }
+        push(@implContent, "}\n\n");
     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
         AddIncludesForTypeInImpl($interfaceName);
         push(@implContent, "${className}::$className(VM& vm, Structure* structure, Ref<$implType>&& impl)\n");
@@ -2358,12 +2397,7 @@ sub GenerateImplementation
 
             # Global constructors can be disabled at runtime.
             if ($attribute->signature->type =~ /Constructor$/) {
-                if ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) {
-                    AddToImplIncludes("RuntimeEnabledFeatures.h");
-                    my $enable_function = GetRuntimeEnableFunctionName($attribute->signature);
-                    push(@implContent, "    if (!${enable_function}())\n");
-                    push(@implContent, "        return JSValue::encode(jsUndefined());\n");
-                } elsif ($attribute->signature->extendedAttributes->{"EnabledBySetting"}) {
+                if ($attribute->signature->extendedAttributes->{"EnabledBySetting"}) {
                     AddToImplIncludes("Frame.h");
                     AddToImplIncludes("Settings.h");
                     my $enable_function = ToMethodName($attribute->signature->extendedAttributes->{"EnabledBySetting"}) . "Enabled";
index 9433078..3d2dbe0 100644 (file)
@@ -497,7 +497,7 @@ static IDBFactory* assertIDBFactory(ErrorString& errorString, Document* document
         return nullptr;
     }
 
-    IDBFactory* idbFactory = DOMWindowIndexedDatabase::indexedDB(domWindow);
+    IDBFactory* idbFactory = DOMWindowIndexedDatabase::indexedDB(*domWindow);
     if (!idbFactory)
         errorString = ASCIILiteral("No IndexedDB factory for given frame found");