diff options
author | Gavin Peters <gavinp@chromium.org> | 2016-02-29 10:16:10 -0500 |
---|---|---|
committer | Gavin Peters <gavinp@chromium.org> | 2016-02-29 15:19:02 +0000 |
commit | 9d70c7dc0d227152eb568d8eff890132252cb4cc (patch) | |
tree | 2aa52acc227512e2d666d9f5126218894c14ad86 /net | |
parent | b6e68bae31fe8dca3cafe307c319c50fab594edd (diff) | |
download | chromium_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.cc | 38 | ||||
-rw-r--r-- | net/disk_cache/memory/mem_entry_impl.cc | 12 |
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; } // ------------------------------------------------------------------------ |