Diff
Modified: tags/Safari-537.47/LayoutTests/ChangeLog (152115 => 152116)
--- tags/Safari-537.47/LayoutTests/ChangeLog 2013-06-27 18:01:43 UTC (rev 152115)
+++ tags/Safari-537.47/LayoutTests/ChangeLog 2013-06-27 18:08:52 UTC (rev 152116)
@@ -1,5 +1,19 @@
2013-06-27 Lucas Forschler <lforsch...@apple.com>
+ Merge r152038
+
+ 2013-06-26 Jer Noble <jer.no...@apple.com>
+
+ Potential use-after-free after neutering AudioBuffer's underlying ArrayBuffer.
+ https://bugs.webkit.org/show_bug.cgi?id=118040
+
+ Reviewed by Filip Pizlo.
+
+ * webaudio/audiobuffer-neuter.html: Added.
+ * webaudio/audiobuffer-neuter-expected.txt: Added.
+
+2013-06-27 Lucas Forschler <lforsch...@apple.com>
+
Merge r151868
2013-06-21 Brent Fulgham <bfulg...@apple.com>
Copied: tags/Safari-537.47/LayoutTests/webaudio/audiobuffer-neuter-expected.txt (from rev 152038, trunk/LayoutTests/webaudio/audiobuffer-neuter-expected.txt) (0 => 152116)
--- tags/Safari-537.47/LayoutTests/webaudio/audiobuffer-neuter-expected.txt (rev 0)
+++ tags/Safari-537.47/LayoutTests/webaudio/audiobuffer-neuter-expected.txt 2013-06-27 18:08:52 UTC (rev 152116)
@@ -0,0 +1,3 @@
+Tests that neutered AudioBuffers do not produce garbage
+PASS Output matches expectations.
+
Copied: tags/Safari-537.47/LayoutTests/webaudio/audiobuffer-neuter.html (from rev 152038, trunk/LayoutTests/webaudio/audiobuffer-neuter.html) (0 => 152116)
--- tags/Safari-537.47/LayoutTests/webaudio/audiobuffer-neuter.html (rev 0)
+++ tags/Safari-537.47/LayoutTests/webaudio/audiobuffer-neuter.html 2013-06-27 18:08:52 UTC (rev 152116)
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<head>
+ <script src=""
+ <script src=""
+ <script src=""
+ <script>
+ var sampleRate = 44100.0;
+ var lengthInSeconds = 0.1;
+ var context;
+ var source;
+ var sourceBuffer;
+
+ function runTest()
+ {
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+ }
+
+ var numberOfFrames = sampleRate * lengthInSeconds;
+ context = new webkitOfflineAudioContext(1, numberOfFrames, sampleRate);
+ sourceBuffer = createConstantBuffer(context, numberOfFrames, 0.5);
+ var data = ""
+
+ var string = [
+ "_onmessage_ = function(e) {",
+ " var view = new Float32Array(e.data)",
+ " for (var i=0; i < view.length; i++)",
+ " view[i] = 100;",
+ " postMessage('done');",
+ "};"
+ ].join('\n');
+ var blobURL = URL.createObjectURL(new Blob([string]));
+
+ var worker = new Worker(blobURL);
+ worker._onmessage_ = workerReply;
+ worker.postMessage(data, [data]);
+ }
+
+ function workerReply(event) {
+ source = context.createBufferSource();
+ source.buffer = sourceBuffer;
+ source.connect(context.destination);
+ source.start(0);
+ context._oncomplete_ = finishTest;
+ context.startRendering();
+ }
+
+ function finishTest(event) {
+ var renderedBuffer = event.renderedBuffer;
+ var numberOfFrames = sampleRate * lengthInSeconds;
+ var expectedBuffer = createConstantBuffer(context, numberOfFrames, 0.5);
+
+ var renderedData = renderedBuffer.getChannelData(0);
+ var expectedData = expectedBuffer.getChannelData(0);
+
+ for (var i = 0; i < numberOfFrames; ++i) {
+ if (expectedData[i] != renderedData[i]) {
+ testFailed('expected: ' + expectedData[i] + ' actual: ' + renderedData[i]);
+ finishJSTest();
+ if (window.testRunner)
+ testRunner.notifyDone();
+ }
+ }
+
+ testPassed('Output matches expectations.');
+ finishJSTest();
+ if (window.testRunner)
+ testRunner.notifyDone();
+ }
+
+ </script>
+</head>
+<body _onload_="runTest()">
+ <div>Tests that neutered AudioBuffers do not produce garbage</div>
+ <div id="console"></div>
+</body>
+
+
Modified: tags/Safari-537.47/Source/WTF/ChangeLog (152115 => 152116)
--- tags/Safari-537.47/Source/WTF/ChangeLog 2013-06-27 18:01:43 UTC (rev 152115)
+++ tags/Safari-537.47/Source/WTF/ChangeLog 2013-06-27 18:08:52 UTC (rev 152116)
@@ -1,5 +1,31 @@
2013-06-27 Lucas Forschler <lforsch...@apple.com>
+ Merge r152038
+
+ 2013-06-26 Jer Noble <jer.no...@apple.com>
+
+ Potential use-after-free after neutering AudioBuffer's underlying ArrayBuffer.
+ https://bugs.webkit.org/show_bug.cgi?id=118040
+
+ Reviewed by Filip Pizlo.
+
+ Add support for 'unneuterable' ArrayBufferViews. Views marked as such will have their underlying
+ ArrayBuffer objects copied rather than transferred to a new view.
+
+ * wtf/ArrayBuffer.cpp:
+ (WTF::ArrayBuffer::transfer): Check whether the associated views are neuterable, and if not
+ clone the ArrayBuffer rather than transferring it.
+ * wtf/ArrayBuffer.h:
+ (WTF::ArrayBufferContents::copyTo): Added. Utility function.
+ * wtf/ArrayBufferView.cpp:
+ (WTF::ArrayBufferView::ArrayBufferView):
+ (WTF::ArrayBufferView::neuter):
+ * wtf/ArrayBufferView.h:
+ (WTF::ArrayBufferView::setNeuterable):
+ (WTF::ArrayBufferView::isNeuterable):
+
+2013-06-27 Lucas Forschler <lforsch...@apple.com>
+
Merge r152035
2013-06-26 Brent Fulgham <bfulg...@apple.com>
Modified: tags/Safari-537.47/Source/WTF/wtf/ArrayBuffer.cpp (152115 => 152116)
--- tags/Safari-537.47/Source/WTF/wtf/ArrayBuffer.cpp 2013-06-27 18:01:43 UTC (rev 152115)
+++ tags/Safari-537.47/Source/WTF/wtf/ArrayBuffer.cpp 2013-06-27 18:08:52 UTC (rev 152116)
@@ -42,12 +42,25 @@
return false;
}
- m_contents.transfer(result);
+ bool allViewsAreNeuterable = true;
+ for (ArrayBufferView* i = m_firstView; i; i = i->m_nextView) {
+ if (!i->isNeuterable())
+ allViewsAreNeuterable = false;
+ }
+ if (allViewsAreNeuterable)
+ m_contents.transfer(result);
+ else {
+ m_contents.copyTo(result);
+ if (!result.m_data)
+ return false;
+ }
+
while (m_firstView) {
ArrayBufferView* current = m_firstView;
removeView(current);
- current->neuter();
+ if (allViewsAreNeuterable || current->isNeuterable())
+ current->neuter();
neuteredViews.append(current);
}
return true;
Modified: tags/Safari-537.47/Source/WTF/wtf/ArrayBuffer.h (152115 => 152116)
--- tags/Safari-537.47/Source/WTF/wtf/ArrayBuffer.h 2013-06-27 18:01:43 UTC (rev 152115)
+++ tags/Safari-537.47/Source/WTF/wtf/ArrayBuffer.h 2013-06-27 18:08:52 UTC (rev 152116)
@@ -72,6 +72,16 @@
m_sizeInBytes = 0;
}
+ void copyTo(ArrayBufferContents& other)
+ {
+ ASSERT(!other.m_data);
+ ArrayBufferContents::tryAllocate(m_sizeInBytes, sizeof(char), ArrayBufferContents::DontInitialize, other);
+ if (!other.m_data)
+ return;
+ memcpy(other.m_data, m_data, m_sizeInBytes);
+ other.m_sizeInBytes = m_sizeInBytes;
+ }
+
void* m_data;
unsigned m_sizeInBytes;
};
Modified: tags/Safari-537.47/Source/WTF/wtf/ArrayBufferView.cpp (152115 => 152116)
--- tags/Safari-537.47/Source/WTF/wtf/ArrayBufferView.cpp 2013-06-27 18:01:43 UTC (rev 152115)
+++ tags/Safari-537.47/Source/WTF/wtf/ArrayBufferView.cpp 2013-06-27 18:08:52 UTC (rev 152116)
@@ -33,6 +33,7 @@
ArrayBufferView::ArrayBufferView(PassRefPtr<ArrayBuffer> buffer,
unsigned byteOffset)
: m_byteOffset(byteOffset)
+ , m_isNeuterable(true)
, m_buffer(buffer)
, m_prevView(0)
, m_nextView(0)
Modified: tags/Safari-537.47/Source/WTF/wtf/ArrayBufferView.h (152115 => 152116)
--- tags/Safari-537.47/Source/WTF/wtf/ArrayBufferView.h 2013-06-27 18:01:43 UTC (rev 152115)
+++ tags/Safari-537.47/Source/WTF/wtf/ArrayBufferView.h 2013-06-27 18:08:52 UTC (rev 152116)
@@ -69,6 +69,9 @@
virtual unsigned byteLength() const = 0;
+ void setNeuterable(bool flag) { m_isNeuterable = flag; }
+ bool isNeuterable() const { return m_isNeuterable; }
+
WTF_EXPORT_PRIVATE virtual ~ArrayBufferView();
protected:
@@ -127,7 +130,8 @@
// This is the address of the ArrayBuffer's storage, plus the byte offset.
void* m_baseAddress;
- unsigned m_byteOffset;
+ unsigned m_byteOffset : 31;
+ bool m_isNeuterable : 1;
private:
friend class ArrayBuffer;
Modified: tags/Safari-537.47/Source/WebCore/ChangeLog (152115 => 152116)
--- tags/Safari-537.47/Source/WebCore/ChangeLog 2013-06-27 18:01:43 UTC (rev 152115)
+++ tags/Safari-537.47/Source/WebCore/ChangeLog 2013-06-27 18:08:52 UTC (rev 152116)
@@ -1,5 +1,31 @@
2013-06-27 Lucas Forschler <lforsch...@apple.com>
+ Merge r152038
+
+ 2013-06-26 Jer Noble <jer.no...@apple.com>
+
+ Potential use-after-free after neutering AudioBuffer's underlying ArrayBuffer.
+ https://bugs.webkit.org/show_bug.cgi?id=118040
+
+ Reviewed by Filip Pizlo.
+
+ Test: webaudio/audiobuffer-neuter.html
+
+ When creating an AudioBuffer's backing ArrayBufferView objects, mark them as 'unneuterable',
+ meaning the underlying data will be copied in a neuter scenario rather than transferred. This
+ means the underlying assumtions of the webaudio code can continue to assume that the memory
+ areas owned by the ArrayBufferView will be present until the AudioBuffer is itself destroyed.
+
+ In order to not expose the 'unneuterable' behavior to _javascript_, return a fresh Float32Array
+ wrapper around the ArrayBuffer object, rather than our own.
+
+ * Modules/webaudio/AudioBuffer.cpp:
+ (WebCore::AudioBuffer::AudioBuffer): Mark the newly created channels as not neuterable.
+ (WebCore::AudioBuffer::getChannelData): Return a new Float32Array object rather than a pointer to our own.
+ * Modules/webaudio/AudioBuffer.h:
+
+2013-06-27 Lucas Forschler <lforsch...@apple.com>
+
Merge r152035
2013-06-26 Brent Fulgham <bfulg...@apple.com>
Modified: tags/Safari-537.47/Source/WebCore/Modules/webaudio/AudioBuffer.cpp (152115 => 152116)
--- tags/Safari-537.47/Source/WebCore/Modules/webaudio/AudioBuffer.cpp 2013-06-27 18:01:43 UTC (rev 152115)
+++ tags/Safari-537.47/Source/WebCore/Modules/webaudio/AudioBuffer.cpp 2013-06-27 18:08:52 UTC (rev 152116)
@@ -36,6 +36,7 @@
#include "AudioContext.h"
#include "AudioFileReader.h"
#include "ExceptionCode.h"
+#include "ExceptionCodePlaceholder.h"
namespace WebCore {
@@ -65,6 +66,7 @@
for (unsigned i = 0; i < numberOfChannels; ++i) {
RefPtr<Float32Array> channelDataArray = Float32Array::create(m_length);
+ channelDataArray->setNeuterable(false);
m_channels.append(channelDataArray);
}
}
@@ -79,6 +81,7 @@
m_channels.reserveCapacity(numberOfChannels);
for (unsigned i = 0; i < numberOfChannels; ++i) {
RefPtr<Float32Array> channelDataArray = Float32Array::create(m_length);
+ channelDataArray->setNeuterable(false);
channelDataArray->setRange(bus->channel(i)->data(), m_length, 0);
m_channels.append(channelDataArray);
}
@@ -89,14 +92,15 @@
m_channels.clear();
}
-Float32Array* AudioBuffer::getChannelData(unsigned channelIndex, ExceptionCode& ec)
+PassRefPtr<Float32Array> AudioBuffer::getChannelData(unsigned channelIndex, ExceptionCode& ec)
{
if (channelIndex >= m_channels.size()) {
ec = SYNTAX_ERR;
return 0;
}
- return m_channels[channelIndex].get();
+ Float32Array* channelData = m_channels[channelIndex].get();
+ return Float32Array::create(channelData->buffer(), channelData->byteOffset(), channelData->length());
}
Float32Array* AudioBuffer::getChannelData(unsigned channelIndex)
Modified: tags/Safari-537.47/Source/WebCore/Modules/webaudio/AudioBuffer.h (152115 => 152116)
--- tags/Safari-537.47/Source/WebCore/Modules/webaudio/AudioBuffer.h 2013-06-27 18:01:43 UTC (rev 152115)
+++ tags/Safari-537.47/Source/WebCore/Modules/webaudio/AudioBuffer.h 2013-06-27 18:08:52 UTC (rev 152116)
@@ -55,7 +55,7 @@
// Channel data access
unsigned numberOfChannels() const { return m_channels.size(); }
- Float32Array* getChannelData(unsigned channelIndex, ExceptionCode&);
+ PassRefPtr<Float32Array> getChannelData(unsigned channelIndex, ExceptionCode&);
Float32Array* getChannelData(unsigned channelIndex);
void zero();