Title: [288763] trunk
Revision
288763
Author
[email protected]
Date
2022-01-28 16:05:54 -0800 (Fri, 28 Jan 2022)

Log Message

Remove showModalDialog-specific logic from JSDOMWindow::getOwnPropertySlot()
https://bugs.webkit.org/show_bug.cgi?id=234282

Reviewed by Yusuke Suzuki.

Source/WebCore:

This change removes showModalDialog-specific logic from JSDOMWindow::getOwnPropertySlot()
in favor of a setter-less CustomValue property on `window`, which returns a function only
if modals are allowed, and can be overriden by userland code.

Since we need to support setCanRunModal(true) being called after DOMWindow is initialized,
[EnabledByQuirk] and friends could not be used. However, once the function was exposed,
there is no point in hiding it, so the CustomValue getter replaces itself with a regular
data property to preserve function's identity (covered by fast/dom/wrapper-identity.html).

The patch makes JSDOMWindow's getOwnPropertySlot() consistent with its getOwnPropertyNames()
regarding the presence of "showModalDialog" property, and fixes JSDOMWindow::getOwnPropertySlot()
being ignored by LLInt when accessing "showModalDialog" from scope, which resulted in exposing
the function even if modals were disallowed.

Test: fast/dom/Window/forbid-showModalDialog.html

* bindings/js/JSDOMWindowBase.cpp:
(WebCore::JSDOMWindowBase::finishCreation):
* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::getOwnPropertySlot):
(WebCore::JSC_DEFINE_CUSTOM_GETTER):
(WebCore::JSC_DEFINE_HOST_FUNCTION):
(WebCore::JSDOMWindow::showModalDialog): Deleted.
* bindings/js/JSDOMWindowCustom.h:
* page/DOMWindow.idl:

LayoutTests:

* fast/dom/Window/forbid-showModalDialog-expected.txt:
* fast/dom/Window/forbid-showModalDialog.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (288762 => 288763)


--- trunk/LayoutTests/ChangeLog	2022-01-28 23:12:40 UTC (rev 288762)
+++ trunk/LayoutTests/ChangeLog	2022-01-29 00:05:54 UTC (rev 288763)
@@ -1,3 +1,13 @@
+2022-01-28  Alexey Shvayka  <[email protected]>
+
+        Remove showModalDialog-specific logic from JSDOMWindow::getOwnPropertySlot()
+        https://bugs.webkit.org/show_bug.cgi?id=234282
+
+        Reviewed by Yusuke Suzuki.
+
+        * fast/dom/Window/forbid-showModalDialog-expected.txt:
+        * fast/dom/Window/forbid-showModalDialog.html:
+
 2022-01-28  Jon Lee  <[email protected]>
 
         Add copy-to-clipboard button for fuzzy matching meta tag

Modified: trunk/LayoutTests/fast/dom/Window/forbid-showModalDialog-expected.txt (288762 => 288763)


--- trunk/LayoutTests/fast/dom/Window/forbid-showModalDialog-expected.txt	2022-01-28 23:12:40 UTC (rev 288762)
+++ trunk/LayoutTests/fast/dom/Window/forbid-showModalDialog-expected.txt	2022-01-29 00:05:54 UTC (rev 288763)
@@ -6,11 +6,12 @@
 Make sure window.showModalDialog is undefined when modal dialogs are not allowed.
 internals.setCanShowModalDialogOverride(false)
 PASS window.showModalDialog is undefined
-PASS window.hasOwnProperty('showModalDialog') is false
+PASS window.hasOwnProperty('showModalDialog') is true
+PASS Object.getOwnPropertyNames(window).includes('showModalDialog') is true
 
 Tests having a named property with name 'showModalDialog'.
 document.body.append(testFrame)
-PASS window.showModalDialog is testFrame.contentWindow
+PASS window.showModalDialog is undefined
 testFrame.remove()
 PASS window.showModalDialog is undefined
 
@@ -19,6 +20,7 @@
 PASS window.showModalDialog is not undefined
 PASS window.hasOwnProperty('showModalDialog') is true
 PASS window.showModalDialog is an instance of Function
