WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
135069
Sharing SharedBuffer between WebCore and ImageIO is racy and crash prone
https://bugs.webkit.org/show_bug.cgi?id=135069
Summary
Sharing SharedBuffer between WebCore and ImageIO is racy and crash prone
Pratik Solanki
Reported
2014-07-18 13:44:49 PDT
We currently pass a SharedBuffer to ImageIO by creating a WebCoreSharedBufferData wrapper around it. ImageIO access this buffer on a separate thread. This can lead to race conditions and crashes if the main thread modifies m_buffer (because it is in the middle of loading a large image) while ImageIO is trying to decode the image.
Attachments
Part 1 of WIP patch
(8.16 KB, patch)
2014-07-20 23:17 PDT
,
Pratik Solanki
no flags
Details
Formatted Diff
Diff
Part 2 of WIP patch
(5.91 KB, patch)
2014-07-20 23:18 PDT
,
Pratik Solanki
no flags
Details
Formatted Diff
Diff
Patch
(16.27 KB, patch)
2014-07-22 12:14 PDT
,
Pratik Solanki
no flags
Details
Formatted Diff
Diff
Patch
(16.07 KB, patch)
2014-07-22 23:44 PDT
,
Pratik Solanki
no flags
Details
Formatted Diff
Diff
Archive of layout-test-results from webkit-ews-15 for mac-mountainlion-wk2
(1.71 MB, application/zip)
2014-07-23 13:37 PDT
,
Build Bot
no flags
Details
Archive of layout-test-results from webkit-ews-06 for mac-mountainlion
(344.65 KB, application/zip)
2014-07-23 16:15 PDT
,
Build Bot
no flags
Details
Patch
(16.38 KB, patch)
2014-07-23 18:08 PDT
,
Pratik Solanki
simon.fraser
: review+
Details
Formatted Diff
Diff
Show Obsolete
(4)
View All
Add attachment
proposed patch, testcase, etc.
Pratik Solanki
Comment 1
2014-07-18 13:45:06 PDT
<
rdar://problem/17470655
>
Pratik Solanki
Comment 2
2014-07-20 23:17:57 PDT
Created
attachment 235205
[details]
Part 1 of WIP patch
Pratik Solanki
Comment 3
2014-07-20 23:18:21 PDT
Created
attachment 235206
[details]
Part 2 of WIP patch
Pratik Solanki
Comment 4
2014-07-22 12:14:37 PDT
Created
attachment 235306
[details]
Patch
Simon Fraser (smfr)
Comment 5
2014-07-22 15:29:27 PDT
Comment on
attachment 235306
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=235306&action=review
I would prefer if the behavior was made very explicit, rather than the implicit "copy on write".
> Source/WebCore/platform/SharedBuffer.cpp:426 > + if (!m_buffer->hasOneRef() && m_size > m_buffer->data.capacity()) { > + InternalBuffer* newBuffer = new InternalBuffer; > + newBuffer->data.reserveInitialCapacity(m_size); > + newBuffer->data = m_buffer->data; > + m_buffer = adoptRef(newBuffer); > + }
I would prefer a very explicit function call which says what we're doing here. Like replaceInternalBuffer() or something.
> Source/WebCore/platform/SharedBuffer.cpp:432 > + if (!m_buffer->hasOneRef())
Is hasOneRef the right thing to use? What if the other thread has two refs to its buffer? Can we make the "this is no longer shared" much more explicit?
> Source/WebCore/platform/SharedBuffer.cpp:465 > + InternalBuffer* newBuffer = new InternalBuffer; > + newBuffer->data.reserveInitialCapacity(m_size); > + newBuffer->data = m_buffer->data; > + m_buffer = adoptRef(newBuffer);
This looks familiar.
> Source/WebCore/platform/SharedBuffer.h:177 > + struct InternalBuffer : public RefCounted<InternalBuffer> {
It's not an "internal buffer" if this is public :\ I'd call it RefCountedBuffer or just DataBuffer or something.
Pratik Solanki
Comment 6
2014-07-22 23:43:28 PDT
(In reply to
comment #5
)
> (From update of
attachment 235306
[details]
) > View in context:
https://bugs.webkit.org/attachment.cgi?id=235306&action=review
> > I would prefer if the behavior was made very explicit, rather than the implicit "copy on write".
Ok.
> > Source/WebCore/platform/SharedBuffer.cpp:426 > > + if (!m_buffer->hasOneRef() && m_size > m_buffer->data.capacity()) { > > + InternalBuffer* newBuffer = new InternalBuffer; > > + newBuffer->data.reserveInitialCapacity(m_size); > > + newBuffer->data = m_buffer->data; > > + m_buffer = adoptRef(newBuffer); > > + } > > I would prefer a very explicit function call which says what we're doing here. Like replaceInternalBuffer() or something.
Good idea.
> > Source/WebCore/platform/SharedBuffer.cpp:432 > > + if (!m_buffer->hasOneRef()) > > Is hasOneRef the right thing to use? What if the other thread has two refs to its buffer? Can we make the "this is no longer shared" much more explicit?
I think hasOneRef() is the best approach - we could have a helper function that returns m_buffer->hasOneRef() if that would make the code clearer.
> > Source/WebCore/platform/SharedBuffer.cpp:465 > > + InternalBuffer* newBuffer = new InternalBuffer; > > + newBuffer->data.reserveInitialCapacity(m_size); > > + newBuffer->data = m_buffer->data; > > + m_buffer = adoptRef(newBuffer); > > This looks familiar. > > > Source/WebCore/platform/SharedBuffer.h:177 > > + struct InternalBuffer : public RefCounted<InternalBuffer> { > > It's not an "internal buffer" if this is public :\ > > I'd call it RefCountedBuffer or just DataBuffer or something.
DataBuffer it is!
Pratik Solanki
Comment 7
2014-07-22 23:44:15 PDT
Created
attachment 235345
[details]
Patch
Pratik Solanki
Comment 8
2014-07-22 23:45:40 PDT
Mac isn't happy with my patch - I am seeing images failing to load. Review comments on the current patch would be nice but this needs more work before it can be checked in.
Simon Fraser (smfr)
Comment 9
2014-07-23 10:22:40 PDT
Comment on
attachment 235345
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=235345&action=review
> Source/WebCore/platform/SharedBuffer.cpp:424 > + DataBuffer* newBuffer = new DataBuffer;
We normally avoid bare "new" calls; I think you should wrap this in a local RefPtr. and then do m_buffer = newBuffer.release() at the end.
> Source/WebCore/platform/SharedBuffer.h:177 > + struct DataBuffer : public RefCounted<DataBuffer> {
Does this need to be ThreadSafeRefCounted?
> Source/WebCore/platform/mac/SharedBufferMac.mm:111 > + return adoptCF((CFDataRef)adoptNS([[WebCoreSharedBufferData alloc] initWithSharedBufferDataBuffer:copiedBuffer.get()]).leakRef());
That's a lot of adopting! I don't get why the intermediate adoptNS() is useful.
Build Bot
Comment 10
2014-07-23 13:37:08 PDT
Comment on
attachment 235345
[details]
Patch
Attachment 235345
[details]
did not pass mac-wk2-ews (mac-wk2): Output:
http://webkit-queues.appspot.com/results/6352807233847296
New failing tests: fast/images/cmyk-jpeg-with-color-profile.html editing/pasteboard/4989774.html fast/canvas/image-potential-subsample.html http/tests/css/vertical-align-baseline-after-image-load-3.html http/tests/css/vertical-align-baseline-after-image-load-2.html editing/pasteboard/paste-noscript.html http/tests/css/vertical-align-baseline-after-image-load.html fast/replaced/pdf-as-image.html editing/pasteboard/paste-noscript-xhtml.xhtml editing/pasteboard/styled-element-markup.html editing/pasteboard/paste-visible-script.html fast/images/pdf-as-image-landscape.html editing/pasteboard/4641033.html fast/images/animated-gif-restored-from-bfcache.html fast/images/pdf-as-image.html
Build Bot
Comment 11
2014-07-23 13:37:12 PDT
Created
attachment 235372
[details]
Archive of layout-test-results from webkit-ews-15 for mac-mountainlion-wk2 The attached test failures were seen while running run-webkit-tests on the mac-wk2-ews. Bot: webkit-ews-15 Port: mac-mountainlion-wk2 Platform: Mac OS X 10.8.5
Build Bot
Comment 12
2014-07-23 16:15:24 PDT
Comment on
attachment 235345
[details]
Patch
Attachment 235345
[details]
did not pass mac-ews (mac): Output:
http://webkit-queues.appspot.com/results/6514147680321536
New failing tests: editing/pasteboard/contenteditable-pre-2.html editing/pasteboard/5761530-1.html editing/pasteboard/4944770-2.html http/tests/css/vertical-align-baseline-after-image-load-2.html editing/execCommand/find-after-replace.html editing/selection/4895428-1.html editing/pasteboard/5780697-2.html editing/inserting/insert-3786362-fix.html editing/pasteboard/4944770-1.html editing/pasteboard/4242293.html editing/pasteboard/avoid-copying-body-with-background.html editing/selection/4895428-4.html editing/execCommand/paste-1.html editing/inserting/insert-3907422-fix.html editing/pasteboard/block-wrappers-necessary.html editing/pasteboard/5601583-1.html editing/deleting/paste-with-transparent-background-color.html editing/style/font-family-with-space.html editing/pasteboard/5075944.html editing/pasteboard/19644-2.html editing/pasteboard/5065605.html editing/pasteboard/cleanup-on-move.html editing/pasteboard/4922709.html editing/pasteboard/4989774.html editing/style/non-inheritable-styles.html http/tests/css/vertical-align-baseline-after-image-load.html editing/pasteboard/4242293-1.html editing/pasteboard/contenteditable-pre.html editing/pasteboard/5071074.html editing/pasteboard/4641033.html
Build Bot
Comment 13
2014-07-23 16:15:25 PDT
Created
attachment 235387
[details]
Archive of layout-test-results from webkit-ews-06 for mac-mountainlion The attached test failures were seen while running run-webkit-tests on the mac-ews. Bot: webkit-ews-06 Port: mac-mountainlion Platform: Mac OS X 10.8.5
Pratik Solanki
Comment 14
2014-07-23 17:51:14 PDT
(In reply to
comment #9
)
> (From update of
attachment 235345
[details]
) > View in context:
https://bugs.webkit.org/attachment.cgi?id=235345&action=review
> > > Source/WebCore/platform/SharedBuffer.cpp:424 > > + DataBuffer* newBuffer = new DataBuffer; > > We normally avoid bare "new" calls; I think you should wrap this in a local RefPtr. and then do m_buffer = newBuffer.release() at the end.
Ok.
> > Source/WebCore/platform/SharedBuffer.h:177 > > + struct DataBuffer : public RefCounted<DataBuffer> { > > Does this need to be ThreadSafeRefCounted?
I guess that would be better.
> > Source/WebCore/platform/mac/SharedBufferMac.mm:111 > > + return adoptCF((CFDataRef)adoptNS([[WebCoreSharedBufferData alloc] initWithSharedBufferDataBuffer:copiedBuffer.get()]).leakRef()); > > That's a lot of adopting! I don't get why the intermediate adoptNS() is useful.
Yeah I agree. Will get rid of it. I've fixed the layout test failures. We need to call data() to coalesce the buffer before creating WebcoreSharedBufferData. And createNSData() needs the same code changes as createCFData().
Pratik Solanki
Comment 15
2014-07-23 18:08:38 PDT
Created
attachment 235395
[details]
Patch
Simon Fraser (smfr)
Comment 16
2014-07-24 13:05:54 PDT
Comment on
attachment 235395
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=235395&action=review
> Source/WebCore/platform/SharedBuffer.cpp:81 > + , m_buffer(adoptRef(new DataBuffer))
We don't pass the size to the DataBuffer?
Pratik Solanki
Comment 17
2014-07-24 14:38:16 PDT
Committed
r171526
: <
http://trac.webkit.org/changeset/171526
>
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug