OfflineAudioContext does not validate allocation of destination buffer
https://bugs.webkit.org/show_bug.cgi?id=177259

Patch by Bjorn Melinder <bjornm@spotify.com> on 2019-10-11
Reviewed by Eric Carlson.

Moved the allocation of the destination buffer to the static
OfflineAudioContext::create method where we are able to handle a failed
allocation properly and return an Exception. This change handles both
negative lengths as well as too large lengths where the memory cannot
be allocated.

Source/WebCore:

* Modules/webaudio/AudioContext.cpp:
(WebCore::AudioContext::AudioContext):
* Modules/webaudio/AudioContext.h:
* Modules/webaudio/OfflineAudioContext.cpp:
(WebCore::OfflineAudioContext::OfflineAudioContext):
(WebCore::OfflineAudioContext::create):
* Modules/webaudio/OfflineAudioContext.h:

LayoutTests:

* webaudio/offlineaudiocontext-constructor-expected.txt:
* webaudio/offlineaudiocontext-constructor.html:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251007 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index c269e3a..91a216e 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,19 @@
+2019-10-11  Bjorn Melinder  <bjornm@spotify.com>
+
+        OfflineAudioContext does not validate allocation of destination buffer
+        https://bugs.webkit.org/show_bug.cgi?id=177259
+
+        Reviewed by Eric Carlson.
+
+        Moved the allocation of the destination buffer to the static
+        OfflineAudioContext::create method where we are able to handle a failed
+        allocation properly and return an Exception. This change handles both
+        negative lengths as well as too large lengths where the memory cannot
+        be allocated.
+
+        * webaudio/offlineaudiocontext-constructor-expected.txt:
+        * webaudio/offlineaudiocontext-constructor.html:
+
 2019-10-11  Chris Lord  <clord@igalia.com>
 
         Flaky test: imported/w3c/web-platform-tests/offscreen-canvas/compositing/2d.composite.canvas.destination-in.html
diff --git a/LayoutTests/webaudio/offlineaudiocontext-constructor-expected.txt b/LayoutTests/webaudio/offlineaudiocontext-constructor-expected.txt
index 4d5b555..7ccc0d8 100644
--- a/LayoutTests/webaudio/offlineaudiocontext-constructor-expected.txt
+++ b/LayoutTests/webaudio/offlineaudiocontext-constructor-expected.txt
@@ -4,6 +4,8 @@
 
 
 PASS new webkitOfflineAudioContext(1, 0, 44100) threw exception SyntaxError: The string did not match the expected pattern..
+PASS new webkitOfflineAudioContext(1, -1, 44100) threw exception SyntaxError: The string did not match the expected pattern..
+PASS new webkitOfflineAudioContext(1, 99999999999, 44100) threw exception SyntaxError: The string did not match the expected pattern..
 PASS new webkitOfflineAudioContext(0, 1, 44100) threw exception SyntaxError: The string did not match the expected pattern..
 PASS new webkitOfflineAudioContext(1, 1, 0) threw exception SyntaxError: The string did not match the expected pattern..
 PASS new webkitOfflineAudioContext(1, 1, 44100) did not throw exception.
diff --git a/LayoutTests/webaudio/offlineaudiocontext-constructor.html b/LayoutTests/webaudio/offlineaudiocontext-constructor.html
index 6805474..1af2653 100644
--- a/LayoutTests/webaudio/offlineaudiocontext-constructor.html
+++ b/LayoutTests/webaudio/offlineaudiocontext-constructor.html
@@ -6,6 +6,8 @@
         <script>
             description('This tests that passing zero to the "numberOfFrames" parameter of the OfflineAudioContext constructor does not cause a crash.');
             shouldThrow('new webkitOfflineAudioContext(1, 0, 44100)');
+            shouldThrow('new webkitOfflineAudioContext(1, -1, 44100)');
+            shouldThrow('new webkitOfflineAudioContext(1, 99999999999, 44100)');
             shouldThrow('new webkitOfflineAudioContext(0, 1, 44100)');
             shouldThrow('new webkitOfflineAudioContext(1, 1, 0)');
             shouldNotThrow('new webkitOfflineAudioContext(1, 1, 44100)');
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index f3f0780..2eaa342 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,24 @@
+2019-10-11  Bjorn Melinder  <bjornm@spotify.com>
+
+        OfflineAudioContext does not validate allocation of destination buffer
+        https://bugs.webkit.org/show_bug.cgi?id=177259
+
+        Reviewed by Eric Carlson.
+
+        Moved the allocation of the destination buffer to the static
+        OfflineAudioContext::create method where we are able to handle a failed
+        allocation properly and return an Exception. This change handles both
+        negative lengths as well as too large lengths where the memory cannot
+        be allocated.
+
+        * Modules/webaudio/AudioContext.cpp:
+        (WebCore::AudioContext::AudioContext):
+        * Modules/webaudio/AudioContext.h:
+        * Modules/webaudio/OfflineAudioContext.cpp:
+        (WebCore::OfflineAudioContext::OfflineAudioContext):
+        (WebCore::OfflineAudioContext::create):
+        * Modules/webaudio/OfflineAudioContext.h:
+
 2019-10-10  Konstantin Tokarev  <annulen@yandex.ru>
 
         Guard GCrypt-specific code with USE(GCRYPT) instead of PLATFORM macros