+PASS window.showModalDialog.name is 'showModalDialog'
 
 Make sure window.showModalDialog can be shadowed.
 window.showModalDialog = 1

Modified: trunk/LayoutTests/fast/dom/Window/forbid-showModalDialog.html (288762 => 288763)


--- trunk/LayoutTests/fast/dom/Window/forbid-showModalDialog.html	2022-01-28 23:12:40 UTC (rev 288762)
+++ trunk/LayoutTests/fast/dom/Window/forbid-showModalDialog.html	2022-01-29 00:05:54 UTC (rev 288763)
@@ -8,8 +8,11 @@
 debug("Make sure window.showModalDialog is undefined when modal dialogs are not allowed.");
 evalAndLog("internals.setCanShowModalDialogOverride(false)");
 shouldBe("window.showModalDialog", "undefined");
-shouldBeFalse("window.hasOwnProperty('showModalDialog')");
+shouldBeTrue("window.hasOwnProperty('showModalDialog')");
+shouldBeTrue("Object.getOwnPropertyNames(window).includes('showModalDialog')");
 
+if (showModalDialog !== undefined)
+    testFailed("showModalDialog !== undefined");
 
 debug("");
 debug("Tests having a named property with name 'showModalDialog'.");
@@ -16,7 +19,7 @@
 var testFrame = document.createElement("iframe");
 testFrame.name = "showModalDialog";
 evalAndLog("document.body.append(testFrame)");
-shouldBe("window.showModalDialog", "testFrame.contentWindow");
+shouldBe("window.showModalDialog", "undefined");
 evalAndLog("testFrame.remove()");
 shouldBe("window.showModalDialog", "undefined");
 
@@ -26,6 +29,7 @@
 shouldNotBe("window.showModalDialog", "undefined");
 shouldBeTrue("window.hasOwnProperty('showModalDialog')");
 shouldBeType("window.showModalDialog", "Function");
+shouldBe("window.showModalDialog.name", "'showModalDialog'");
 
 debug("");
 debug("Make sure window.showModalDialog can be shadowed.");

Modified: trunk/Source/WebCore/ChangeLog (288762 => 288763)


--- trunk/Source/WebCore/ChangeLog	2022-01-28 23:12:40 UTC (rev 288762)
+++ trunk/Source/WebCore/ChangeLog	2022-01-29 00:05:54 UTC (rev 288763)
@@ -1,3 +1,36 @@
+2022-01-28  Alexey Shvayka  <[email protected]>
+
+        Remove showModalDialog-specific logic from JSDOMWindow::getOwnPropertySlot()
+        https://bugs.webkit.org/show_bug.cgi?id=234282
+
+        Reviewed by Yusuke Suzuki.
+
+        This change removes showModalDialog-specific logic from JSDOMWindow::getOwnPropertySlot()
+        in favor of a setter-less CustomValue property on `window`, which returns a function only
+        if modals are allowed, and can be overriden by userland code.
+
+        Since we need to support setCanRunModal(true) being called after DOMWindow is initialized,
+        [EnabledByQuirk] and friends could not be used. However, once the function was exposed,
+        there is no point in hiding it, so the CustomValue getter replaces itself with a regular
+        data property to preserve function's identity (covered by fast/dom/wrapper-identity.html).
+
+        The patch makes JSDOMWindow's getOwnPropertySlot() consistent with its getOwnPropertyNames()
+        regarding the presence of "showModalDialog" property, and fixes JSDOMWindow::getOwnPropertySlot()
+        being ignored by LLInt when accessing "showModalDialog" from scope, which resulted in exposing
+        the function even if modals were disallowed.
+
+        Test: fast/dom/Window/forbid-showModalDialog.html
+
+        * bindings/js/JSDOMWindowBase.cpp:
+        (WebCore::JSDOMWindowBase::finishCreation):
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::JSDOMWindow::getOwnPropertySlot):
+        (WebCore::JSC_DEFINE_CUSTOM_GETTER):
+        (WebCore::JSC_DEFINE_HOST_FUNCTION):
+        (WebCore::JSDOMWindow::showModalDialog): Deleted.
+        * bindings/js/JSDOMWindowCustom.h:
+        * page/DOMWindow.idl:
+
 2022-01-28  Chris Dumez  <[email protected]>
 
         ASSERTION FAILED: m_processCallback in WebCore::AudioWorkletProcessor::process

Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp (288762 => 288763)


--- trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp	2022-01-28 23:12:40 UTC (rev 288762)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp	2022-01-29 00:05:54 UTC (rev 288763)
@@ -127,6 +127,8 @@
 
     if (m_wrapped && m_wrapped->frame() && m_wrapped->frame()->settings().needsSiteSpecificQuirks())
         setNeedsSiteSpecificQuirks(true);
+
+    putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().showModalDialogPublicName(), CustomGetterSetter::create(vm, showModalDialogGetter, nullptr), static_cast<unsigned>(PropertyAttribute::CustomValue));
 }
 
 void JSDOMWindowBase::destroy(JSCell* cell)

Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp (288762 => 288763)


--- trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp	2022-01-28 23:12:40 UTC (rev 288762)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp	2022-01-29 00:05:54 UTC (rev 288763)
@@ -208,20 +208,9 @@
         slot.setWatchpointSet(*thisObject->m_windowCloseWatchpoints);
 
     // (2) Regular own properties.
-    PropertySlot slotCopy = slot;
-    if (Base::getOwnPropertySlot(thisObject, lexicalGlobalObject, propertyName, slot)) {
-        auto* frame = thisObject->wrapped().frame();
-
-        // Detect when we're getting the property 'showModalDialog', this is disabled, and has its original value.
-        bool isShowModalDialogAndShouldHide = propertyName == static_cast<JSVMClientData*>(lexicalGlobalObject->vm().clientData)->builtinNames().showModalDialogPublicName()
-            && (!frame || !DOMWindow::canShowModalDialog(*frame))
-            && slot.isValue() && isHostFunction(slot.getValue(lexicalGlobalObject, propertyName), s_info.staticPropHashTable->entry(propertyName)->function());
-        // Unless we're in the showModalDialog special case, we're done.
-        if (!isShowModalDialogAndShouldHide)
-            return true;
-        slot = slotCopy;
-
-    } else if (UNLIKELY(slot.isVMInquiry() && slot.isTaintedByOpaqueObject()))
+    if (Base::getOwnPropertySlot(thisObject, lexicalGlobalObject, propertyName, slot))
+        return true;
+    if (UNLIKELY(slot.isVMInquiry() && slot.isTaintedByOpaqueObject()))
         return false;
 
 #if ENABLE(USER_MESSAGE_HANDLERS)
@@ -499,26 +488,60 @@
     return slot.getValue(&m_globalObject, identifier);
 }
 
-JSValue JSDOMWindow::showModalDialog(JSGlobalObject& lexicalGlobalObject, CallFrame& callFrame)
+static JSC_DECLARE_HOST_FUNCTION(showModalDialog);
+
+JSC_DEFINE_CUSTOM_GETTER(showModalDialogGetter, (JSGlobalObject* lexicalGlobalObject, EncodedJSValue thisValue, PropertyName propertyName))
 {
+    VM& vm = lexicalGlobalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* thisObject = castThisValue<JSDOMWindow>(*lexicalGlobalObject, JSValue::decode(thisValue));
+    if (UNLIKELY(!thisObject))
+        return throwVMDOMAttributeGetterTypeError(lexicalGlobalObject, scope, JSDOMWindow::info(), propertyName);
+
+    if (auto* frame = thisObject->wrapped().frame()) {
+        if (DOMWindow::canShowModalDialog(*frame)) {
+            auto* jsFunction = JSFunction::create(vm, lexicalGlobalObject, 1, "showModalDialog"_s, showModalDialog);
+            thisObject->putDirect(vm, propertyName, jsFunction);
+            return JSValue::encode(jsFunction);
+        }
+    }
+
+    return JSValue::encode(jsUndefined());
+}
+
+JSC_DEFINE_HOST_FUNCTION(showModalDialog, (JSGlobalObject* lexicalGlobalObjectPtr, CallFrame* callFramePtr))
+{
+    auto& lexicalGlobalObject = *lexicalGlobalObjectPtr;
+    auto& callFrame = *callFramePtr;
+
     VM& vm = lexicalGlobalObject.vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
+    auto* thisObject = IDLOperation<JSDOMWindow>::cast(lexicalGlobalObject, callFrame);
+    if (UNLIKELY(!thisObject))
+        return throwThisTypeError(lexicalGlobalObject, scope, "Window"_s, "showModalDialog"_s);
+
+    bool shouldAllowAccess = BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObjectPtr, thisObject->wrapped(), ThrowSecurityError);
+    EXCEPTION_ASSERT_UNUSED(scope, !scope.exception() || !shouldAllowAccess);
+    if (!shouldAllowAccess)
+        return JSValue::encode(jsUndefined());
+
     if (UNLIKELY(callFrame.argumentCount() < 1))
