summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMagnus Jedvert <magjed@google.com>2015-05-12 18:36:12 +0200
committerMagnus Jedvert <magjed@google.com>2015-05-12 16:37:14 +0000
commit2fad8c928e5d5b10bbcc2b9a94ee4f4220c0ed9f (patch)
tree0ce803675c26a73d06b3b744e32ecf402164a978
parentbeca77c820c579ee29ff8387b5a42765ef8ccee4 (diff)
downloadchromium_src-2fad8c928e5d5b10bbcc2b9a94ee4f4220c0ed9f.zip
chromium_src-2fad8c928e5d5b10bbcc2b9a94ee4f4220c0ed9f.tar.gz
chromium_src-2fad8c928e5d5b10bbcc2b9a94ee4f4220c0ed9f.tar.bz2
Fix PartialCircularBuffer OOB memcpy().
BUG=474029 TEST=PartialCircularBufferTest.WrapTwiceWithSingleWrite NOPRESUBMIT=true Review URL: https://codereview.chromium.org/1061053002 Cr-Commit-Position: refs/heads/master@{#326341} (cherry picked from commit ab42594ec3070953971f43b384f38f3c2b65d4ea) R=tommi@chromium.org TBR=gzobqq@gmail.com, thakis@chromium.org Review URL: https://codereview.chromium.org/1131943003 Cr-Commit-Position: refs/branch-heads/2357@{#370} Cr-Branched-From: 59d4494849b405682265ed5d3f5164573b9a939b-refs/heads/master@{#323860}
-rw-r--r--chrome/common/partial_circular_buffer.cc57
-rw-r--r--chrome/common/partial_circular_buffer.h2
-rw-r--r--chrome/common/partial_circular_buffer_unittest.cc21
3 files changed, 60 insertions, 20 deletions
diff --git a/chrome/common/partial_circular_buffer.cc b/chrome/common/partial_circular_buffer.cc
index 4161cc1..6e3e017 100644
--- a/chrome/common/partial_circular_buffer.cc
+++ b/chrome/common/partial_circular_buffer.cc
@@ -139,30 +139,49 @@ uint32 PartialCircularBuffer::Read(void* buffer, uint32 buffer_size) {
void PartialCircularBuffer::Write(const void* buffer, uint32 buffer_size) {
DCHECK(buffer_data_);
- uint32 position_before_write = position_;
-
- uint32 to_eof = data_size_ - position_;
- uint32 to_write = std::min(buffer_size, to_eof);
- DoWrite(buffer_data_->data + position_, buffer, to_write);
- if (position_ >= data_size_) {
- DCHECK_EQ(position_, data_size_);
- position_ = buffer_data_->wrap_position;
+ const uint8* input = static_cast<const uint8*>(buffer);
+ uint32 wrap_position = buffer_data_->wrap_position;
+ uint32 cycle_size = data_size_ - wrap_position;
+
+ // First write the non-wrapping part.
+ if (position_ < wrap_position) {
+ uint32 space_left = wrap_position - position_;
+ uint32 write_size = std::min(buffer_size, space_left);
+ DoWrite(input, write_size);
+ input += write_size;
+ buffer_size -= write_size;
}
- if (to_write < buffer_size) {
- uint32 remainder_to_write = buffer_size - to_write;
- DCHECK_LT(position_, position_before_write);
- DCHECK_LE(position_ + remainder_to_write, position_before_write);
- DoWrite(buffer_data_->data + position_,
- reinterpret_cast<const uint8*>(buffer) + to_write,
- remainder_to_write);
+ // Skip the part that would overlap.
+ if (buffer_size > cycle_size) {
+ uint32 skip = buffer_size - cycle_size;
+ input += skip;
+ buffer_size -= skip;
+ position_ = wrap_position + (position_ - wrap_position + skip) % cycle_size;
}
+
+ // Finally write the wrapping part.
+ DoWrite(input, buffer_size);
}
-void PartialCircularBuffer::DoWrite(void* dest, const void* src, uint32 num) {
- memcpy(dest, src, num);
- position_ += num;
+void PartialCircularBuffer::DoWrite(const uint8* input, uint32 input_size) {
+ DCHECK_LT(position_, data_size_);
buffer_data_->total_written =
- std::min(buffer_data_->total_written + num, data_size_);
+ std::min(buffer_data_->total_written + input_size, data_size_);
+
+ // Write() skips any overlapping part, so this loop will run at most twice.
+ while (input_size > 0) {
+ uint32 space_left = data_size_ - position_;
+ uint32 write_size = std::min(input_size, space_left);
+ memcpy(buffer_data_->data + position_, input, write_size);
+ input += write_size;
+ input_size -= write_size;
+ position_ += write_size;
+ if (position_ >= data_size_) {
+ DCHECK_EQ(position_, data_size_);
+ position_ = buffer_data_->wrap_position;
+ }
+ }
+
buffer_data_->end_position = position_;
}
diff --git a/chrome/common/partial_circular_buffer.h b/chrome/common/partial_circular_buffer.h
index 1f986cc..e1fb118 100644
--- a/chrome/common/partial_circular_buffer.h
+++ b/chrome/common/partial_circular_buffer.h
@@ -52,7 +52,7 @@ class PartialCircularBuffer {
};
#pragma pack(pop)
- void DoWrite(void* dest, const void* src, uint32 num);
+ void DoWrite(const uint8* input, uint32 input_size);
// Used for reading and writing.
BufferData* buffer_data_;
diff --git a/chrome/common/partial_circular_buffer_unittest.cc b/chrome/common/partial_circular_buffer_unittest.cc
index 85153fa..701aefa 100644
--- a/chrome/common/partial_circular_buffer_unittest.cc
+++ b/chrome/common/partial_circular_buffer_unittest.cc
@@ -189,3 +189,24 @@ TEST_F(PartialCircularBufferTest, WrapOnceThenOverwriteWithNoWrap) {
EXPECT_EQ(0u, pcb_read_->Read(output_data, sizeof(output_data)));
}
+
+TEST_F(PartialCircularBufferTest, WrapTwiceWithSingleWrite) {
+ const size_t kInputSize = sizeof(kInputData);
+ const size_t kLargeSize = kInputSize * 7;
+ uint8 large_input[kLargeSize] = {0};
+ for (size_t offset = 0; offset < kLargeSize; offset += kInputSize)
+ memcpy(large_input + offset, kInputData, kInputSize);
+
+ InitWriteBuffer(false);
+ pcb_write_->Write(large_input, kLargeSize);
+ InitReadBuffer();
+
+ uint8 output_data[sizeof(kOutputRefDataWrap)] = {0};
+ EXPECT_EQ(sizeof(output_data),
+ pcb_read_->Read(output_data, sizeof(output_data)));
+
+ EXPECT_EQ(0, memcmp(kOutputRefDataWrap, output_data, sizeof(output_data)));
+
+ EXPECT_EQ(0u, pcb_read_->Read(output_data, sizeof(output_data)));
+}
+