diff --git a/Source/WebCore/Modules/webaudio/AudioContext.cpp b/Source/WebCore/Modules/webaudio/AudioContext.cpp
index c627f33..dd2e5ce 100644
--- a/Source/WebCore/Modules/webaudio/AudioContext.cpp
+++ b/Source/WebCore/Modules/webaudio/AudioContext.cpp
@@ -158,7 +158,7 @@
 }
 
 // Constructor for offline (non-realtime) rendering.
-AudioContext::AudioContext(Document& document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
+AudioContext::AudioContext(Document& document, AudioBuffer* renderTarget)
     : ActiveDOMObject(document)
 #if !RELEASE_LOG_DISABLED
     , m_logger(document.logger())
@@ -167,11 +167,11 @@
     , m_isOfflineContext(true)
     , m_mediaSession(PlatformMediaSession::create(*this))
     , m_eventQueue(MainThreadGenericEventQueue::create(*this))
+    , m_renderTarget(renderTarget)
 {
     constructCommon();
 
     // Create a new destination for offline rendering.
-    m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
     m_destinationNode = OfflineAudioDestinationNode::create(*this, m_renderTarget.get());
 }
 
diff --git a/Source/WebCore/Modules/webaudio/AudioContext.h b/Source/WebCore/Modules/webaudio/AudioContext.h
index 0c45ad5..e466f45 100644
--- a/Source/WebCore/Modules/webaudio/AudioContext.h
+++ b/Source/WebCore/Modules/webaudio/AudioContext.h
@@ -296,7 +296,7 @@
 
 protected:
     explicit AudioContext(Document&);
-    AudioContext(Document&, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate);
+    AudioContext(Document&, AudioBuffer* renderTarget);
     
     static bool isSampleRateRangeGood(float sampleRate);
     void clearPendingActivity();
diff --git a/Source/WebCore/Modules/webaudio/OfflineAudioContext.cpp b/Source/WebCore/Modules/webaudio/OfflineAudioContext.cpp
index ef78ce7..11be75a 100644
--- a/Source/WebCore/Modules/webaudio/OfflineAudioContext.cpp
+++ b/Source/WebCore/Modules/webaudio/OfflineAudioContext.cpp
@@ -35,8 +35,8 @@
 
 WTF_MAKE_ISO_ALLOCATED_IMPL(OfflineAudioContext);
 
-inline OfflineAudioContext::OfflineAudioContext(Document& document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
-    : AudioContext(document, numberOfChannels, numberOfFrames, sampleRate)
+inline OfflineAudioContext::OfflineAudioContext(Document& document, AudioBuffer* renderTarget)
+    : AudioContext(document, renderTarget)
 {
 }
 
@@ -47,7 +47,11 @@
         return Exception { NotSupportedError };
     if (!numberOfChannels || numberOfChannels > 10 || !numberOfFrames || !isSampleRateRangeGood(sampleRate))
         return Exception { SyntaxError };
-    auto audioContext = adoptRef(*new OfflineAudioContext(downcast<Document>(context), numberOfChannels, numberOfFrames, sampleRate));
+    auto renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
+    if (!renderTarget)
+        return Exception { SyntaxError };
+
+    auto audioContext = adoptRef(*new OfflineAudioContext(downcast<Document>(context), renderTarget.get()));
     audioContext->suspendIfNeeded();
     return audioContext;
 }
diff --git a/Source/WebCore/Modules/webaudio/OfflineAudioContext.h b/Source/WebCore/Modules/webaudio/OfflineAudioContext.h
index 39cdff5..85a595f 100644
--- a/Source/WebCore/Modules/webaudio/OfflineAudioContext.h
+++ b/Source/WebCore/Modules/webaudio/OfflineAudioContext.h
@@ -34,7 +34,7 @@
     static ExceptionOr<Ref<OfflineAudioContext>> create(ScriptExecutionContext&, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate);
 
 private:
-    OfflineAudioContext(Document&, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate);
+    OfflineAudioContext(Document&, AudioBuffer* renderTarget);
 };
 
 } // namespace WebCore