Bug 189021

Summary: MediaDevices should be collectable as soon as its document is stopped
Product: WebKit Reporter: youenn fablet <youennf>
Component: WebRTCAssignee: youenn fablet <youennf>
Status: RESOLVED FIXED    
Severity: Normal CC: achristensen, cdumez, commit-queue, darin, eric.carlson, ews-watchlist, ggaren, rniwa, sam, webkit-bug-importer, youennf
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=189018
https://bugs.webkit.org/show_bug.cgi?id=189704
Attachments:
Description Flags
Patch
none
Archive of layout-test-results from ews112 for mac-sierra
none
Archive of layout-test-results from ews102 for mac-sierra
none
Patch
none
Patch
none
Patch
none
Patch for landing none

Description youenn fablet 2018-08-27 15:42:03 PDT
MediaDevices should be collectable as soon as its document is stopped
Comment 1 youenn fablet 2018-08-27 15:54:42 PDT
Created attachment 348223 [details]
Patch
Comment 2 EWS Watchlist 2018-08-27 18:19:29 PDT
Comment on attachment 348223 [details]
Patch

Attachment 348223 [details] did not pass mac-debug-ews (mac):
Output: https://webkit-queues.webkit.org/results/9003424

New failing tests:
http/tests/media/collect-media-devices.https.html
Comment 3 EWS Watchlist 2018-08-27 18:19:31 PDT
Created attachment 348247 [details]
Archive of layout-test-results from ews112 for mac-sierra

The attached test failures were seen while running run-webkit-tests on the mac-debug-ews.
Bot: ews112  Port: mac-sierra  Platform: Mac OS X 10.12.6
Comment 4 EWS Watchlist 2018-08-27 19:11:07 PDT
Comment on attachment 348223 [details]
Patch

Attachment 348223 [details] did not pass mac-ews (mac):
Output: https://webkit-queues.webkit.org/results/9004309

New failing tests:
http/tests/media/collect-media-devices.https.html
Comment 5 EWS Watchlist 2018-08-27 19:11:09 PDT
Created attachment 348251 [details]
Archive of layout-test-results from ews102 for mac-sierra

The attached test failures were seen while running run-webkit-tests on the mac-ews.
Bot: ews102  Port: mac-sierra  Platform: Mac OS X 10.12.6
Comment 6 youenn fablet 2018-08-27 19:50:46 PDT
Created attachment 348255 [details]
Patch
Comment 7 youenn fablet 2018-08-27 19:54:45 PDT
Created attachment 348256 [details]
Patch
Comment 8 youenn fablet 2018-08-28 10:02:29 PDT
Created attachment 348302 [details]
Patch
Comment 9 youenn fablet 2018-08-28 13:14:11 PDT
Created attachment 348328 [details]
Patch for landing
Comment 10 WebKit Commit Bot 2018-08-28 13:53:25 PDT
Comment on attachment 348328 [details]
Patch for landing

Clearing flags on attachment: 348328

Committed r235438: <https://trac.webkit.org/changeset/235438>
Comment 11 WebKit Commit Bot 2018-08-28 13:53:27 PDT
All reviewed patches have been landed.  Closing bug.
Comment 12 Radar WebKit Bug Importer 2018-08-28 13:54:21 PDT
<rdar://problem/43812760>
Comment 13 Darin Adler 2018-08-28 21:06:26 PDT
Comment on attachment 348302 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=348302&action=review

> Source/WebCore/Modules/mediastream/MediaDevices.cpp:166
>  bool MediaDevices::hasPendingActivity() const
>  {
> -    return scriptExecutionContext() && hasEventListeners(m_eventNames.devicechangeEvent);
> +    return !isContextStopped() && hasEventListeners(m_eventNames.devicechangeEvent);
>  }

Can this new rule be built into ActiveDOMObject instead of of putting it into each override of hasPendingActivity? Or is it not true for all active DOM objects?
Comment 14 youenn fablet 2018-08-28 21:51:07 PDT
> > Source/WebCore/Modules/mediastream/MediaDevices.cpp:166
> >  bool MediaDevices::hasPendingActivity() const
> >  {
> > -    return scriptExecutionContext() && hasEventListeners(m_eventNames.devicechangeEvent);
> > +    return !isContextStopped() && hasEventListeners(m_eventNames.devicechangeEvent);
> >  }
> 
> Can this new rule be built into ActiveDOMObject instead of of putting it
> into each override of hasPendingActivity? Or is it not true for all active
> DOM objects?

I believe we want this to be true and we should build this into ActiveDOMObject.
bug 189018 is a first step in that direction:
- Enforce this to all ActiveDOMObjects that do not override hasPendingActivity
- ASSERT that all ActiveDOMObject::hasPendingActivity return false when context is stopped
If everything succeeds, we could enforce this also for hasPendingActivity overrides.
Comment 15 Geoffrey Garen 2018-08-29 10:06:27 PDT
You could encode this rule mechanically like so:

(*) Make ActiveDOMObject::hasPendingActivity non-virtual, and make it do this:

if (/* document is stopped /*)
    return false;
return hasPendingActivityVirtual();

(*) Rename subclass implementations of hasPendingActivity to hasPendingActivityVirtual.

(*) Remove /* document is stopped */ checks from subclass implementations.
Comment 16 youenn fablet 2018-08-29 10:23:51 PDT
(In reply to Geoffrey Garen from comment #15)
> You could encode this rule mechanically like so:
> 
> (*) Make ActiveDOMObject::hasPendingActivity non-virtual, and make it do
> this:
> 
> if (/* document is stopped /*)
>     return false;
> return hasPendingActivityVirtual();
> 
> (*) Rename subclass implementations of hasPendingActivity to
> hasPendingActivityVirtual.
> 
> (*) Remove /* document is stopped */ checks from subclass implementations.

Sure, one potential issue is that hasPendingActivity be used for other purposes than GC. I was leaning towards adding a non virtual isCollectable method instead.
Comment 17 Geoffrey Garen 2018-08-29 10:49:25 PDT
> Sure, one potential issue is that hasPendingActivity be used for other
> purposes than GC. I was leaning towards adding a non virtual isCollectable
> method instead.

I think that all uses of hasPendingActivity correlate both with GC and document lifetime, and I think I can prove that any use of hasPendingActivity that did not correlate with GC and document lifetime would be a bug.

If you have pending activity but you allow GC, that means that you might fire an event after you collect an object's wrapper and event listeners. That's a compatibility bug.

If you continue pending activity after unloading the document, that means that you have a God-mode activity that the user can't cancel by closing the tab. That's a security / memory leak bug.

Tying document lifetime, GC, and pending activity together in a single function can make that function harder to write -- but it's the good kind of hard because it forces you to ask the hard questions that are required for correct behavior. If isCollectible made it easier not to worry about whether an object had pending activity, it would also make it easier to write incorrect code that collected an object while it still had events to fire, or failed to collect an object even after it was guaranteed not to do any more work or fire any more events.