Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(679)

Unified Diff: src/core/SkRWBuffer.cpp

Issue 1872853002: Fix race condition in SkROBuffer. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « include/core/SkRWBuffer.h ('k') | tests/DataRefTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkRWBuffer.cpp
diff --git a/src/core/SkRWBuffer.cpp b/src/core/SkRWBuffer.cpp
index c0a93bdf53c037ce768a0699983f1d7cf1ce30d5..75a51b81b62231698a897825a1d804023de5dbc4 100644
--- a/src/core/SkRWBuffer.cpp
+++ b/src/core/SkRWBuffer.cpp
@@ -12,9 +12,9 @@
static const size_t kMinAllocSize = 4096;
struct SkBufferBlock {
- SkBufferBlock* fNext;
- size_t fUsed;
- size_t fCapacity;
+ SkBufferBlock* fNext; // updated by the writer
+ size_t fUsed; // updated by the writer
+ size_t fCapacity; // never changes after the block is created
scroggo 2016/04/08 18:18:52 const? I guess we need a constructor to do that...
bungeman-skia 2016/04/08 18:39:29 It would actually be nice to write a private const
reed1 2016/04/08 19:18:11 Done.
const void* startData() const { return this + 1; };
@@ -30,7 +30,9 @@ struct SkBufferBlock {
return block;
}
- // Return number of bytes actually appended
+ // Return number of bytes actually appended. Important that we always completely this block
+ // before spilling into the next, since the reader uses fCapacity to know how many it can read.
+ //
size_t append(const void* src, size_t length) {
this->validate();
size_t amount = SkTMin(this->avail(), length);
@@ -114,19 +116,25 @@ struct SkBufferHead {
}
};
-SkROBuffer::SkROBuffer(const SkBufferHead* head, size_t used) : fHead(head), fUsed(used) {
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// The reader can only access block.fCapacity (which never changes), and cannot access
+// block.fUsed, which may be updated by the writer.
+//
+SkROBuffer::SkROBuffer(const SkBufferHead* head, size_t available)
+ : fHead(head), fAvailable(available)
+{
if (head) {
fHead->ref();
- SkASSERT(used > 0);
- head->validate(used);
+ SkASSERT(available > 0);
+ head->validate(available);
} else {
- SkASSERT(0 == used);
+ SkASSERT(0 == available);
}
}
SkROBuffer::~SkROBuffer() {
if (fHead) {
- fHead->validate(fUsed);
+ fHead->validate(fAvailable);
fHead->unref();
}
}
@@ -138,7 +146,7 @@ SkROBuffer::Iter::Iter(const SkROBuffer* buffer) {
void SkROBuffer::Iter::reset(const SkROBuffer* buffer) {
if (buffer) {
fBlock = &buffer->fHead->fBlock;
- fRemaining = buffer->fUsed;
+ fRemaining = buffer->fAvailable;
} else {
fBlock = nullptr;
fRemaining = 0;
@@ -153,7 +161,7 @@ size_t SkROBuffer::Iter::size() const {
if (!fBlock) {
return 0;
}
- return SkTMin(fBlock->fUsed, fRemaining);
+ return SkTMin(fBlock->fCapacity, fRemaining);
}
bool SkROBuffer::Iter::next() {
@@ -164,6 +172,8 @@ bool SkROBuffer::Iter::next() {
return fRemaining != 0;
}
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
SkRWBuffer::SkRWBuffer(size_t initialCapacity) : fHead(nullptr), fTail(nullptr), fTotalUsed(0) {}
SkRWBuffer::~SkRWBuffer() {
@@ -173,6 +183,10 @@ SkRWBuffer::~SkRWBuffer() {
}
}
+// It is important that we always completely fill the current block before spilling over to the
+// next, since our reader will be using fCapacity (min'd against its total available) to know how
+// many bytes to read from a given block.
+//
void SkRWBuffer::append(const void* src, size_t length) {
this->validate();
if (0 == length) {
@@ -201,28 +215,6 @@ void SkRWBuffer::append(const void* src, size_t length) {
this->validate();
}
-void* SkRWBuffer::append(size_t length) {
- this->validate();
- if (0 == length) {
- return nullptr;
- }
-
- fTotalUsed += length;
-
- if (nullptr == fHead) {
- fHead = SkBufferHead::Alloc(length);
- fTail = &fHead->fBlock;
- } else if (fTail->avail() < length) {
- SkBufferBlock* block = SkBufferBlock::Alloc(length);
- fTail->fNext = block;
- fTail = block;
- }
-
- fTail->fUsed += length;
- this->validate();
- return (char*)fTail->availData() - length;
-}
-
#ifdef SK_DEBUG
void SkRWBuffer::validate() const {
if (fHead) {
« no previous file with comments | « include/core/SkRWBuffer.h ('k') | tests/DataRefTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698