Changeset 203931 in webkit


Ignore:
Timestamp:
Jul 29, 2016 5:30:13 PM (8 years ago)
Author:
dbates@webkit.org
Message:

Crash under HTMLMediaElement::{resolve, reject}PendingPlayPromises() when playback is interrupted
https://bugs.webkit.org/show_bug.cgi?id=160366
<rdar://problem/27317407>

Reviewed by Eric Carlson.

Source/WebCore:

Fixes a crash/assertion failure in DeferredWrapper::{resolve, rejectWithValue}() caused by a Promise
being settled twice. In particular, if a system interruption occurs when media.play() is invoked
the returned Promise may ultimately be settled twice upon cessation of the interruption.

A Promise can be settled (resolved) exactly once. When a system interruption occurs media
playback is paused and resumes on cessation of the interruption. Currently we also immediately
reject the Promise p retuned by media.play() if the interruption occurs during its invocation.
So, when we resume playback on cessation of an interruption we try to resolve p again. But a
Promise can only be resolved once and hence we violate the assertions that p has both a valid
reference to a JSPromiseDeferred object and a reference to the global object of the page.

Tests: media/non-existent-video-playback-interrupted.html

media/video-playback-interrupted.html

  • html/HTMLMediaElement.cpp:

(WebCore::HTMLMediaElement::play): Modified to reject the Promise and return immediately if
playInternal() returns false.
(WebCore::HTMLMediaElement::playInternal): Treat an interruption as success and return true
so that HTMLMediaElement::play() adds the Promise to the end of the list of pending promises.
We treat an interruption as a success because we will resume playback (assuming the media
can be loaded and is well-formed) upon cessation of the interruption and therefore can either
fulfill or reject the Promise object returned by media.play().

LayoutTests:

  • media/non-existent-video-playback-interrupted-expected.txt: Added.
  • media/non-existent-video-playback-interrupted.html: Added.
  • media/video-playback-interrupted-expected.txt: Added.
  • media/video-playback-interrupted.html: Added.
Location:
trunk
Files:
4 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r203929 r203931  
     12016-07-29  Daniel Bates  <dabates@apple.com>
     2
     3        Crash under HTMLMediaElement::{resolve, reject}PendingPlayPromises() when playback is interrupted
     4        https://bugs.webkit.org/show_bug.cgi?id=160366
     5        <rdar://problem/27317407>
     6
     7        Reviewed by Eric Carlson.
     8
     9        * media/non-existent-video-playback-interrupted-expected.txt: Added.
     10        * media/non-existent-video-playback-interrupted.html: Added.
     11        * media/video-playback-interrupted-expected.txt: Added.
     12        * media/video-playback-interrupted.html: Added.
     13
    1142016-07-29  Ryan Haddad  <ryanhaddad@apple.com>
    215
  • trunk/Source/WebCore/ChangeLog

    r203930 r203931  
     12016-07-29  Daniel Bates  <dabates@apple.com>
     2
     3        Crash under HTMLMediaElement::{resolve, reject}PendingPlayPromises() when playback is interrupted
     4        https://bugs.webkit.org/show_bug.cgi?id=160366
     5        <rdar://problem/27317407>
     6
     7        Reviewed by Eric Carlson.
     8
     9        Fixes a crash/assertion failure in DeferredWrapper::{resolve, rejectWithValue}() caused by a Promise
     10        being settled twice. In particular, if a system interruption occurs when media.play() is invoked
     11        the returned Promise may ultimately be settled twice upon cessation of the interruption.
     12
     13        A Promise can be settled (resolved) exactly once. When a system interruption occurs media
     14        playback is paused and resumes on cessation of the interruption. Currently we also immediately
     15        reject the Promise p retuned by media.play() if the interruption occurs during its invocation.
     16        So, when we resume playback on cessation of an interruption we try to resolve p again. But a
     17        Promise can only be resolved once and hence we violate the assertions that p has both a valid
     18        reference to a JSPromiseDeferred object and a reference to the global object of the page.
     19
     20        Tests: media/non-existent-video-playback-interrupted.html
     21               media/video-playback-interrupted.html
     22
     23        * html/HTMLMediaElement.cpp:
     24        (WebCore::HTMLMediaElement::play): Modified to reject the Promise and return immediately if
     25        playInternal() returns false.
     26        (WebCore::HTMLMediaElement::playInternal): Treat an interruption as success and return true
     27        so that HTMLMediaElement::play() adds the Promise to the end of the list of pending promises.
     28        We treat an interruption as a success because we will resume playback (assuming the media
     29        can be loaded and is well-formed) upon cessation of the interruption and therefore can either
     30        fulfill or reject the Promise object returned by media.play().
     31
    1322016-07-29  Daniel Bates  <dabates@apple.com>
    233
  • trunk/Source/WebCore/html/HTMLMediaElement.cpp

    r203930 r203931  
    30693069        removeBehaviorsRestrictionsAfterFirstUserGesture();
    30703070
    3071     if (!playInternal())
     3071    if (!playInternal()) {
    30723072        promise.reject(NotAllowedError);
     3073        return;
     3074    }
    30733075
    30743076    m_pendingPlayPromises.append(WTFMove(promise));
     
    30933095    if (!m_mediaSession->clientWillBeginPlayback()) {
    30943096        LOG(Media, "  returning because of interruption");
    3095         return false;
     3097        return true; // Treat as success because we will begin playback on cessation of the interruption.
    30963098    }
    30973099
Note: See TracChangeset for help on using the changeset viewer.