diff options
-rw-r--r-- | compiler/compiler.cc | 4 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.cc | 4 | ||||
-rw-r--r-- | runtime/oat.cc | 27 | ||||
-rw-r--r-- | runtime/oat.h | 10 |
4 files changed, 32 insertions, 13 deletions
diff --git a/compiler/compiler.cc b/compiler/compiler.cc index d044c2fe4f..98d73396bc 100644 --- a/compiler/compiler.cc +++ b/compiler/compiler.cc @@ -22,6 +22,7 @@ #include "base/utils.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_file.h" +#include "oat.h" #include "optimizing/optimizing_compiler.h" namespace art { @@ -29,6 +30,9 @@ namespace art { Compiler* Compiler::Create(const CompilerOptions& compiler_options, CompiledMethodStorage* storage, Compiler::Kind kind) { + // Check that oat version when runtime was compiled matches the oat version of the compiler. + constexpr std::array<uint8_t, 4> compiler_oat_version = OatHeader::kOatVersion; + OatHeader::CheckOatVersion(compiler_oat_version); switch (kind) { case kQuick: // TODO: Remove Quick in options. diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 897278f6c8..c39217709e 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -2011,6 +2011,10 @@ bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) { size_t OatWriter::InitOatHeader(uint32_t num_dex_files, SafeMap<std::string, std::string>* key_value_store) { TimingLogger::ScopedTiming split("InitOatHeader", timings_); + // Check that oat version when runtime was compiled matches the oat version + // when dex2oat was compiled. We have seen cases where they got out of sync. + constexpr std::array<uint8_t, 4> dex2oat_oat_version = OatHeader::kOatVersion; + OatHeader::CheckOatVersion(dex2oat_oat_version); oat_header_.reset(OatHeader::Create(GetCompilerOptions().GetInstructionSet(), GetCompilerOptions().GetInstructionSetFeatures(), num_dex_files, diff --git a/runtime/oat.cc b/runtime/oat.cc index b8289876a8..db6cda5027 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -29,8 +29,6 @@ namespace art { using android::base::StringPrintf; -constexpr uint8_t OatHeader::kOatMagic[4]; -constexpr uint8_t OatHeader::kOatVersion[4]; constexpr const char OatHeader::kTrueValue[]; constexpr const char OatHeader::kFalseValue[]; @@ -86,8 +84,8 @@ OatHeader::OatHeader(InstructionSet instruction_set, static_assert(sizeof(version_) == sizeof(kOatVersion), "Oat version and version_ have different lengths."); - memcpy(magic_, kOatMagic, sizeof(kOatMagic)); - memcpy(version_, kOatVersion, sizeof(kOatVersion)); + magic_ = kOatMagic; + version_ = kOatVersion; CHECK_NE(instruction_set, InstructionSet::kNone); @@ -96,10 +94,10 @@ OatHeader::OatHeader(InstructionSet instruction_set, } bool OatHeader::IsValid() const { - if (memcmp(magic_, kOatMagic, sizeof(kOatMagic)) != 0) { + if (magic_ != kOatMagic) { return false; } - if (memcmp(version_, kOatVersion, sizeof(kOatVersion)) != 0) { + if (version_ != kOatVersion) { return false; } if (!IsAligned<kPageSize>(executable_offset_)) { @@ -112,13 +110,13 @@ bool OatHeader::IsValid() const { } std::string OatHeader::GetValidationErrorMessage() const { - if (memcmp(magic_, kOatMagic, sizeof(kOatMagic)) != 0) { + if (magic_ != kOatMagic) { static_assert(sizeof(kOatMagic) == 4, "kOatMagic has unexpected length"); return StringPrintf("Invalid oat magic, expected 0x%x%x%x%x, got 0x%x%x%x%x.", kOatMagic[0], kOatMagic[1], kOatMagic[2], kOatMagic[3], magic_[0], magic_[1], magic_[2], magic_[3]); } - if (memcmp(version_, kOatVersion, sizeof(kOatVersion)) != 0) { + if (version_ != kOatVersion) { static_assert(sizeof(kOatVersion) == 4, "kOatVersion has unexpected length"); return StringPrintf("Invalid oat version, expected 0x%x%x%x%x, got 0x%x%x%x%x.", kOatVersion[0], kOatVersion[1], kOatVersion[2], kOatVersion[3], @@ -133,9 +131,20 @@ std::string OatHeader::GetValidationErrorMessage() const { return ""; } +// Do not move this into the header. The method must be compiled in the runtime library, +// so that we can check that the compile-time oat version matches the version in the caller. +void OatHeader::CheckOatVersion(std::array<uint8_t, 4> version) { + constexpr std::array<uint8_t, 4> expected = kOatVersion; // Runtime oat version. + if (version != kOatVersion) { + LOG(FATAL) << StringPrintf("Invalid oat version, expected 0x%x%x%x%x, got 0x%x%x%x%x.", + expected[0], expected[1], expected[2], expected[3], + version[0], version[1], version[2], version[3]); + } +} + const char* OatHeader::GetMagic() const { CHECK(IsValid()); - return reinterpret_cast<const char*>(magic_); + return reinterpret_cast<const char*>(magic_.data()); } uint32_t OatHeader::GetChecksum() const { diff --git a/runtime/oat.h b/runtime/oat.h index 3877f3eeb5..15059a8a96 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -17,6 +17,7 @@ #ifndef ART_RUNTIME_OAT_H_ #define ART_RUNTIME_OAT_H_ +#include <array> #include <vector> #include "base/macros.h" @@ -30,9 +31,9 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: - static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; + static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } }; // Last oat version changed reason: Remove unused trampoline entrypoints. - static constexpr uint8_t kOatVersion[] = { '1', '7', '0', '\0' }; + static constexpr std::array<uint8_t, 4> kOatVersion { { '1', '7', '0', '\0' } }; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; static constexpr const char* kDebuggableKey = "debuggable"; @@ -55,6 +56,7 @@ class PACKED(4) OatHeader { bool IsValid() const; std::string GetValidationErrorMessage() const; + static void CheckOatVersion(std::array<uint8_t, 4> version); const char* GetMagic() const; uint32_t GetChecksum() const; void SetChecksum(uint32_t checksum); @@ -111,8 +113,8 @@ class PACKED(4) OatHeader { void Flatten(const SafeMap<std::string, std::string>* variable_data); - uint8_t magic_[4]; - uint8_t version_[4]; + std::array<uint8_t, 4> magic_; + std::array<uint8_t, 4> version_; uint32_t oat_checksum_; InstructionSet instruction_set_; |