diff options
author | Sen Jiang <senj@google.com> | 2016-04-11 16:08:03 -0700 |
---|---|---|
committer | Sen Jiang <senj@google.com> | 2016-04-22 14:14:10 -0700 |
commit | b70ee1410349ead84048984d0ed081de0624c42e (patch) | |
tree | 1f4a8e32dae11e6fb392d249cbe9e20b8a4cf117 | |
parent | 79ffca0eec59ce48514af7a3ef8ba13abb3ea4a3 (diff) | |
download | bsdiff-b70ee1410349ead84048984d0ed081de0624c42e.tar.gz |
Fix infinite loop when using extents.
Clearing |buffer_| still actually makes sense because MemoryFile::Close()
is called twice: once explicitly from bspatch to check if Close()
succeeded, once from destructor to ensure that everything is closed. And
if we don't clear |buffer_|, on the second Close(), it will try to write
|buffer_| to |file_| again, and if |file_| is an ExtentsFile, it will
simply return true and set |bytes_written| to 0 on Write() because all
the extents are already written, now WriteAll() became an infinite
loop.
Although returning false if written is 0 in WriteAll() will fix this, but
I think we should not write the same buffer again in the first place.
Test: call bspatch with extents
Bug: 28345972
Change-Id: If3bddcc6e8ca6751c422c066e5b8b02f91086ed5
(cherry picked from commit b14bb55294132466913a07e2c0a54b8765c9240b)
-rw-r--r-- | bspatch.cc | 2 | ||||
-rw-r--r-- | memory_file.cc | 3 |
2 files changed, 4 insertions, 1 deletions
@@ -112,7 +112,7 @@ bool WriteAll(const std::unique_ptr<FileInterface>& file, size_t size) { size_t offset = 0, written; while (offset < size) { - if (!file->Write(data + offset, size - offset, &written)) + if (!file->Write(data + offset, size - offset, &written) || written == 0) return false; offset += written; } diff --git a/memory_file.cc b/memory_file.cc index 996a10e..59e2c7d 100644 --- a/memory_file.cc +++ b/memory_file.cc @@ -35,6 +35,9 @@ bool MemoryFile::Seek(off_t pos) { bool MemoryFile::Close() { if (!WriteAll(file_, buffer_.data(), buffer_.size())) return false; + // Prevent writing |buffer_| to |file_| again if Close() is called more than + // once. + buffer_.clear(); return file_->Close(); } |