diff options
author | ncbray@chromium.org <ncbray@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-26 04:30:12 +0000 |
---|---|---|
committer | ncbray@chromium.org <ncbray@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-26 04:30:12 +0000 |
commit | 8c67083771dd35498e832fa241aa3adb815b47e9 (patch) | |
tree | b23112e2d07565e48e46c8a5e46e1ad14c539ff7 | |
parent | b74b4885d8268a943bb9498abbe1d4a288d97f70 (diff) | |
download | chromium_src-8c67083771dd35498e832fa241aa3adb815b47e9.zip chromium_src-8c67083771dd35498e832fa241aa3adb815b47e9.tar.gz chromium_src-8c67083771dd35498e832fa241aa3adb815b47e9.tar.bz2 |
Persist NaCl's validation cache to disk.
Persisting the cache is straightforward: it is pickled, and the pickle data is sent to the blocking pool to be written to disk. Reading the cache off disk is a little trickier, because it needs to be done before sel_ldr is started in the NaCl process. This is implemented as an asynchronous task that blocks starting sel_ldr, similar to opening the IRT.
Functionality to serialize and deserialize the validation cache was also added. To improve testability, features such as cache enabling / disabling and UMA reporting were shifted from NaClValidationCache onto the NaClBrowser singleton. This allowed unit tests to be written for NaClValidationCache.
BUG= http://code.google.com/p/nativeclient/issues/detail?id=2515
TEST= Run nexe in browser with NACL_VALIDATION_CACHE=1
Review URL: https://chromiumcodereview.appspot.com/10399053
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@139179 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/nacl_host/nacl_browser.cc | 163 | ||||
-rw-r--r-- | chrome/browser/nacl_host/nacl_browser.h | 26 | ||||
-rw-r--r-- | chrome/browser/nacl_host/nacl_process_host.cc | 9 | ||||
-rw-r--r-- | chrome/browser/nacl_host/nacl_validation_cache.cc | 128 | ||||
-rw-r--r-- | chrome/browser/nacl_host/nacl_validation_cache.h | 27 | ||||
-rw-r--r-- | chrome/browser/nacl_host/nacl_validation_cache_unittest.cc | 180 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 2 |
7 files changed, 477 insertions, 58 deletions
diff --git a/chrome/browser/nacl_host/nacl_browser.cc b/chrome/browser/nacl_host/nacl_browser.cc index 84ca17c..e2c0d49 100644 --- a/chrome/browser/nacl_host/nacl_browser.cc +++ b/chrome/browser/nacl_host/nacl_browser.cc @@ -5,13 +5,28 @@ #include "chrome/browser/nacl_host/nacl_browser.h" #include "base/message_loop.h" +#include "base/metrics/histogram.h" #include "base/path_service.h" +#include "base/pickle.h" #include "base/win/windows_version.h" #include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_paths_internal.h" #include "content/public/browser/browser_thread.h" namespace { +// An arbitrary delay to coalesce multiple writes to the cache. +const int kValidationCacheCoalescingTimeMS = 6000; +const char kValidationCacheSequenceName[] = "NaClValidationCache"; +const FilePath::CharType kValidationCacheFileName[] = + FILE_PATH_LITERAL("nacl_validation_cache.bin"); + +enum ValidationCacheStatus { + CACHE_MISS = 0, + CACHE_HIT, + CACHE_MAX +}; + // Determine the name of the IRT file based on the architecture. #define NACL_IRT_FILE_NAME(arch_string) \ (FILE_PATH_LITERAL("nacl_irt_") \ @@ -39,6 +54,36 @@ const FilePath::StringType NaClIrtName() { #endif } +bool CheckEnvVar(const char* name, bool default_value) { + bool result = default_value; + const char* var = getenv(name); + if (var && strlen(var) > 0) { + result = var[0] != '0'; + } + return result; +} + +void ReadCache(const FilePath& filename, std::string* data) { + if (!file_util::ReadFileToString(filename, data)) { + // Zero-size data used as an in-band error code. + data->clear(); + } +} + +void WriteCache(const FilePath& filename, const Pickle* pickle) { + file_util::WriteFile(filename, static_cast<const char*>(pickle->data()), + pickle->size()); +} + +void LogCacheQuery(ValidationCacheStatus status) { + UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Query", status, CACHE_MAX); +} + +void LogCacheSet(ValidationCacheStatus status) { + // Bucket zero is reserved for future use. + UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status, CACHE_MAX); +} + } // namespace NaClBrowser::NaClBrowser() @@ -46,6 +91,10 @@ NaClBrowser::NaClBrowser() irt_platform_file_(base::kInvalidPlatformFileValue), irt_filepath_(), irt_state_(NaClResourceUninitialized), + validation_cache_file_path_(), + validation_cache_is_enabled_(CheckEnvVar("NACL_VALIDATION_CACHE", false)), + validation_cache_is_modified_(false), + validation_cache_state_(NaClResourceUninitialized), ok_(true) { InitIrtFilePath(); } @@ -82,7 +131,9 @@ NaClBrowser* NaClBrowser::GetInstance() { } bool NaClBrowser::IsReady() const { - return IsOk() && irt_state_ == NaClResourceReady; + return (IsOk() && + irt_state_ == NaClResourceReady && + validation_cache_state_ == NaClResourceReady); } bool NaClBrowser::IsOk() const { @@ -96,9 +147,8 @@ base::PlatformFile NaClBrowser::IrtFile() const { } void NaClBrowser::EnsureAllResourcesAvailable() { - // Currently the only resource we need to initialize is the IRT. - // In the future we will need to load the validation cache from disk. EnsureIrtAvailable(); + EnsureValidationCacheAvailable(); } // Load the IRT async. @@ -136,6 +186,66 @@ void NaClBrowser::OnIrtOpened(base::PlatformFileError error_code, CheckWaiting(); } +void NaClBrowser::EnsureValidationCacheAvailable() { + if (IsOk() && validation_cache_state_ == NaClResourceUninitialized) { + if (ValidationCacheIsEnabled()) { + validation_cache_state_ = NaClResourceRequested; + + // Determine where the validation cache resides in the file system. It + // exists in Chrome's cache directory and is not tied to any specific + // profile. + // Start by finding the user data directory. + FilePath user_data_dir; + if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) { + RunWithoutValidationCache(); + return; + } + // The cache directory may or may not be the user data directory. + FilePath cache_file_path; + chrome::GetUserCacheDirectory(user_data_dir, &cache_file_path); + // Append the base file name to the cache directory. + validation_cache_file_path_ = + cache_file_path.Append(kValidationCacheFileName); + + // Structure for carrying data between the callbacks. + std::string* data = new std::string(); + // We can get away not giving this a sequence ID because this is the first + // task and further file access will not occur until after we get a + // response. + if (!content::BrowserThread::PostBlockingPoolTaskAndReply( + FROM_HERE, + base::Bind(ReadCache, validation_cache_file_path_, data), + base::Bind(&NaClBrowser::OnValidationCacheLoaded, + weak_factory_.GetWeakPtr(), + base::Owned(data)))) { + RunWithoutValidationCache(); + } + } else { + RunWithoutValidationCache(); + } + } +} + +void NaClBrowser::OnValidationCacheLoaded(const std::string *data) { + if (data->size() == 0) { + // No file found. + validation_cache_.Reset(); + } else { + Pickle pickle(data->data(), data->size()); + validation_cache_.Deserialize(&pickle); + } + validation_cache_state_ = NaClResourceReady; + CheckWaiting(); +} + +void NaClBrowser::RunWithoutValidationCache() { + // Be paranoid. + validation_cache_.Reset(); + validation_cache_is_enabled_ = false; + validation_cache_state_ = NaClResourceReady; + CheckWaiting(); +} + void NaClBrowser::CheckWaiting() { if (!IsOk() || IsReady()) { // Queue the waiting tasks into the message loop. This helps avoid @@ -164,3 +274,50 @@ void NaClBrowser::WaitForResources(const base::Closure& reply) { const FilePath& NaClBrowser::GetIrtFilePath() { return irt_filepath_; } + +bool NaClBrowser::QueryKnownToValidate(const std::string& signature) { + bool result = validation_cache_.QueryKnownToValidate(signature); + LogCacheQuery(result ? CACHE_HIT : CACHE_MISS); + // Queries can modify the MRU order of the cache. + MarkValidationCacheAsModified(); + return result; +} + +void NaClBrowser::SetKnownToValidate(const std::string& signature) { + validation_cache_.SetKnownToValidate(signature); + // The number of sets should be equal to the number of cache misses, minus + // validation failures and successful validations where stubout occurs. + LogCacheSet(CACHE_HIT); + MarkValidationCacheAsModified(); +} + +void NaClBrowser::MarkValidationCacheAsModified() { + if (!validation_cache_is_modified_) { + // Wait before persisting to disk. This can coalesce multiple cache + // modifications info a single disk write. + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&NaClBrowser::PersistValidationCache, + weak_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(kValidationCacheCoalescingTimeMS)); + validation_cache_is_modified_ = true; + } +} + +void NaClBrowser::PersistValidationCache() { + if (!validation_cache_file_path_.empty()) { + Pickle* pickle = new Pickle(); + validation_cache_.Serialize(pickle); + + // Pass the serialized data to another thread to write to disk. File IO is + // not allowed on the IO thread (which is the thread this method runs on) + // because it can degrade the responsiveness of the browser. + // The task is sequenced so that multiple writes happen in order. + content::BrowserThread::PostBlockingPoolSequencedTask( + kValidationCacheSequenceName, + FROM_HERE, + base::Bind(WriteCache, validation_cache_file_path_, + base::Owned(pickle))); + } + validation_cache_is_modified_ = false; +} diff --git a/chrome/browser/nacl_host/nacl_browser.h b/chrome/browser/nacl_host/nacl_browser.h index 4fac991b..96b63c4 100644 --- a/chrome/browser/nacl_host/nacl_browser.h +++ b/chrome/browser/nacl_host/nacl_browser.h @@ -44,7 +44,16 @@ class NaClBrowser { // IRT file handle, only available when IsReady(). base::PlatformFile IrtFile() const; - NaClValidationCache validation_cache; + bool ValidationCacheIsEnabled() const { + return validation_cache_is_enabled_; + } + + const std::string& GetValidationCacheKey() const { + return validation_cache_.GetValidationCacheKey(); + } + + bool QueryKnownToValidate(const std::string& signature); + void SetKnownToValidate(const std::string& signature); private: friend struct DefaultSingletonTraits<NaClBrowser>; @@ -65,19 +74,32 @@ class NaClBrowser { void OnIrtOpened(base::PlatformFileError error_code, base::PassPlatformFile file, bool created); + void EnsureValidationCacheAvailable(); + void OnValidationCacheLoaded(const std::string* data); + void RunWithoutValidationCache(); + // Dispatch waiting tasks if we are ready, or if we know we'll never be ready. void CheckWaiting(); // Indicate that it is impossible to launch a NaCl process. void MarkAsFailed(); + void MarkValidationCacheAsModified(); + void PersistValidationCache(); + // Singletons get destroyed at shutdown. base::WeakPtrFactory<NaClBrowser> weak_factory_; base::PlatformFile irt_platform_file_; FilePath irt_filepath_; - NaClResourceState irt_state_; + + NaClValidationCache validation_cache_; + FilePath validation_cache_file_path_; + bool validation_cache_is_enabled_; + bool validation_cache_is_modified_; + NaClResourceState validation_cache_state_; + bool ok_; // A list of pending tasks to start NaCl processes. diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc index 3e9ec97..b5aa055 100644 --- a/chrome/browser/nacl_host/nacl_process_host.cc +++ b/chrome/browser/nacl_host/nacl_process_host.cc @@ -599,9 +599,8 @@ bool NaClProcessHost::StartNaClExecution() { NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); nacl::NaClStartParams params; - params.validation_cache_enabled = nacl_browser->validation_cache.IsEnabled(); - params.validation_cache_key = - nacl_browser->validation_cache.GetValidationCacheKey(); + params.validation_cache_enabled = nacl_browser->ValidationCacheIsEnabled(); + params.validation_cache_key = nacl_browser->GetValidationCacheKey(); params.version = chrome::VersionInfo().CreateVersionString(); params.enable_exception_handling = enable_exception_handling_; @@ -684,11 +683,11 @@ bool NaClProcessHost::StartWithLaunchedProcess() { void NaClProcessHost::OnQueryKnownToValidate(const std::string& signature, bool* result) { NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); - *result = nacl_browser->validation_cache.QueryKnownToValidate(signature); + *result = nacl_browser->QueryKnownToValidate(signature); } void NaClProcessHost::OnSetKnownToValidate(const std::string& signature) { - NaClBrowser::GetInstance()->validation_cache.SetKnownToValidate(signature); + NaClBrowser::GetInstance()->SetKnownToValidate(signature); } #if defined(OS_WIN) diff --git a/chrome/browser/nacl_host/nacl_validation_cache.cc b/chrome/browser/nacl_host/nacl_validation_cache.cc index 84c45ab..669fe94 100644 --- a/chrome/browser/nacl_host/nacl_validation_cache.cc +++ b/chrome/browser/nacl_host/nacl_validation_cache.cc @@ -4,7 +4,7 @@ #include "chrome/browser/nacl_host/nacl_validation_cache.h" -#include "base/metrics/histogram.h" +#include "base/pickle.h" #include "base/rand_util.h" namespace { @@ -16,37 +16,16 @@ const size_t kValidationCacheKeySize = 64; // Entry size is equal to the digest size of SHA256. const size_t kValidationCacheEntrySize = 32; -enum ValidationCacheStatus { - CACHE_MISS = 0, - CACHE_HIT, - CACHE_ERROR, - CACHE_MAX -}; - -void LogCacheQuery(ValidationCacheStatus status) { - UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Query", status, CACHE_MAX); -} - -void LogCacheSet(ValidationCacheStatus status) { - // Bucket zero is reserved for future use. - UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status, CACHE_MAX); -} - -bool CheckEnvVar(const char* name, bool default_value) { - bool result = default_value; - const char* var = getenv(name); - if (var && strlen(var) > 0) { - result = var[0] != '0'; - } - return result; -} +const char kValidationCacheBeginMagic[] = "NaCl"; +const char kValidationCacheEndMagic[] = "Done"; } // namespace NaClValidationCache::NaClValidationCache() - : validation_cache_(kValidationCacheCacheSize), - validation_cache_key_(base::RandBytesAsString(kValidationCacheKeySize)), - enabled_(CheckEnvVar("NACL_VALIDATION_CACHE", false)){ + : validation_cache_(kValidationCacheCacheSize) { + // Make sure the cache key is unpredictable, even if the cache has not + // been loaded. + Reset(); } NaClValidationCache::~NaClValidationCache() { @@ -54,28 +33,91 @@ NaClValidationCache::~NaClValidationCache() { } bool NaClValidationCache::QueryKnownToValidate(const std::string& signature) { - bool result = false; - if (signature.length() != kValidationCacheEntrySize) { - // Signature is the wrong size, something is wrong. - LogCacheQuery(CACHE_ERROR); - } else { + if (signature.length() == kValidationCacheEntrySize) { ValidationCacheType::iterator iter = validation_cache_.Get(signature); if (iter != validation_cache_.end()) { - result = iter->second; + return iter->second; } - LogCacheQuery(result ? CACHE_HIT : CACHE_MISS); } - return result; + return false; } void NaClValidationCache::SetKnownToValidate(const std::string& signature) { - if (signature.length() != kValidationCacheEntrySize) { - // Signature is the wrong size, something is wrong. - LogCacheSet(CACHE_ERROR); - } else { + if (signature.length() == kValidationCacheEntrySize) { validation_cache_.Put(signature, true); - // The number of sets should be equal to the number of cache misses, minus - // validation failures and successful validations where stubout occurs. - LogCacheSet(CACHE_HIT); } } + +void NaClValidationCache::Serialize(Pickle* pickle) const { + // Mark the beginning of the data stream. + pickle->WriteString(kValidationCacheBeginMagic); + pickle->WriteString(validation_cache_key_); + pickle->WriteInt(validation_cache_.size()); + + // Serialize the cache in reverse order so that deserializing it can easily + // preserve the MRU order. (Last item deserialized => most recently used.) + ValidationCacheType::const_reverse_iterator iter; + for (iter = validation_cache_.rbegin(); + iter != validation_cache_.rend(); + ++iter) { + pickle->WriteString(iter->first); + } + + // Mark the end of the data stream. + pickle->WriteString(kValidationCacheEndMagic); +} + +void NaClValidationCache::Reset() { + validation_cache_key_ = base::RandBytesAsString(kValidationCacheKeySize); + validation_cache_.Clear(); +} + +bool NaClValidationCache::Deserialize(const Pickle* pickle) { + bool success = DeserializeImpl(pickle); + if (!success) { + Reset(); + } + return success; +} + +bool NaClValidationCache::DeserializeImpl(const Pickle* pickle) { + PickleIterator iter(*pickle); + std::string buffer; + int count; + + // Magic + if (!iter.ReadString(&buffer)) + return false; + if (0 != buffer.compare(kValidationCacheBeginMagic)) + return false; + + // Key + if (!iter.ReadString(&buffer)) + return false; + if (buffer.size() != kValidationCacheKeySize) + return false; + + validation_cache_key_ = buffer; + validation_cache_.Clear(); + + // Cache entries + if (!iter.ReadInt(&count)) + return false; + for (int i = 0; i < count; ++i) { + if (!iter.ReadString(&buffer)) + return false; + if (buffer.size() != kValidationCacheEntrySize) + return false; + validation_cache_.Put(buffer, true); + } + + // Magic + if (!iter.ReadString(&buffer)) + return false; + if (0 != buffer.compare(kValidationCacheEndMagic)) + return false; + + // Success! + return true; +} + diff --git a/chrome/browser/nacl_host/nacl_validation_cache.h b/chrome/browser/nacl_host/nacl_validation_cache.h index eace325..bdcb217 100644 --- a/chrome/browser/nacl_host/nacl_validation_cache.h +++ b/chrome/browser/nacl_host/nacl_validation_cache.h @@ -27,19 +27,36 @@ class NaClValidationCache { // Put the validation signature in the database. void SetKnownToValidate(const std::string& signature); - // Should the cache be used? - bool IsEnabled() { - return enabled_; + void Reset(); + void Serialize(Pickle* pickle) const; + bool Deserialize(const Pickle* pickle); + + // Testing functions + size_t size() const { + return validation_cache_.size(); + } + void SetValidationCacheKey(std::string& key) { + validation_cache_key_ = key; + } + std::vector<std::string> GetContents() const { + std::vector<std::string> contents; + ValidationCacheType::const_iterator iter = validation_cache_.begin(); + for (iter = validation_cache_.begin(); + iter != validation_cache_.end(); + iter++) { + contents.push_back(iter->first); + } + return contents; } private: + bool DeserializeImpl(const Pickle* pickle); + typedef base::HashingMRUCache<std::string, bool> ValidationCacheType; ValidationCacheType validation_cache_; std::string validation_cache_key_; - bool enabled_; - DISALLOW_COPY_AND_ASSIGN(NaClValidationCache); }; diff --git a/chrome/browser/nacl_host/nacl_validation_cache_unittest.cc b/chrome/browser/nacl_host/nacl_validation_cache_unittest.cc new file mode 100644 index 0000000..42c9653 --- /dev/null +++ b/chrome/browser/nacl_host/nacl_validation_cache_unittest.cc @@ -0,0 +1,180 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/pickle.h" +#include "chrome/browser/nacl_host/nacl_validation_cache.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +const char key1[65] = + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"; +const char key2[65] = + "a 64-byte string of various junk................................"; +const char sig1[33] = "0123456789ABCDEF0123456789ABCDEF"; +const char sig2[33] = "a 32-byte string of various junk"; + +class NaClValidationCacheTest : public ::testing::Test { + protected: + NaClValidationCache cache1; + NaClValidationCache cache2; + + void SetUp() { + // The compiler chokes if std::string(key1) is passed directly as an arg. + std::string key(key1); + cache1.SetValidationCacheKey(key); + cache2.SetValidationCacheKey(key); + } + + bool IsIdentical(const NaClValidationCache& a, + const NaClValidationCache& b) const { + if (a.GetValidationCacheKey() != b.GetValidationCacheKey()) + return false; + if (a.size() != b.size()) + return false; + return a.GetContents() == b.GetContents(); + } +}; + +TEST_F(NaClValidationCacheTest, Sanity) { + ASSERT_EQ(0, (int) cache1.size()); + ASSERT_FALSE(cache1.QueryKnownToValidate(sig1)); + ASSERT_FALSE(cache1.QueryKnownToValidate(sig2)); +} + +TEST_F(NaClValidationCacheTest, Sig1) { + cache1.SetKnownToValidate(sig1); + ASSERT_EQ(1, (int) cache1.size()); + ASSERT_TRUE(cache1.QueryKnownToValidate(sig1)); + ASSERT_FALSE(cache1.QueryKnownToValidate(sig2)); +} + +TEST_F(NaClValidationCacheTest, Sig2) { + cache1.SetKnownToValidate(sig2); + ASSERT_EQ(1, (int) cache1.size()); + ASSERT_FALSE(cache1.QueryKnownToValidate(sig1)); + ASSERT_TRUE(cache1.QueryKnownToValidate(sig2)); +} + +TEST_F(NaClValidationCacheTest, SigBoth) { + cache1.SetKnownToValidate(sig1); + cache1.SetKnownToValidate(sig2); + ASSERT_EQ(2, (int) cache1.size()); + ASSERT_TRUE(cache1.QueryKnownToValidate(sig1)); + ASSERT_TRUE(cache1.QueryKnownToValidate(sig2)); +} + +TEST_F(NaClValidationCacheTest, DoubleSet) { + cache1.SetKnownToValidate(sig1); + cache1.SetKnownToValidate(sig1); + ASSERT_EQ(1, (int) cache1.size()); + ASSERT_TRUE(cache1.QueryKnownToValidate(sig1)); +} + +TEST_F(NaClValidationCacheTest, EmptyIdentical) { + ASSERT_TRUE(IsIdentical(cache1, cache2)); +} + +TEST_F(NaClValidationCacheTest, DifferentKeysNotIdentical) { + std::string key(key2); + cache2.SetValidationCacheKey(key); + ASSERT_FALSE(IsIdentical(cache1, cache2)); +} + + +TEST_F(NaClValidationCacheTest, DifferentSizesNotIdentical) { + cache1.SetKnownToValidate(sig1); + + ASSERT_FALSE(IsIdentical(cache1, cache2)); +} + +TEST_F(NaClValidationCacheTest, SameSigsIdentical) { + cache1.SetKnownToValidate(sig1); + + cache2.SetKnownToValidate(sig1); + + ASSERT_TRUE(IsIdentical(cache1, cache2)); +} + +TEST_F(NaClValidationCacheTest, DifferentSigsNotIdentical) { + cache1.SetKnownToValidate(sig1); + + cache2.SetKnownToValidate(sig2); + + ASSERT_FALSE(IsIdentical(cache1, cache2)); +} + +TEST_F(NaClValidationCacheTest, InOrderIdentical) { + cache1.SetKnownToValidate(sig1); + cache1.SetKnownToValidate(sig2); + + cache2.SetKnownToValidate(sig1); + cache2.SetKnownToValidate(sig2); + + ASSERT_TRUE(IsIdentical(cache1, cache2)); +} + +TEST_F(NaClValidationCacheTest, OutOfOrderNotIdentical) { + cache1.SetKnownToValidate(sig1); + cache1.SetKnownToValidate(sig2); + + cache2.SetKnownToValidate(sig2); + cache2.SetKnownToValidate(sig1); + + ASSERT_FALSE(IsIdentical(cache1, cache2)); +} + +TEST_F(NaClValidationCacheTest, SerializeDeserialize) { + std::string key(key2); + cache1.SetValidationCacheKey(key); + cache1.SetKnownToValidate(sig1); + cache1.SetKnownToValidate(sig2); + + Pickle pickle; + cache1.Serialize(&pickle); + ASSERT_TRUE(cache2.Deserialize(&pickle)); + ASSERT_EQ(2, (int) cache2.size()); + ASSERT_TRUE(IsIdentical(cache1, cache2)); +} + +TEST_F(NaClValidationCacheTest, SerializeDeserializeTruncated) { + std::string key(key2); + cache1.SetValidationCacheKey(key); + cache1.SetKnownToValidate(sig1); + cache1.SetKnownToValidate(sig2); + + Pickle pickle; + cache1.Serialize(&pickle); + Pickle truncated(static_cast<const char*>(pickle.data()), pickle.size()-20); + ASSERT_FALSE(cache2.Deserialize(&truncated)); + ASSERT_EQ(0, (int) cache2.size()); +} + +TEST_F(NaClValidationCacheTest, DeserializeBadKey) { + std::string key(sig1); // Too short, will cause the deserialization to error. + cache1.SetValidationCacheKey(key); + cache1.SetKnownToValidate(sig1); + cache1.SetKnownToValidate(sig2); + + Pickle pickle; + cache1.Serialize(&pickle); + ASSERT_FALSE(cache2.Deserialize(&pickle)); + ASSERT_EQ(0, (int) cache2.size()); +} + +TEST_F(NaClValidationCacheTest, DeserializeNothing) { + cache1.SetKnownToValidate(sig1); + Pickle pickle("", 0); + ASSERT_FALSE(cache1.Deserialize(&pickle)); + ASSERT_EQ(0, (int) cache1.size()); +} + +TEST_F(NaClValidationCacheTest, DeserializeJunk) { + cache1.SetKnownToValidate(sig1); + Pickle pickle(key1, strlen(key1)); + ASSERT_FALSE(cache1.Deserialize(&pickle)); + ASSERT_EQ(0, (int) cache1.size()); +} + +} diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index b586d65..ab9a9d0 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1306,6 +1306,7 @@ 'browser/metrics/metrics_service_unittest.cc', 'browser/metrics/thread_watcher_unittest.cc', 'browser/metrics/variations_service_unittest.cc', + 'browser/nacl_host/nacl_validation_cache_unittest.cc', 'browser/net/chrome_fraudulent_certificate_reporter_unittest.cc', 'browser/net/chrome_net_log_unittest.cc', 'browser/net/connection_tester_unittest.cc', @@ -2012,6 +2013,7 @@ }], ['disable_nacl==1', { 'sources!':[ + 'browser/nacl_host/nacl_validation_cache_unittest.cc', 'nacl/nacl_ipc_adapter_unittest.cc', 'nacl/nacl_validation_query_unittest.cc', ], |