⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 181656 in webkit


Ignore:
Timestamp:
Mar 17, 2015, 12:15:54 PM (11 years ago)
Author:
timothy_horton@apple.com
Message:

Reproducible null deref under ScriptedAnimationController::createDisplayRefreshMonitor
https://bugs.webkit.org/show_bug.cgi?id=142776
<rdar://problem/18921338>

Reviewed by Alexey Proskuryakov.

Test: fast/animation/request-animation-frame-unparented-iframe-crash.html

In some cases (like the new test), we can end up trying to start
requestAnimationFrame on a Document that has no Page. Most paths null-checked
the Page and did the right thing, but one failed to do so. In addition,
the current fallback (when Page is null) can result in us constructing
the wrong kind of DisplayRefreshMonitor, which could lead to trouble
down the road when it's reused. Instead, just completely avoid making a
DisplayRefreshMonitor in the null-page case.

  • dom/ScriptedAnimationController.cpp:

(WebCore::ScriptedAnimationController::createDisplayRefreshMonitor):
If the page is null, bail.

  • dom/ScriptedAnimationController.h:
  • platform/graphics/DisplayRefreshMonitor.cpp:

(WebCore::DisplayRefreshMonitor::create):
Use Optional<> to make it easy to distinguish between ChromeClient
being unreachable (because we don't have a Page for some reason) and
ChromeClient declaring that it doesn't want to override the type of
DisplayRefreshMonitor that is created.

If ChromeClient was unreachable for some reason, we'll get back an engaged
nullptr and return it (instead of creating a DisplayRefreshMonitor based
on the platform). This avoids creating the wrong type of DisplayRefreshMonitor
in the rare case where we can't reach the ChromeClient (e.g. a freshly unparented
IFrame).

If instead the client returns a disengaged Nullopt, we'll interpret that as
"construct the default type", which falls back on the platform #ifdefs to
decide what to make.

  • platform/graphics/DisplayRefreshMonitorManager.cpp:

(WebCore::DisplayRefreshMonitorManager::ensureMonitorForClient):
(WebCore::DisplayRefreshMonitorManager::scheduleAnimation):
Silently handle the case where we failed to make a DisplayRefreshMonitor.

  • platform/graphics/DisplayRefreshMonitor.h:
  • platform/graphics/DisplayRefreshMonitorClient.h:
  • platform/graphics/GraphicsLayerUpdater.cpp:

(WebCore::GraphicsLayerUpdater::createDisplayRefreshMonitor):

  • platform/graphics/GraphicsLayerUpdater.h:
  • rendering/RenderLayerCompositor.cpp:

(WebCore::RenderLayerCompositor::createDisplayRefreshMonitor):

  • rendering/RenderLayerCompositor.h:

Adjust to the new signature of createDisplayRefreshMonitor, and return
an engaged (nullptr) Optional if we can't get to ChromeClient for any reason.

  • page/ChromeClient.h:

Return Nullopt (indicating a lack of override) by default.

  • WebProcess/WebCoreSupport/WebChromeClient.cpp:

(WebKit::WebChromeClient::createDisplayRefreshMonitor):

  • WebProcess/WebCoreSupport/WebChromeClient.h:

Adjust to the new signature.

  • fast/animation/request-animation-frame-unparented-iframe-crash-expected.txt: Added.
  • fast/animation/request-animation-frame-unparented-iframe-crash.html: Added.

Add a test that ensures that calling requestAnimationFrame on a recently-unparented
frame doesn't crash.

