diff --git a/src/cache.cc b/src/cache.cc index 5b12de42..2d0dc41e 100644 --- a/src/cache.cc +++ b/src/cache.cc @@ -30,11 +30,7 @@ std::unique_ptr LoadCachedIndex(Config* config, if (!file_content) return nullptr; - optional indexed = Deserialize(filename, *file_content); - if (indexed && indexed->version == IndexFile::kCurrentVersion) - return MakeUnique(indexed.value()); - - return nullptr; + return Deserialize(filename, *file_content, IndexFile::kCurrentVersion); } optional LoadCachedFileContents(Config* config, diff --git a/src/serializer.cc b/src/serializer.cc index c1ea7e57..3ba55f0b 100644 --- a/src/serializer.cc +++ b/src/serializer.cc @@ -179,29 +179,39 @@ std::string Serialize(IndexFile& file) { return output.GetString(); } -optional Deserialize(std::string path, std::string serialized) { +std::unique_ptr Deserialize(std::string path, std::string serialized, optional expected_version) { rapidjson::Document reader; reader.Parse(serialized.c_str()); if (reader.HasParseError()) - return nullopt; + return nullptr; - IndexFile file(path); - Reflect(reader, file); + // Do not deserialize a document with a bad version. Doing so could cause a + // crash because the file format may have changed. + if (expected_version) { + auto actual_version = reader.FindMember("version"); + if (actual_version == reader.MemberEnd() || + actual_version->value.GetInt() != expected_version) { + return nullptr; + } + } + + auto file = MakeUnique(path); + Reflect(reader, *file); // Restore non-serialized state. - file.path = path; - file.id_cache.primary_file = file.path; - for (const auto& type : file.types) { - file.id_cache.type_id_to_usr[type.id] = type.def.usr; - file.id_cache.usr_to_type_id[type.def.usr] = type.id; + file->path = path; + file->id_cache.primary_file = file->path; + for (const auto& type : file->types) { + file->id_cache.type_id_to_usr[type.id] = type.def.usr; + file->id_cache.usr_to_type_id[type.def.usr] = type.id; } - for (const auto& func : file.funcs) { - file.id_cache.func_id_to_usr[func.id] = func.def.usr; - file.id_cache.usr_to_func_id[func.def.usr] = func.id; + for (const auto& func : file->funcs) { + file->id_cache.func_id_to_usr[func.id] = func.def.usr; + file->id_cache.usr_to_func_id[func.def.usr] = func.id; } - for (const auto& var : file.vars) { - file.id_cache.var_id_to_usr[var.id] = var.def.usr; - file.id_cache.usr_to_var_id[var.def.usr] = var.id; + for (const auto& var : file->vars) { + file->id_cache.var_id_to_usr[var.id] = var.def.usr; + file->id_cache.usr_to_var_id[var.def.usr] = var.id; } return file; diff --git a/src/serializer.h b/src/serializer.h index d989472c..52ccd5a0 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -5,8 +5,9 @@ #include #include -#include +#include #include +#include using std::experimental::optional; @@ -222,6 +223,6 @@ void ReflectMember(Reader& visitor, const char* name, T& value) { } std::string Serialize(IndexFile& file); -optional Deserialize(std::string path, std::string serialized); +std::unique_ptr Deserialize(std::string path, std::string serialized, optional expected_version); void SetTestOutputMode(); \ No newline at end of file diff --git a/src/test.cc b/src/test.cc index 9fbf15b1..9b23d8e8 100644 --- a/src/test.cc +++ b/src/test.cc @@ -66,7 +66,8 @@ void DiffDocuments(std::string path, std::string path_section, rapidjson::Docume void VerifySerializeToFrom(IndexFile* file) { std::string expected = file->ToString(); - std::string actual = Deserialize("--.cc", Serialize(*file)).value().ToString(); + std::unique_ptr result = Deserialize("--.cc", Serialize(*file), nullopt /*expected_version*/); + std::string actual = result->ToString(); if (expected != actual) { std::cerr << "Serialization failure" << std::endl;; assert(false);