summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorGavin Peters <gavinp@chromium.org>2016-02-29 10:16:10 -0500
committerGavin Peters <gavinp@chromium.org>2016-02-29 15:19:02 +0000
commit9d70c7dc0d227152eb568d8eff890132252cb4cc (patch)
tree2aa52acc227512e2d666d9f5126218894c14ad86 /net
parentb6e68bae31fe8dca3cafe307c319c50fab594edd (diff)
downloadchromium_src-9d70c7dc0d227152eb568d8eff890132252cb4cc.zip
chromium_src-9d70c7dc0d227152eb568d8eff890132252cb4cc.tar.gz
chromium_src-9d70c7dc0d227152eb568d8eff890132252cb4cc.tar.bz2
[Merge M49] Fix use after free in memory only backend.
(Manually merged the fix because of significant refactoring around this area in the m50 timeframe.) Writing to a sparse entry could result that entry being evicted while the write was still in progress. This fix considers sparse entries in use if any of their children are in use; this can drive up memory use but avoids tickling the dragon by expanding the hand rolled refcounting implementation in the in memory cache. BUG=589186 R=mmenke@chromium.org Review URL: https://codereview.chromium.org/1735183002 . Cr-Commit-Position: refs/branch-heads/2623@{#535} Cr-Branched-From: 92d77538a86529ca35f9220bd3cd512cbea1f086-refs/heads/master@{#369907}
Diffstat (limited to 'net')
-rw-r--r--net/disk_cache/backend_unittest.cc38
-rw-r--r--net/disk_cache/memory/mem_entry_impl.cc12
2 files changed, 42 insertions, 8 deletions
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index fb7396c..245c091 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -2866,6 +2866,44 @@ TEST_F(DiskCacheBackendTest, NewEvictionDisabledAPI) {
BackendDisabledAPI();
}
+// This overly specific looking test is a regression test aimed at
+// crbug.com/589186.
+TEST_F(DiskCacheBackendTest, MemoryOnlyUseAfterFree) {
+ SetMemoryOnlyMode();
+
+ const int kMaxSize = 200 * 1024;
+ const int kMaxEntryCount = 20;
+ const int kWriteSize = kMaxSize / kMaxEntryCount;
+
+ SetMaxSize(kMaxSize);
+ InitCache();
+
+ scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kWriteSize));
+ CacheTestFillBuffer(buffer->data(), kWriteSize, false);
+
+ // Create an entry to be our sparse entry that gets written later.
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry("first parent", &entry));
+ disk_cache::ScopedEntryPtr first_parent(entry);
+
+ // Create a ton of entries, and keep them open, to put the cache well above
+ // its eviction threshhold.
+ const int kTooManyEntriesCount = kMaxEntryCount * 2;
+ std::list<disk_cache::ScopedEntryPtr> open_entries;
+ std::string key_prefix("prefix");
+ for (int i = 0; i < kTooManyEntriesCount; ++i) {
+ ASSERT_EQ(net::OK, CreateEntry(key_prefix + base::IntToString(i), &entry));
+ EXPECT_EQ(kWriteSize,
+ WriteData(entry, 1, 0, buffer.get(), kWriteSize, false));
+ open_entries.push_back(disk_cache::ScopedEntryPtr(entry));
+ }
+ EXPECT_LT(kMaxSize, CalculateSizeOfAllEntries());
+
+ // Writing this sparse data should not crash.
+ EXPECT_EQ(1024, first_parent->WriteSparseData(32768, buffer.get(), 1024,
+ net::CompletionCallback()));
+}
+
TEST_F(DiskCacheTest, Backend_UsageStatsTimer) {
MessageLoopHelper helper;
diff --git a/net/disk_cache/memory/mem_entry_impl.cc b/net/disk_cache/memory/mem_entry_impl.cc
index 6925518..9f47e46 100644
--- a/net/disk_cache/memory/mem_entry_impl.cc
+++ b/net/disk_cache/memory/mem_entry_impl.cc
@@ -131,14 +131,10 @@ void MemEntryImpl::Open() {
}
bool MemEntryImpl::InUse() {
- if (type() == kParentEntry) {
- return ref_count_ > 0;
- } else {
- // A child entry is always not in use. The consequence is that a child entry
- // can always be evicted while the associated parent entry is currently in
- // used (i.e. opened).
- return false;
- }
+ if (type() == kChildEntry)
+ return parent_->InUse();
+
+ return ref_count_ > 0;
}
// ------------------------------------------------------------------------