-        return throwException(&lexicalGlobalObject, scope, createNotEnoughArgumentsError(&lexicalGlobalObject));
+        return throwVMException(&lexicalGlobalObject, scope, createNotEnoughArgumentsError(&lexicalGlobalObject));
 
     String urlString = convert<IDLNullable<IDLDOMString>>(lexicalGlobalObject, callFrame.argument(0));
-    RETURN_IF_EXCEPTION(scope, JSValue());
+    RETURN_IF_EXCEPTION(scope, { });
     String dialogFeaturesString = convert<IDLNullable<IDLDOMString>>(lexicalGlobalObject, callFrame.argument(2));
-    RETURN_IF_EXCEPTION(scope, JSValue());
+    RETURN_IF_EXCEPTION(scope, { });
 
     DialogHandler handler(lexicalGlobalObject, callFrame);
 
-    wrapped().showModalDialog(urlString, dialogFeaturesString, activeDOMWindow(lexicalGlobalObject), firstDOMWindow(lexicalGlobalObject), [&handler](DOMWindow& dialog) {
+    thisObject->wrapped().showModalDialog(urlString, dialogFeaturesString, activeDOMWindow(lexicalGlobalObject), firstDOMWindow(lexicalGlobalObject), [&handler](DOMWindow& dialog) {
         handler.dialogCreated(dialog);
     });
 
-    return handler.returnValue();
+    return JSValue::encode(handler.returnValue());
 }
 
 JSValue JSDOMWindow::queueMicrotask(JSGlobalObject& lexicalGlobalObject, CallFrame& callFrame)

Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.h (288762 => 288763)


--- trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.h	2022-01-28 23:12:40 UTC (rev 288762)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.h	2022-01-29 00:05:54 UTC (rev 288763)
@@ -54,4 +54,6 @@
     return frame ? &mainWorldGlobalObject(*frame) : nullptr;
 }
 
+JSC_DECLARE_CUSTOM_GETTER(showModalDialogGetter);
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/DOMWindow.idl (288762 => 288763)


--- trunk/Source/WebCore/page/DOMWindow.idl	2022-01-28 23:12:40 UTC (rev 288762)
+++ trunk/Source/WebCore/page/DOMWindow.idl	2022-01-29 00:05:54 UTC (rev 288763)
@@ -114,9 +114,6 @@
     [NotEnumerable, Conditional=IOS_GESTURE_EVENTS] attribute EventHandler ongestureend;
     [NotEnumerable, Conditional=IOS_GESTURE_EVENTS] attribute EventHandler ongesturestart;
 
-    // Non-standard: This has been dropped from the HTML specification and by other browsers.
-    [Custom] any showModalDialog(DOMString url, optional any dialogArgs, optional DOMString featureArgs);
-
     // Non-standard: should probably deprecate this (https://bugs.webkit.org/show_bug.cgi?id=79653).
     // Blink already deprecated it (https://bugs.chromium.org/p/chromium/issues/detail?id=437569).
     CSSRuleList getMatchedCSSRules(optional Element? element = null, optional DOMString? pseudoElement = null);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to