diff options
author | Magnus Jedvert <magjed@google.com> | 2015-05-12 18:36:12 +0200 |
---|---|---|
committer | Magnus Jedvert <magjed@google.com> | 2015-05-12 16:37:14 +0000 |
commit | 2fad8c928e5d5b10bbcc2b9a94ee4f4220c0ed9f (patch) | |
tree | 0ce803675c26a73d06b3b744e32ecf402164a978 | |
parent | beca77c820c579ee29ff8387b5a42765ef8ccee4 (diff) | |
download | chromium_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.cc | 57 | ||||
-rw-r--r-- | chrome/common/partial_circular_buffer.h | 2 | ||||
-rw-r--r-- | chrome/common/partial_circular_buffer_unittest.cc | 21 |
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))); +} + |