summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSen Jiang <senj@google.com>2016-04-11 16:08:03 -0700
committerSen Jiang <senj@google.com>2016-04-22 14:14:10 -0700
commitb70ee1410349ead84048984d0ed081de0624c42e (patch)
tree1f4a8e32dae11e6fb392d249cbe9e20b8a4cf117
parent79ffca0eec59ce48514af7a3ef8ba13abb3ea4a3 (diff)
downloadbsdiff-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.cc2
-rw-r--r--memory_file.cc3
2 files changed, 4 insertions, 1 deletions
diff --git a/bspatch.cc b/bspatch.cc
index aae6118..550c6c7 100644
--- a/bspatch.cc
+++ b/bspatch.cc
@@ -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();
}