CRASH in MediaPlayerPrivateMediaSourceAVFObjC::addAudioRenderer(), uncaught ObjC exception
https://bugs.webkit.org/show_bug.cgi?id=209827
<rdar://problem/61113080>
Reviewed by Eric Carlson.
-[AVSampleBufferAudioRenderer init] can, in exceptional conditions, return nil. Passing a
nil object, or another object that AVSampleBufferRenderSynchronizer considers "invalid", into
-[AVSampleBufferRenderSynchronizer addRenderer:] will throw an exception. Protect against this
scenario in two ways:
- Check the return value of -[AVSampleBufferAudioRenderer init], and if nil, log an error,
log to console, and set the network state to "DecodeError".
- Wrap calls to -addRenderer: in @try/@catch blocks, which if caught, log an error, assert,
and set the network state to "DecodeError".
* Modules/mediasource/MediaSource.cpp:
(WebCore::MediaSource::failedToCreateRenderer):
* Modules/mediasource/MediaSource.h:
* platform/graphics/MediaSourcePrivateClient.h:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::ensureLayer):
* platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h:
* platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm:
(WebCore::MediaSourcePrivateAVFObjC::failedToCreateAudioRenderer):
(WebCore::MediaSourcePrivateAVFObjC::failedToCreateVideoRenderer):
* platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
(WebCore::SourceBufferPrivateAVFObjC::trackDidChangeEnabled):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@259363 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 2f22d49..0c4d86c 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,34 @@
+2020-04-01 Jer Noble <jer.noble@apple.com>
+
+ CRASH in MediaPlayerPrivateMediaSourceAVFObjC::addAudioRenderer(), uncaught ObjC exception
+ https://bugs.webkit.org/show_bug.cgi?id=209827
+ <rdar://problem/61113080>
+
+ Reviewed by Eric Carlson.
+
+ -[AVSampleBufferAudioRenderer init] can, in exceptional conditions, return nil. Passing a
+ nil object, or another object that AVSampleBufferRenderSynchronizer considers "invalid", into
+ -[AVSampleBufferRenderSynchronizer addRenderer:] will throw an exception. Protect against this
+ scenario in two ways:
+
+ - Check the return value of -[AVSampleBufferAudioRenderer init], and if nil, log an error,
+ log to console, and set the network state to "DecodeError".
+ - Wrap calls to -addRenderer: in @try/@catch blocks, which if caught, log an error, assert,
+ and set the network state to "DecodeError".
+
+ * Modules/mediasource/MediaSource.cpp:
+ (WebCore::MediaSource::failedToCreateRenderer):
+ * Modules/mediasource/MediaSource.h:
+ * platform/graphics/MediaSourcePrivateClient.h:
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
+ (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::ensureLayer):
+ * platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h:
+ * platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm:
+ (WebCore::MediaSourcePrivateAVFObjC::failedToCreateAudioRenderer):
+ (WebCore::MediaSourcePrivateAVFObjC::failedToCreateVideoRenderer):
+ * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
+ (WebCore::SourceBufferPrivateAVFObjC::trackDidChangeEnabled):
+
2020-04-01 Chris Dumez <cdumez@apple.com>
ASSERTION FAILED: m_wrapper on imported/w3c/web-platform-tests/html/semantics/embedded-content/media-elements/ready-states/autoplay.html
diff --git a/Source/WebCore/Modules/mediasource/MediaSource.cpp b/Source/WebCore/Modules/mediasource/MediaSource.cpp
index 4d1aca5..99f7fd0 100644
--- a/Source/WebCore/Modules/mediasource/MediaSource.cpp
+++ b/Source/WebCore/Modules/mediasource/MediaSource.cpp
@@ -1093,6 +1093,12 @@
}
#endif
+void MediaSource::failedToCreateRenderer(RendererType type)
+{
+ if (auto context = scriptExecutionContext())
+ context->addConsoleMessage(MessageSource::JS, MessageLevel::Error, makeString("MediaSource ", type == RendererType::Video ? "video" : "audio", " renderer creation failed."));
+}
+
}
#endif
diff --git a/Source/WebCore/Modules/mediasource/MediaSource.h b/Source/WebCore/Modules/mediasource/MediaSource.h
index 83d1c4f..71dc06c 100644
--- a/Source/WebCore/Modules/mediasource/MediaSource.h
+++ b/Source/WebCore/Modules/mediasource/MediaSource.h
@@ -122,6 +122,8 @@
void setLogIdentifier(const void*) final;
#endif
+ void failedToCreateRenderer(RendererType) final;
+
private:
explicit MediaSource(ScriptExecutionContext&);
diff --git a/Source/WebCore/platform/graphics/MediaSourcePrivateClient.h b/Source/WebCore/platform/graphics/MediaSourcePrivateClient.h
index 1941382..3fe2ad4 100644
--- a/Source/WebCore/platform/graphics/MediaSourcePrivateClient.h
+++ b/Source/WebCore/platform/graphics/MediaSourcePrivateClient.h
@@ -50,6 +50,9 @@
#if !RELEASE_LOG_DISABLED
virtual void setLogIdentifier(const void*) = 0;
#endif
+
+ enum class RendererType { Audio, Video };
+ virtual void failedToCreateRenderer(RendererType) = 0;
};
}
diff --git a/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm b/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm
index b42f491..38696dc 100644
--- a/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm
+++ b/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm
@@ -766,6 +766,14 @@
[m_sampleBufferDisplayLayer setName:@"MediaPlayerPrivateMediaSource AVSampleBufferDisplayLayer"];
#endif
+ if (!m_sampleBufferDisplayLayer) {
+ ERROR_LOG(LOGIDENTIFIER, "Failed to create AVSampleBufferDisplayLayer");
+ if (m_mediaSourcePrivate)
+ m_mediaSourcePrivate->failedToCreateRenderer(MediaSourcePrivateAVFObjC::RendererType::Video);
+ setNetworkState(MediaPlayer::NetworkState::DecodeError);
+ return;
+ }
+
#if HAVE(AVSAMPLEBUFFERVIDEOOUTPUT)
ASSERT(!m_videoOutput);
if (isVideoOutputAvailable()) {
@@ -775,17 +783,19 @@
}
#endif
- ASSERT(m_sampleBufferDisplayLayer);
- if (!m_sampleBufferDisplayLayer) {
- ERROR_LOG(LOGIDENTIFIER, "Failed to create AVSampleBufferDisplayLayer");
+ if ([m_sampleBufferDisplayLayer respondsToSelector:@selector(setPreventsDisplaySleepDuringVideoPlayback:)])
+ m_sampleBufferDisplayLayer.get().preventsDisplaySleepDuringVideoPlayback = NO;
+
+ @try {
+ [m_synchronizer addRenderer:m_sampleBufferDisplayLayer.get()];
+ } @catch(NSException *exception) {
+ ERROR_LOG(LOGIDENTIFIER, "-[AVSampleBufferRenderSynchronizer addRenderer:] threw an exception: ", [[exception name] UTF8String], ", reason : ", [[exception reason] UTF8String]);
+ ASSERT_NOT_REACHED();
+
setNetworkState(MediaPlayer::NetworkState::DecodeError);
return;
}
- if ([m_sampleBufferDisplayLayer respondsToSelector:@selector(setPreventsDisplaySleepDuringVideoPlayback:)])
- m_sampleBufferDisplayLayer.get().preventsDisplaySleepDuringVideoPlayback = NO;
-
- [m_synchronizer addRenderer:m_sampleBufferDisplayLayer.get()];
if (m_mediaSourcePrivate)
m_mediaSourcePrivate->setVideoLayer(m_sampleBufferDisplayLayer.get());
m_videoLayerManager->setVideoLayer(m_sampleBufferDisplayLayer.get(), snappedIntRect(m_player->playerContentBoxRect()).size());
@@ -1153,6 +1163,11 @@
void MediaPlayerPrivateMediaSourceAVFObjC::addAudioRenderer(AVSampleBufferAudioRenderer* audioRenderer)
ALLOW_NEW_API_WITHOUT_GUARDS_END
{
+ if (!audioRenderer) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+
if (!m_sampleBufferAudioRendererMap.add((__bridge CFTypeRef)audioRenderer, AudioRendererProperties()).isNewEntry)
return;
@@ -1160,7 +1175,15 @@
[audioRenderer setVolume:m_player->volume()];
[audioRenderer setAudioTimePitchAlgorithm:(m_player->preservesPitch() ? AVAudioTimePitchAlgorithmSpectral : AVAudioTimePitchAlgorithmVarispeed)];
- [m_synchronizer addRenderer:audioRenderer];
+ @try {
+ [m_synchronizer addRenderer:audioRenderer];
+ } @catch(NSException *exception) {
+ ERROR_LOG(LOGIDENTIFIER, "-[AVSampleBufferRenderSynchronizer addRenderer:] threw an exception: ", [[exception name] UTF8String], ", reason : ", [[exception reason] UTF8String]);
+ ASSERT_NOT_REACHED();
+
+ setNetworkState(MediaPlayer::NetworkState::DecodeError);
+ return;
+ }
m_player->renderingModeChanged();
}
diff --git a/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h b/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h
index e421cef..e1e4aa7 100644
--- a/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h
+++ b/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h
@@ -29,6 +29,7 @@
#if ENABLE(MEDIA_SOURCE) && USE(AVFOUNDATION)
#include "MediaSourcePrivate.h"
+#include "MediaSourcePrivateClient.h"
#include <wtf/Deque.h>
#include <wtf/LoggerHelper.h>
#include <wtf/RefPtr.h>
@@ -110,6 +111,9 @@
const void* nextSourceBufferLogIdentifier() { return childLogIdentifier(m_logIdentifier, ++m_nextSourceBufferID); }
#endif
+ using RendererType = MediaSourcePrivateClient::RendererType;
+ void failedToCreateRenderer(RendererType);
+
private:
MediaSourcePrivateAVFObjC(MediaPlayerPrivateMediaSourceAVFObjC*, MediaSourcePrivateClient*);
diff --git a/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm b/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm
index 0e7ae05..eac444c 100644
--- a/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm
+++ b/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm
@@ -325,6 +325,11 @@
}
#endif
+void MediaSourcePrivateAVFObjC::failedToCreateRenderer(RendererType type)
+{
+ m_client->failedToCreateRenderer(type);
+}
+
}
#endif // ENABLE(MEDIA_SOURCE) && USE(AVFOUNDATION)
diff --git a/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm b/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm
index b2f1db6..4909fdd 100644
--- a/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm
+++ b/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm
@@ -897,6 +897,15 @@
ALLOW_NEW_API_WITHOUT_GUARDS_END
if (!m_audioRenderers.contains(trackID)) {
renderer = adoptNS([PAL::allocAVSampleBufferAudioRendererInstance() init]);
+
+ if (!renderer) {
+ ERROR_LOG(LOGIDENTIFIER, "-[AVSampleBufferAudioRenderer init] returned nil! bailing!");
+ if (m_mediaSource)
+ m_mediaSource->failedToCreateRenderer(MediaSourcePrivateAVFObjC::RendererType::Audio);
+ m_mediaSource->player()->setNetworkState(MediaPlayer::NetworkState::DecodeError);
+ return;
+ }
+
auto weakThis = makeWeakPtr(*this);
[renderer requestMediaDataWhenReadyOnQueue:dispatch_get_main_queue() usingBlock:^{
if (weakThis)