Bug 200924 - Fix unsafe usage of MediaStreamTrackPrivate from background thread in MediaStreamTrackPrivate::audioSamplesAvailable()
Summary: Fix unsafe usage of MediaStreamTrackPrivate from background thread in MediaSt...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebKit2 (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: youenn fablet
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2019-08-20 09:59 PDT by Chris Dumez
Modified: 2019-08-22 02:43 PDT (History)
8 users (show)

See Also:


Attachments
Patch (4.40 KB, patch)
2019-08-20 10:10 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Dumez 2019-08-20 09:59:54 PDT
Fix unsafe usage of MediaStreamTrackPrivate from background thread in MediaStreamTrackPrivate::audioSamplesAvailable(). It may ref |this| on the background thread while the destructor is already running on the main thread, which could lead to a double free.
Comment 1 Chris Dumez 2019-08-20 10:10:40 PDT
Created attachment 376778 [details]
Patch
Comment 2 youenn fablet 2019-08-20 10:19:18 PDT
Comment on attachment 376778 [details]
Patch

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

> Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp:78
>      m_source->removeObserver(*this);

We should probably unregister MediaStreamTrackPrivate when endTrack is called since this is no longer useful to receive notifications from the source.
This would make the makeRef safe.

If we go with the weakThis approach, I would change MediaStreamTrackPrivate to RefCounted.
This way, we would remove the temptation to do some refs from the background thread with the new assertions.
Comment 3 Chris Dumez 2019-08-20 10:25:58 PDT
(In reply to youenn fablet from comment #2)
> Comment on attachment 376778 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=376778&action=review
> 
> > Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp:78
> >      m_source->removeObserver(*this);
> 
> We should probably unregister MediaStreamTrackPrivate when endTrack is
> called since this is no longer useful to receive notifications from the
> source.
> This would make the makeRef safe.
> 
> If we go with the weakThis approach, I would change MediaStreamTrackPrivate
> to RefCounted.
> This way, we would remove the temptation to do some refs from the background
> thread with the new assertions.

Would you mind taking over since you are more familiar with this code? I went with what I felt I was confident about given my current understanding of the code.

Note that there are other cases that need to be reviewed as well:
Source/WebCore/platform/mediastream/CaptureDeviceManager.cpp:    callOnMainThread([weakThis = makeWeakPtr(*this)] {
Source/WebCore/platform/mediastream/MediaStreamPrivate.cpp:    callOnMainThread([weakThis = makeWeakPtr(*this), function = WTFMove(function)] {
Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp:        callOnMainThread([this, protectedThis = makeRef(*this)] {
Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp:    callOnMainThread([protectedThis = makeRef(*this), function = WTFMove(function)] {
Source/WebCore/platform/mediastream/RealtimeOutgoingAudioSource.cpp:    callOnMainThread([protectedThis = makeRef(*this)]() {
Source/WebCore/platform/mediastream/RealtimeOutgoingVideoSource.cpp:    callOnMainThread([protectedThis = makeRef(*this)]() {
Source/WebCore/platform/mediastream/RealtimeOutgoingVideoSource.cpp:    callOnMainThread([protectedThis = makeRef(*this)]() {
Comment 4 youenn fablet 2019-08-20 10:43:06 PDT
(In reply to Chris Dumez from comment #3)
> (In reply to youenn fablet from comment #2)
> > Comment on attachment 376778 [details]
> > Patch
> > 
> > View in context:
> > https://bugs.webkit.org/attachment.cgi?id=376778&action=review
> > 
> > > Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp:78
> > >      m_source->removeObserver(*this);
> > 
> > We should probably unregister MediaStreamTrackPrivate when endTrack is
> > called since this is no longer useful to receive notifications from the
> > source.
> > This would make the makeRef safe.
> > 
> > If we go with the weakThis approach, I would change MediaStreamTrackPrivate
> > to RefCounted.
> > This way, we would remove the temptation to do some refs from the background
> > thread with the new assertions.
> 
> Would you mind taking over since you are more familiar with this code?

OK, will do.

> O went with what I felt I was confident about given my current understanding
> of the code.
> 
> Note that there are other cases that need to be reviewed as well:

Will do as well.

> Source/WebCore/platform/mediastream/CaptureDeviceManager.cpp:   
> callOnMainThread([weakThis = makeWeakPtr(*this)] {
> Source/WebCore/platform/mediastream/MediaStreamPrivate.cpp:   
> callOnMainThread([weakThis = makeWeakPtr(*this), function =
> WTFMove(function)] {
> Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp:       
> callOnMainThread([this, protectedThis = makeRef(*this)] {
> Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp:   
> callOnMainThread([protectedThis = makeRef(*this), function =
> WTFMove(function)] {
> Source/WebCore/platform/mediastream/RealtimeOutgoingAudioSource.cpp:   
> callOnMainThread([protectedThis = makeRef(*this)]() {
> Source/WebCore/platform/mediastream/RealtimeOutgoingVideoSource.cpp:   
> callOnMainThread([protectedThis = makeRef(*this)]() {
> Source/WebCore/platform/mediastream/RealtimeOutgoingVideoSource.cpp:   
> callOnMainThread([protectedThis = makeRef(*this)]() {
Comment 5 youenn fablet 2019-08-20 11:57:24 PDT
> > Source/WebCore/platform/mediastream/CaptureDeviceManager.cpp:   
> > callOnMainThread([weakThis = makeWeakPtr(*this)] {

Safe for CoreAudioCaptureSource, unclear whether safe in case of suspension for AV devices.
We should try to optimise and not callOnMainThread if not needed, use m_weakThis otherwise.

> > Source/WebCore/platform/mediastream/MediaStreamPrivate.cpp:   
> > callOnMainThread([weakThis = makeWeakPtr(*this), function =
> > WTFMove(function)] {

This should be safe as all call sites should be on main thread.
We could do m_weakThis for extra safety.

> > Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp:   
> > callOnMainThread([protectedThis = makeRef(*this), function =
> > WTFMove(function)] {

Should be safe, RealtimeMediaSource is thread-safe refcounted and the call sites are fine as well.
This seems fragile though and extending the lifetime of RealtimeMediaSource is not great.
m_weakThis seems like a good tradeoff.

> > Source/WebCore/platform/mediastream/RealtimeOutgoingAudioSource.cpp:   
> > callOnMainThread([protectedThis = makeRef(*this)]() {

Should be safe, libwebrtc should call this method while holding a ref to it.

> > Source/WebCore/platform/mediastream/RealtimeOutgoingVideoSource.cpp:   
> > callOnMainThread([protectedThis = makeRef(*this)]() {

Ditto.

> > Source/WebCore/platform/mediastream/RealtimeOutgoingVideoSource.cpp:   
> > callOnMainThread([protectedThis = makeRef(*this)]() {

Ditto.
Comment 6 youenn fablet 2019-08-22 02:11:19 PDT
Digging in further, the approach to stop observing the source sooner will not fix the issue in some cases, at least MediaRecorder.
Let's start by fixing the issue as you are proposing in that patch.
I'll do follow-ups (move to RefCounted and sort observing the source sooner in some cases).
Comment 7 youenn fablet 2019-08-22 02:12:07 PDT
I'll also do a follow-up to remove m_weakThis.
Comment 8 WebKit Commit Bot 2019-08-22 02:42:04 PDT
Comment on attachment 376778 [details]
Patch

Clearing flags on attachment: 376778

Committed r249000: <https://trac.webkit.org/changeset/249000>
Comment 9 WebKit Commit Bot 2019-08-22 02:42:06 PDT
All reviewed patches have been landed.  Closing bug.
Comment 10 Radar WebKit Bug Importer 2019-08-22 02:43:20 PDT
<rdar://problem/54591668>