<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[171526] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/171526">171526</a></dd>
<dt>Author</dt> <dd>psolanki@apple.com</dd>
<dt>Date</dt> <dd>2014-07-24 14:37:43 -0700 (Thu, 24 Jul 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Sharing SharedBuffer between WebCore and ImageIO is racy and crash prone
https://bugs.webkit.org/show_bug.cgi?id=135069
&lt;rdar://problem/17470655&gt;

Reviewed by Simon Fraser.

When passing image data to ImageIO for decoding, we pass an NSData subclass that is a wraper
around SharedBuffer. This can be a problem when ImageIO tries to access the data on the CA
thread. End result is data corruption on large image loads and potential crashes. The fix is
to have SharedBuffer create a copy of its data if the data has been passed to ImageIO and
might be accessed concurrently.

Since Vector is not refcounted, we do this by having a new refcounted object in SharedBuffer
that contains the buffer and we pass that in our NSData subclass WebCoreSharedBufferData.
Code that would result in the Vector memory moving e.g. append(), resize(), now checks to
see if the buffer was shared and if so, will create a new copy of the vector. This ensures
that the main thread does not end up invalidating the vector memory that we have passed it
to ImageIO.

No new tests because no functional changes.

* loader/cache/CachedResource.cpp:
(WebCore::CachedResource::makePurgeable):
    Remove early return - createPurgeableMemory() has the correct check now.
* platform/SharedBuffer.cpp:
(WebCore::SharedBuffer::SharedBuffer):
(WebCore::SharedBuffer::adoptVector):
(WebCore::SharedBuffer::createPurgeableBuffer):
    Don't create purgeable buffer if we are sharing the buffer.
(WebCore::SharedBuffer::append):
(WebCore::SharedBuffer::clear):
(WebCore::SharedBuffer::copy):
(WebCore::SharedBuffer::duplicateDataBufferIfNecessary): Added.
    Create a new copy of the data if we have shared the buffer and if appending to it would
    exceed the capacity of the vector resulting in memmove.
(WebCore::SharedBuffer::appendToInternalBuffer): Added.
(WebCore::SharedBuffer::clearInternalBuffer): Added.
(WebCore::SharedBuffer::buffer):
    Create a new copy of the buffer if we have shared it.
(WebCore::SharedBuffer::getSomeData):
* platform/SharedBuffer.h:
* platform/cf/SharedBufferCF.cpp:
(WebCore::SharedBuffer::SharedBuffer):
(WebCore::SharedBuffer::singleDataArrayBuffer):
(WebCore::SharedBuffer::maybeAppendDataArray):
* platform/mac/SharedBufferMac.mm:
    Pass the InternalBuffer object to WebCoreSharedBufferData
(-[WebCoreSharedBufferData dealloc]):
(-[WebCoreSharedBufferData initWithSharedBufferInternalBuffer:]):
(-[WebCoreSharedBufferData length]):
(-[WebCoreSharedBufferData bytes]):
(WebCore::SharedBuffer::createNSData):
    Call createCFData() instead of duplicating code.
(WebCore::SharedBuffer::createCFData):
    If the data is in purgeable memory, make a copy of it since m_buffer was cleared when
    creating the purgeable buffer.
(-[WebCoreSharedBufferData initWithSharedBuffer:]): Deleted.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreloadercacheCachedResourcecpp">trunk/Source/WebCore/loader/cache/CachedResource.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformSharedBuffercpp">trunk/Source/WebCore/platform/SharedBuffer.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformSharedBufferh">trunk/Source/WebCore/platform/SharedBuffer.h</a></li>
<li><a href="#trunkSourceWebCoreplatformcfSharedBufferCFcpp">trunk/Source/WebCore/platform/cf/SharedBufferCF.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmacSharedBufferMacmm">trunk/Source/WebCore/platform/mac/SharedBufferMac.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (171525 => 171526)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-07-24 21:12:53 UTC (rev 171525)
+++ trunk/Source/WebCore/ChangeLog        2014-07-24 21:37:43 UTC (rev 171526)
</span><span class="lines">@@ -1,3 +1,63 @@
</span><ins>+2014-07-24  Pratik Solanki  &lt;psolanki@apple.com&gt;
+
+        Sharing SharedBuffer between WebCore and ImageIO is racy and crash prone
+        https://bugs.webkit.org/show_bug.cgi?id=135069
+        &lt;rdar://problem/17470655&gt;
+
+        Reviewed by Simon Fraser.
+
+        When passing image data to ImageIO for decoding, we pass an NSData subclass that is a wraper
+        around SharedBuffer. This can be a problem when ImageIO tries to access the data on the CA
+        thread. End result is data corruption on large image loads and potential crashes. The fix is
+        to have SharedBuffer create a copy of its data if the data has been passed to ImageIO and
+        might be accessed concurrently.
+
+        Since Vector is not refcounted, we do this by having a new refcounted object in SharedBuffer
+        that contains the buffer and we pass that in our NSData subclass WebCoreSharedBufferData.
+        Code that would result in the Vector memory moving e.g. append(), resize(), now checks to
+        see if the buffer was shared and if so, will create a new copy of the vector. This ensures
+        that the main thread does not end up invalidating the vector memory that we have passed it
+        to ImageIO.
+
+        No new tests because no functional changes.
+
+        * loader/cache/CachedResource.cpp:
+        (WebCore::CachedResource::makePurgeable):
+            Remove early return - createPurgeableMemory() has the correct check now.
+        * platform/SharedBuffer.cpp:
+        (WebCore::SharedBuffer::SharedBuffer):
+        (WebCore::SharedBuffer::adoptVector):
+        (WebCore::SharedBuffer::createPurgeableBuffer):
+            Don't create purgeable buffer if we are sharing the buffer.
+        (WebCore::SharedBuffer::append):
+        (WebCore::SharedBuffer::clear):
+        (WebCore::SharedBuffer::copy):
+        (WebCore::SharedBuffer::duplicateDataBufferIfNecessary): Added.
+            Create a new copy of the data if we have shared the buffer and if appending to it would
+            exceed the capacity of the vector resulting in memmove.
+        (WebCore::SharedBuffer::appendToInternalBuffer): Added.
+        (WebCore::SharedBuffer::clearInternalBuffer): Added.
+        (WebCore::SharedBuffer::buffer):
+            Create a new copy of the buffer if we have shared it.
+        (WebCore::SharedBuffer::getSomeData):
+        * platform/SharedBuffer.h:
+        * platform/cf/SharedBufferCF.cpp:
+        (WebCore::SharedBuffer::SharedBuffer):
+        (WebCore::SharedBuffer::singleDataArrayBuffer):
+        (WebCore::SharedBuffer::maybeAppendDataArray):
+        * platform/mac/SharedBufferMac.mm:
+            Pass the InternalBuffer object to WebCoreSharedBufferData
+        (-[WebCoreSharedBufferData dealloc]):
+        (-[WebCoreSharedBufferData initWithSharedBufferInternalBuffer:]):
+        (-[WebCoreSharedBufferData length]):
+        (-[WebCoreSharedBufferData bytes]):
+        (WebCore::SharedBuffer::createNSData):
+            Call createCFData() instead of duplicating code.
+        (WebCore::SharedBuffer::createCFData):
+            If the data is in purgeable memory, make a copy of it since m_buffer was cleared when
+            creating the purgeable buffer.
+        (-[WebCoreSharedBufferData initWithSharedBuffer:]): Deleted.
+
</ins><span class="cx"> 2014-07-24  peavo@outlook.com  &lt;peavo@outlook.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Curl] Enable file logging.
</span></span></pre></div>
<a id="trunkSourceWebCoreloadercacheCachedResourcecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/cache/CachedResource.cpp (171525 => 171526)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/cache/CachedResource.cpp        2014-07-24 21:12:53 UTC (rev 171525)
+++ trunk/Source/WebCore/loader/cache/CachedResource.cpp        2014-07-24 21:37:43 UTC (rev 171526)
</span><span class="lines">@@ -811,10 +811,6 @@
</span><span class="cx">         if (!m_data)
</span><span class="cx">             return false;
</span><span class="cx">         
</span><del>-        // Should not make buffer purgeable if it has refs other than this since we don't want two copies.
-        if (!m_data-&gt;hasOneRef())
-            return false;
-
</del><span class="cx">         m_data-&gt;createPurgeableBuffer();
</span><span class="cx">         if (!m_data-&gt;hasPurgeableBuffer())
</span><span class="cx">             return false;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformSharedBuffercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/SharedBuffer.cpp (171525 => 171526)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/SharedBuffer.cpp        2014-07-24 21:12:53 UTC (rev 171525)
+++ trunk/Source/WebCore/platform/SharedBuffer.cpp        2014-07-24 21:37:43 UTC (rev 171526)
</span><span class="lines">@@ -65,6 +65,7 @@
</span><span class="cx"> 
</span><span class="cx"> SharedBuffer::SharedBuffer()
</span><span class="cx">     : m_size(0)
</span><ins>+    , m_buffer(adoptRef(new DataBuffer))
</ins><span class="cx">     , m_shouldUsePurgeableMemory(false)
</span><span class="cx"> #if ENABLE(DISK_IMAGE_CACHE)
</span><span class="cx">     , m_isMemoryMapped(false)
</span><span class="lines">@@ -77,7 +78,7 @@
</span><span class="cx"> 
</span><span class="cx"> SharedBuffer::SharedBuffer(unsigned size)
</span><span class="cx">     : m_size(size)
</span><del>-    , m_buffer(size)
</del><ins>+    , m_buffer(adoptRef(new DataBuffer))
</ins><span class="cx">     , m_shouldUsePurgeableMemory(false)
</span><span class="cx"> #if ENABLE(DISK_IMAGE_CACHE)
</span><span class="cx">     , m_isMemoryMapped(false)
</span><span class="lines">@@ -90,6 +91,7 @@
</span><span class="cx"> 
</span><span class="cx"> SharedBuffer::SharedBuffer(const char* data, unsigned size)
</span><span class="cx">     : m_size(0)
</span><ins>+    , m_buffer(adoptRef(new DataBuffer))
</ins><span class="cx">     , m_shouldUsePurgeableMemory(false)
</span><span class="cx"> #if ENABLE(DISK_IMAGE_CACHE)
</span><span class="cx">     , m_isMemoryMapped(false)
</span><span class="lines">@@ -103,6 +105,7 @@
</span><span class="cx"> 
</span><span class="cx"> SharedBuffer::SharedBuffer(const unsigned char* data, unsigned size)
</span><span class="cx">     : m_size(0)
</span><ins>+    , m_buffer(adoptRef(new DataBuffer))
</ins><span class="cx">     , m_shouldUsePurgeableMemory(false)
</span><span class="cx"> #if ENABLE(DISK_IMAGE_CACHE)
</span><span class="cx">     , m_isMemoryMapped(false)
</span><span class="lines">@@ -129,8 +132,8 @@
</span><span class="cx"> PassRefPtr&lt;SharedBuffer&gt; SharedBuffer::adoptVector(Vector&lt;char&gt;&amp; vector)
</span><span class="cx"> {
</span><span class="cx">     RefPtr&lt;SharedBuffer&gt; buffer = create();
</span><del>-    buffer-&gt;m_buffer.swap(vector);
-    buffer-&gt;m_size = buffer-&gt;m_buffer.size();
</del><ins>+    buffer-&gt;m_buffer-&gt;data.swap(vector);
+    buffer-&gt;m_size = buffer-&gt;m_buffer-&gt;data.size();
</ins><span class="cx">     return buffer.release();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -232,7 +235,7 @@
</span><span class="cx">         return;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    if (!hasOneRef())
</del><ins>+    if (!m_buffer-&gt;hasOneRef())
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     if (!m_shouldUsePurgeableMemory)
</span><span class="lines">@@ -242,11 +245,11 @@
</span><span class="cx">     m_purgeableBuffer = PurgeableBuffer::createUninitialized(m_size, destination);
</span><span class="cx">     if (!m_purgeableBuffer)
</span><span class="cx">         return;
</span><del>-    unsigned bufferSize = m_buffer.size();
</del><ins>+    unsigned bufferSize = m_buffer-&gt;data.size();
</ins><span class="cx">     if (bufferSize) {
</span><del>-        memcpy(destination, m_buffer.data(), bufferSize);
</del><ins>+        memcpy(destination, m_buffer-&gt;data.data(), bufferSize);
</ins><span class="cx">         destination += bufferSize;
</span><del>-        m_buffer.clear();
</del><ins>+        (const_cast&lt;SharedBuffer*&gt;(this))-&gt;clearDataBuffer();
</ins><span class="cx">     }
</span><span class="cx">     copyBufferAndClear(destination, m_size - bufferSize);
</span><span class="cx"> }
</span><span class="lines">@@ -323,14 +326,14 @@
</span><span class="cx">     maybeTransferPlatformData();
</span><span class="cx"> 
</span><span class="cx"> #if !USE(NETWORK_CFDATA_ARRAY_CALLBACK)
</span><del>-    unsigned positionInSegment = offsetInSegment(m_size - m_buffer.size());
</del><ins>+    unsigned positionInSegment = offsetInSegment(m_size - m_buffer-&gt;data.size());
</ins><span class="cx">     m_size += length;
</span><span class="cx"> 
</span><span class="cx">     if (m_size &lt;= segmentSize) {
</span><span class="cx">         // No need to use segments for small resource data
</span><del>-        if (m_buffer.isEmpty())
-            m_buffer.reserveInitialCapacity(length);
-        m_buffer.append(data, length);
</del><ins>+        if (m_buffer-&gt;data.isEmpty())
+            m_buffer-&gt;data.reserveInitialCapacity(length);
+        appendToDataBuffer(data, length);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -356,10 +359,10 @@
</span><span class="cx">         bytesToCopy = std::min(length, segmentSize);
</span><span class="cx">     }
</span><span class="cx"> #else
</span><del>-    if (m_buffer.isEmpty())
-        m_buffer.reserveInitialCapacity(length);
-    m_buffer.append(data, length);
</del><span class="cx">     m_size += length;
</span><ins>+    if (m_buffer-&gt;data.isEmpty())
+        m_buffer-&gt;data.reserveInitialCapacity(length);
+    appendToDataBuffer(data, length);
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -382,7 +385,7 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     m_size = 0;
</span><del>-    m_buffer.clear();
</del><ins>+    clearDataBuffer();
</ins><span class="cx">     m_purgeableBuffer.clear();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -395,11 +398,11 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     clone-&gt;m_size = m_size;
</span><del>-    clone-&gt;m_buffer.reserveCapacity(m_size);
-    clone-&gt;m_buffer.append(m_buffer.data(), m_buffer.size());
</del><ins>+    clone-&gt;m_buffer-&gt;data.reserveCapacity(m_size);
+    clone-&gt;m_buffer-&gt;data.append(m_buffer-&gt;data.data(), m_buffer-&gt;data.size());
</ins><span class="cx"> #if !USE(NETWORK_CFDATA_ARRAY_CALLBACK)
</span><span class="cx">     for (unsigned i = 0; i &lt; m_segments.size(); ++i)
</span><del>-        clone-&gt;m_buffer.append(m_segments[i], segmentSize);
</del><ins>+        clone-&gt;m_buffer-&gt;data.append(m_segments[i], segmentSize);
</ins><span class="cx"> #else
</span><span class="cx">     for (unsigned i = 0; i &lt; m_dataArray.size(); ++i)
</span><span class="cx">         clone-&gt;append(m_dataArray[i].get());
</span><span class="lines">@@ -413,6 +416,31 @@
</span><span class="cx">     return m_purgeableBuffer.release(); 
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SharedBuffer::duplicateDataBufferIfNecessary() const
+{
+    if (m_buffer-&gt;hasOneRef() || m_size &lt;= m_buffer-&gt;data.capacity())
+        return;
+
+    RefPtr&lt;DataBuffer&gt; newBuffer = adoptRef(new DataBuffer);
+    newBuffer-&gt;data.reserveInitialCapacity(m_size);
+    newBuffer-&gt;data = m_buffer-&gt;data;
+    m_buffer = newBuffer.release();
+}
+
+void SharedBuffer::appendToDataBuffer(const char *data, unsigned length) const
+{
+    duplicateDataBufferIfNecessary();
+    m_buffer-&gt;data.append(data, length);
+}
+
+void SharedBuffer::clearDataBuffer()
+{
+    if (!m_buffer-&gt;hasOneRef())
+        m_buffer = adoptRef(new DataBuffer);
+    else
+        m_buffer-&gt;data.clear();
+}
+
</ins><span class="cx"> #if !USE(NETWORK_CFDATA_ARRAY_CALLBACK)
</span><span class="cx"> void SharedBuffer::copyBufferAndClear(char* destination, unsigned bytesToCopy) const
</span><span class="cx"> {
</span><span class="lines">@@ -432,12 +460,13 @@
</span><span class="cx"> #if ENABLE(DISK_IMAGE_CACHE)
</span><span class="cx">     ASSERT(!isMemoryMapped());
</span><span class="cx"> #endif
</span><del>-    unsigned bufferSize = m_buffer.size();
</del><ins>+    unsigned bufferSize = m_buffer-&gt;data.size();
</ins><span class="cx">     if (m_size &gt; bufferSize) {
</span><del>-        m_buffer.resize(m_size);
-        copyBufferAndClear(m_buffer.data() + bufferSize, m_size - bufferSize);
</del><ins>+        duplicateDataBufferIfNecessary();
+        m_buffer-&gt;data.resize(m_size);
+        copyBufferAndClear(m_buffer-&gt;data.data() + bufferSize, m_size - bufferSize);
</ins><span class="cx">     }
</span><del>-    return m_buffer;
</del><ins>+    return m_buffer-&gt;data;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> unsigned SharedBuffer::getSomeData(const char*&amp; someData, unsigned position) const
</span><span class="lines">@@ -464,9 +493,9 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ASSERT_WITH_SECURITY_IMPLICATION(position &lt; m_size);
</span><del>-    unsigned consecutiveSize = m_buffer.size();
</del><ins>+    unsigned consecutiveSize = m_buffer-&gt;data.size();
</ins><span class="cx">     if (position &lt; consecutiveSize) {
</span><del>-        someData = m_buffer.data() + position;
</del><ins>+        someData = m_buffer-&gt;data.data() + position;
</ins><span class="cx">         return consecutiveSize - position;
</span><span class="cx">     }
</span><span class="cx">  
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformSharedBufferh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/SharedBuffer.h (171525 => 171526)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/SharedBuffer.h        2014-07-24 21:12:53 UTC (rev 171525)
+++ trunk/Source/WebCore/platform/SharedBuffer.h        2014-07-24 21:37:43 UTC (rev 171526)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include &lt;wtf/Forward.h&gt;
</span><span class="cx"> #include &lt;wtf/OwnPtr.h&gt;
</span><span class="cx"> #include &lt;wtf/RefCounted.h&gt;
</span><ins>+#include &lt;wtf/ThreadSafeRefCounted.h&gt;
</ins><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><span class="cx"> #include &lt;wtf/text/WTFString.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -158,6 +159,10 @@
</span><span class="cx">     void tryReplaceContentsWithPlatformBuffer(SharedBuffer*);
</span><span class="cx">     bool hasPlatformData() const;
</span><span class="cx"> 
</span><ins>+    struct DataBuffer : public ThreadSafeRefCounted&lt;DataBuffer&gt; {
+        Vector&lt;char&gt; data;
+    };
+
</ins><span class="cx"> private:
</span><span class="cx">     SharedBuffer();
</span><span class="cx">     explicit SharedBuffer(unsigned);
</span><span class="lines">@@ -177,8 +182,13 @@
</span><span class="cx"> 
</span><span class="cx">     void copyBufferAndClear(char* destination, unsigned bytesToCopy) const;
</span><span class="cx"> 
</span><ins>+    void appendToDataBuffer(const char *, unsigned) const;
+    void duplicateDataBufferIfNecessary() const;
+    void clearDataBuffer();
+
</ins><span class="cx">     unsigned m_size;
</span><del>-    mutable Vector&lt;char&gt; m_buffer;
</del><ins>+    mutable RefPtr&lt;DataBuffer&gt; m_buffer;
+
</ins><span class="cx">     bool m_shouldUsePurgeableMemory;
</span><span class="cx">     mutable OwnPtr&lt;PurgeableBuffer&gt; m_purgeableBuffer;
</span><span class="cx"> #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformcfSharedBufferCFcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/cf/SharedBufferCF.cpp (171525 => 171526)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/cf/SharedBufferCF.cpp        2014-07-24 21:12:53 UTC (rev 171525)
+++ trunk/Source/WebCore/platform/cf/SharedBufferCF.cpp        2014-07-24 21:37:43 UTC (rev 171526)
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx"> 
</span><span class="cx"> SharedBuffer::SharedBuffer(CFDataRef cfData)
</span><span class="cx">     : m_size(0)
</span><ins>+    , m_buffer(adoptRef(new DataBuffer))
</ins><span class="cx">     , m_shouldUsePurgeableMemory(false)
</span><span class="cx"> #if ENABLE(DISK_IMAGE_CACHE)
</span><span class="cx">     , m_isMemoryMapped(false)
</span><span class="lines">@@ -128,6 +129,7 @@
</span><span class="cx"> 
</span><span class="cx"> SharedBuffer::SharedBuffer(CFArrayRef cfDataArray)
</span><span class="cx">     : m_size(0)
</span><ins>+    , m_buffer(adoptRef(new DataBuffer))
</ins><span class="cx">     , m_shouldUsePurgeableMemory(false)
</span><span class="cx"> #if ENABLE(DISK_IMAGE_CACHE)
</span><span class="cx">     , m_isMemoryMapped(false)
</span><span class="lines">@@ -187,7 +189,7 @@
</span><span class="cx"> {
</span><span class="cx">     // If we had previously copied data into m_buffer in copyDataArrayAndClear() or some other
</span><span class="cx">     // function, then we can't return a pointer to the CFDataRef buffer.
</span><del>-    if (m_buffer.size())
</del><ins>+    if (m_buffer-&gt;data.size())
</ins><span class="cx">         return 0;
</span><span class="cx"> 
</span><span class="cx">     if (m_dataArray.size() != 1)
</span><span class="lines">@@ -198,7 +200,7 @@
</span><span class="cx"> 
</span><span class="cx"> bool SharedBuffer::maybeAppendDataArray(SharedBuffer* data)
</span><span class="cx"> {
</span><del>-    if (m_buffer.size() || m_cfData || !data-&gt;m_dataArray.size())
</del><ins>+    if (m_buffer-&gt;data.size() || m_cfData || !data-&gt;m_dataArray.size())
</ins><span class="cx">         return false;
</span><span class="cx"> #if !ASSERT_DISABLED
</span><span class="cx">     unsigned originalSize = size();
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmacSharedBufferMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mac/SharedBufferMac.mm (171525 => 171526)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mac/SharedBufferMac.mm        2014-07-24 21:12:53 UTC (rev 171525)
+++ trunk/Source/WebCore/platform/mac/SharedBufferMac.mm        2014-07-24 21:37:43 UTC (rev 171526)
</span><span class="lines">@@ -32,15 +32,14 @@
</span><span class="cx"> #include &lt;wtf/MainThread.h&gt;
</span><span class="cx"> #include &lt;wtf/PassRefPtr.h&gt;
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> using namespace WebCore;
</span><span class="cx"> 
</span><span class="cx"> @interface WebCoreSharedBufferData : NSData
</span><span class="cx"> {
</span><del>-    RefPtr&lt;SharedBuffer&gt; sharedBuffer;
</del><ins>+    RefPtr&lt;SharedBuffer::DataBuffer&gt; buffer;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (id)initWithSharedBuffer:(SharedBuffer*)buffer;
</del><ins>+- (id)initWithSharedBufferDataBuffer:(SharedBuffer::DataBuffer*)dataBuffer;
</ins><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> @implementation WebCoreSharedBufferData
</span><span class="lines">@@ -58,7 +57,7 @@
</span><span class="cx"> {
</span><span class="cx">     if (WebCoreObjCScheduleDeallocateOnMainThread([WebCoreSharedBufferData class], self))
</span><span class="cx">         return;
</span><del>-    
</del><ins>+
</ins><span class="cx">     [super dealloc];
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -67,24 +66,24 @@
</span><span class="cx">     [super finalize];
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (id)initWithSharedBuffer:(SharedBuffer*)buffer
</del><ins>+- (id)initWithSharedBufferDataBuffer:(SharedBuffer::DataBuffer*)dataBuffer
</ins><span class="cx"> {
</span><span class="cx">     self = [super init];
</span><span class="cx">     
</span><span class="cx">     if (self)
</span><del>-        sharedBuffer = buffer;
-    
</del><ins>+        buffer = dataBuffer;
+
</ins><span class="cx">     return self;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (NSUInteger)length
</span><span class="cx"> {
</span><del>-    return sharedBuffer-&gt;size();
</del><ins>+    return buffer-&gt;data.size();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (const void *)bytes
</span><span class="cx"> {
</span><del>-    return reinterpret_cast&lt;const void*&gt;(sharedBuffer-&gt;data());
</del><ins>+    return reinterpret_cast&lt;const void*&gt;(buffer-&gt;data.data());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> @end
</span><span class="lines">@@ -98,7 +97,7 @@
</span><span class="cx"> 
</span><span class="cx"> RetainPtr&lt;NSData&gt; SharedBuffer::createNSData()
</span><span class="cx"> {
</span><del>-    return adoptNS([[WebCoreSharedBufferData alloc] initWithSharedBuffer:this]);
</del><ins>+    return adoptNS((NSData *)createCFData().leakRef());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> RetainPtr&lt;CFDataRef&gt; SharedBuffer::createCFData()
</span><span class="lines">@@ -106,7 +105,14 @@
</span><span class="cx">     if (m_cfData)
</span><span class="cx">         return m_cfData;
</span><span class="cx"> 
</span><del>-    return adoptCF((CFDataRef)adoptNS([[WebCoreSharedBufferData alloc] initWithSharedBuffer:this]).leakRef());
</del><ins>+    data(); // Force data into m_buffer from segments or data array.
+    if (hasPurgeableBuffer()) {
+        RefPtr&lt;SharedBuffer::DataBuffer&gt; copiedBuffer = adoptRef(new DataBuffer);
+        copiedBuffer-&gt;data.append(data(), size());
+        return adoptCF(reinterpret_cast&lt;CFDataRef&gt;([[WebCoreSharedBufferData alloc] initWithSharedBufferDataBuffer:copiedBuffer.get()]));
+    }
+
+    return adoptCF(reinterpret_cast&lt;CFDataRef&gt;([[WebCoreSharedBufferData alloc] initWithSharedBufferDataBuffer:m_buffer.get()]));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PassRefPtr&lt;SharedBuffer&gt; SharedBuffer::createWithContentsOfFile(const String&amp; filePath)
</span></span></pre>
</div>
</div>

</body>
</html>