From 8de09846d1fb62e1bb6105199881a1262005f303 Mon Sep 17 00:00:00 2001 From: Lev Dragunov Date: Mon, 24 Aug 2015 14:08:55 +0300 Subject: [PATCH] [search] History corruption handling. --- search/query_saver.cpp | 49 +++++++++++++++++++---- search/query_saver.hpp | 4 +- search/search_tests/query_saver_tests.cpp | 15 ++++++- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/search/query_saver.cpp b/search/query_saver.cpp index c5a4acce7c..a67b785c66 100644 --- a/search/query_saver.cpp +++ b/search/query_saver.cpp @@ -6,6 +6,8 @@ #include "coding/reader.hpp" #include "coding/writer.hpp" +#include "base/logging.hpp" + namespace { size_t constexpr kMaxSuggestCount = 10; @@ -44,10 +46,10 @@ void QuerySaver::Clear() Settings::Delete(kSettingsKey); } -void QuerySaver::Serialize(vector & data) const +void QuerySaver::Serialize(string & data) const { - data.clear(); - MemWriter> writer(data); + vector rawData; + MemWriter> writer(rawData); TLength size = m_topQueries.size(); writer.Write(&size, kLengthTypeSize); for (auto const & query : m_topQueries) @@ -56,20 +58,53 @@ void QuerySaver::Serialize(vector & data) const writer.Write(&size, kLengthTypeSize); writer.Write(query.c_str(), size); } + data = ToHex(&rawData[0], rawData.size()); +} + +void QuerySaver::EmergencyReset() +{ + Clear(); + LOG(LWARNING, ("Search history data corrupted! Creating new one.")); } void QuerySaver::Deserialize(string const & data) { - MemReader rawReader(data.c_str(), data.size()); + string decodedData; + try + { + decodedData = FromHex(data); + } + catch (RootException const & ex) + { + EmergencyReset(); + return; + } + MemReader rawReader(decodedData.c_str(), decodedData.size()); ReaderSource reader(rawReader); TLength queriesCount; reader.Read(&queriesCount, kLengthTypeSize); + if (queriesCount > kMaxSuggestCount) + { + EmergencyReset(); + return; + } + for (TLength i = 0; i < queriesCount; ++i) { TLength stringLength; + if (reader.Size() < kLengthTypeSize) + { + EmergencyReset(); + return; + } reader.Read(&stringLength, kLengthTypeSize); + if (reader.Size() < stringLength) + { + EmergencyReset(); + return; + } vector str(stringLength); reader.Read(&str[0], stringLength); m_topQueries.emplace_back(&str[0], stringLength); @@ -78,9 +113,9 @@ void QuerySaver::Deserialize(string const & data) void QuerySaver::Save() { - vector data; + string data; Serialize(data); - Settings::Set(kSettingsKey, ToHex(&data[0], data.size())); + Settings::Set(kSettingsKey, data); } void QuerySaver::Load() @@ -89,6 +124,6 @@ void QuerySaver::Load() Settings::Get(kSettingsKey, hexData); if (hexData.empty()) return; - Deserialize(FromHex(hexData)); + Deserialize(hexData); } } // namesapce search diff --git a/search/query_saver.hpp b/search/query_saver.hpp index 78d858c113..ccc603f796 100644 --- a/search/query_saver.hpp +++ b/search/query_saver.hpp @@ -18,12 +18,14 @@ public: private: friend void UnitTest_QuerySaverSerializerTest(); - void Serialize(vector & data) const; + friend void UnitTest_QuerySaverCorruptedStringTest(); + void Serialize(string & data) const; void Deserialize(string const & data); void Save(); void Load(); + void EmergencyReset(); list m_topQueries; }; } // namespace search diff --git a/search/search_tests/query_saver_tests.cpp b/search/search_tests/query_saver_tests.cpp index 169cd5df54..7d8216fc3d 100644 --- a/search/search_tests/query_saver_tests.cpp +++ b/search/search_tests/query_saver_tests.cpp @@ -62,12 +62,12 @@ UNIT_TEST(QuerySaverSerializerTest) saver.Clear(); saver.Add(record1); saver.Add(record2); - vector data; + string data; saver.Serialize(data); TEST_GREATER(data.size(), 0, ()); saver.Clear(); TEST_EQUAL(saver.Get().size(), 0, ()); - saver.Deserialize(string(data.begin(), data.end())); + saver.Deserialize(data); list const & result = saver.Get(); TEST_EQUAL(result.size(), 2, ()); @@ -75,6 +75,17 @@ UNIT_TEST(QuerySaverSerializerTest) TEST_EQUAL(result.front(), record2, ()); } +UNIT_TEST(QuerySaverCorruptedStringTest) +{ + // We can't catch the ASEERT exception on the DEBUG build. + // So we check only valid HEX string case. + QuerySaver saver; + string corrupted("DEADBEEF"); + saver.Deserialize(corrupted); + list const & result = saver.Get(); + TEST_EQUAL(result.size(), 0, ()); +} + UNIT_TEST(QuerySaverPersistanceStore) { {