Location:
trunk
Files:
2 added
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r181655 r181656  
     12015-03-17  Timothy Horton  <timothy_horton@apple.com>
     2
     3        Reproducible null deref under ScriptedAnimationController::createDisplayRefreshMonitor
     4        https://bugs.webkit.org/show_bug.cgi?id=142776
     5        <rdar://problem/18921338>
     6
     7        Reviewed by Alexey Proskuryakov.
     8
     9        * fast/animation/request-animation-frame-unparented-iframe-crash-expected.txt: Added.
     10        * fast/animation/request-animation-frame-unparented-iframe-crash.html: Added.
     11        Add a test that ensures that calling requestAnimationFrame on a recently-unparented
     12        frame doesn't crash.
     13
    1142015-03-17  Dean Jackson  <dino@apple.com>
    215
  • trunk/Source/WebCore/ChangeLog

    r181655 r181656  
     12015-03-17  Timothy Horton  <timothy_horton@apple.com>
     2
     3        Reproducible null deref under ScriptedAnimationController::createDisplayRefreshMonitor
     4        https://bugs.webkit.org/show_bug.cgi?id=142776
     5        <rdar://problem/18921338>
     6
     7        Reviewed by Alexey Proskuryakov.
     8
     9        Test: fast/animation/request-animation-frame-unparented-iframe-crash.html
     10
     11        In some cases (like the new test), we can end up trying to start
     12        requestAnimationFrame on a Document that has no Page. Most paths null-checked
     13        the Page and did the right thing, but one failed to do so. In addition,
     14        the current fallback (when Page is null) can result in us constructing
     15        the wrong kind of DisplayRefreshMonitor, which could lead to trouble
     16        down the road when it's reused. Instead, just completely avoid making a
     17        DisplayRefreshMonitor in the null-page case.
     18
     19        * dom/ScriptedAnimationController.cpp:
     20        (WebCore::ScriptedAnimationController::createDisplayRefreshMonitor):
     21        If the page is null, bail.
     22
     23        * dom/ScriptedAnimationController.h:
     24        * platform/graphics/DisplayRefreshMonitor.cpp:
     25        (WebCore::DisplayRefreshMonitor::create):
     26        Use Optional<> to make it easy to distinguish between ChromeClient
     27        being unreachable (because we don't have a Page for some reason) and
     28        ChromeClient declaring that it doesn't want to override the type of
     29        DisplayRefreshMonitor that is created.
     30
     31        If ChromeClient was unreachable for some reason, we'll get back an engaged
     32        nullptr and return it (instead of creating a DisplayRefreshMonitor based
     33        on the platform). This avoids creating the wrong type of DisplayRefreshMonitor
     34        in the rare case where we can't reach the ChromeClient (e.g. a freshly unparented
     35        IFrame).
     36
     37        If instead the client returns a disengaged Nullopt, we'll interpret that as
     38        "construct the default type", which falls back on the platform #ifdefs to
     39        decide what to make.
     40
     41        * platform/graphics/DisplayRefreshMonitorManager.cpp:
     42        (WebCore::DisplayRefreshMonitorManager::ensureMonitorForClient):
     43        (WebCore::DisplayRefreshMonitorManager::scheduleAnimation):
     44        Silently handle the case where we failed to make a DisplayRefreshMonitor.
     45
     46        * platform/graphics/DisplayRefreshMonitor.h:
     47        * platform/graphics/DisplayRefreshMonitorClient.h:
     48        * platform/graphics/GraphicsLayerUpdater.cpp:
     49        (WebCore::GraphicsLayerUpdater::createDisplayRefreshMonitor):
     50        * platform/graphics/GraphicsLayerUpdater.h:
     51        * rendering/RenderLayerCompositor.cpp:
     52        (WebCore::RenderLayerCompositor::createDisplayRefreshMonitor):
     53        * rendering/RenderLayerCompositor.h:
     54        Adjust to the new signature of createDisplayRefreshMonitor, and return
     55        an engaged (nullptr) Optional if we can't get to ChromeClient for any reason.
     56
     57        * page/ChromeClient.h:
     58        Return Nullopt (indicating a lack of override) by default.
     59
    1602015-03-17  Dean Jackson  <dino@apple.com>
    261
  • trunk/Source/WebCore/dom/ScriptedAnimationController.cpp

    r178859 r181656  
    227227
    228228#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    229 PassRefPtr<DisplayRefreshMonitor> ScriptedAnimationController::createDisplayRefreshMonitor(PlatformDisplayID displayID) const
    230 {
    231     return m_document->page()->chrome().client().createDisplayRefreshMonitor(displayID);
    232 }
    233 #endif
    234 
    235 
    236 }
    237 
    238 #endif
     229Optional<RefPtr<DisplayRefreshMonitor>> ScriptedAnimationController::createDisplayRefreshMonitor(PlatformDisplayID displayID) const
     230{
     231    if (!m_document->page())
     232        return Optional<RefPtr<DisplayRefreshMonitor>>(nullptr);
     233    return Optional<RefPtr<DisplayRefreshMonitor>>(m_document->page()->chrome().client().createDisplayRefreshMonitor(displayID));
     234}
     235#endif
     236
     237
     238}
     239
     240#endif
  • trunk/Source/WebCore/dom/ScriptedAnimationController.h

    r176459 r181656  
    9292    // Override for DisplayRefreshMonitorClient
    9393    virtual void displayRefreshFired(double timestamp) override;
    94     virtual PassRefPtr<DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const override;
     94    virtual Optional<RefPtr<DisplayRefreshMonitor>> createDisplayRefreshMonitor(PlatformDisplayID) const override;
    9595
    9696    bool m_isUsingTimer;
  • trunk/Source/WebCore/page/ChromeClient.h

    r181442 r181656  
    291291
    292292#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    293     virtual PassRefPtr<DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const { return nullptr; }
     293    virtual Optional<RefPtr<DisplayRefreshMonitor>> createDisplayRefreshMonitor(PlatformDisplayID) const { return Nullopt; }
    294294#endif
    295295
  • trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitor.cpp

    r169299 r181656  
    3636namespace WebCore {
    3737
    38 PassRefPtr<DisplayRefreshMonitor> DisplayRefreshMonitor::create(DisplayRefreshMonitorClient* client)
     38RefPtr<DisplayRefreshMonitor> DisplayRefreshMonitor::create(DisplayRefreshMonitorClient* client)
    3939{
    4040    PlatformDisplayID displayID = client->displayID();
    4141
    42     if (RefPtr<DisplayRefreshMonitor> monitor = client->createDisplayRefreshMonitor(displayID))
    43         return monitor.release();
     42    if (Optional<RefPtr<DisplayRefreshMonitor>> monitor = client->createDisplayRefreshMonitor(displayID))
     43        return monitor.value();
     44
     45    // If ChromeClient returned Nullopt, we'll go ahead and make one of the default type.
    4446
    4547#if PLATFORM(MAC)
  • trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitor.h

    r172814 r181656  
    4242class DisplayRefreshMonitor : public RefCounted<DisplayRefreshMonitor> {
    4343public:
    44     static PassRefPtr<DisplayRefreshMonitor> create(DisplayRefreshMonitorClient*);
     44    static RefPtr<DisplayRefreshMonitor> create(DisplayRefreshMonitorClient*);
    4545    WEBCORE_EXPORT virtual ~DisplayRefreshMonitor();
    4646   
  • trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitorClient.h

    r169299 r181656  
    3030
    3131#include "PlatformScreen.h"
     32#include <wtf/Optional.h>
    3233
    3334namespace WebCore {
     
    4445    virtual void displayRefreshFired(double timestamp) = 0;
    4546
    46     virtual PassRefPtr<DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const = 0;
     47    // Returning nullopt indicates that WebCore should create whatever DisplayRefreshMonitor it deems
     48    // most appropriate for the current platform. Returning nullptr indicates that we should not try to
     49    // create a DisplayRefreshMonitor at all (and should instead fall back to using a timer).
     50    virtual Optional<RefPtr<DisplayRefreshMonitor>> createDisplayRefreshMonitor(PlatformDisplayID) const = 0;
    4751
    4852    PlatformDisplayID displayID() const { return m_displayID; }
  • trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitorManager.cpp

    r179850 r181656  
    4545}
    4646
    47 DisplayRefreshMonitor* DisplayRefreshMonitorManager::ensureMonitorForClient(DisplayRefreshMonitorClient* client)
     47DisplayRefreshMonitor* DisplayRefreshMonitorManager::createMonitorForClient(DisplayRefreshMonitorClient* client)
    4848{
    4949    PlatformDisplayID clientDisplayID = client->displayID();
     
    5656
    5757    RefPtr<DisplayRefreshMonitor> monitor = DisplayRefreshMonitor::create(client);
     58    if (!monitor)
     59        return nullptr;
    5860    monitor->addClient(client);
    5961    DisplayRefreshMonitor* result = monitor.get();
     
    6769        return;
    6870
    69     ensureMonitorForClient(client);
     71    createMonitorForClient(client);
    7072}
    7173
     
    9395        return false;
    9496
    95     DisplayRefreshMonitor* monitor = ensureMonitorForClient(client);
     97    DisplayRefreshMonitor* monitor = createMonitorForClient(client);
     98    if (!monitor)
     99        return false;
    96100
    97101    client->setIsScheduled(true);
  • trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitorManager.h

    r179850 r181656  
    5555    virtual ~DisplayRefreshMonitorManager();
    5656
    57     DisplayRefreshMonitor* ensureMonitorForClient(DisplayRefreshMonitorClient*);
     57    DisplayRefreshMonitor* createMonitorForClient(DisplayRefreshMonitorClient*);
    5858
    5959    Vector<RefPtr<DisplayRefreshMonitor>> m_monitors;
  • trunk/Source/WebCore/platform/graphics/GraphicsLayerUpdater.cpp

    r180441 r181656  
    8282
    8383#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    84 PassRefPtr<DisplayRefreshMonitor> GraphicsLayerUpdater::createDisplayRefreshMonitor(PlatformDisplayID displayID) const
     84Optional<RefPtr<DisplayRefreshMonitor>> GraphicsLayerUpdater::createDisplayRefreshMonitor(PlatformDisplayID displayID) const
    8585{
    86     return m_client ? m_client->createDisplayRefreshMonitor(displayID) : nullptr;
     86    if (!m_client)
     87        return Optional<RefPtr<DisplayRefreshMonitor>>(nullptr);
     88    return m_client->createDisplayRefreshMonitor(displayID);
    8789}
    8890#endif
  • trunk/Source/WebCore/platform/graphics/GraphicsLayerUpdater.h

    r180441 r181656  
    3939    virtual void flushLayersSoon(GraphicsLayerUpdater*) = 0;
    4040#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    41     virtual PassRefPtr<DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const = 0;
     41    virtual Optional<RefPtr<DisplayRefreshMonitor>> createDisplayRefreshMonitor(PlatformDisplayID) const = 0;
    4242#endif
    4343};
     
    5656
    5757#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    58     virtual PassRefPtr<DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const override;
     58    virtual Optional<RefPtr<DisplayRefreshMonitor>> createDisplayRefreshMonitor(PlatformDisplayID) const override;
    5959#endif
    6060
  • trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp

    r181515 r181656  
    41514151
    41524152#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    4153 PassRefPtr<DisplayRefreshMonitor> RenderLayerCompositor::createDisplayRefreshMonitor(PlatformDisplayID displayID) const
     4153Optional<RefPtr<DisplayRefreshMonitor>> RenderLayerCompositor::createDisplayRefreshMonitor(PlatformDisplayID displayID) const
    41544154{
    41554155    Frame& frame = m_renderView.frameView().frame();
    41564156    Page* page = frame.page();
    41574157    if (!page)
    4158         return nullptr;
    4159 
    4160     return page->chrome().client().createDisplayRefreshMonitor(displayID);
     4158        return Optional<RefPtr<DisplayRefreshMonitor>>(nullptr);
     4159
     4160    return Optional<RefPtr<DisplayRefreshMonitor>>(page->chrome().client().createDisplayRefreshMonitor(displayID));
    41614161}
    41624162#endif
  • trunk/Source/WebCore/rendering/RenderLayerCompositor.h

    r181515 r181656  
    400400
    401401#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    402     PassRefPtr<DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const override;
     402    Optional<RefPtr<DisplayRefreshMonitor>> createDisplayRefreshMonitor(PlatformDisplayID) const override;
    403403#endif
    404404
  • trunk/Source/WebKit2/ChangeLog

    r181651 r181656  
     12015-03-17  Timothy Horton  <timothy_horton@apple.com>
     2
     3        Reproducible null deref under ScriptedAnimationController::createDisplayRefreshMonitor
     4        https://bugs.webkit.org/show_bug.cgi?id=142776
     5        <rdar://problem/18921338>
     6
     7        Reviewed by Alexey Proskuryakov.
     8
     9        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
     10        (WebKit::WebChromeClient::createDisplayRefreshMonitor):
     11        * WebProcess/WebCoreSupport/WebChromeClient.h:
     12        Adjust to the new signature.
     13
    1142015-03-17  Antti Koivisto  <antti@apple.com>
    215
  • trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.cpp

    r181442 r181656  
    851851
    852852#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    853 PassRefPtr<WebCore::DisplayRefreshMonitor> WebChromeClient::createDisplayRefreshMonitor(PlatformDisplayID displayID) const
    854 {
    855     return m_page->drawingArea()->createDisplayRefreshMonitor(displayID);
     853Optional<RefPtr<WebCore::DisplayRefreshMonitor>> WebChromeClient::createDisplayRefreshMonitor(PlatformDisplayID displayID) const
     854{
     855    return Optional<RefPtr<WebCore::DisplayRefreshMonitor>>(m_page->drawingArea()->createDisplayRefreshMonitor(displayID));
    856856}
    857857#endif
  • trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.h

    r181442 r181656  
    218218
    219219#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    220     virtual PassRefPtr<WebCore::DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const override;
     220    virtual Optional<RefPtr<WebCore::DisplayRefreshMonitor>> createDisplayRefreshMonitor(PlatformDisplayID) const override;
    221221#endif
    222222
Note: See TracChangeset for help on using the changeset viewer.