diff options
53 files changed, 1358 insertions, 1116 deletions
diff --git a/compiler/dex/arena_allocator.cc b/compiler/dex/arena_allocator.cc index 2da8064..95e44b3 100644 --- a/compiler/dex/arena_allocator.cc +++ b/compiler/dex/arena_allocator.cc @@ -50,7 +50,9 @@ Arena::Arena(size_t size) map_(nullptr), next_(nullptr) { if (kUseMemMap) { - map_ = MemMap::MapAnonymous("dalvik-arena", NULL, size, PROT_READ | PROT_WRITE); + std::string error_msg; + map_ = MemMap::MapAnonymous("dalvik-arena", NULL, size, PROT_READ | PROT_WRITE, &error_msg); + CHECK(map_ != nullptr) << error_msg; memory_ = map_->Begin(); size_ = map_->Size(); } else { diff --git a/compiler/elf_fixup.cc b/compiler/elf_fixup.cc index 359c493..c571288 100644 --- a/compiler/elf_fixup.cc +++ b/compiler/elf_fixup.cc @@ -27,8 +27,9 @@ namespace art { static const bool DEBUG_FIXUP = false; bool ElfFixup::Fixup(File* file, uintptr_t oat_data_begin) { - UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false)); - CHECK(elf_file.get() != NULL); + std::string error_msg; + UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false, &error_msg)); + CHECK(elf_file.get() != nullptr) << error_msg; // Lookup "oatdata" symbol address. ::llvm::ELF::Elf32_Addr oatdata_address = ElfWriter::GetOatDataAddress(elf_file.get()); diff --git a/compiler/elf_stripper.cc b/compiler/elf_stripper.cc index 7fc662c..7ee8d3c 100644 --- a/compiler/elf_stripper.cc +++ b/compiler/elf_stripper.cc @@ -27,9 +27,11 @@ namespace art { -bool ElfStripper::Strip(File* file) { - UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false)); - CHECK(elf_file.get() != NULL); +bool ElfStripper::Strip(File* file, std::string* error_msg) { + UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false, error_msg)); + if (elf_file.get() == nullptr) { + return false; + } // ELF files produced by MCLinker look roughly like this // @@ -120,7 +122,8 @@ bool ElfStripper::Strip(File* file) { elf_file->GetHeader().e_shoff = shoff; int result = ftruncate(file->Fd(), offset); if (result != 0) { - PLOG(ERROR) << "Failed to truncate while stripping ELF file: " << file->GetPath(); + *error_msg = StringPrintf("Failed to truncate while stripping ELF file: '%s': %s", + file->GetPath().c_str(), strerror(errno)); return false; } return true; diff --git a/compiler/elf_stripper.h b/compiler/elf_stripper.h index 6015b30..f1a1d46 100644 --- a/compiler/elf_stripper.h +++ b/compiler/elf_stripper.h @@ -17,6 +17,8 @@ #ifndef ART_COMPILER_ELF_STRIPPER_H_ #define ART_COMPILER_ELF_STRIPPER_H_ +#include <string> + #include "base/macros.h" #include "os.h" @@ -26,7 +28,7 @@ class ElfStripper { public: // Strip an ELF file of unneeded debugging information. // Returns true on success, false on failure. - static bool Strip(File* file); + static bool Strip(File* file, std::string* error_msg); private: DISALLOW_IMPLICIT_CONSTRUCTORS(ElfStripper); diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc index d3c13dd..0bfe4a4 100644 --- a/compiler/elf_writer.cc +++ b/compiler/elf_writer.cc @@ -47,8 +47,9 @@ llvm::ELF::Elf32_Addr ElfWriter::GetOatDataAddress(ElfFile* elf_file) { void ElfWriter::GetOatElfInformation(File* file, size_t& oat_loaded_size, size_t& oat_data_offset) { - UniquePtr<ElfFile> elf_file(ElfFile::Open(file, false, false)); - CHECK(elf_file.get() != NULL); + std::string error_msg; + UniquePtr<ElfFile> elf_file(ElfFile::Open(file, false, false, &error_msg)); + CHECK(elf_file.get() != NULL) << error_msg; oat_loaded_size = elf_file->GetLoadedSize(); CHECK_NE(0U, oat_loaded_size); diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc index ffe1f72..eca67a8 100644 --- a/compiler/elf_writer_test.cc +++ b/compiler/elf_writer_test.cc @@ -65,23 +65,26 @@ TEST_F(ElfWriterTest, dlsym) { UniquePtr<File> file(OS::OpenFileForReading(elf_filename.c_str())); ASSERT_TRUE(file.get() != NULL); { - UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false)); - CHECK(ef.get() != NULL); + std::string error_msg; + UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false, &error_msg)); + CHECK(ef.get() != nullptr) << error_msg; EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", false); EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", false); EXPECT_ELF_FILE_ADDRESS(ef, dl_oatlastword, "oatlastword", false); } { - UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false)); - CHECK(ef.get() != NULL); + std::string error_msg; + UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false, &error_msg)); + CHECK(ef.get() != nullptr) << error_msg; EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", true); EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", true); EXPECT_ELF_FILE_ADDRESS(ef, dl_oatlastword, "oatlastword", true); } { - UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, true)); - CHECK(ef.get() != NULL); - ef->Load(false); + std::string error_msg; + UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, true, &error_msg)); + CHECK(ef.get() != nullptr) << error_msg; + CHECK(ef->Load(false, &error_msg)) << error_msg; EXPECT_EQ(dl_oatdata, ef->FindDynamicSymbolAddress("oatdata")); EXPECT_EQ(dl_oatexec, ef->FindDynamicSymbolAddress("oatexec")); EXPECT_EQ(dl_oatlastword, ef->FindDynamicSymbolAddress("oatlastword")); diff --git a/compiler/image_test.cc b/compiler/image_test.cc index d4be7c0..a8b7c88 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -112,8 +112,11 @@ TEST_F(ImageTest, WriteRead) { runtime_.reset(); java_lang_dex_file_ = NULL; - UniquePtr<const DexFile> dex(DexFile::Open(GetLibCoreDexFileName(), GetLibCoreDexFileName())); - ASSERT_TRUE(dex.get() != NULL); + std::string error_msg; + UniquePtr<const DexFile> dex(DexFile::Open(GetLibCoreDexFileName().c_str(), + GetLibCoreDexFileName().c_str(), + &error_msg)); + ASSERT_TRUE(dex.get() != nullptr) << error_msg; // Remove the reservation of the memory for use to load the image. UnreserveImageSpace(); diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index bcdc1c1..871cfd5 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -82,12 +82,14 @@ bool ImageWriter::Write(const std::string& image_filename, LOG(ERROR) << "Failed to open oat file " << oat_filename << " for " << oat_location; return false; } - oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location); - if (oat_file_ == NULL) { - LOG(ERROR) << "Failed to open writable oat file " << oat_filename << " for " << oat_location; + std::string error_msg; + oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location, &error_msg); + if (oat_file_ == nullptr) { + LOG(ERROR) << "Failed to open writable oat file " << oat_filename << " for " << oat_location + << ": " << error_msg; return false; } - class_linker->RegisterOatFile(*oat_file_); + CHECK_EQ(class_linker->RegisterOatFile(oat_file_), oat_file_); interpreter_to_interpreter_bridge_offset_ = oat_file_->GetOatHeader().GetInterpreterToInterpreterBridgeOffset(); @@ -192,9 +194,10 @@ bool ImageWriter::AllocMemory() { int prot = PROT_READ | PROT_WRITE; size_t length = RoundUp(size, kPageSize); - image_.reset(MemMap::MapAnonymous("image writer image", NULL, length, prot)); - if (image_.get() == NULL) { - LOG(ERROR) << "Failed to allocate memory for image file generation"; + std::string error_msg; + image_.reset(MemMap::MapAnonymous("image writer image", NULL, length, prot, &error_msg)); + if (UNLIKELY(image_.get() == nullptr)) { + LOG(ERROR) << "Failed to allocate memory for image file generation: " << error_msg; return false; } return true; diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 6ac5d6a..634a160 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -100,8 +100,10 @@ TEST_F(OatTest, WriteRead) { base::TimingLogger timings("CommonTest::WriteRead", false, false); compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings); } - UniquePtr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), NULL, false)); - ASSERT_TRUE(oat_file.get() != NULL); + std::string error_msg; + UniquePtr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), NULL, false, + &error_msg)); + ASSERT_TRUE(oat_file.get() != nullptr) << error_msg; const OatHeader& oat_header = oat_file->GetOatHeader(); ASSERT_TRUE(oat_header.IsValid()); ASSERT_EQ(1U, oat_header.GetDexFileCount()); // core @@ -111,8 +113,9 @@ TEST_F(OatTest, WriteRead) { const DexFile* dex_file = java_lang_dex_file_; uint32_t dex_file_checksum = dex_file->GetLocationChecksum(); - const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file->GetLocation(), + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file->GetLocation().c_str(), &dex_file_checksum); + ASSERT_TRUE(oat_dex_file != nullptr); CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum()); for (size_t i = 0; i < dex_file->NumClassDefs(); i++) { const DexFile::ClassDef& class_def = dex_file->GetClassDef(i); diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index d5d1303..d8112ea 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -200,21 +200,24 @@ class Dex2Oat { } // Reads the class names (java.lang.Object) and returns a set of descriptors (Ljava/lang/Object;) - CompilerDriver::DescriptorSet* ReadImageClassesFromZip(const std::string& zip_filename, - const char* image_classes_filename) { - UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename)); + CompilerDriver::DescriptorSet* ReadImageClassesFromZip(const char* zip_filename, + const char* image_classes_filename, + std::string* error_msg) { + UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename, error_msg)); if (zip_archive.get() == NULL) { - LOG(ERROR) << "Failed to open zip file " << zip_filename; return NULL; } UniquePtr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename)); if (zip_entry.get() == NULL) { - LOG(ERROR) << "Failed to find " << image_classes_filename << " within " << zip_filename; + *error_msg = StringPrintf("Failed to find '%s' within '%s': %s", image_classes_filename, + zip_filename, error_msg->c_str()); return NULL; } - UniquePtr<MemMap> image_classes_file(zip_entry->ExtractToMemMap(image_classes_filename)); + UniquePtr<MemMap> image_classes_file(zip_entry->ExtractToMemMap(image_classes_filename, + error_msg)); if (image_classes_file.get() == NULL) { - LOG(ERROR) << "Failed to extract " << image_classes_filename << " from " << zip_filename; + *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", image_classes_filename, + zip_filename, error_msg->c_str()); return NULL; } const std::string image_classes_string(reinterpret_cast<char*>(image_classes_file->Begin()), @@ -368,9 +371,10 @@ class Dex2Oat { if (DexFilesContains(dex_files, parsed[i])) { continue; } - const DexFile* dex_file = DexFile::Open(parsed[i], parsed[i]); + std::string error_msg; + const DexFile* dex_file = DexFile::Open(parsed[i].c_str(), parsed[i].c_str(), &error_msg); if (dex_file == NULL) { - LOG(WARNING) << "Failed to open dex file " << parsed[i]; + LOG(WARNING) << "Failed to open dex file '" << parsed[i] << "': " << error_msg; } else { dex_files.push_back(dex_file); } @@ -416,9 +420,10 @@ static size_t OpenDexFiles(const std::vector<const char*>& dex_filenames, for (size_t i = 0; i < dex_filenames.size(); i++) { const char* dex_filename = dex_filenames[i]; const char* dex_location = dex_locations[i]; - const DexFile* dex_file = DexFile::Open(dex_filename, dex_location); + std::string error_msg; + const DexFile* dex_file = DexFile::Open(dex_filename, dex_location, &error_msg); if (dex_file == NULL) { - LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "'\n"; + LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg; ++failure_count; } else { dex_files.push_back(dex_file); @@ -887,14 +892,17 @@ static int dex2oat(int argc, char** argv) { // If --image-classes was specified, calculate the full list of classes to include in the image UniquePtr<CompilerDriver::DescriptorSet> image_classes(NULL); if (image_classes_filename != NULL) { + std::string error_msg; if (image_classes_zip_filename != NULL) { image_classes.reset(dex2oat->ReadImageClassesFromZip(image_classes_zip_filename, - image_classes_filename)); + image_classes_filename, + &error_msg)); } else { image_classes.reset(dex2oat->ReadImageClassesFromFile(image_classes_filename)); } if (image_classes.get() == NULL) { - LOG(ERROR) << "Failed to create list of image classes from " << image_classes_filename; + LOG(ERROR) << "Failed to create list of image classes from '" << image_classes_filename << + "': " << error_msg; return EXIT_FAILURE; } } @@ -904,14 +912,18 @@ static int dex2oat(int argc, char** argv) { dex_files = Runtime::Current()->GetClassLinker()->GetBootClassPath(); } else { if (dex_filenames.empty()) { - UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd)); + std::string error_msg; + UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd, zip_location.c_str(), + &error_msg)); if (zip_archive.get() == NULL) { - LOG(ERROR) << "Failed to open zip from file descriptor for " << zip_location; + LOG(ERROR) << "Failed to open zip from file descriptor for '" << zip_location << "': " + << error_msg; return EXIT_FAILURE; } - const DexFile* dex_file = DexFile::Open(*zip_archive.get(), zip_location); + const DexFile* dex_file = DexFile::Open(*zip_archive.get(), zip_location, &error_msg); if (dex_file == NULL) { - LOG(ERROR) << "Failed to open dex from file descriptor for zip file: " << zip_location; + LOG(ERROR) << "Failed to open dex from file descriptor for zip file '" << zip_location + << "': " << error_msg; return EXIT_FAILURE; } dex_files.push_back(dex_file); @@ -1063,7 +1075,8 @@ static int dex2oat(int argc, char** argv) { // Strip unneeded sections for target off_t seek_actual = lseek(oat_file->Fd(), 0, SEEK_SET); CHECK_EQ(0, seek_actual); - ElfStripper::Strip(oat_file.get()); + std::string error_msg; + CHECK(ElfStripper::Strip(oat_file.get(), &error_msg)) << error_msg; // We wrote the oat file successfully, and want to keep it. diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 6db5813..ea06b02 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -173,9 +173,13 @@ class OatDumper { MethodHelper mh(m); for (size_t i = 0; i < oat_dex_files_.size(); i++) { const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; - CHECK(oat_dex_file != NULL); - UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile()); - if (dex_file.get() != NULL) { + CHECK(oat_dex_file != nullptr); + std::string error_msg; + UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg)); + if (dex_file.get() == nullptr) { + LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation() + << "': " << error_msg; + } else { const DexFile::ClassDef* class_def = dex_file->FindClassDef(mh.GetDeclaringClassDescriptor()); if (class_def != NULL) { @@ -199,8 +203,11 @@ class OatDumper { for (size_t i = 0; i < oat_dex_files_.size(); i++) { const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; CHECK(oat_dex_file != NULL); - UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile()); - if (dex_file.get() == NULL) { + std::string error_msg; + UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg)); + if (dex_file.get() == nullptr) { + LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation() + << "': " << error_msg; continue; } offsets_.insert(reinterpret_cast<uint32_t>(&dex_file->GetHeader())); @@ -245,9 +252,10 @@ class OatDumper { os << "OAT DEX FILE:\n"; os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str()); os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum()); - UniquePtr<const DexFile> dex_file(oat_dex_file.OpenDexFile()); + std::string error_msg; + UniquePtr<const DexFile> dex_file(oat_dex_file.OpenDexFile(&error_msg)); if (dex_file.get() == NULL) { - os << "NOT FOUND\n\n"; + os << "NOT FOUND: " << error_msg << "\n\n"; return; } for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) { @@ -727,9 +735,10 @@ class ImageDumper { os << " (" << oat_location << ")"; } os << "\n"; - const OatFile* oat_file = class_linker->FindOatFileFromOatLocation(oat_location); + std::string error_msg; + const OatFile* oat_file = class_linker->FindOatFileFromOatLocation(oat_location, &error_msg); if (oat_file == NULL) { - os << "NOT FOUND\n"; + os << "NOT FOUND: " << error_msg << "\n"; return; } os << "\n"; @@ -775,7 +784,7 @@ class ImageDumper { os << "STATS:\n" << std::flush; UniquePtr<File> file(OS::OpenFileForReading(image_filename_.c_str())); if (file.get() == NULL) { - std::string cache_location(GetDalvikCacheFilenameOrDie(image_filename_)); + std::string cache_location(GetDalvikCacheFilenameOrDie(image_filename_.c_str())); file.reset(OS::OpenFileForReading(cache_location.c_str())); if (file.get() == NULL) { LOG(WARNING) << "Failed to find image in " << image_filename_ @@ -1412,10 +1421,11 @@ static int oatdump(int argc, char** argv) { } if (oat_filename != NULL) { + std::string error_msg; OatFile* oat_file = - OatFile::Open(oat_filename, oat_filename, NULL, false); + OatFile::Open(oat_filename, oat_filename, NULL, false, &error_msg); if (oat_file == NULL) { - fprintf(stderr, "Failed to open oat file from %s\n", oat_filename); + fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str()); return EXIT_FAILURE; } OatDumper oat_dumper(*host_prefix.get(), *oat_file); diff --git a/runtime/base/macros.h b/runtime/base/macros.h index 6531858..d00c64a 100644 --- a/runtime/base/macros.h +++ b/runtime/base/macros.h @@ -138,8 +138,10 @@ char (&ArraySizeHelper(T (&array)[N]))[N]; #if defined (__APPLE__) #define HOT_ATTR +#define COLD_ATTR #else #define HOT_ATTR __attribute__ ((hot)) +#define COLD_ATTR __attribute__ ((cold)) #endif #define PURE __attribute__ ((__pure__)) diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc index 36f8ba7..f48c76d 100644 --- a/runtime/base/unix_file/fd_file.cc +++ b/runtime/base/unix_file/fd_file.cc @@ -102,10 +102,6 @@ bool FdFile::IsOpened() const { return fd_ >= 0; } -std::string FdFile::GetPath() const { - return file_path_; -} - bool FdFile::ReadFully(void* buffer, int64_t byte_count) { char* ptr = static_cast<char*>(buffer); while (byte_count > 0) { diff --git a/runtime/base/unix_file/fd_file.h b/runtime/base/unix_file/fd_file.h index 79a0db9..19e3511 100644 --- a/runtime/base/unix_file/fd_file.h +++ b/runtime/base/unix_file/fd_file.h @@ -57,7 +57,9 @@ class FdFile : public RandomAccessFile { // Bonus API. int Fd() const; bool IsOpened() const; - std::string GetPath() const; + const std::string& GetPath() const { + return file_path_; + } void DisableAutoClose(); bool ReadFully(void* buffer, int64_t byte_count); bool WriteFully(const void* buffer, int64_t byte_count); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index aa5f2bf..eb42e0a 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -540,9 +540,10 @@ void ClassLinker::RunRootClinits() { } } -bool ClassLinker::GenerateOatFile(const std::string& dex_filename, +bool ClassLinker::GenerateOatFile(const char* dex_filename, int oat_fd, - const std::string& oat_cache_filename) { + const char* oat_cache_filename) { + Locks::mutator_lock_->AssertNotHeld(Thread::Current()); // Avoid starving GC. std::string dex2oat_string(GetAndroidRoot()); dex2oat_string += (kIsDebugBuild ? "/bin/dex2oatd" : "/bin/dex2oat"); const char* dex2oat = dex2oat_string.c_str(); @@ -567,7 +568,8 @@ bool ClassLinker::GenerateOatFile(const std::string& dex_filename, const char* oat_location_option = oat_location_option_string.c_str(); std::string oat_compiler_filter_string("-compiler-filter:"); - switch (Runtime::Current()->GetCompilerFilter()) { + Runtime::CompilerFilter filter = Runtime::Current()->GetCompilerFilter(); + switch (filter) { case Runtime::kInterpretOnly: oat_compiler_filter_string += "interpret-only"; break; @@ -584,7 +586,7 @@ bool ClassLinker::GenerateOatFile(const std::string& dex_filename, oat_compiler_filter_string += "everything"; break; default: - LOG(FATAL) << "Unexpected case."; + LOG(FATAL) << "Unexpected case: " << filter; } const char* oat_compiler_filter_option = oat_compiler_filter_string.c_str(); @@ -633,49 +635,55 @@ bool ClassLinker::GenerateOatFile(const std::string& dex_filename, int status; pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); if (got_pid != pid) { - PLOG(ERROR) << "waitpid failed: wanted " << pid << ", got " << got_pid; + ScopedObjectAccess soa(Thread::Current()); + ThrowIOException("Failed to create oat file. Waitpid failed: wanted %d, got %d", pid, + got_pid); return false; } if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - LOG(ERROR) << dex2oat << " failed with dex-file=" << dex_filename; + ScopedObjectAccess soa(Thread::Current()); + ThrowIOException("Failed to create oat file. %s failed with dex-file '%s'", dex2oat, + dex_filename); return false; } } return true; } -void ClassLinker::RegisterOatFile(const OatFile& oat_file) { +const OatFile* ClassLinker::RegisterOatFile(const OatFile* oat_file) { WriterMutexLock mu(Thread::Current(), dex_lock_); - RegisterOatFileLocked(oat_file); -} - -void ClassLinker::RegisterOatFileLocked(const OatFile& oat_file) { - dex_lock_.AssertExclusiveHeld(Thread::Current()); - if (kIsDebugBuild) { - for (size_t i = 0; i < oat_files_.size(); ++i) { - CHECK_NE(&oat_file, oat_files_[i]) << oat_file.GetLocation(); + for (size_t i = 0; i < oat_files_.size(); ++i) { + if (UNLIKELY(oat_file->GetLocation() == oat_files_[i]->GetLocation())) { + VLOG(class_linker) << "Attempt to register oat file that's already registered: " + << oat_file->GetLocation(); + for (size_t j = i; j < oat_files_.size(); ++j) { + CHECK_NE(oat_file, oat_files_[j]) << "Attempt to re-register dex file."; + } + delete oat_file; + return oat_files_[i]; } } - VLOG(class_linker) << "Registering " << oat_file.GetLocation(); - oat_files_.push_back(&oat_file); + VLOG(class_linker) << "Registering " << oat_file->GetLocation(); + oat_files_.push_back(oat_file); + return oat_file; } OatFile& ClassLinker::GetImageOatFile(gc::space::ImageSpace* space) { VLOG(startup) << "ClassLinker::GetImageOatFile entering"; - OatFile& oat_file = space->ReleaseOatFile(); - WriterMutexLock mu(Thread::Current(), dex_lock_); - RegisterOatFileLocked(oat_file); + OatFile* oat_file = space->ReleaseOatFile(); + CHECK_EQ(RegisterOatFile(oat_file), oat_file); VLOG(startup) << "ClassLinker::GetImageOatFile exiting"; - return oat_file; + return *oat_file; } const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) { - ReaderMutexLock mu(Thread::Current(), dex_lock_); - return FindOpenedOatFileFromDexLocation(dex_file.GetLocation(), dex_file.GetLocationChecksum()); + return FindOpenedOatFileFromDexLocation(dex_file.GetLocation().c_str(), + dex_file.GetLocationChecksum()); } -const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(const std::string& dex_location, +const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(const char* dex_location, uint32_t dex_location_checksum) { + ReaderMutexLock mu(Thread::Current(), dex_lock_); for (size_t i = 0; i < oat_files_.size(); i++) { const OatFile* oat_file = oat_files_[i]; DCHECK(oat_file != NULL); @@ -689,82 +697,83 @@ const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(const std::string& return NULL; } -const DexFile* ClassLinker::FindDexFileInOatLocation(const std::string& dex_location, +const DexFile* ClassLinker::FindDexFileInOatLocation(const char* dex_location, uint32_t dex_location_checksum, - const std::string& oat_location) { + const char* oat_location, + std::string* error_msg) { UniquePtr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, NULL, - !Runtime::Current()->IsCompiler())); - if (oat_file.get() == NULL) { - VLOG(class_linker) << "Failed to find existing oat file at " << oat_location; - return NULL; + !Runtime::Current()->IsCompiler(), + error_msg)); + if (oat_file.get() == nullptr) { + *error_msg = StringPrintf("Failed to find existing oat file at %s: %s", oat_location, + error_msg->c_str()); + return nullptr; } Runtime* runtime = Runtime::Current(); const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader(); uint32_t expected_image_oat_checksum = image_header.GetOatChecksum(); uint32_t actual_image_oat_checksum = oat_file->GetOatHeader().GetImageFileLocationOatChecksum(); if (expected_image_oat_checksum != actual_image_oat_checksum) { - VLOG(class_linker) << "Failed to find oat file at " << oat_location - << " with expected image oat checksum of " << expected_image_oat_checksum - << ", found " << actual_image_oat_checksum; - return NULL; + *error_msg = StringPrintf("Failed to find oat file at '%s' with expected image oat checksum of " + "0x%x, found 0x%x", oat_location, expected_image_oat_checksum, + actual_image_oat_checksum); + return nullptr; } uint32_t expected_image_oat_offset = reinterpret_cast<uint32_t>(image_header.GetOatDataBegin()); uint32_t actual_image_oat_offset = oat_file->GetOatHeader().GetImageFileLocationOatDataBegin(); if (expected_image_oat_offset != actual_image_oat_offset) { - VLOG(class_linker) << "Failed to find oat file at " << oat_location - << " with expected image oat offset " << expected_image_oat_offset - << ", found " << actual_image_oat_offset; - return NULL; - } - const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, &dex_location_checksum); - if (oat_dex_file == NULL) { - VLOG(class_linker) << "Failed to find oat file at " << oat_location << " containing " << dex_location; - return NULL; + *error_msg = StringPrintf("Failed to find oat file at '%s' with expected image oat offset %ud, " + "found %ud", oat_location, expected_image_oat_offset, + actual_image_oat_offset); + return nullptr; + } + // TODO: this registers the oat file now as we may use the oat_dex_file later and we want the + // intern behavior of RegisterOatFile. However, if we take an early return we could remove + // the oat file. + const OatFile* opened_oat_file = RegisterOatFile(oat_file.release()); + const OatFile::OatDexFile* oat_dex_file = opened_oat_file->GetOatDexFile(dex_location, + &dex_location_checksum); + if (oat_dex_file == nullptr) { + *error_msg = StringPrintf("Failed to find oat file at '%s' containing '%s'", oat_location, + dex_location); + return nullptr; } uint32_t expected_dex_checksum = dex_location_checksum; uint32_t actual_dex_checksum = oat_dex_file->GetDexFileLocationChecksum(); if (expected_dex_checksum != actual_dex_checksum) { - VLOG(class_linker) << "Failed to find oat file at " << oat_location - << " with expected dex checksum of " << expected_dex_checksum - << ", found " << actual_dex_checksum; - return NULL; + *error_msg = StringPrintf("Failed to find oat file at '%s' with expected dex checksum of 0x%x, " + "found 0x%x", oat_location, expected_dex_checksum, + actual_dex_checksum); + return nullptr; } - RegisterOatFileLocked(*oat_file.release()); - return oat_dex_file->OpenDexFile(); -} - -const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(const std::string& dex_location, - uint32_t dex_location_checksum, - const std::string& oat_location) { - WriterMutexLock mu(Thread::Current(), dex_lock_); - return FindOrCreateOatFileForDexLocationLocked(dex_location, dex_location_checksum, oat_location); + return oat_dex_file->OpenDexFile(error_msg); } class ScopedFlock { public: ScopedFlock() {} - bool Init(const std::string& filename) { + bool Init(const char* filename, std::string* error_msg) { while (true) { - file_.reset(OS::OpenFileWithFlags(filename.c_str(), O_CREAT | O_RDWR)); + file_.reset(OS::OpenFileWithFlags(filename, O_CREAT | O_RDWR)); if (file_.get() == NULL) { - LOG(ERROR) << "Failed to open file: " << filename; + *error_msg = StringPrintf("Failed to open file '%s'", filename); return false; } int flock_result = TEMP_FAILURE_RETRY(flock(file_->Fd(), LOCK_EX)); if (flock_result != 0) { - PLOG(ERROR) << "Failed to lock file: " << filename; + *error_msg = StringPrintf("Failed to lock file '%s': %s", filename, strerror(errno)); return false; } struct stat fstat_stat; int fstat_result = TEMP_FAILURE_RETRY(fstat(file_->Fd(), &fstat_stat)); if (fstat_result != 0) { - PLOG(ERROR) << "Failed to fstat: " << filename; + *error_msg = StringPrintf("Failed to fstat file '%s': %s", filename, strerror(errno)); return false; } struct stat stat_stat; - int stat_result = TEMP_FAILURE_RETRY(stat(filename.c_str(), &stat_stat)); + int stat_result = TEMP_FAILURE_RETRY(stat(filename, &stat_stat)); if (stat_result != 0) { PLOG(WARNING) << "Failed to stat, will retry: " << filename; // ENOENT can happen if someone racing with us unlinks the file we created so just retry. @@ -795,49 +804,54 @@ class ScopedFlock { DISALLOW_COPY_AND_ASSIGN(ScopedFlock); }; -const DexFile* ClassLinker::FindOrCreateOatFileForDexLocationLocked(const std::string& dex_location, - uint32_t dex_location_checksum, - const std::string& oat_location) { +const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(const char* dex_location, + uint32_t dex_location_checksum, + const char* oat_location, + std::string* error_msg) { // We play a locking game here so that if two different processes // race to generate (or worse, one tries to open a partial generated // file) we will be okay. This is actually common with apps that use // DexClassLoader to work around the dex method reference limit and // that have a background service running in a separate process. ScopedFlock scoped_flock; - if (!scoped_flock.Init(oat_location)) { - LOG(ERROR) << "Failed to open locked oat file: " << oat_location; - return NULL; + if (!scoped_flock.Init(oat_location, error_msg)) { + return nullptr; } // Check if we already have an up-to-date output file - const DexFile* dex_file = FindDexFileInOatLocation(dex_location, - dex_location_checksum, - oat_location); - if (dex_file != NULL) { + const DexFile* dex_file = FindDexFileInOatLocation(dex_location, dex_location_checksum, + oat_location, error_msg); + if (dex_file != nullptr) { return dex_file; } + VLOG(class_linker) << "Failed to find dex file '" << dex_location << "' in oat location '" + << oat_location << "': " << *error_msg; + error_msg->clear(); // Generate the output oat file for the dex file VLOG(class_linker) << "Generating oat file " << oat_location << " for " << dex_location; if (!GenerateOatFile(dex_location, scoped_flock.GetFile().Fd(), oat_location)) { - LOG(ERROR) << "Failed to generate oat file: " << oat_location; - return NULL; + CHECK(Thread::Current()->IsExceptionPending()); + return nullptr; } const OatFile* oat_file = OatFile::Open(oat_location, oat_location, NULL, - !Runtime::Current()->IsCompiler()); - if (oat_file == NULL) { - LOG(ERROR) << "Failed to open generated oat file: " << oat_location; - return NULL; - } - RegisterOatFileLocked(*oat_file); - const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, &dex_location_checksum); - if (oat_dex_file == NULL) { - LOG(ERROR) << "Failed to find dex file " << dex_location - << " (checksum " << dex_location_checksum - << ") in generated oat file: " << oat_location; - return NULL; + !Runtime::Current()->IsCompiler(), + error_msg); + if (oat_file == nullptr) { + *error_msg = StringPrintf("Failed to open generated oat file '%s': %s", + oat_location, error_msg->c_str()); + return nullptr; + } + oat_file = RegisterOatFile(oat_file); + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, + &dex_location_checksum); + if (oat_dex_file == nullptr) { + *error_msg = StringPrintf("Failed to find dex file '%s' (checksum 0x%x) in generated out file " + "'%s'", dex_location, dex_location_checksum, oat_location); + return nullptr; } - const DexFile* result = oat_dex_file->OpenDexFile(); + const DexFile* result = oat_dex_file->OpenDexFile(error_msg); + CHECK(result != nullptr) << *error_msg; CHECK_EQ(dex_location_checksum, result->GetLocationChecksum()) << "dex_location=" << dex_location << " oat_location=" << oat_location << std::hex << " dex_location_checksum=" << dex_location_checksum @@ -846,8 +860,9 @@ const DexFile* ClassLinker::FindOrCreateOatFileForDexLocationLocked(const std::s } bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file, - const std::string& dex_location, - uint32_t dex_location_checksum) { + const char* dex_location, + uint32_t dex_location_checksum, + std::string* error_msg) { Runtime* runtime = Runtime::Current(); const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader(); uint32_t image_oat_checksum = image_header.GetOatChecksum(); @@ -857,14 +872,14 @@ bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file, const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, &dex_location_checksum); if (oat_dex_file == NULL) { - LOG(ERROR) << "oat file " << oat_file->GetLocation() - << " does not contain contents for " << dex_location - << " with checksum " << dex_location_checksum; + *error_msg = StringPrintf("oat file '%s' does not contain contents for '%s' with checksum 0x%x", + oat_file->GetLocation().c_str(), dex_location, dex_location_checksum); std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file->GetOatDexFiles(); for (size_t i = 0; i < oat_dex_files.size(); i++) { const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i]; - LOG(ERROR) << "oat file " << oat_file->GetLocation() - << " contains contents for " << oat_dex_file->GetDexFileLocation(); + *error_msg += StringPrintf("\noat file '%s' contains contents for '%s'", + oat_file->GetLocation().c_str(), + oat_dex_file->GetDexFileLocation().c_str()); } return false; } @@ -875,116 +890,123 @@ bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file, } if (!image_check) { - std::string image_file(image_header.GetImageRoot( - ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8()); - LOG(WARNING) << "oat file " << oat_file->GetLocation() - << " mismatch (" << std::hex << oat_file->GetOatHeader().GetImageFileLocationOatChecksum() - << ", " << oat_file->GetOatHeader().GetImageFileLocationOatDataBegin() - << ") with " << image_file - << " (" << image_oat_checksum << ", " << std::hex << image_oat_data_begin << ")"; + ScopedObjectAccess soa(Thread::Current()); + mirror::String* oat_location = image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString(); + std::string image_file(oat_location->ToModifiedUtf8()); + *error_msg = StringPrintf("oat file '%s' mismatch (0x%x, %d) with '%s' (0x%x, %d)", + oat_file->GetLocation().c_str(), + oat_file->GetOatHeader().GetImageFileLocationOatChecksum(), + oat_file->GetOatHeader().GetImageFileLocationOatDataBegin(), + image_file.c_str(), image_oat_checksum, image_oat_data_begin); } if (!dex_check) { - LOG(WARNING) << "oat file " << oat_file->GetLocation() - << " mismatch (" << std::hex << oat_dex_file->GetDexFileLocationChecksum() - << ") with " << dex_location - << " (" << std::hex << dex_location_checksum << ")"; + *error_msg = StringPrintf("oat file '%s' mismatch (0x%x) with '%s' (0x%x)", + oat_file->GetLocation().c_str(), + oat_dex_file->GetDexFileLocationChecksum(), + dex_location, dex_location_checksum); } return false; } -const DexFile* ClassLinker::VerifyAndOpenDexFileFromOatFile(const OatFile* oat_file, - const std::string& dex_location, - uint32_t dex_location_checksum) { - bool verified = VerifyOatFileChecksums(oat_file, dex_location, dex_location_checksum); +const DexFile* ClassLinker::VerifyAndOpenDexFileFromOatFile(const std::string& oat_file_location, + const char* dex_location, + std::string* error_msg, + bool* open_failed) { + UniquePtr<const OatFile> oat_file(FindOatFileFromOatLocation(oat_file_location, error_msg)); + if (oat_file.get() == nullptr) { + *open_failed = true; + return nullptr; + } + *open_failed = false; + uint32_t dex_location_checksum; + if (!DexFile::GetChecksum(dex_location, &dex_location_checksum, error_msg)) { + // If no classes.dex found in dex_location, it has been stripped or is corrupt, assume oat is + // up-to-date. This is the common case in user builds for jar's and apk's in the /system + // directory. + const OatFile* opened_oat_file = oat_file.release(); + opened_oat_file = RegisterOatFile(opened_oat_file); + const OatFile::OatDexFile* oat_dex_file = opened_oat_file->GetOatDexFile(dex_location, NULL); + if (oat_dex_file == nullptr) { + *error_msg = StringPrintf("Dex checksum mismatch for location '%s' and failed to find oat " + "dex file '%s': %s", oat_file_location.c_str(), dex_location, + error_msg->c_str()); + return nullptr; + } + return oat_dex_file->OpenDexFile(error_msg); + } + + bool verified = VerifyOatFileChecksums(oat_file.get(), dex_location, dex_location_checksum, + error_msg); if (!verified) { - delete oat_file; - return NULL; + return nullptr; } - RegisterOatFileLocked(*oat_file); - return oat_file->GetOatDexFile(dex_location, &dex_location_checksum)->OpenDexFile(); + const OatFile* opened_oat_file = oat_file.release(); + opened_oat_file = RegisterOatFile(opened_oat_file); + return opened_oat_file->GetOatDexFile(dex_location, + &dex_location_checksum)->OpenDexFile(error_msg); } -const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const std::string& dex_location, - uint32_t dex_location_checksum) { - WriterMutexLock mu(Thread::Current(), dex_lock_); - +const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const char* dex_location, + uint32_t dex_location_checksum, + std::string* error_msg) { const OatFile* open_oat_file = FindOpenedOatFileFromDexLocation(dex_location, dex_location_checksum); - if (open_oat_file != NULL) { - return open_oat_file->GetOatDexFile(dex_location, &dex_location_checksum)->OpenDexFile(); + if (open_oat_file != nullptr) { + const OatFile::OatDexFile* oat_dex_file = open_oat_file->GetOatDexFile(dex_location, + &dex_location_checksum); + return oat_dex_file->OpenDexFile(error_msg); } // Look for an existing file next to dex. for example, for // /foo/bar/baz.jar, look for /foo/bar/baz.odex. std::string odex_filename(OatFile::DexFilenameToOdexFilename(dex_location)); - UniquePtr<const OatFile> oat_file(FindOatFileFromOatLocationLocked(odex_filename)); - if (oat_file.get() != NULL) { - uint32_t dex_location_checksum; - if (!DexFile::GetChecksum(dex_location, &dex_location_checksum)) { - // If no classes.dex found in dex_location, it has been stripped, assume oat is up-to-date. - // This is the common case in user builds for jar's and apk's in the /system directory. - const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, NULL); - CHECK(oat_dex_file != NULL) << odex_filename << " " << dex_location; - RegisterOatFileLocked(*oat_file); - return oat_dex_file->OpenDexFile(); - } - const DexFile* dex_file = VerifyAndOpenDexFileFromOatFile(oat_file.release(), - dex_location, - dex_location_checksum); - if (dex_file != NULL) { - return dex_file; - } - } - // Look for an existing file in the dalvik-cache, validating the result if found - // not found in /foo/bar/baz.odex? try /data/dalvik-cache/foo@bar@baz.jar@classes.dex + bool open_failed; + const DexFile* dex_file = VerifyAndOpenDexFileFromOatFile(odex_filename, dex_location, + error_msg, &open_failed); + if (dex_file != nullptr) { + return dex_file; + } + std::string cache_error_msg; std::string cache_location(GetDalvikCacheFilenameOrDie(dex_location)); - oat_file.reset(FindOatFileFromOatLocationLocked(cache_location)); - if (oat_file.get() != NULL) { - uint32_t dex_location_checksum; - if (!DexFile::GetChecksum(dex_location, &dex_location_checksum)) { - LOG(WARNING) << "Failed to compute checksum: " << dex_location; - return NULL; - } - const DexFile* dex_file = VerifyAndOpenDexFileFromOatFile(oat_file.release(), - dex_location, - dex_location_checksum); - if (dex_file != NULL) { - return dex_file; - } - if (TEMP_FAILURE_RETRY(unlink(cache_location.c_str())) != 0) { - PLOG(FATAL) << "Failed to remove obsolete oat file from " << cache_location; - } + dex_file = VerifyAndOpenDexFileFromOatFile(cache_location, dex_location, &cache_error_msg, + &open_failed); + if (dex_file != nullptr) { + return dex_file; + } + if (!open_failed && TEMP_FAILURE_RETRY(unlink(cache_location.c_str())) != 0) { + PLOG(FATAL) << "Failed to remove obsolete oat file from " << cache_location; } - LOG(INFO) << "Failed to open oat file from " << odex_filename << " or " << cache_location << "."; + VLOG(class_linker) << "Failed to open oat file from " << odex_filename + << " (error '" << *error_msg << "') or " << cache_location + << " (error '" << cache_error_msg << "')."; // Try to generate oat file if it wasn't found or was obsolete. - std::string oat_cache_filename(GetDalvikCacheFilenameOrDie(dex_location)); - return FindOrCreateOatFileForDexLocationLocked(dex_location, dex_location_checksum, oat_cache_filename); + error_msg->clear(); + return FindOrCreateOatFileForDexLocation(dex_location, dex_location_checksum, + cache_location.c_str(), error_msg); } const OatFile* ClassLinker::FindOpenedOatFileFromOatLocation(const std::string& oat_location) { + ReaderMutexLock mu(Thread::Current(), dex_lock_); for (size_t i = 0; i < oat_files_.size(); i++) { const OatFile* oat_file = oat_files_[i]; - DCHECK(oat_file != NULL); + DCHECK(oat_file != nullptr); if (oat_file->GetLocation() == oat_location) { return oat_file; } } - return NULL; -} - -const OatFile* ClassLinker::FindOatFileFromOatLocation(const std::string& oat_location) { - ReaderMutexLock mu(Thread::Current(), dex_lock_); - return FindOatFileFromOatLocationLocked(oat_location); + return nullptr; } -const OatFile* ClassLinker::FindOatFileFromOatLocationLocked(const std::string& oat_location) { +const OatFile* ClassLinker::FindOatFileFromOatLocation(const std::string& oat_location, + std::string* error_msg) { const OatFile* oat_file = FindOpenedOatFileFromOatLocation(oat_location); - if (oat_file != NULL) { + if (oat_file != nullptr) { return oat_file; } - oat_file = OatFile::Open(oat_location, oat_location, NULL, !Runtime::Current()->IsCompiler()); + oat_file = OatFile::Open(oat_location, oat_location, NULL, !Runtime::Current()->IsCompiler(), + error_msg); if (oat_file == NULL) { return NULL; } @@ -1041,12 +1063,15 @@ void ClassLinker::InitFromImage() { for (int32_t i = 0; i < dex_caches->GetLength(); i++) { SirtRef<mirror::DexCache> dex_cache(self, dex_caches->Get(i)); const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8()); - const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(dex_file_location, NULL); + const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(dex_file_location.c_str(), + nullptr); CHECK(oat_dex_file != NULL) << oat_file.GetLocation() << " " << dex_file_location; - const DexFile* dex_file = oat_dex_file->OpenDexFile(); + std::string error_msg; + const DexFile* dex_file = oat_dex_file->OpenDexFile(&error_msg); if (dex_file == NULL) { LOG(FATAL) << "Failed to open dex file " << dex_file_location - << " from within oat file " << oat_file.GetLocation(); + << " from within oat file " << oat_file.GetLocation() + << " error '" << error_msg << "'"; } CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum()); @@ -1510,7 +1535,7 @@ const OatFile::OatClass* ClassLinker::GetOatClass(const DexFile& dex_file, uint1 const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file); CHECK(oat_file != NULL) << dex_file.GetLocation(); uint dex_location_checksum = dex_file.GetLocationChecksum(); - const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation(), + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(), &dex_location_checksum); CHECK(oat_dex_file != NULL) << dex_file.GetLocation(); const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_idx); @@ -2559,7 +2584,7 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass); uint dex_location_checksum = dex_file.GetLocationChecksum(); - const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation(), + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(), &dex_location_checksum); CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass); uint16_t class_def_index = klass->GetDexClassDefIndex(); @@ -4025,7 +4050,7 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, DCHECK(dex_cache != NULL); // Check for hit in the dex cache. mirror::ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx); - if (resolved != NULL) { + if (resolved != NULL && !resolved->IsRuntimeMethod()) { return resolved; } // Fail, get the declaring class. diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 11ba78b..0bc1b5f 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -215,7 +215,7 @@ class ClassLinker { LOCKS_EXCLUDED(dex_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void RegisterOatFile(const OatFile& oat_file) + const OatFile* RegisterOatFile(const OatFile* oat_file) LOCKS_EXCLUDED(dex_lock_); const std::vector<const DexFile*>& GetBootClassPath() { @@ -244,43 +244,37 @@ class ClassLinker { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Generate an oat file from a dex file - bool GenerateOatFile(const std::string& dex_filename, + bool GenerateOatFile(const char* dex_filename, int oat_fd, - const std::string& oat_cache_filename); + const char* oat_cache_filename); + LOCKS_EXCLUDED(Locks::mutator_lock_); - const OatFile* FindOatFileFromOatLocation(const std::string& location) + const OatFile* FindOatFileFromOatLocation(const std::string& location, + std::string* error_msg) LOCKS_EXCLUDED(dex_lock_); - const OatFile* FindOatFileFromOatLocationLocked(const std::string& location) - SHARED_LOCKS_REQUIRED(dex_lock_); - // Finds the oat file for a dex location, generating the oat file if // it is missing or out of date. Returns the DexFile from within the // created oat file. - const DexFile* FindOrCreateOatFileForDexLocation(const std::string& dex_location, + const DexFile* FindOrCreateOatFileForDexLocation(const char* dex_location, uint32_t dex_location_checksum, - const std::string& oat_location) - LOCKS_EXCLUDED(dex_lock_) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const DexFile* FindOrCreateOatFileForDexLocationLocked(const std::string& dex_location, - uint32_t dex_location_checksum, - const std::string& oat_location) - EXCLUSIVE_LOCKS_REQUIRED(dex_lock_) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const char* oat_location, + std::string* error_msg) + LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_); // Find a DexFile within an OatFile given a DexFile location. Note // that this returns null if the location checksum of the DexFile // does not match the OatFile. - const DexFile* FindDexFileInOatFileFromDexLocation(const std::string& location, - uint32_t location_checksum) - LOCKS_EXCLUDED(dex_lock_) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const DexFile* FindDexFileInOatFileFromDexLocation(const char* location, + uint32_t location_checksum, + std::string* error_msg) + LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_); // Returns true if oat file contains the dex file with the given location and checksum. static bool VerifyOatFileChecksums(const OatFile* oat_file, - const std::string& dex_location, - uint32_t dex_location_checksum) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const char* dex_location, + uint32_t dex_location_checksum, + std::string* error_msg); // TODO: replace this with multiple methods that allocate the correct managed type. template <class T> @@ -430,8 +424,6 @@ class ClassLinker { EXCLUSIVE_LOCKS_REQUIRED(dex_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool IsDexFileRegisteredLocked(const DexFile& dex_file) const SHARED_LOCKS_REQUIRED(dex_lock_); - void RegisterOatFileLocked(const OatFile& oat_file) EXCLUSIVE_LOCKS_REQUIRED(dex_lock_) - EXCLUSIVE_LOCKS_REQUIRED(dex_lock_); bool InitializeClass(mirror::Class* klass, bool can_run_clinit, bool can_init_parents) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -493,22 +485,22 @@ class ClassLinker { const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file) LOCKS_EXCLUDED(dex_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const OatFile* FindOpenedOatFileFromDexLocation(const std::string& dex_location, + const OatFile* FindOpenedOatFileFromDexLocation(const char* dex_location, uint32_t dex_location_checksum) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, dex_lock_); + LOCKS_EXCLUDED(dex_lock); const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location) - SHARED_LOCKS_REQUIRED(dex_lock_); - const DexFile* FindDexFileInOatLocation(const std::string& dex_location, + LOCKS_EXCLUDED(dex_lock_); + const DexFile* FindDexFileInOatLocation(const char* dex_location, uint32_t dex_location_checksum, - const std::string& oat_location) - EXCLUSIVE_LOCKS_REQUIRED(dex_lock_) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const char* oat_location, + std::string* error_msg) + LOCKS_EXCLUDED(dex_lock_); - const DexFile* VerifyAndOpenDexFileFromOatFile(const OatFile* oat_file, - const std::string& dex_location, - uint32_t dex_location_checksum) - EXCLUSIVE_LOCKS_REQUIRED(dex_lock_) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const DexFile* VerifyAndOpenDexFileFromOatFile(const std::string& oat_file_location, + const char* dex_location, + std::string* error_msg, + bool* open_failed) + LOCKS_EXCLUDED(dex_lock_); mirror::ArtMethod* CreateProxyConstructor(Thread* self, SirtRef<mirror::Class>& klass, mirror::Class* proxy_class) diff --git a/runtime/common_test.h b/runtime/common_test.h index fe54d03..899eab1 100644 --- a/runtime/common_test.h +++ b/runtime/common_test.h @@ -282,9 +282,12 @@ class CommonTest : public testing::Test { int mkdir_result = mkdir(dalvik_cache_.c_str(), 0700); ASSERT_EQ(mkdir_result, 0); - java_lang_dex_file_ = DexFile::Open(GetLibCoreDexFileName(), GetLibCoreDexFileName()); + std::string error_msg; + java_lang_dex_file_ = DexFile::Open(GetLibCoreDexFileName().c_str(), + GetLibCoreDexFileName().c_str(), &error_msg); if (java_lang_dex_file_ == NULL) { - LOG(FATAL) << "Could not open .dex file '" << GetLibCoreDexFileName() << "'\n"; + LOG(FATAL) << "Could not open .dex file '" << GetLibCoreDexFileName() << "': " + << error_msg << "\n"; } boot_class_path_.push_back(java_lang_dex_file_); @@ -423,8 +426,9 @@ class CommonTest : public testing::Test { filename += "art-test-dex-"; filename += name; filename += ".jar"; - const DexFile* dex_file = DexFile::Open(filename, filename); - CHECK(dex_file != NULL) << "Failed to open " << filename; + std::string error_msg; + const DexFile* dex_file = DexFile::Open(filename.c_str(), filename.c_str(), &error_msg); + CHECK(dex_file != NULL) << "Failed to open '" << filename << "': " << error_msg; CHECK_EQ(PROT_READ, dex_file->GetPermissions()); CHECK(dex_file->IsReadOnly()); opened_dex_files_.push_back(dex_file); @@ -498,10 +502,12 @@ class CommonTest : public testing::Test { void ReserveImageSpace() { // Reserve where the image will be loaded up front so that other parts of test set up don't // accidentally end up colliding with the fixed memory address when we need to load the image. + std::string error_msg; image_reservation_.reset(MemMap::MapAnonymous("image reservation", reinterpret_cast<byte*>(ART_BASE_ADDRESS), (size_t)100 * 1024 * 1024, // 100MB - PROT_NONE)); + PROT_NONE, &error_msg)); + CHECK(image_reservation_.get() != nullptr) << error_msg; } void UnreserveImageSpace() { diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index 189e3ed..0419dab 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -230,6 +230,15 @@ void ThrowIncompatibleClassChangeError(const mirror::Class* referrer, const char va_end(args); } +// IOException + +void ThrowIOException(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + ThrowException(NULL, "Ljava/io/IOException;", NULL, fmt, &args); + va_end(args); +} + // LinkageError void ThrowLinkageError(const mirror::Class* referrer, const char* fmt, ...) { diff --git a/runtime/common_throws.h b/runtime/common_throws.h index 1d77e2d..3164f30 100644 --- a/runtime/common_throws.h +++ b/runtime/common_throws.h @@ -22,10 +22,10 @@ namespace art { namespace mirror { -class ArtField; -class ArtMethod; -class Class; -class Object; + class ArtField; + class ArtMethod; + class Class; + class Object; } // namespace mirror class Signature; class StringPiece; @@ -34,102 +34,110 @@ class ThrowLocation; // AbstractMethodError void ThrowAbstractMethodError(const mirror::ArtMethod* method) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // ArithmeticException -void ThrowArithmeticExceptionDivideByZero() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +void ThrowArithmeticExceptionDivideByZero() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // ArrayIndexOutOfBoundsException void ThrowArrayIndexOutOfBoundsException(int index, int length) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // ArrayStoreException void ThrowArrayStoreException(const mirror::Class* element_class, const mirror::Class* array_class) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // ClassCircularityError -void ThrowClassCircularityError(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +void ThrowClassCircularityError(mirror::Class* c) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // ClassCastException void ThrowClassCastException(const mirror::Class* dest_type, const mirror::Class* src_type) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowClassCastException(const ThrowLocation* throw_location, const char* msg) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // ClassFormatError void ThrowClassFormatError(const mirror::Class* referrer, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // IllegalAccessError void ThrowIllegalAccessErrorClass(mirror::Class* referrer, mirror::Class* accessed) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowIllegalAccessErrorClassForMethodDispatch(mirror::Class* referrer, mirror::Class* accessed, const mirror::ArtMethod* caller, const mirror::ArtMethod* called, InvokeType type) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowIllegalAccessErrorMethod(mirror::Class* referrer, mirror::ArtMethod* accessed) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowIllegalAccessErrorField(mirror::Class* referrer, mirror::ArtField* accessed) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowIllegalAccessErrorFinalField(const mirror::ArtMethod* referrer, mirror::ArtField* accessed) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowIllegalAccessError(mirror::Class* referrer, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // IllegalArgumentException void ThrowIllegalArgumentException(const ThrowLocation* throw_location, const char* msg) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // IncompatibleClassChangeError void ThrowIncompatibleClassChangeError(InvokeType expected_type, InvokeType found_type, mirror::ArtMethod* method, const mirror::ArtMethod* referrer) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(const mirror::ArtMethod* interface_method, mirror::Object* this_object, const mirror::ArtMethod* referrer) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowIncompatibleClassChangeErrorField(const mirror::ArtField* resolved_field, bool is_static, const mirror::ArtMethod* referrer) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowIncompatibleClassChangeError(const mirror::Class* referrer, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; + +// IOException + +void ThrowIOException(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2))) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // LinkageError void ThrowLinkageError(const mirror::Class* referrer, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // NegativeArraySizeException -void ThrowNegativeArraySizeException(int size) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +void ThrowNegativeArraySizeException(int size) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; -void ThrowNegativeArraySizeException(const char* msg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +void ThrowNegativeArraySizeException(const char* msg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // NoSuchFieldError @@ -142,45 +150,45 @@ void ThrowNoSuchFieldError(const StringPiece& scope, mirror::Class* c, void ThrowNoSuchMethodError(InvokeType type, mirror::Class* c, const StringPiece& name, const Signature& signature) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowNoSuchMethodError(uint32_t method_idx) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // NullPointerException void ThrowNullPointerExceptionForFieldAccess(const ThrowLocation& throw_location, mirror::ArtField* field, bool is_read) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowNullPointerExceptionForMethodAccess(const ThrowLocation& throw_location, uint32_t method_idx, InvokeType type) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowNullPointerExceptionForMethodAccess(const ThrowLocation& throw_location, mirror::ArtMethod* method, InvokeType type) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowNullPointerExceptionFromDexPC(const ThrowLocation& throw_location) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowNullPointerException(const ThrowLocation* throw_location, const char* msg) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // RuntimeException void ThrowRuntimeException(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2))) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // VerifyError void ThrowVerifyError(const mirror::Class* referrer, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; } // namespace art diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index ac133a3..a0f5601 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -62,72 +62,77 @@ DexFile::ClassPathEntry DexFile::FindInClassPath(const char* descriptor, reinterpret_cast<const DexFile::ClassDef*>(NULL)); } -int OpenAndReadMagic(const std::string& filename, uint32_t* magic) { +static int OpenAndReadMagic(const char* filename, uint32_t* magic, std::string* error_msg) { CHECK(magic != NULL); - int fd = open(filename.c_str(), O_RDONLY, 0); + int fd = open(filename, O_RDONLY, 0); if (fd == -1) { - PLOG(WARNING) << "Unable to open '" << filename << "'"; + *error_msg = StringPrintf("Unable to open '%s' : %s", filename, strerror(errno)); return -1; } int n = TEMP_FAILURE_RETRY(read(fd, magic, sizeof(*magic))); if (n != sizeof(*magic)) { - PLOG(ERROR) << "Failed to find magic in '" << filename << "'"; + *error_msg = StringPrintf("Failed to find magic in '%s'", filename); return -1; } if (lseek(fd, 0, SEEK_SET) != 0) { - PLOG(ERROR) << "Failed to seek to beginning of file '" << filename << "'"; + *error_msg = StringPrintf("Failed to seek to beginning of file '%s' : %s", filename, + strerror(errno)); return -1; } return fd; } -bool DexFile::GetChecksum(const std::string& filename, uint32_t* checksum) { +bool DexFile::GetChecksum(const char* filename, uint32_t* checksum, std::string* error_msg) { CHECK(checksum != NULL); uint32_t magic; - int fd = OpenAndReadMagic(filename, &magic); + int fd = OpenAndReadMagic(filename, &magic, error_msg); if (fd == -1) { + DCHECK(!error_msg->empty()); return false; } if (IsZipMagic(magic)) { - UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd)); + UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, filename, error_msg)); if (zip_archive.get() == NULL) { + *error_msg = StringPrintf("Failed to open zip archive '%s'", filename); return false; } UniquePtr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex)); if (zip_entry.get() == NULL) { - LOG(ERROR) << "Zip archive '" << filename << "' doesn't contain " << kClassesDex; + *error_msg = StringPrintf("Zip archive '%s' doesn\'t contain %s", filename, kClassesDex); return false; } *checksum = zip_entry->GetCrc32(); return true; } if (IsDexMagic(magic)) { - UniquePtr<const DexFile> dex_file(DexFile::OpenFile(fd, filename, false)); + UniquePtr<const DexFile> dex_file(DexFile::OpenFile(fd, filename, false, error_msg)); if (dex_file.get() == NULL) { return false; } *checksum = dex_file->GetHeader().checksum_; return true; } - LOG(ERROR) << "Expected valid zip or dex file: " << filename; + *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename); return false; } -const DexFile* DexFile::Open(const std::string& filename, - const std::string& location) { +const DexFile* DexFile::Open(const char* filename, + const char* location, + std::string* error_msg) { uint32_t magic; - int fd = OpenAndReadMagic(filename, &magic); + int fd = OpenAndReadMagic(filename, &magic, error_msg); if (fd == -1) { + DCHECK(!error_msg->empty()); return NULL; } if (IsZipMagic(magic)) { - return DexFile::OpenZip(fd, location); + return DexFile::OpenZip(fd, location, error_msg); } if (IsDexMagic(magic)) { - return DexFile::OpenFile(fd, location, true); + return DexFile::OpenFile(fd, location, true, error_msg); } - LOG(ERROR) << "Expected valid zip or dex file: " << filename; - return NULL; + *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename); + return nullptr; } int DexFile::GetPermissions() const { @@ -160,46 +165,48 @@ bool DexFile::DisableWrite() const { } } -const DexFile* DexFile::OpenFile(int fd, - const std::string& location, - bool verify) { - CHECK(!location.empty()); +const DexFile* DexFile::OpenFile(int fd, const char* location, bool verify, + std::string* error_msg) { + CHECK(location != nullptr); struct stat sbuf; memset(&sbuf, 0, sizeof(sbuf)); if (fstat(fd, &sbuf) == -1) { - PLOG(ERROR) << "fstat \"" << location << "\" failed"; + *error_msg = StringPrintf("DexFile: fstat \'%s\' failed: %s", location, strerror(errno)); close(fd); - return NULL; + return nullptr; } if (S_ISDIR(sbuf.st_mode)) { - LOG(ERROR) << "attempt to mmap directory \"" << location << "\""; - return NULL; + *error_msg = StringPrintf("Attempt to mmap directory '%s'", location); + return nullptr; } size_t length = sbuf.st_size; - UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ, MAP_PRIVATE, fd, 0)); - if (map.get() == NULL) { - LOG(ERROR) << "mmap \"" << location << "\" failed"; + UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ, MAP_PRIVATE, fd, 0, location, + error_msg)); + if (map.get() == nullptr) { + DCHECK(!error_msg->empty()); close(fd); - return NULL; + return nullptr; } close(fd); if (map->Size() < sizeof(DexFile::Header)) { - LOG(ERROR) << "Failed to open dex file '" << location << "' that is too short to have a header"; - return NULL; + *error_msg = StringPrintf( + "DexFile: failed to open dex file \'%s\' that is too short to have a header", location); + return nullptr; } const Header* dex_header = reinterpret_cast<const Header*>(map->Begin()); - const DexFile* dex_file = OpenMemory(location, dex_header->checksum_, map.release()); - if (dex_file == NULL) { - LOG(ERROR) << "Failed to open dex file '" << location << "' from memory"; - return NULL; + const DexFile* dex_file = OpenMemory(location, dex_header->checksum_, map.release(), error_msg); + if (dex_file == nullptr) { + *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location, + error_msg->c_str()); + return nullptr; } - if (verify && !DexFileVerifier::Verify(dex_file, dex_file->Begin(), dex_file->Size())) { - LOG(ERROR) << "Failed to verify dex file '" << location << "'"; - return NULL; + if (verify && !DexFileVerifier::Verify(dex_file, dex_file->Begin(), dex_file->Size(), location, + error_msg)) { + return nullptr; } return dex_file; @@ -207,49 +214,55 @@ const DexFile* DexFile::OpenFile(int fd, const char* DexFile::kClassesDex = "classes.dex"; -const DexFile* DexFile::OpenZip(int fd, const std::string& location) { - UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd)); - if (zip_archive.get() == NULL) { - LOG(ERROR) << "Failed to open " << location << " when looking for classes.dex"; - return NULL; +const DexFile* DexFile::OpenZip(int fd, const std::string& location, std::string* error_msg) { + UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg)); + if (zip_archive.get() == nullptr) { + DCHECK(!error_msg->empty()); + return nullptr; } - return DexFile::Open(*zip_archive.get(), location); + return DexFile::Open(*zip_archive.get(), location, error_msg); } const DexFile* DexFile::OpenMemory(const std::string& location, uint32_t location_checksum, - MemMap* mem_map) { + MemMap* mem_map, + std::string* error_msg) { return OpenMemory(mem_map->Begin(), mem_map->Size(), location, location_checksum, - mem_map); + mem_map, + error_msg); } -const DexFile* DexFile::Open(const ZipArchive& zip_archive, const std::string& location) { +const DexFile* DexFile::Open(const ZipArchive& zip_archive, const std::string& location, + std::string* error_msg) { CHECK(!location.empty()); UniquePtr<ZipEntry> zip_entry(zip_archive.Find(kClassesDex)); if (zip_entry.get() == NULL) { - LOG(ERROR) << "Failed to find classes.dex within '" << location << "'"; - return NULL; + *error_msg = StringPrintf("Failed to find classes.dex within '%s'", location.c_str()); + return nullptr; } - UniquePtr<MemMap> map(zip_entry->ExtractToMemMap(kClassesDex)); + UniquePtr<MemMap> map(zip_entry->ExtractToMemMap(kClassesDex, error_msg)); if (map.get() == NULL) { - LOG(ERROR) << "Failed to extract '" << kClassesDex << "' from '" << location << "'"; - return NULL; + *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", kClassesDex, location.c_str(), + error_msg->c_str()); + return nullptr; } - UniquePtr<const DexFile> dex_file(OpenMemory(location, zip_entry->GetCrc32(), map.release())); - if (dex_file.get() == NULL) { - LOG(ERROR) << "Failed to open dex file '" << location << "' from memory"; - return NULL; + UniquePtr<const DexFile> dex_file(OpenMemory(location, zip_entry->GetCrc32(), map.release(), + error_msg)); + if (dex_file.get() == nullptr) { + *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(), + error_msg->c_str()); + return nullptr; } - if (!DexFileVerifier::Verify(dex_file.get(), dex_file->Begin(), dex_file->Size())) { - LOG(ERROR) << "Failed to verify dex file '" << location << "'"; - return NULL; + if (!DexFileVerifier::Verify(dex_file.get(), dex_file->Begin(), dex_file->Size(), + location.c_str(), error_msg)) { + return nullptr; } if (!dex_file->DisableWrite()) { - LOG(ERROR) << "Failed to make dex file read only '" << location << "'"; - return NULL; + *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str()); + return nullptr; } CHECK(dex_file->IsReadOnly()) << location; return dex_file.release(); @@ -259,11 +272,11 @@ const DexFile* DexFile::OpenMemory(const byte* base, size_t size, const std::string& location, uint32_t location_checksum, - MemMap* mem_map) { + MemMap* mem_map, std::string* error_msg) { CHECK_ALIGNED(base, 4); // various dex file structures must be word aligned UniquePtr<DexFile> dex_file(new DexFile(base, size, location, location_checksum, mem_map)); - if (!dex_file->Init()) { - return NULL; + if (!dex_file->Init(error_msg)) { + return nullptr; } else { return dex_file.release(); } @@ -276,9 +289,9 @@ DexFile::~DexFile() { // the global reference table is otherwise empty! } -bool DexFile::Init() { +bool DexFile::Init(std::string* error_msg) { InitMembers(); - if (!CheckMagicAndVersion()) { + if (!CheckMagicAndVersion(error_msg)) { return false; } return true; @@ -296,22 +309,26 @@ void DexFile::InitMembers() { class_defs_ = reinterpret_cast<const ClassDef*>(b + h->class_defs_off_); } -bool DexFile::CheckMagicAndVersion() const { +bool DexFile::CheckMagicAndVersion(std::string* error_msg) const { CHECK(header_->magic_ != NULL) << GetLocation(); if (!IsMagicValid(header_->magic_)) { - LOG(ERROR) << "Unrecognized magic number in " << GetLocation() << ":" + std::ostringstream oss; + oss << "Unrecognized magic number in " << GetLocation() << ":" << " " << header_->magic_[0] << " " << header_->magic_[1] << " " << header_->magic_[2] << " " << header_->magic_[3]; + *error_msg = oss.str(); return false; } if (!IsVersionValid(header_->magic_)) { - LOG(ERROR) << "Unrecognized version number in " << GetLocation() << ":" + std::ostringstream oss; + oss << "Unrecognized version number in " << GetLocation() << ":" << " " << header_->magic_[4] << " " << header_->magic_[5] << " " << header_->magic_[6] << " " << header_->magic_[7]; + *error_msg = oss.str(); return false; } return true; diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 12e8440..035a691 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -350,22 +350,22 @@ class DexFile { // For .dex files, this is the header checksum. // For zip files, this is the classes.dex zip entry CRC32 checksum. // Return true if the checksum could be found, false otherwise. - static bool GetChecksum(const std::string& filename, uint32_t* checksum) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + static bool GetChecksum(const char* filename, uint32_t* checksum, std::string* error_msg); // Opens .dex file, guessing the container format based on file extension - static const DexFile* Open(const std::string& filename, - const std::string& location); + static const DexFile* Open(const char* filename, const char* location, std::string* error_msg); // Opens .dex file, backed by existing memory static const DexFile* Open(const uint8_t* base, size_t size, const std::string& location, - uint32_t location_checksum) { - return OpenMemory(base, size, location, location_checksum, NULL); + uint32_t location_checksum, + std::string* error_msg) { + return OpenMemory(base, size, location, location_checksum, NULL, error_msg); } // Opens .dex file from the classes.dex in a zip archive - static const DexFile* Open(const ZipArchive& zip_archive, const std::string& location); + static const DexFile* Open(const ZipArchive& zip_archive, const std::string& location, + std::string* error_msg); // Closes a .dex file. virtual ~DexFile(); @@ -820,24 +820,24 @@ class DexFile { private: // Opens a .dex file - static const DexFile* OpenFile(int fd, - const std::string& location, - bool verify); + static const DexFile* OpenFile(int fd, const char* location, bool verify, std::string* error_msg); // Opens a dex file from within a .jar, .zip, or .apk file - static const DexFile* OpenZip(int fd, const std::string& location); + static const DexFile* OpenZip(int fd, const std::string& location, std::string* error_msg); // Opens a .dex file at the given address backed by a MemMap static const DexFile* OpenMemory(const std::string& location, uint32_t location_checksum, - MemMap* mem_map); + MemMap* mem_map, + std::string* error_msg); // Opens a .dex file at the given address, optionally backed by a MemMap static const DexFile* OpenMemory(const byte* dex_file, size_t size, const std::string& location, uint32_t location_checksum, - MemMap* mem_map); + MemMap* mem_map, + std::string* error_msg); DexFile(const byte* base, size_t size, const std::string& location, @@ -861,13 +861,13 @@ class DexFile { } // Top-level initializer that calls other Init methods. - bool Init(); + bool Init(std::string* error_msg); // Caches pointers into to the various file sections. void InitMembers(); // Returns true if the header magic and version numbers are of the expected values. - bool CheckMagicAndVersion() const; + bool CheckMagicAndVersion(std::string* error_msg) const; void DecodeDebugInfo0(const CodeItem* code_item, bool is_static, uint32_t method_idx, DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb, diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc index 7575d4a..543a7b0 100644 --- a/runtime/dex_file_test.cc +++ b/runtime/dex_file_test.cc @@ -56,7 +56,7 @@ static const char kRawDex[] = "AAMgAAACAAAAiAIAAAQgAAADAAAAlAIAAAAgAAACAAAAqwIAAAAQAAABAAAAxAIAAA=="; static const DexFile* OpenDexFileBase64(const char* base64, - const std::string& location) { + const char* location) { // decode base64 CHECK(base64 != NULL); size_t length; @@ -64,7 +64,7 @@ static const DexFile* OpenDexFileBase64(const char* base64, CHECK(dex_bytes.get() != NULL); // write to provided file - UniquePtr<File> file(OS::CreateEmptyFile(location.c_str())); + UniquePtr<File> file(OS::CreateEmptyFile(location)); CHECK(file.get() != NULL); if (!file->WriteFully(dex_bytes.get(), length)) { PLOG(FATAL) << "Failed to write base64 as dex file"; @@ -73,8 +73,9 @@ static const DexFile* OpenDexFileBase64(const char* base64, // read dex file ScopedObjectAccess soa(Thread::Current()); - const DexFile* dex_file = DexFile::Open(location, location); - CHECK(dex_file != NULL); + std::string error_msg; + const DexFile* dex_file = DexFile::Open(location, location, &error_msg); + CHECK(dex_file != nullptr) << error_msg; EXPECT_EQ(PROT_READ, dex_file->GetPermissions()); EXPECT_TRUE(dex_file->IsReadOnly()); return dex_file; @@ -82,7 +83,7 @@ static const DexFile* OpenDexFileBase64(const char* base64, TEST_F(DexFileTest, Header) { ScratchFile tmp; - UniquePtr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename())); + UniquePtr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename().c_str())); ASSERT_TRUE(raw.get() != NULL); const DexFile::Header& header = raw->GetHeader(); @@ -120,7 +121,9 @@ TEST_F(DexFileTest, GetLocationChecksum) { TEST_F(DexFileTest, GetChecksum) { uint32_t checksum; ScopedObjectAccess soa(Thread::Current()); - EXPECT_TRUE(DexFile::GetChecksum(GetLibCoreDexFileName(), &checksum)); + std::string error_msg; + EXPECT_TRUE(DexFile::GetChecksum(GetLibCoreDexFileName().c_str(), &checksum, &error_msg)) + << error_msg; EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksum); } diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc index 7dc2b31..56bf21d 100644 --- a/runtime/dex_file_verifier.cc +++ b/runtime/dex_file_verifier.cc @@ -65,12 +65,22 @@ static bool IsDataSectionType(uint32_t map_type) { return true; } -static bool CheckShortyDescriptorMatch(char shorty_char, const char* descriptor, - bool is_return_type) { +bool DexFileVerifier::Verify(const DexFile* dex_file, const byte* begin, size_t size, + const char* location, std::string* error_msg) { + UniquePtr<DexFileVerifier> verifier(new DexFileVerifier(dex_file, begin, size, location)); + if (!verifier->Verify()) { + *error_msg = verifier->FailureReason(); + return false; + } + return true; +} + +bool DexFileVerifier::CheckShortyDescriptorMatch(char shorty_char, const char* descriptor, + bool is_return_type) { switch (shorty_char) { case 'V': - if (!is_return_type) { - LOG(ERROR) << "Invalid use of void"; + if (UNLIKELY(!is_return_type)) { + ErrorStringPrintf("Invalid use of void"); return false; } // Intentional fallthrough. @@ -82,62 +92,58 @@ static bool CheckShortyDescriptorMatch(char shorty_char, const char* descriptor, case 'J': case 'S': case 'Z': - if ((descriptor[0] != shorty_char) || (descriptor[1] != '\0')) { - LOG(ERROR) << StringPrintf("Shorty vs. primitive type mismatch: '%c', '%s'", shorty_char, descriptor); + if (UNLIKELY((descriptor[0] != shorty_char) || (descriptor[1] != '\0'))) { + ErrorStringPrintf("Shorty vs. primitive type mismatch: '%c', '%s'", + shorty_char, descriptor); return false; } break; case 'L': - if ((descriptor[0] != 'L') && (descriptor[0] != '[')) { - LOG(ERROR) << StringPrintf("Shorty vs. type mismatch: '%c', '%s'", shorty_char, descriptor); + if (UNLIKELY((descriptor[0] != 'L') && (descriptor[0] != '['))) { + ErrorStringPrintf("Shorty vs. type mismatch: '%c', '%s'", shorty_char, descriptor); return false; } break; default: - LOG(ERROR) << "Bad shorty character: '" << shorty_char << "'"; + ErrorStringPrintf("Bad shorty character: '%c'", shorty_char); return false; } return true; } -bool DexFileVerifier::Verify(const DexFile* dex_file, const byte* begin, size_t size) { - UniquePtr<DexFileVerifier> verifier(new DexFileVerifier(dex_file, begin, size)); - return verifier->Verify(); -} - -bool DexFileVerifier::CheckPointerRange(const void* start, const void* end, const char* label) const { +bool DexFileVerifier::CheckPointerRange(const void* start, const void* end, const char* label) { uint32_t range_start = reinterpret_cast<uint32_t>(start); uint32_t range_end = reinterpret_cast<uint32_t>(end); uint32_t file_start = reinterpret_cast<uint32_t>(begin_); uint32_t file_end = file_start + size_; - if ((range_start < file_start) || (range_start > file_end) || - (range_end < file_start) || (range_end > file_end)) { - LOG(ERROR) << StringPrintf("Bad range for %s: %x to %x", label, - range_start - file_start, range_end - file_start); + if (UNLIKELY((range_start < file_start) || (range_start > file_end) || + (range_end < file_start) || (range_end > file_end))) { + ErrorStringPrintf("Bad range for %s: %x to %x", label, + range_start - file_start, range_end - file_start); return false; } return true; } bool DexFileVerifier::CheckListSize(const void* start, uint32_t count, - uint32_t element_size, const char* label) const { + uint32_t element_size, const char* label) { const byte* list_start = reinterpret_cast<const byte*>(start); return CheckPointerRange(list_start, list_start + (count * element_size), label); } -bool DexFileVerifier::CheckIndex(uint32_t field, uint32_t limit, const char* label) const { - if (field >= limit) { - LOG(ERROR) << StringPrintf("Bad index for %s: %x >= %x", label, field, limit); +bool DexFileVerifier::CheckIndex(uint32_t field, uint32_t limit, const char* label) { + if (UNLIKELY(field >= limit)) { + ErrorStringPrintf("Bad index for %s: %x >= %x", label, field, limit); return false; } return true; } -bool DexFileVerifier::CheckHeader() const { +bool DexFileVerifier::CheckHeader() { // Check file size from the header. uint32_t expected_size = header_->file_size_; if (size_ != expected_size) { - LOG(ERROR) << "Bad file size (" << size_ << ", expected " << expected_size << ")"; + ErrorStringPrintf("Bad file size (%zd, expected %ud)", size_, expected_size); return false; } @@ -147,25 +153,25 @@ bool DexFileVerifier::CheckHeader() const { const byte* non_sum_ptr = reinterpret_cast<const byte*>(header_) + non_sum; adler_checksum = adler32(adler_checksum, non_sum_ptr, expected_size - non_sum); if (adler_checksum != header_->checksum_) { - LOG(ERROR) << StringPrintf("Bad checksum (%08x, expected %08x)", adler_checksum, header_->checksum_); + ErrorStringPrintf("Bad checksum (%08x, expected %08x)", adler_checksum, header_->checksum_); return false; } // Check the contents of the header. if (header_->endian_tag_ != DexFile::kDexEndianConstant) { - LOG(ERROR) << StringPrintf("Unexpected endian_tag: %x", header_->endian_tag_); + ErrorStringPrintf("Unexpected endian_tag: %x", header_->endian_tag_); return false; } if (header_->header_size_ != sizeof(DexFile::Header)) { - LOG(ERROR) << "Bad header size: " << header_->header_size_; + ErrorStringPrintf("Bad header size: %ud", header_->header_size_); return false; } return true; } -bool DexFileVerifier::CheckMap() const { +bool DexFileVerifier::CheckMap() { const DexFile::MapList* map = reinterpret_cast<const DexFile::MapList*>(begin_ + header_->map_off_); const DexFile::MapItem* item = map->list_; @@ -182,19 +188,20 @@ bool DexFileVerifier::CheckMap() const { // Check the items listed in the map. for (uint32_t i = 0; i < count; i++) { - if (last_offset >= item->offset_ && i != 0) { - LOG(ERROR) << StringPrintf("Out of order map item: %x then %x", last_offset, item->offset_); + if (UNLIKELY(last_offset >= item->offset_ && i != 0)) { + ErrorStringPrintf("Out of order map item: %x then %x", last_offset, item->offset_); return false; } - if (item->offset_ >= header_->file_size_) { - LOG(ERROR) << StringPrintf("Map item after end of file: %x, size %x", item->offset_, header_->file_size_); + if (UNLIKELY(item->offset_ >= header_->file_size_)) { + ErrorStringPrintf("Map item after end of file: %x, size %x", + item->offset_, header_->file_size_); return false; } if (IsDataSectionType(item->type_)) { uint32_t icount = item->size_; - if (icount > data_items_left) { - LOG(ERROR) << "Too many items in data section: " << data_item_count + icount; + if (UNLIKELY(icount > data_items_left)) { + ErrorStringPrintf("Too many items in data section: %ud", data_item_count + icount); return false; } data_items_left -= icount; @@ -203,13 +210,13 @@ bool DexFileVerifier::CheckMap() const { uint32_t bit = MapTypeToBitMask(item->type_); - if (bit == 0) { - LOG(ERROR) << StringPrintf("Unknown map section type %x", item->type_); + if (UNLIKELY(bit == 0)) { + ErrorStringPrintf("Unknown map section type %x", item->type_); return false; } - if ((used_bits & bit) != 0) { - LOG(ERROR) << StringPrintf("Duplicate map section of type %x", item->type_); + if (UNLIKELY((used_bits & bit) != 0)) { + ErrorStringPrintf("Duplicate map section of type %x", item->type_); return false; } @@ -219,63 +226,59 @@ bool DexFileVerifier::CheckMap() const { } // Check for missing sections in the map. - if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeHeaderItem)) == 0) { - LOG(ERROR) << "Map is missing header entry"; + if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeHeaderItem)) == 0)) { + ErrorStringPrintf("Map is missing header entry"); return false; } - if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeMapList)) == 0) { - LOG(ERROR) << "Map is missing map_list entry"; + if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeMapList)) == 0)) { + ErrorStringPrintf("Map is missing map_list entry"); return false; } - if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeStringIdItem)) == 0 && - ((header_->string_ids_off_ != 0) || (header_->string_ids_size_ != 0))) { - LOG(ERROR) << "Map is missing string_ids entry"; + if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeStringIdItem)) == 0 && + ((header_->string_ids_off_ != 0) || (header_->string_ids_size_ != 0)))) { + ErrorStringPrintf("Map is missing string_ids entry"); return false; } - if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeTypeIdItem)) == 0 && - ((header_->type_ids_off_ != 0) || (header_->type_ids_size_ != 0))) { - LOG(ERROR) << "Map is missing type_ids entry"; + if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeTypeIdItem)) == 0 && + ((header_->type_ids_off_ != 0) || (header_->type_ids_size_ != 0)))) { + ErrorStringPrintf("Map is missing type_ids entry"); return false; } - if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeProtoIdItem)) == 0 && - ((header_->proto_ids_off_ != 0) || (header_->proto_ids_size_ != 0))) { - LOG(ERROR) << "Map is missing proto_ids entry"; + if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeProtoIdItem)) == 0 && + ((header_->proto_ids_off_ != 0) || (header_->proto_ids_size_ != 0)))) { + ErrorStringPrintf("Map is missing proto_ids entry"); return false; } - if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeFieldIdItem)) == 0 && - ((header_->field_ids_off_ != 0) || (header_->field_ids_size_ != 0))) { - LOG(ERROR) << "Map is missing field_ids entry"; + if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeFieldIdItem)) == 0 && + ((header_->field_ids_off_ != 0) || (header_->field_ids_size_ != 0)))) { + ErrorStringPrintf("Map is missing field_ids entry"); return false; } - if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeMethodIdItem)) == 0 && - ((header_->method_ids_off_ != 0) || (header_->method_ids_size_ != 0))) { - LOG(ERROR) << "Map is missing method_ids entry"; + if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeMethodIdItem)) == 0 && + ((header_->method_ids_off_ != 0) || (header_->method_ids_size_ != 0)))) { + ErrorStringPrintf("Map is missing method_ids entry"); return false; } - if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeClassDefItem)) == 0 && - ((header_->class_defs_off_ != 0) || (header_->class_defs_size_ != 0))) { - LOG(ERROR) << "Map is missing class_defs entry"; + if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeClassDefItem)) == 0 && + ((header_->class_defs_off_ != 0) || (header_->class_defs_size_ != 0)))) { + ErrorStringPrintf("Map is missing class_defs entry"); return false; } - return true; } uint32_t DexFileVerifier::ReadUnsignedLittleEndian(uint32_t size) { uint32_t result = 0; - if (!CheckPointerRange(ptr_, ptr_ + size, "encoded_value")) { - return 0; - } - - for (uint32_t i = 0; i < size; i++) { - result |= ((uint32_t) *(ptr_++)) << (i * 8); + if (LIKELY(CheckPointerRange(ptr_, ptr_ + size, "encoded_value"))) { + for (uint32_t i = 0; i < size; i++) { + result |= ((uint32_t) *(ptr_++)) << (i * 8); + } } - return result; } bool DexFileVerifier::CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_item, - uint32_t* handler_offsets, uint32_t handlers_size) { + uint32_t* handler_offsets, uint32_t handlers_size) { const byte* handlers_base = DexFile::GetCatchHandlerData(*code_item, 0); for (uint32_t i = 0; i < handlers_size; i++) { @@ -283,8 +286,8 @@ bool DexFileVerifier::CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_it uint32_t offset = reinterpret_cast<uint32_t>(ptr_) - reinterpret_cast<uint32_t>(handlers_base); int32_t size = DecodeSignedLeb128(&ptr_); - if ((size < -65536) || (size > 65536)) { - LOG(ERROR) << "Invalid exception handler size: " << size; + if (UNLIKELY((size < -65536) || (size > 65536))) { + ErrorStringPrintf("Invalid exception handler size: %d", size); return false; } @@ -304,16 +307,16 @@ bool DexFileVerifier::CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_it } uint32_t addr = DecodeUnsignedLeb128(&ptr_); - if (addr >= code_item->insns_size_in_code_units_) { - LOG(ERROR) << StringPrintf("Invalid handler addr: %x", addr); + if (UNLIKELY(addr >= code_item->insns_size_in_code_units_)) { + ErrorStringPrintf("Invalid handler addr: %x", addr); return false; } } if (catch_all) { uint32_t addr = DecodeUnsignedLeb128(&ptr_); - if (addr >= code_item->insns_size_in_code_units_) { - LOG(ERROR) << StringPrintf("Invalid handler catch_all_addr: %x", addr); + if (UNLIKELY(addr >= code_item->insns_size_in_code_units_)) { + ErrorStringPrintf("Invalid handler catch_all_addr: %x", addr); return false; } } @@ -323,21 +326,21 @@ bool DexFileVerifier::CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_it } bool DexFileVerifier::CheckClassDataItemField(uint32_t idx, uint32_t access_flags, - bool expect_static) const { + bool expect_static) { if (!CheckIndex(idx, header_->field_ids_size_, "class_data_item field_idx")) { return false; } bool is_static = (access_flags & kAccStatic) != 0; - if (is_static != expect_static) { - LOG(ERROR) << "Static/instance field not in expected list"; + if (UNLIKELY(is_static != expect_static)) { + ErrorStringPrintf("Static/instance field not in expected list"); return false; } uint32_t access_field_mask = kAccPublic | kAccPrivate | kAccProtected | kAccStatic | kAccFinal | kAccVolatile | kAccTransient | kAccSynthetic | kAccEnum; - if ((access_flags & ~access_field_mask) != 0) { - LOG(ERROR) << StringPrintf("Bad class_data_item field access_flags %x", access_flags); + if (UNLIKELY((access_flags & ~access_field_mask) != 0)) { + ErrorStringPrintf("Bad class_data_item field access_flags %x", access_flags); return false; } @@ -345,7 +348,7 @@ bool DexFileVerifier::CheckClassDataItemField(uint32_t idx, uint32_t access_flag } bool DexFileVerifier::CheckClassDataItemMethod(uint32_t idx, uint32_t access_flags, - uint32_t code_offset, bool expect_direct) const { + uint32_t code_offset, bool expect_direct) { if (!CheckIndex(idx, header_->method_ids_size_, "class_data_item method_idx")) { return false; } @@ -355,26 +358,27 @@ bool DexFileVerifier::CheckClassDataItemMethod(uint32_t idx, uint32_t access_fla bool is_synchronized = (access_flags & kAccSynchronized) != 0; bool allow_synchronized = (access_flags & kAccNative) != 0; - if (is_direct != expect_direct) { - LOG(ERROR) << "Direct/virtual method not in expected list"; + if (UNLIKELY(is_direct != expect_direct)) { + ErrorStringPrintf("Direct/virtual method not in expected list"); return false; } uint32_t access_method_mask = kAccPublic | kAccPrivate | kAccProtected | kAccStatic | kAccFinal | kAccSynchronized | kAccBridge | kAccVarargs | kAccNative | kAccAbstract | kAccStrict | kAccSynthetic | kAccConstructor | kAccDeclaredSynchronized; - if (((access_flags & ~access_method_mask) != 0) || (is_synchronized && !allow_synchronized)) { - LOG(ERROR) << StringPrintf("Bad class_data_item method access_flags %x", access_flags); + if (UNLIKELY(((access_flags & ~access_method_mask) != 0) || + (is_synchronized && !allow_synchronized))) { + ErrorStringPrintf("Bad class_data_item method access_flags %x", access_flags); return false; } - if (expect_code && code_offset == 0) { - LOG(ERROR)<< StringPrintf("Unexpected zero value for class_data_item method code_off" - " with access flags %x", access_flags); + if (UNLIKELY(expect_code && (code_offset == 0))) { + ErrorStringPrintf("Unexpected zero value for class_data_item method code_off with access " + "flags %x", access_flags); return false; - } else if (!expect_code && code_offset != 0) { - LOG(ERROR) << StringPrintf("Unexpected non-zero value %x for class_data_item method code_off" - " with access flags %x", code_offset, access_flags); + } else if (UNLIKELY(!expect_code && (code_offset != 0))) { + ErrorStringPrintf("Unexpected non-zero value %x for class_data_item method code_off" + " with access flags %x", code_offset, access_flags); return false; } @@ -387,8 +391,8 @@ bool DexFileVerifier::CheckPadding(uint32_t offset, uint32_t aligned_offset) { return false; } while (offset < aligned_offset) { - if (*ptr_ != '\0') { - LOG(ERROR) << StringPrintf("Non-zero padding %x before section start at %x", *ptr_, offset); + if (UNLIKELY(*ptr_ != '\0')) { + ErrorStringPrintf("Non-zero padding %x before section start at %x", *ptr_, offset); return false; } ptr_++; @@ -409,24 +413,24 @@ bool DexFileVerifier::CheckEncodedValue() { switch (value_type) { case DexFile::kDexAnnotationByte: - if (value_arg != 0) { - LOG(ERROR) << StringPrintf("Bad encoded_value byte size %x", value_arg); + if (UNLIKELY(value_arg != 0)) { + ErrorStringPrintf("Bad encoded_value byte size %x", value_arg); return false; } ptr_++; break; case DexFile::kDexAnnotationShort: case DexFile::kDexAnnotationChar: - if (value_arg > 1) { - LOG(ERROR) << StringPrintf("Bad encoded_value char/short size %x", value_arg); + if (UNLIKELY(value_arg > 1)) { + ErrorStringPrintf("Bad encoded_value char/short size %x", value_arg); return false; } ptr_ += value_arg + 1; break; case DexFile::kDexAnnotationInt: case DexFile::kDexAnnotationFloat: - if (value_arg > 3) { - LOG(ERROR) << StringPrintf("Bad encoded_value int/float size %x", value_arg); + if (UNLIKELY(value_arg > 3)) { + ErrorStringPrintf("Bad encoded_value int/float size %x", value_arg); return false; } ptr_ += value_arg + 1; @@ -436,8 +440,8 @@ bool DexFileVerifier::CheckEncodedValue() { ptr_ += value_arg + 1; break; case DexFile::kDexAnnotationString: { - if (value_arg > 3) { - LOG(ERROR) << StringPrintf("Bad encoded_value string size %x", value_arg); + if (UNLIKELY(value_arg > 3)) { + ErrorStringPrintf("Bad encoded_value string size %x", value_arg); return false; } uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1); @@ -447,8 +451,8 @@ bool DexFileVerifier::CheckEncodedValue() { break; } case DexFile::kDexAnnotationType: { - if (value_arg > 3) { - LOG(ERROR) << StringPrintf("Bad encoded_value type size %x", value_arg); + if (UNLIKELY(value_arg > 3)) { + ErrorStringPrintf("Bad encoded_value type size %x", value_arg); return false; } uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1); @@ -459,8 +463,8 @@ bool DexFileVerifier::CheckEncodedValue() { } case DexFile::kDexAnnotationField: case DexFile::kDexAnnotationEnum: { - if (value_arg > 3) { - LOG(ERROR) << StringPrintf("Bad encoded_value field/enum size %x", value_arg); + if (UNLIKELY(value_arg > 3)) { + ErrorStringPrintf("Bad encoded_value field/enum size %x", value_arg); return false; } uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1); @@ -470,8 +474,8 @@ bool DexFileVerifier::CheckEncodedValue() { break; } case DexFile::kDexAnnotationMethod: { - if (value_arg > 3) { - LOG(ERROR) << StringPrintf("Bad encoded_value method size %x", value_arg); + if (UNLIKELY(value_arg > 3)) { + ErrorStringPrintf("Bad encoded_value method size %x", value_arg); return false; } uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1); @@ -481,8 +485,8 @@ bool DexFileVerifier::CheckEncodedValue() { break; } case DexFile::kDexAnnotationArray: - if (value_arg != 0) { - LOG(ERROR) << StringPrintf("Bad encoded_value array value_arg %x", value_arg); + if (UNLIKELY(value_arg != 0)) { + ErrorStringPrintf("Bad encoded_value array value_arg %x", value_arg); return false; } if (!CheckEncodedArray()) { @@ -490,8 +494,8 @@ bool DexFileVerifier::CheckEncodedValue() { } break; case DexFile::kDexAnnotationAnnotation: - if (value_arg != 0) { - LOG(ERROR) << StringPrintf("Bad encoded_value annotation value_arg %x", value_arg); + if (UNLIKELY(value_arg != 0)) { + ErrorStringPrintf("Bad encoded_value annotation value_arg %x", value_arg); return false; } if (!CheckEncodedAnnotation()) { @@ -499,19 +503,19 @@ bool DexFileVerifier::CheckEncodedValue() { } break; case DexFile::kDexAnnotationNull: - if (value_arg != 0) { - LOG(ERROR) << StringPrintf("Bad encoded_value null value_arg %x", value_arg); + if (UNLIKELY(value_arg != 0)) { + ErrorStringPrintf("Bad encoded_value null value_arg %x", value_arg); return false; } break; case DexFile::kDexAnnotationBoolean: - if (value_arg > 1) { - LOG(ERROR) << StringPrintf("Bad encoded_value boolean size %x", value_arg); + if (UNLIKELY(value_arg > 1)) { + ErrorStringPrintf("Bad encoded_value boolean size %x", value_arg); return false; } break; default: - LOG(ERROR) << StringPrintf("Bogus encoded_value value_type %x", value_type); + ErrorStringPrintf("Bogus encoded_value value_type %x", value_type); return false; } @@ -523,7 +527,7 @@ bool DexFileVerifier::CheckEncodedArray() { while (size--) { if (!CheckEncodedValue()) { - LOG(ERROR) << "Bad encoded_array value"; + failure_reason_ = StringPrintf("Bad encoded_array value: %s", failure_reason_.c_str()); return false; } } @@ -545,9 +549,9 @@ bool DexFileVerifier::CheckEncodedAnnotation() { return false; } - if (last_idx >= idx && i != 0) { - LOG(ERROR) << StringPrintf("Out-of-order annotation_element name_idx: %x then %x", - last_idx, idx); + if (UNLIKELY(last_idx >= idx && i != 0)) { + ErrorStringPrintf("Out-of-order annotation_element name_idx: %x then %x", + last_idx, idx); return false; } @@ -596,21 +600,22 @@ bool DexFileVerifier::CheckIntraCodeItem() { return false; } - if (code_item->ins_size_ > code_item->registers_size_) { - LOG(ERROR) << "ins_size (" << code_item->ins_size_ << ") > registers_size (" - << code_item->registers_size_ << ")"; + if (UNLIKELY(code_item->ins_size_ > code_item->registers_size_)) { + ErrorStringPrintf("ins_size (%ud) > registers_size (%ud)", + code_item->ins_size_, code_item->registers_size_); return false; } - if ((code_item->outs_size_ > 5) && (code_item->outs_size_ > code_item->registers_size_)) { + if (UNLIKELY((code_item->outs_size_ > 5) && + (code_item->outs_size_ > code_item->registers_size_))) { /* * outs_size can be up to 5, even if registers_size is smaller, since the * short forms of method invocation allow repetitions of a register multiple * times within a single parameter list. However, longer parameter lists * need to be represented in-order in the register file. */ - LOG(ERROR) << "outs_size (" << code_item->outs_size_ << ") > registers_size (" - << code_item->registers_size_ << ")"; + ErrorStringPrintf("outs_size (%ud) > registers_size (%ud)", + code_item->outs_size_, code_item->registers_size_); return false; } @@ -629,7 +634,7 @@ bool DexFileVerifier::CheckIntraCodeItem() { // try_items are 4-byte aligned. Verify the spacer is 0. if ((((uint32_t) &insns[insns_size] & 3) != 0) && (insns[insns_size] != 0)) { - LOG(ERROR) << StringPrintf("Non-zero padding: %x", insns[insns_size]); + ErrorStringPrintf("Non-zero padding: %x", insns[insns_size]); return false; } @@ -641,8 +646,8 @@ bool DexFileVerifier::CheckIntraCodeItem() { return false; } - if ((handlers_size == 0) || (handlers_size >= 65536)) { - LOG(ERROR) << "Invalid handlers_size: " << handlers_size; + if (UNLIKELY((handlers_size == 0) || (handlers_size >= 65536))) { + ErrorStringPrintf("Invalid handlers_size: %ud", handlers_size); return false; } @@ -653,14 +658,13 @@ bool DexFileVerifier::CheckIntraCodeItem() { uint32_t last_addr = 0; while (try_items_size--) { - if (try_items->start_addr_ < last_addr) { - LOG(ERROR) << StringPrintf("Out-of_order try_item with start_addr: %x", - try_items->start_addr_); + if (UNLIKELY(try_items->start_addr_ < last_addr)) { + ErrorStringPrintf("Out-of_order try_item with start_addr: %x", try_items->start_addr_); return false; } - if (try_items->start_addr_ >= insns_size) { - LOG(ERROR) << StringPrintf("Invalid try_item start_addr: %x", try_items->start_addr_); + if (UNLIKELY(try_items->start_addr_ >= insns_size)) { + ErrorStringPrintf("Invalid try_item start_addr: %x", try_items->start_addr_); return false; } @@ -671,14 +675,14 @@ bool DexFileVerifier::CheckIntraCodeItem() { } } - if (i == handlers_size) { - LOG(ERROR) << StringPrintf("Bogus handler offset: %x", try_items->handler_off_); + if (UNLIKELY(i == handlers_size)) { + ErrorStringPrintf("Bogus handler offset: %x", try_items->handler_off_); return false; } last_addr = try_items->start_addr_ + try_items->insn_count_; - if (last_addr > insns_size) { - LOG(ERROR) << StringPrintf("Invalid try_item insn_count: %x", try_items->insn_count_); + if (UNLIKELY(last_addr > insns_size)) { + ErrorStringPrintf("Invalid try_item insn_count: %x", try_items->insn_count_); return false; } @@ -693,8 +697,8 @@ bool DexFileVerifier::CheckIntraStringDataItem() { const byte* file_end = begin_ + size_; for (uint32_t i = 0; i < size; i++) { - if (ptr_ >= file_end) { - LOG(ERROR) << "String data would go beyond end-of-file"; + if (UNLIKELY(ptr_ >= file_end)) { + ErrorStringPrintf("String data would go beyond end-of-file"); return false; } @@ -704,8 +708,8 @@ bool DexFileVerifier::CheckIntraStringDataItem() { switch (byte >> 4) { case 0x00: // Special case of bit pattern 0xxx. - if (byte == 0) { - LOG(ERROR) << StringPrintf("String data shorter than indicated utf16_size %x", size); + if (UNLIKELY(byte == 0)) { + ErrorStringPrintf("String data shorter than indicated utf16_size %x", size); return false; } break; @@ -725,19 +729,19 @@ bool DexFileVerifier::CheckIntraStringDataItem() { case 0x0f: // Illegal bit patterns 10xx or 1111. // Note: 1111 is valid for normal UTF-8, but not here. - LOG(ERROR) << StringPrintf("Illegal start byte %x in string data", byte); + ErrorStringPrintf("Illegal start byte %x in string data", byte); return false; case 0x0c: case 0x0d: { // Bit pattern 110x has an additional byte. uint8_t byte2 = *(ptr_++); - if ((byte2 & 0xc0) != 0x80) { - LOG(ERROR) << StringPrintf("Illegal continuation byte %x in string data", byte2); + if (UNLIKELY((byte2 & 0xc0) != 0x80)) { + ErrorStringPrintf("Illegal continuation byte %x in string data", byte2); return false; } uint16_t value = ((byte & 0x1f) << 6) | (byte2 & 0x3f); - if ((value != 0) && (value < 0x80)) { - LOG(ERROR) << StringPrintf("Illegal representation for value %x in string data", value); + if (UNLIKELY((value != 0) && (value < 0x80))) { + ErrorStringPrintf("Illegal representation for value %x in string data", value); return false; } break; @@ -745,18 +749,18 @@ bool DexFileVerifier::CheckIntraStringDataItem() { case 0x0e: { // Bit pattern 1110 has 2 additional bytes. uint8_t byte2 = *(ptr_++); - if ((byte2 & 0xc0) != 0x80) { - LOG(ERROR) << StringPrintf("Illegal continuation byte %x in string data", byte2); + if (UNLIKELY((byte2 & 0xc0) != 0x80)) { + ErrorStringPrintf("Illegal continuation byte %x in string data", byte2); return false; } uint8_t byte3 = *(ptr_++); - if ((byte3 & 0xc0) != 0x80) { - LOG(ERROR) << StringPrintf("Illegal continuation byte %x in string data", byte3); + if (UNLIKELY((byte3 & 0xc0) != 0x80)) { + ErrorStringPrintf("Illegal continuation byte %x in string data", byte3); return false; } uint16_t value = ((byte & 0x0f) << 12) | ((byte2 & 0x3f) << 6) | (byte3 & 0x3f); - if (value < 0x800) { - LOG(ERROR) << StringPrintf("Illegal representation for value %x in string data", value); + if (UNLIKELY(value < 0x800)) { + ErrorStringPrintf("Illegal representation for value %x in string data", value); return false; } break; @@ -764,8 +768,8 @@ bool DexFileVerifier::CheckIntraStringDataItem() { } } - if (*(ptr_++) != '\0') { - LOG(ERROR) << StringPrintf("String longer than indicated size %x", size); + if (UNLIKELY(*(ptr_++) != '\0')) { + ErrorStringPrintf("String longer than indicated size %x", size); return false; } @@ -775,8 +779,8 @@ bool DexFileVerifier::CheckIntraStringDataItem() { bool DexFileVerifier::CheckIntraDebugInfoItem() { DecodeUnsignedLeb128(&ptr_); uint32_t parameters_size = DecodeUnsignedLeb128(&ptr_); - if (parameters_size > 65536) { - LOG(ERROR) << StringPrintf("Invalid parameters_size: %x", parameters_size); + if (UNLIKELY(parameters_size > 65536)) { + ErrorStringPrintf("Invalid parameters_size: %x", parameters_size); return false; } @@ -806,8 +810,8 @@ bool DexFileVerifier::CheckIntraDebugInfoItem() { } case DexFile::DBG_START_LOCAL: { uint32_t reg_num = DecodeUnsignedLeb128(&ptr_); - if (reg_num >= 65536) { - LOG(ERROR) << StringPrintf("Bad reg_num for opcode %x", opcode); + if (UNLIKELY(reg_num >= 65536)) { + ErrorStringPrintf("Bad reg_num for opcode %x", opcode); return false; } uint32_t name_idx = DecodeUnsignedLeb128(&ptr_); @@ -829,16 +833,16 @@ bool DexFileVerifier::CheckIntraDebugInfoItem() { case DexFile::DBG_END_LOCAL: case DexFile::DBG_RESTART_LOCAL: { uint32_t reg_num = DecodeUnsignedLeb128(&ptr_); - if (reg_num >= 65536) { - LOG(ERROR) << StringPrintf("Bad reg_num for opcode %x", opcode); + if (UNLIKELY(reg_num >= 65536)) { + ErrorStringPrintf("Bad reg_num for opcode %x", opcode); return false; } break; } case DexFile::DBG_START_LOCAL_EXTENDED: { uint32_t reg_num = DecodeUnsignedLeb128(&ptr_); - if (reg_num >= 65536) { - LOG(ERROR) << StringPrintf("Bad reg_num for opcode %x", opcode); + if (UNLIKELY(reg_num >= 65536)) { + ErrorStringPrintf("Bad reg_num for opcode %x", opcode); return false; } uint32_t name_idx = DecodeUnsignedLeb128(&ptr_); @@ -890,7 +894,7 @@ bool DexFileVerifier::CheckIntraAnnotationItem() { case DexFile::kDexVisibilitySystem: break; default: - LOG(ERROR) << StringPrintf("Bad annotation visibility: %x", *ptr_); + ErrorStringPrintf("Bad annotation visibility: %x", *ptr_); return false; } @@ -918,8 +922,8 @@ bool DexFileVerifier::CheckIntraAnnotationsDirectoryItem() { uint32_t last_idx = 0; for (uint32_t i = 0; i < field_count; i++) { - if (last_idx >= field_item->field_idx_ && i != 0) { - LOG(ERROR) << StringPrintf("Out-of-order field_idx for annotation: %x then %x", last_idx, field_item->field_idx_); + if (UNLIKELY(last_idx >= field_item->field_idx_ && i != 0)) { + ErrorStringPrintf("Out-of-order field_idx for annotation: %x then %x", last_idx, field_item->field_idx_); return false; } last_idx = field_item->field_idx_; @@ -936,9 +940,9 @@ bool DexFileVerifier::CheckIntraAnnotationsDirectoryItem() { last_idx = 0; for (uint32_t i = 0; i < method_count; i++) { - if (last_idx >= method_item->method_idx_ && i != 0) { - LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x", - last_idx, method_item->method_idx_); + if (UNLIKELY(last_idx >= method_item->method_idx_ && i != 0)) { + ErrorStringPrintf("Out-of-order method_idx for annotation: %x then %x", + last_idx, method_item->method_idx_); return false; } last_idx = method_item->method_idx_; @@ -950,15 +954,15 @@ bool DexFileVerifier::CheckIntraAnnotationsDirectoryItem() { reinterpret_cast<const DexFile::ParameterAnnotationsItem*>(method_item); uint32_t parameter_count = item->parameters_size_; if (!CheckListSize(parameter_item, parameter_count, sizeof(DexFile::ParameterAnnotationsItem), - "parameter_annotations list")) { + "parameter_annotations list")) { return false; } last_idx = 0; for (uint32_t i = 0; i < parameter_count; i++) { - if (last_idx >= parameter_item->method_idx_ && i != 0) { - LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x", - last_idx, parameter_item->method_idx_); + if (UNLIKELY(last_idx >= parameter_item->method_idx_ && i != 0)) { + ErrorStringPrintf("Out-of-order method_idx for annotation: %x then %x", + last_idx, parameter_item->method_idx_); return false; } last_idx = parameter_item->method_idx_; @@ -1059,7 +1063,7 @@ bool DexFileVerifier::CheckIntraSectionIterate(uint32_t offset, uint32_t count, if (!CheckPointerRange(list, list + 1, "annotation_set_ref_list") || !CheckListSize(item, count, sizeof(DexFile::AnnotationSetRefItem), - "annotation_set_ref_list size")) { + "annotation_set_ref_list size")) { return false; } ptr_ = reinterpret_cast<const byte*>(item + count); @@ -1121,7 +1125,7 @@ bool DexFileVerifier::CheckIntraSectionIterate(uint32_t offset, uint32_t count, break; } default: - LOG(ERROR) << StringPrintf("Unknown map item type %x", type); + ErrorStringPrintf("Unknown map item type %x", type); return false; } @@ -1130,8 +1134,8 @@ bool DexFileVerifier::CheckIntraSectionIterate(uint32_t offset, uint32_t count, } aligned_offset = reinterpret_cast<uint32_t>(ptr_) - reinterpret_cast<uint32_t>(begin_); - if (aligned_offset > size_) { - LOG(ERROR) << StringPrintf("Item %d at ends out of bounds", i); + if (UNLIKELY(aligned_offset > size_)) { + ErrorStringPrintf("Item %d at ends out of bounds", i); return false; } @@ -1172,17 +1176,17 @@ bool DexFileVerifier::CheckIntraIdSection(uint32_t offset, uint32_t count, uint1 expected_size = header_->class_defs_size_; break; default: - LOG(ERROR) << StringPrintf("Bad type for id section: %x", type); + ErrorStringPrintf("Bad type for id section: %x", type); return false; } // Check that the offset and size are what were expected from the header. - if (offset != expected_offset) { - LOG(ERROR) << StringPrintf("Bad offset for section: got %x, expected %x", offset, expected_offset); + if (UNLIKELY(offset != expected_offset)) { + ErrorStringPrintf("Bad offset for section: got %x, expected %x", offset, expected_offset); return false; } - if (count != expected_size) { - LOG(ERROR) << StringPrintf("Bad size for section: got %x, expected %x", count, expected_size); + if (UNLIKELY(count != expected_size)) { + ErrorStringPrintf("Bad size for section: got %x, expected %x", count, expected_size); return false; } @@ -1194,8 +1198,8 @@ bool DexFileVerifier::CheckIntraDataSection(uint32_t offset, uint32_t count, uin uint32_t data_end = data_start + header_->data_size_; // Sanity check the offset of the section. - if ((offset < data_start) || (offset > data_end)) { - LOG(ERROR) << StringPrintf("Bad offset for data subsection: %x", offset); + if (UNLIKELY((offset < data_start) || (offset > data_end))) { + ErrorStringPrintf("Bad offset for data subsection: %x", offset); return false; } @@ -1205,7 +1209,7 @@ bool DexFileVerifier::CheckIntraDataSection(uint32_t offset, uint32_t count, uin uint32_t next_offset = reinterpret_cast<uint32_t>(ptr_) - reinterpret_cast<uint32_t>(begin_); if (next_offset > data_end) { - LOG(ERROR) << StringPrintf("Out-of-bounds end of data subsection: %x", next_offset); + ErrorStringPrintf("Out-of-bounds end of data subsection: %x", next_offset); return false; } @@ -1229,20 +1233,20 @@ bool DexFileVerifier::CheckIntraSection() { // Check for padding and overlap between items. if (!CheckPadding(offset, section_offset)) { return false; - } else if (offset > section_offset) { - LOG(ERROR) << StringPrintf("Section overlap or out-of-order map: %x, %x", offset, section_offset); + } else if (UNLIKELY(offset > section_offset)) { + ErrorStringPrintf("Section overlap or out-of-order map: %x, %x", offset, section_offset); return false; } // Check each item based on its type. switch (type) { case DexFile::kDexTypeHeaderItem: - if (section_count != 1) { - LOG(ERROR) << "Multiple header items"; + if (UNLIKELY(section_count != 1)) { + ErrorStringPrintf("Multiple header items"); return false; } - if (section_offset != 0) { - LOG(ERROR) << StringPrintf("Header at %x, not at start of file", section_offset); + if (UNLIKELY(section_offset != 0)) { + ErrorStringPrintf("Header at %x, not at start of file", section_offset); return false; } ptr_ = begin_ + header_->header_size_; @@ -1260,13 +1264,13 @@ bool DexFileVerifier::CheckIntraSection() { offset = reinterpret_cast<uint32_t>(ptr_) - reinterpret_cast<uint32_t>(begin_); break; case DexFile::kDexTypeMapList: - if (section_count != 1) { - LOG(ERROR) << "Multiple map list items"; + if (UNLIKELY(section_count != 1)) { + ErrorStringPrintf("Multiple map list items"); return false; } - if (section_offset != header_->map_off_) { - LOG(ERROR) << StringPrintf("Map not at header-defined offset: %x, expected %x", - section_offset, header_->map_off_); + if (UNLIKELY(section_offset != header_->map_off_)) { + ErrorStringPrintf("Map not at header-defined offset: %x, expected %x", + section_offset, header_->map_off_); return false; } ptr_ += sizeof(uint32_t) + (map->size_ * sizeof(DexFile::MapItem)); @@ -1288,7 +1292,7 @@ bool DexFileVerifier::CheckIntraSection() { offset = reinterpret_cast<uint32_t>(ptr_) - reinterpret_cast<uint32_t>(begin_); break; default: - LOG(ERROR) << StringPrintf("Unknown map item type %x", type); + ErrorStringPrintf("Unknown map item type %x", type); return false; } @@ -1300,13 +1304,13 @@ bool DexFileVerifier::CheckIntraSection() { bool DexFileVerifier::CheckOffsetToTypeMap(uint32_t offset, uint16_t type) { auto it = offset_to_type_map_.find(offset); - if (it == offset_to_type_map_.end()) { - LOG(ERROR) << StringPrintf("No data map entry found @ %x; expected %x", offset, type); + if (UNLIKELY(it == offset_to_type_map_.end())) { + ErrorStringPrintf("No data map entry found @ %x; expected %x", offset, type); return false; } - if (it->second != type) { - LOG(ERROR) << StringPrintf("Unexpected data map entry @ %x; expected %x, found %x", - offset, type, it->second); + if (UNLIKELY(it->second != type)) { + ErrorStringPrintf("Unexpected data map entry @ %x; expected %x, found %x", + offset, type, it->second); return false; } return true; @@ -1365,8 +1369,8 @@ bool DexFileVerifier::CheckInterStringIdItem() { const DexFile::StringId* prev_item = reinterpret_cast<const DexFile::StringId*>(previous_item_); const char* prev_str = dex_file_->GetStringData(*prev_item); const char* str = dex_file_->GetStringData(*item); - if (CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(prev_str, str) >= 0) { - LOG(ERROR) << StringPrintf("Out-of-order string_ids: '%s' then '%s'", prev_str, str); + if (UNLIKELY(CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(prev_str, str) >= 0)) { + ErrorStringPrintf("Out-of-order string_ids: '%s' then '%s'", prev_str, str); return false; } } @@ -1380,17 +1384,17 @@ bool DexFileVerifier::CheckInterTypeIdItem() { const char* descriptor = dex_file_->StringDataByIdx(item->descriptor_idx_); // Check that the descriptor is a valid type. - if (!IsValidDescriptor(descriptor)) { - LOG(ERROR) << StringPrintf("Invalid type descriptor: '%s'", descriptor); + if (UNLIKELY(!IsValidDescriptor(descriptor))) { + ErrorStringPrintf("Invalid type descriptor: '%s'", descriptor); return false; } // Check ordering between items. if (previous_item_ != NULL) { const DexFile::TypeId* prev_item = reinterpret_cast<const DexFile::TypeId*>(previous_item_); - if (prev_item->descriptor_idx_ >= item->descriptor_idx_) { - LOG(ERROR) << StringPrintf("Out-of-order type_ids: %x then %x", - prev_item->descriptor_idx_, item->descriptor_idx_); + if (UNLIKELY(prev_item->descriptor_idx_ >= item->descriptor_idx_)) { + ErrorStringPrintf("Out-of-order type_ids: %x then %x", + prev_item->descriptor_idx_, item->descriptor_idx_); return false; } } @@ -1422,16 +1426,16 @@ bool DexFileVerifier::CheckInterProtoIdItem() { it.Next(); shorty++; } - if (it.HasNext() || *shorty != '\0') { - LOG(ERROR) << "Mismatched length for parameters and shorty"; + if (UNLIKELY(it.HasNext() || *shorty != '\0')) { + ErrorStringPrintf("Mismatched length for parameters and shorty"); return false; } // Check ordering between items. This relies on type_ids being in order. if (previous_item_ != NULL) { const DexFile::ProtoId* prev = reinterpret_cast<const DexFile::ProtoId*>(previous_item_); - if (prev->return_type_idx_ > item->return_type_idx_) { - LOG(ERROR) << "Out-of-order proto_id return types"; + if (UNLIKELY(prev->return_type_idx_ > item->return_type_idx_)) { + ErrorStringPrintf("Out-of-order proto_id return types"); return false; } else if (prev->return_type_idx_ == item->return_type_idx_) { DexFileParameterIterator curr_it(*dex_file_, *item); @@ -1443,15 +1447,15 @@ bool DexFileVerifier::CheckInterProtoIdItem() { if (prev_idx == DexFile::kDexNoIndex16) { break; } - if (curr_idx == DexFile::kDexNoIndex16) { - LOG(ERROR) << "Out-of-order proto_id arguments"; + if (UNLIKELY(curr_idx == DexFile::kDexNoIndex16)) { + ErrorStringPrintf("Out-of-order proto_id arguments"); return false; } if (prev_idx < curr_idx) { break; - } else if (prev_idx > curr_idx) { - LOG(ERROR) << "Out-of-order proto_id arguments"; + } else if (UNLIKELY(prev_idx > curr_idx)) { + ErrorStringPrintf("Out-of-order proto_id arguments"); return false; } @@ -1470,38 +1474,38 @@ bool DexFileVerifier::CheckInterFieldIdItem() { // Check that the class descriptor is valid. const char* descriptor = dex_file_->StringByTypeIdx(item->class_idx_); - if (!IsValidDescriptor(descriptor) || descriptor[0] != 'L') { - LOG(ERROR) << "Invalid descriptor for class_idx: '" << descriptor << '"'; + if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] != 'L')) { + ErrorStringPrintf("Invalid descriptor for class_idx: '%s'", descriptor); return false; } // Check that the type descriptor is a valid field name. descriptor = dex_file_->StringByTypeIdx(item->type_idx_); - if (!IsValidDescriptor(descriptor) || descriptor[0] == 'V') { - LOG(ERROR) << "Invalid descriptor for type_idx: '" << descriptor << '"'; + if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] == 'V')) { + ErrorStringPrintf("Invalid descriptor for type_idx: '%s'", descriptor); return false; } // Check that the name is valid. descriptor = dex_file_->StringDataByIdx(item->name_idx_); - if (!IsValidMemberName(descriptor)) { - LOG(ERROR) << "Invalid field name: '" << descriptor << '"'; + if (UNLIKELY(!IsValidMemberName(descriptor))) { + ErrorStringPrintf("Invalid field name: '%s'", descriptor); return false; } // Check ordering between items. This relies on the other sections being in order. if (previous_item_ != NULL) { const DexFile::FieldId* prev_item = reinterpret_cast<const DexFile::FieldId*>(previous_item_); - if (prev_item->class_idx_ > item->class_idx_) { - LOG(ERROR) << "Out-of-order field_ids"; + if (UNLIKELY(prev_item->class_idx_ > item->class_idx_)) { + ErrorStringPrintf("Out-of-order field_ids"); return false; } else if (prev_item->class_idx_ == item->class_idx_) { - if (prev_item->name_idx_ > item->name_idx_) { - LOG(ERROR) << "Out-of-order field_ids"; + if (UNLIKELY(prev_item->name_idx_ > item->name_idx_)) { + ErrorStringPrintf("Out-of-order field_ids"); return false; } else if (prev_item->name_idx_ == item->name_idx_) { - if (prev_item->type_idx_ >= item->type_idx_) { - LOG(ERROR) << "Out-of-order field_ids"; + if (UNLIKELY(prev_item->type_idx_ >= item->type_idx_)) { + ErrorStringPrintf("Out-of-order field_ids"); return false; } } @@ -1517,31 +1521,31 @@ bool DexFileVerifier::CheckInterMethodIdItem() { // Check that the class descriptor is a valid reference name. const char* descriptor = dex_file_->StringByTypeIdx(item->class_idx_); - if (!IsValidDescriptor(descriptor) || (descriptor[0] != 'L' && descriptor[0] != '[')) { - LOG(ERROR) << "Invalid descriptor for class_idx: '" << descriptor << '"'; + if (UNLIKELY(!IsValidDescriptor(descriptor) || (descriptor[0] != 'L' && descriptor[0] != '['))) { + ErrorStringPrintf("Invalid descriptor for class_idx: '%s'", descriptor); return false; } // Check that the name is valid. descriptor = dex_file_->StringDataByIdx(item->name_idx_); - if (!IsValidMemberName(descriptor)) { - LOG(ERROR) << "Invalid method name: '" << descriptor << '"'; + if (UNLIKELY(!IsValidMemberName(descriptor))) { + ErrorStringPrintf("Invalid method name: '%s'", descriptor); return false; } // Check ordering between items. This relies on the other sections being in order. if (previous_item_ != NULL) { const DexFile::MethodId* prev_item = reinterpret_cast<const DexFile::MethodId*>(previous_item_); - if (prev_item->class_idx_ > item->class_idx_) { - LOG(ERROR) << "Out-of-order method_ids"; + if (UNLIKELY(prev_item->class_idx_ > item->class_idx_)) { + ErrorStringPrintf("Out-of-order method_ids"); return false; } else if (prev_item->class_idx_ == item->class_idx_) { - if (prev_item->name_idx_ > item->name_idx_) { - LOG(ERROR) << "Out-of-order method_ids"; + if (UNLIKELY(prev_item->name_idx_ > item->name_idx_)) { + ErrorStringPrintf("Out-of-order method_ids"); return false; } else if (prev_item->name_idx_ == item->name_idx_) { - if (prev_item->proto_idx_ >= item->proto_idx_) { - LOG(ERROR) << "Out-of-order method_ids"; + if (UNLIKELY(prev_item->proto_idx_ >= item->proto_idx_)) { + ErrorStringPrintf("Out-of-order method_ids"); return false; } } @@ -1557,8 +1561,8 @@ bool DexFileVerifier::CheckInterClassDefItem() { uint32_t class_idx = item->class_idx_; const char* descriptor = dex_file_->StringByTypeIdx(class_idx); - if (!IsValidDescriptor(descriptor) || descriptor[0] != 'L') { - LOG(ERROR) << "Invalid class descriptor: '" << descriptor << "'"; + if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] != 'L')) { + ErrorStringPrintf("Invalid class descriptor: '%s'", descriptor); return false; } @@ -1581,8 +1585,8 @@ bool DexFileVerifier::CheckInterClassDefItem() { if (item->superclass_idx_ != DexFile::kDexNoIndex16) { descriptor = dex_file_->StringByTypeIdx(item->superclass_idx_); - if (!IsValidDescriptor(descriptor) || descriptor[0] != 'L') { - LOG(ERROR) << "Invalid superclass: '" << descriptor << "'"; + if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] != 'L')) { + ErrorStringPrintf("Invalid superclass: '%s'", descriptor); return false; } } @@ -1594,8 +1598,8 @@ bool DexFileVerifier::CheckInterClassDefItem() { // Ensure that all interfaces refer to classes (not arrays or primitives). for (uint32_t i = 0; i < size; i++) { descriptor = dex_file_->StringByTypeIdx(interfaces->GetTypeItem(i).type_idx_); - if (!IsValidDescriptor(descriptor) || descriptor[0] != 'L') { - LOG(ERROR) << "Invalid interface: '" << descriptor << "'"; + if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] != 'L')) { + ErrorStringPrintf("Invalid interface: '%s'", descriptor); return false; } } @@ -1608,8 +1612,8 @@ bool DexFileVerifier::CheckInterClassDefItem() { uint32_t idx1 = interfaces->GetTypeItem(i).type_idx_; for (uint32_t j =0; j < i; j++) { uint32_t idx2 = interfaces->GetTypeItem(j).type_idx_; - if (idx1 == idx2) { - LOG(ERROR) << "Duplicate interface: '" << dex_file_->StringByTypeIdx(idx1) << "'"; + if (UNLIKELY(idx1 == idx2)) { + ErrorStringPrintf("Duplicate interface: '%s'", dex_file_->StringByTypeIdx(idx1)); return false; } } @@ -1620,8 +1624,8 @@ bool DexFileVerifier::CheckInterClassDefItem() { if (item->class_data_off_ != 0) { const byte* data = begin_ + item->class_data_off_; uint16_t data_definer = FindFirstClassDataDefiner(data); - if ((data_definer != item->class_idx_) && (data_definer != DexFile::kDexNoIndex16)) { - LOG(ERROR) << "Invalid class_data_item"; + if (UNLIKELY((data_definer != item->class_idx_) && (data_definer != DexFile::kDexNoIndex16))) { + ErrorStringPrintf("Invalid class_data_item"); return false; } } @@ -1630,8 +1634,9 @@ bool DexFileVerifier::CheckInterClassDefItem() { if (item->annotations_off_ != 0) { const byte* data = begin_ + item->annotations_off_; uint16_t annotations_definer = FindFirstAnnotationsDirectoryDefiner(data); - if ((annotations_definer != item->class_idx_) && (annotations_definer != DexFile::kDexNoIndex16)) { - LOG(ERROR) << "Invalid annotations_directory_item"; + if (UNLIKELY((annotations_definer != item->class_idx_) && + (annotations_definer != DexFile::kDexNoIndex16))) { + ErrorStringPrintf("Invalid annotations_directory_item"); return false; } } @@ -1675,8 +1680,8 @@ bool DexFileVerifier::CheckInterAnnotationSetItem() { const uint8_t* data = annotation->annotation_; uint32_t idx = DecodeUnsignedLeb128(&data); - if (last_idx >= idx && i != 0) { - LOG(ERROR) << StringPrintf("Out-of-order entry types: %x then %x", last_idx, idx); + if (UNLIKELY(last_idx >= idx && i != 0)) { + ErrorStringPrintf("Out-of-order entry types: %x then %x", last_idx, idx); return false; } @@ -1694,8 +1699,8 @@ bool DexFileVerifier::CheckInterClassDataItem() { for (; it.HasNextStaticField() || it.HasNextInstanceField(); it.Next()) { const DexFile::FieldId& field = dex_file_->GetFieldId(it.GetMemberIndex()); - if (field.class_idx_ != defining_class) { - LOG(ERROR) << "Mismatched defining class for class_data_item field"; + if (UNLIKELY(field.class_idx_ != defining_class)) { + ErrorStringPrintf("Mismatched defining class for class_data_item field"); return false; } } @@ -1705,8 +1710,8 @@ bool DexFileVerifier::CheckInterClassDataItem() { return false; } const DexFile::MethodId& method = dex_file_->GetMethodId(it.GetMemberIndex()); - if (method.class_idx_ != defining_class) { - LOG(ERROR) << "Mismatched defining class for class_data_item method"; + if (UNLIKELY(method.class_idx_ != defining_class)) { + ErrorStringPrintf("Mismatched defining class for class_data_item method"); return false; } } @@ -1731,8 +1736,8 @@ bool DexFileVerifier::CheckInterAnnotationsDirectoryItem() { uint32_t field_count = item->fields_size_; for (uint32_t i = 0; i < field_count; i++) { const DexFile::FieldId& field = dex_file_->GetFieldId(field_item->field_idx_); - if (field.class_idx_ != defining_class) { - LOG(ERROR) << "Mismatched defining class for field_annotation"; + if (UNLIKELY(field.class_idx_ != defining_class)) { + ErrorStringPrintf("Mismatched defining class for field_annotation"); return false; } if (!CheckOffsetToTypeMap(field_item->annotations_off_, DexFile::kDexTypeAnnotationSetItem)) { @@ -1747,8 +1752,8 @@ bool DexFileVerifier::CheckInterAnnotationsDirectoryItem() { uint32_t method_count = item->methods_size_; for (uint32_t i = 0; i < method_count; i++) { const DexFile::MethodId& method = dex_file_->GetMethodId(method_item->method_idx_); - if (method.class_idx_ != defining_class) { - LOG(ERROR) << "Mismatched defining class for method_annotation"; + if (UNLIKELY(method.class_idx_ != defining_class)) { + ErrorStringPrintf("Mismatched defining class for method_annotation"); return false; } if (!CheckOffsetToTypeMap(method_item->annotations_off_, DexFile::kDexTypeAnnotationSetItem)) { @@ -1763,8 +1768,8 @@ bool DexFileVerifier::CheckInterAnnotationsDirectoryItem() { uint32_t parameter_count = item->parameters_size_; for (uint32_t i = 0; i < parameter_count; i++) { const DexFile::MethodId& parameter_method = dex_file_->GetMethodId(parameter_item->method_idx_); - if (parameter_method.class_idx_ != defining_class) { - LOG(ERROR) << "Mismatched defining class for parameter_annotation"; + if (UNLIKELY(parameter_method.class_idx_ != defining_class)) { + ErrorStringPrintf("Mismatched defining class for parameter_annotation"); return false; } if (!CheckOffsetToTypeMap(parameter_item->annotations_off_, @@ -1860,7 +1865,7 @@ bool DexFileVerifier::CheckInterSectionIterate(uint32_t offset, uint32_t count, break; } default: - LOG(ERROR) << StringPrintf("Unknown map item type %x", type); + ErrorStringPrintf("Unknown map item type %x", type); return false; } @@ -1908,7 +1913,7 @@ bool DexFileVerifier::CheckInterSection() { break; } default: - LOG(ERROR) << StringPrintf("Unknown map item type %x", type); + ErrorStringPrintf("Unknown map item type %x", type); return false; } @@ -1942,4 +1947,13 @@ bool DexFileVerifier::Verify() { return true; } +void DexFileVerifier::ErrorStringPrintf(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + DCHECK(failure_reason_.empty()) << failure_reason_; + failure_reason_ = StringPrintf("Failure to verify dex file '%s': ", location_); + StringAppendV(&failure_reason_, fmt, ap); + va_end(ap); +} + } // namespace art diff --git a/runtime/dex_file_verifier.h b/runtime/dex_file_verifier.h index 3797dc7..4b8b80a 100644 --- a/runtime/dex_file_verifier.h +++ b/runtime/dex_file_verifier.h @@ -24,29 +24,35 @@ namespace art { class DexFileVerifier { public: - static bool Verify(const DexFile* dex_file, const byte* begin, size_t size); + static bool Verify(const DexFile* dex_file, const byte* begin, size_t size, + const char* location, std::string* error_msg); + + const std::string& FailureReason() const { + return failure_reason_; + } private: - DexFileVerifier(const DexFile* dex_file, const byte* begin, size_t size) - : dex_file_(dex_file), begin_(begin), size_(size), + DexFileVerifier(const DexFile* dex_file, const byte* begin, size_t size, const char* location) + : dex_file_(dex_file), begin_(begin), size_(size), location_(location), header_(&dex_file->GetHeader()), ptr_(NULL), previous_item_(NULL) { } bool Verify(); - bool CheckPointerRange(const void* start, const void* end, const char* label) const; - bool CheckListSize(const void* start, uint32_t count, uint32_t element_size, const char* label) const; - bool CheckIndex(uint32_t field, uint32_t limit, const char* label) const; + bool CheckShortyDescriptorMatch(char shorty_char, const char* descriptor, bool is_return_type); + bool CheckPointerRange(const void* start, const void* end, const char* label); + bool CheckListSize(const void* start, uint32_t count, uint32_t element_size, const char* label); + bool CheckIndex(uint32_t field, uint32_t limit, const char* label); - bool CheckHeader() const; - bool CheckMap() const; + bool CheckHeader(); + bool CheckMap(); uint32_t ReadUnsignedLittleEndian(uint32_t size); bool CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_item, - uint32_t* handler_offsets, uint32_t handlers_size); - bool CheckClassDataItemField(uint32_t idx, uint32_t access_flags, bool expect_static) const; + uint32_t* handler_offsets, uint32_t handlers_size); + bool CheckClassDataItemField(uint32_t idx, uint32_t access_flags, bool expect_static); bool CheckClassDataItemMethod(uint32_t idx, uint32_t access_flags, uint32_t code_offset, - bool expect_direct) const; + bool expect_direct); bool CheckPadding(uint32_t offset, uint32_t aligned_offset); bool CheckEncodedValue(); bool CheckEncodedArray(); @@ -82,14 +88,20 @@ class DexFileVerifier { bool CheckInterSectionIterate(uint32_t offset, uint32_t count, uint16_t type); bool CheckInterSection(); - const DexFile* dex_file_; - const byte* begin_; - size_t size_; - const DexFile::Header* header_; + void ErrorStringPrintf(const char* fmt, ...) + __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR; + + const DexFile* const dex_file_; + const byte* const begin_; + const size_t size_; + const char* const location_; + const DexFile::Header* const header_; SafeMap<uint32_t, uint16_t> offset_to_type_map_; const byte* ptr_; const void* previous_item_; + + std::string failure_reason_; }; } // namespace art diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc index 64c645e..9961df9 100644 --- a/runtime/dex_method_iterator_test.cc +++ b/runtime/dex_method_iterator_test.cc @@ -20,16 +20,27 @@ namespace art { -class DexMethodIteratorTest : public CommonTest {}; +class DexMethodIteratorTest : public CommonTest { + public: + const DexFile* OpenDexFile(const std::string& partial_filename) { + std::string dfn = GetDexFileName(partial_filename); + std::string error_msg; + const DexFile* dexfile = DexFile::Open(dfn.c_str(), dfn.c_str(), &error_msg); + if (dexfile == nullptr) { + LG << "Failed to open '" << dfn << "': " << error_msg; + } + return dexfile; + } +}; TEST_F(DexMethodIteratorTest, Basic) { ScopedObjectAccess soa(Thread::Current()); std::vector<const DexFile*> dex_files; - dex_files.push_back(DexFile::Open(GetDexFileName("core"), GetDexFileName("core"))); - dex_files.push_back(DexFile::Open(GetDexFileName("conscrypt"), GetDexFileName("conscrypt"))); - dex_files.push_back(DexFile::Open(GetDexFileName("okhttp"), GetDexFileName("okhttp"))); - dex_files.push_back(DexFile::Open(GetDexFileName("core-junit"), GetDexFileName("core-junit"))); - dex_files.push_back(DexFile::Open(GetDexFileName("bouncycastle"), GetDexFileName("bouncycastle"))); + dex_files.push_back(OpenDexFile("core")); + dex_files.push_back(OpenDexFile("conscrypt")); + dex_files.push_back(OpenDexFile("okhttp")); + dex_files.push_back(OpenDexFile("core-junit")); + dex_files.push_back(OpenDexFile("bouncycastle")); DexMethodIterator it(dex_files); while (it.HasNext()) { const DexFile& dex_file = it.GetDexFile(); diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index dfb6819..15c95f2 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -40,15 +40,16 @@ ElfFile::ElfFile() symtab_symbol_table_(NULL), dynsym_symbol_table_(NULL) {} -ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only) { +ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, + std::string* error_msg) { UniquePtr<ElfFile> elf_file(new ElfFile()); - if (!elf_file->Setup(file, writable, program_header_only)) { - return NULL; + if (!elf_file->Setup(file, writable, program_header_only, error_msg)) { + return nullptr; } return elf_file.release(); } -bool ElfFile::Setup(File* file, bool writable, bool program_header_only) { +bool ElfFile::Setup(File* file, bool writable, bool program_header_only, std::string* error_msg) { CHECK(file != NULL); file_ = file; writable_ = writable; @@ -66,40 +67,42 @@ bool ElfFile::Setup(File* file, bool writable, bool program_header_only) { int64_t file_length = file_->GetLength(); if (file_length < 0) { errno = -file_length; - PLOG(WARNING) << "Failed to get length of file: " << file_->GetPath() << " fd=" << file_->Fd(); + *error_msg = StringPrintf("Failed to get length of file: '%s' fd=%d: %s", + file_->GetPath().c_str(), file_->Fd(), strerror(errno)); return false; } if (file_length < sizeof(llvm::ELF::Elf32_Ehdr)) { - if (writable) { - LOG(WARNING) << "File size of " << file_length - << " bytes not large enough to contain ELF header of " - << sizeof(llvm::ELF::Elf32_Ehdr) << " bytes: " << file_->GetPath(); - } + *error_msg = StringPrintf("File size of %lld bytes not large enough to contain ELF header of " + "%zd bytes: '%s'", file_length, sizeof(llvm::ELF::Elf32_Ehdr), + file_->GetPath().c_str()); return false; } if (program_header_only) { // first just map ELF header to get program header size information size_t elf_header_size = sizeof(llvm::ELF::Elf32_Ehdr); - if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file_->Fd(), 0))) { + if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file_->Fd(), 0, + file_->GetPath().c_str(), error_msg))) { return false; } // then remap to cover program header size_t program_header_size = header_->e_phoff + (header_->e_phentsize * header_->e_phnum); if (file_length < program_header_size) { - LOG(WARNING) << "File size of " << file_length - << " bytes not large enough to contain ELF program header of " - << program_header_size << " bytes: " << file_->GetPath(); + *error_msg = StringPrintf("File size of %lld bytes not large enough to contain ELF program " + "header of %zd bytes: '%s'", file_length, + sizeof(llvm::ELF::Elf32_Ehdr), file_->GetPath().c_str()); return false; } - if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file_->Fd(), 0))) { - LOG(WARNING) << "Failed to map ELF program headers: " << file_->GetPath(); + if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file_->Fd(), 0, + file_->GetPath().c_str(), error_msg))) { + *error_msg = StringPrintf("Failed to map ELF program headers: %s", error_msg->c_str()); return false; } } else { // otherwise map entire file - if (!SetMap(MemMap::MapFile(file_->GetLength(), prot, flags, file_->Fd(), 0))) { - LOG(WARNING) << "Failed to map ELF file: " << file_->GetPath(); + if (!SetMap(MemMap::MapFile(file_->GetLength(), prot, flags, file_->Fd(), 0, + file_->GetPath().c_str(), error_msg))) { + *error_msg = StringPrintf("Failed to map ELF file: %s", error_msg->c_str()); return false; } } @@ -114,7 +117,8 @@ bool ElfFile::Setup(File* file, bool writable, bool program_header_only) { // Find .dynamic section info from program header dynamic_program_header_ = FindProgamHeaderByType(llvm::ELF::PT_DYNAMIC); if (dynamic_program_header_ == NULL) { - LOG(WARNING) << "Failed to find PT_DYNAMIC program header in ELF file: " << file_->GetPath(); + *error_msg = StringPrintf("Failed to find PT_DYNAMIC program header in ELF file: '%s'", + file_->GetPath().c_str()); return false; } @@ -596,7 +600,7 @@ size_t ElfFile::GetLoadedSize() { return loaded_size; } -bool ElfFile::Load(bool executable) { +bool ElfFile::Load(bool executable, std::string* error_msg) { // TODO: actually return false error CHECK(program_header_only_) << file_->GetPath(); for (llvm::ELF::Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) { @@ -628,9 +632,10 @@ bool ElfFile::Load(bool executable) { if (program_header.p_vaddr == 0) { std::string reservation_name("ElfFile reservation for "); reservation_name += file_->GetPath(); + std::string error_msg; UniquePtr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(), - NULL, GetLoadedSize(), PROT_NONE)); - CHECK(reserve.get() != NULL) << file_->GetPath(); + NULL, GetLoadedSize(), PROT_NONE, &error_msg)); + CHECK(reserve.get() != NULL) << file_->GetPath() << ": " << error_msg; base_address_ = reserve->Begin(); segments_.push_back(reserve.release()); } @@ -657,18 +662,20 @@ bool ElfFile::Load(bool executable) { flags |= MAP_PRIVATE; } if (file_length < (program_header.p_offset + program_header.p_memsz)) { - LOG(WARNING) << "File size of " << file_length - << " bytes not large enough to contain ELF segment " << i - << " of " << (program_header.p_offset + program_header.p_memsz) - << " bytes: " << file_->GetPath(); + *error_msg = StringPrintf("File size of %lld bytes not large enough to contain ELF segment " + "%d of %d bytes: '%s'", file_length, i, + program_header.p_offset + program_header.p_memsz, + file_->GetPath().c_str()); return false; } UniquePtr<MemMap> segment(MemMap::MapFileAtAddress(p_vaddr, program_header.p_memsz, prot, flags, file_->Fd(), program_header.p_offset, - true)); - CHECK(segment.get() != NULL) << file_->GetPath(); + true, + file_->GetPath().c_str(), + error_msg)); + CHECK(segment.get() != nullptr) << *error_msg; CHECK_EQ(segment->Begin(), p_vaddr) << file_->GetPath(); segments_.push_back(segment.release()); } diff --git a/runtime/elf_file.h b/runtime/elf_file.h index 33b5fc3..b025137 100644 --- a/runtime/elf_file.h +++ b/runtime/elf_file.h @@ -35,7 +35,7 @@ namespace art { // ELFObjectFile. class ElfFile { public: - static ElfFile* Open(File* file, bool writable, bool program_header_only); + static ElfFile* Open(File* file, bool writable, bool program_header_only, std::string* error_msg); ~ElfFile(); // Load segments into memory based on PT_LOAD program headers @@ -115,12 +115,12 @@ class ElfFile { // Load segments into memory based on PT_LOAD program headers. // executable is true at run time, false at compile time. - bool Load(bool executable); + bool Load(bool executable, std::string* error_msg); private: ElfFile(); - bool Setup(File* file, bool writable, bool program_header_only); + bool Setup(File* file, bool writable, bool program_header_only, std::string* error_msg); bool SetMap(MemMap* map); diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h index 997d725..8fa5b86 100644 --- a/runtime/gc/accounting/atomic_stack.h +++ b/runtime/gc/accounting/atomic_stack.h @@ -163,8 +163,10 @@ class AtomicStack { // Size in number of elements. void Init() { - mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(T), PROT_READ | PROT_WRITE)); - CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack"; + std::string error_msg; + mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(T), + PROT_READ | PROT_WRITE, &error_msg)); + CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack.\n" << error_msg; byte* addr = mem_map_->Begin(); CHECK(addr != NULL); debug_is_sorted_ = true; diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc index 85034a0..7818bc8 100644 --- a/runtime/gc/accounting/card_table.cc +++ b/runtime/gc/accounting/card_table.cc @@ -54,9 +54,11 @@ CardTable* CardTable::Create(const byte* heap_begin, size_t heap_capacity) { /* Set up the card table */ size_t capacity = heap_capacity / kCardSize; /* Allocate an extra 256 bytes to allow fixed low-byte of base */ + std::string error_msg; UniquePtr<MemMap> mem_map(MemMap::MapAnonymous("card table", NULL, - capacity + 256, PROT_READ | PROT_WRITE)); - CHECK(mem_map.get() != NULL) << "couldn't allocate card table"; + capacity + 256, PROT_READ | PROT_WRITE, + &error_msg)); + CHECK(mem_map.get() != NULL) << "couldn't allocate card table: " << error_msg; // All zeros is the correct initial value; all clean. Anonymous mmaps are initialized to zero, we // don't clear the card table to avoid unnecessary pages being allocated COMPILE_ASSERT(kCardClean == 0, card_clean_must_be_0); diff --git a/runtime/gc/accounting/gc_allocator.cc b/runtime/gc/accounting/gc_allocator.cc index 11d0e67..49d84fa 100644 --- a/runtime/gc/accounting/gc_allocator.cc +++ b/runtime/gc/accounting/gc_allocator.cc @@ -22,15 +22,17 @@ namespace art { namespace gc { namespace accounting { - void* RegisterGCAllocation(size_t bytes) { - Runtime::Current()->GetHeap()->RegisterGCAllocation(bytes); - return malloc(bytes); - } - void RegisterGCDeAllocation(void* p, size_t bytes) { - Runtime::Current()->GetHeap()->RegisterGCDeAllocation(bytes); - free(p); - } +void* RegisterGcAllocation(size_t bytes) { + Runtime::Current()->GetHeap()->RegisterGCAllocation(bytes); + return malloc(bytes); +} + +void RegisterGcDeallocation(void* p, size_t bytes) { + Runtime::Current()->GetHeap()->RegisterGCDeAllocation(bytes); + free(p); +} + } // namespace accounting } // namespace gc } // namespace art diff --git a/runtime/gc/accounting/gc_allocator.h b/runtime/gc/accounting/gc_allocator.h index 1fba858..4fe9367 100644 --- a/runtime/gc/accounting/gc_allocator.h +++ b/runtime/gc/accounting/gc_allocator.h @@ -26,55 +26,56 @@ namespace art { namespace gc { namespace accounting { - void* RegisterGCAllocation(size_t bytes); - void RegisterGCDeAllocation(void* p, size_t bytes); - static const bool kMeasureGCMemoryOverhead = false; +void* RegisterGcAllocation(size_t bytes); +void RegisterGcDeallocation(void* p, size_t bytes); - template <typename T> - class GCAllocatorImpl : public std::allocator<T> { - public: - typedef typename std::allocator<T>::value_type value_type; - typedef typename std::allocator<T>::size_type size_type; - typedef typename std::allocator<T>::difference_type difference_type; - typedef typename std::allocator<T>::pointer pointer; - typedef typename std::allocator<T>::const_pointer const_pointer; - typedef typename std::allocator<T>::reference reference; - typedef typename std::allocator<T>::const_reference const_reference; +static const bool kMeasureGcMemoryOverhead = false; - // Used internally by STL data structures. - template <class U> - GCAllocatorImpl(const GCAllocatorImpl<U>& alloc) throw() { - } +template <typename T> +class GcAllocatorImpl : public std::allocator<T> { + public: + typedef typename std::allocator<T>::value_type value_type; + typedef typename std::allocator<T>::size_type size_type; + typedef typename std::allocator<T>::difference_type difference_type; + typedef typename std::allocator<T>::pointer pointer; + typedef typename std::allocator<T>::const_pointer const_pointer; + typedef typename std::allocator<T>::reference reference; + typedef typename std::allocator<T>::const_reference const_reference; - // Used internally by STL data structures. - GCAllocatorImpl() throw() { - } + // Used internally by STL data structures. + template <class U> + GcAllocatorImpl(const GcAllocatorImpl<U>& alloc) throw() { + } - // Enables an allocator for objects of one type to allocate storage for objects of another type. - // Used internally by STL data structures. - template <class U> - struct rebind { - typedef GCAllocatorImpl<U> other; - }; + // Used internally by STL data structures. + GcAllocatorImpl() throw() { + } - pointer allocate(size_type n, const_pointer hint = 0) { - return reinterpret_cast<pointer>(RegisterGCAllocation(n * sizeof(T))); - } - - template <typename PT> - void deallocate(PT p, size_type n) { - RegisterGCDeAllocation(p, n * sizeof(T)); - } + // Enables an allocator for objects of one type to allocate storage for objects of another type. + // Used internally by STL data structures. + template <class U> + struct rebind { + typedef GcAllocatorImpl<U> other; }; - // C++ doesn't allow template typedefs. This is a workaround template typedef which is - // GCAllocatorImpl<T> if kMeasureGCMemoryOverhead is true, std::allocator<T> otherwise. - template <typename T> - class GCAllocator : public TypeStaticIf<kMeasureGCMemoryOverhead, - GCAllocatorImpl<T>, - std::allocator<T> >::value { - }; + pointer allocate(size_type n, const_pointer hint = 0) { + return reinterpret_cast<pointer>(RegisterGcAllocation(n * sizeof(T))); + } + + template <typename PT> + void deallocate(PT p, size_type n) { + RegisterGcDeallocation(p, n * sizeof(T)); + } +}; + +// C++ doesn't allow template typedefs. This is a workaround template typedef which is +// GCAllocatorImpl<T> if kMeasureGCMemoryOverhead is true, std::allocator<T> otherwise. +template <typename T> +class GcAllocator : public TypeStaticIf<kMeasureGcMemoryOverhead, GcAllocatorImpl<T>, + std::allocator<T> >::value { +}; + } // namespace accounting } // namespace gc } // namespace art diff --git a/runtime/gc/accounting/heap_bitmap.h b/runtime/gc/accounting/heap_bitmap.h index 2ca8c4a..24ebbaa 100644 --- a/runtime/gc/accounting/heap_bitmap.h +++ b/runtime/gc/accounting/heap_bitmap.h @@ -31,8 +31,8 @@ namespace accounting { class HeapBitmap { public: - typedef std::vector<SpaceBitmap*, GCAllocator<SpaceBitmap*> > SpaceBitmapVector; - typedef std::vector<SpaceSetMap*, GCAllocator<SpaceSetMap*> > SpaceSetMapVector; + typedef std::vector<SpaceBitmap*, GcAllocator<SpaceBitmap*> > SpaceBitmapVector; + typedef std::vector<SpaceSetMap*, GcAllocator<SpaceSetMap*> > SpaceSetMapVector; bool Test(const mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) { SpaceBitmap* bitmap = GetContinuousSpaceBitmap(obj); diff --git a/runtime/gc/accounting/mod_union_table.h b/runtime/gc/accounting/mod_union_table.h index d874c60..5a99f1b 100644 --- a/runtime/gc/accounting/mod_union_table.h +++ b/runtime/gc/accounting/mod_union_table.h @@ -51,7 +51,7 @@ class HeapBitmap; // cleared between GC phases, reducing the number of dirty cards that need to be scanned. class ModUnionTable { public: - typedef std::set<byte*, std::less<byte*>, GCAllocator<byte*> > CardSet; + typedef std::set<byte*, std::less<byte*>, GcAllocator<byte*> > CardSet; explicit ModUnionTable(const std::string& name, Heap* heap, space::ContinuousSpace* space) : name_(name), @@ -125,7 +125,7 @@ class ModUnionTableReferenceCache : public ModUnionTable { // Maps from dirty cards to their corresponding alloc space references. SafeMap<const byte*, std::vector<mirror::Object**>, std::less<const byte*>, - GCAllocator<std::pair<const byte*, std::vector<mirror::Object**> > > > references_; + GcAllocator<std::pair<const byte*, std::vector<mirror::Object**> > > > references_; }; // Card caching implementation. Keeps track of which cards we cleared and only this information. diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc index 63b24ff..52c02f7 100644 --- a/runtime/gc/accounting/space_bitmap.cc +++ b/runtime/gc/accounting/space_bitmap.cc @@ -62,9 +62,11 @@ SpaceBitmap* SpaceBitmap::Create(const std::string& name, byte* heap_begin, size CHECK(heap_begin != NULL); // Round up since heap_capacity is not necessarily a multiple of kAlignment * kBitsPerWord. size_t bitmap_size = OffsetToIndex(RoundUp(heap_capacity, kAlignment * kBitsPerWord)) * kWordSize; - UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), NULL, bitmap_size, PROT_READ | PROT_WRITE)); - if (mem_map.get() == NULL) { - LOG(ERROR) << "Failed to allocate bitmap " << name; + std::string error_msg; + UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), NULL, bitmap_size, + PROT_READ | PROT_WRITE, &error_msg)); + if (UNLIKELY(mem_map.get() == nullptr)) { + LOG(ERROR) << "Failed to allocate bitmap " << name << ": " << error_msg; return NULL; } return CreateFromMemMap(name, mem_map.release(), heap_begin, heap_capacity); diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h index 4cf8872..21709ad 100644 --- a/runtime/gc/accounting/space_bitmap.h +++ b/runtime/gc/accounting/space_bitmap.h @@ -212,7 +212,7 @@ class SpaceSetMap { public: typedef std::set< const mirror::Object*, std::less<const mirror::Object*>, - GCAllocator<const mirror::Object*> > Objects; + GcAllocator<const mirror::Object*> > Objects; bool IsEmpty() const { return contained_.empty(); diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index d26e28c..804c669 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -66,7 +66,7 @@ static constexpr bool kDumpGcPerformanceOnShutdown = false; static constexpr size_t kMinConcurrentRemainingBytes = 128 * KB; Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free, - double target_utilization, size_t capacity, const std::string& original_image_file_name, + double target_utilization, size_t capacity, const std::string& image_file_name, bool concurrent_gc, size_t parallel_gc_threads, size_t conc_gc_threads, bool low_memory_mode, size_t long_pause_log_threshold, size_t long_gc_log_threshold, bool ignore_max_footprint) @@ -144,9 +144,8 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max // Requested begin for the alloc space, to follow the mapped image and oat files byte* requested_alloc_space_begin = NULL; - std::string image_file_name(original_image_file_name); if (!image_file_name.empty()) { - space::ImageSpace* image_space = space::ImageSpace::Create(image_file_name); + space::ImageSpace* image_space = space::ImageSpace::Create(image_file_name.c_str()); CHECK(image_space != NULL) << "Failed to create space for " << image_file_name; AddContinuousSpace(image_space); // Oat files referenced by image files immediately follow them in memory, ensure alloc space diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc index 468d1d2..8c13d79 100644 --- a/runtime/gc/space/dlmalloc_space.cc +++ b/runtime/gc/space/dlmalloc_space.cc @@ -183,11 +183,12 @@ DlMallocSpace* DlMallocSpace::Create(const std::string& name, size_t initial_siz growth_limit = RoundUp(growth_limit, kPageSize); capacity = RoundUp(capacity, kPageSize); + std::string error_msg; UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), requested_begin, capacity, - PROT_READ | PROT_WRITE)); + PROT_READ | PROT_WRITE, &error_msg)); if (mem_map.get() == NULL) { LOG(ERROR) << "Failed to allocate pages for alloc space (" << name << ") of size " - << PrettySize(capacity); + << PrettySize(capacity) << ": " << error_msg; return NULL; } @@ -307,7 +308,10 @@ DlMallocSpace* DlMallocSpace::CreateZygoteSpace(const char* alloc_space_name) { VLOG(heap) << "Size " << GetMemMap()->Size(); VLOG(heap) << "GrowthLimit " << PrettySize(growth_limit); VLOG(heap) << "Capacity " << PrettySize(capacity); - UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(alloc_space_name, End(), capacity, PROT_READ | PROT_WRITE)); + std::string error_msg; + UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(alloc_space_name, End(), capacity, + PROT_READ | PROT_WRITE, &error_msg)); + CHECK(mem_map.get() != nullptr) << error_msg; void* mspace = CreateMallocSpace(end_, starting_size, initial_size); // Protect memory beyond the initial size. byte* end = mem_map->Begin() + starting_size; diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 1cd33ee..fa28642 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -44,12 +44,13 @@ ImageSpace::ImageSpace(const std::string& name, MemMap* mem_map, live_bitmap_.reset(live_bitmap); } -static bool GenerateImage(const std::string& image_file_name) { +static bool GenerateImage(const std::string& image_file_name, std::string* error_msg) { const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString()); std::vector<std::string> boot_class_path; Split(boot_class_path_string, ':', boot_class_path); if (boot_class_path.empty()) { - LOG(FATAL) << "Failed to generate image because no boot class path specified"; + *error_msg = "Failed to generate image because no boot class path specified"; + return false; } std::vector<std::string> arg_vector; @@ -112,41 +113,57 @@ static bool GenerateImage(const std::string& image_file_name) { return false; } else { if (pid == -1) { - PLOG(ERROR) << "fork failed"; + *error_msg = StringPrintf("Failed to generate image '%s' because fork failed: %s", + image_file_name.c_str(), strerror(errno)); + return false; } // wait for dex2oat to finish int status; pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); if (got_pid != pid) { - PLOG(ERROR) << "waitpid failed: wanted " << pid << ", got " << got_pid; + *error_msg = StringPrintf("Failed to generate image '%s' because waitpid failed: " + "wanted %d, got %d: %s", + image_file_name.c_str(), pid, got_pid, strerror(errno)); return false; } if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - LOG(ERROR) << dex2oat << " failed: " << command_line; + *error_msg = StringPrintf("Failed to generate image '%s' because dex2oat failed: %s", + image_file_name.c_str(), command_line.c_str()); return false; } } return true; } -ImageSpace* ImageSpace::Create(const std::string& original_image_file_name) { - if (OS::FileExists(original_image_file_name.c_str())) { +ImageSpace* ImageSpace::Create(const char* original_image_file_name) { + if (OS::FileExists(original_image_file_name)) { // If the /system file exists, it should be up-to-date, don't try to generate - return space::ImageSpace::Init(original_image_file_name, false); + std::string error_msg; + ImageSpace* space = ImageSpace::Init(original_image_file_name, false, &error_msg); + if (space == nullptr) { + LOG(FATAL) << "Failed to load image '" << original_image_file_name << "': " << error_msg; + } + return space; } // If the /system file didn't exist, we need to use one from the dalvik-cache. // If the cache file exists, try to open, but if it fails, regenerate. // If it does not exist, generate. std::string image_file_name(GetDalvikCacheFilenameOrDie(original_image_file_name)); + std::string error_msg; if (OS::FileExists(image_file_name.c_str())) { - space::ImageSpace* image_space = space::ImageSpace::Init(image_file_name, true); - if (image_space != NULL) { + space::ImageSpace* image_space = ImageSpace::Init(image_file_name.c_str(), true, &error_msg); + if (image_space != nullptr) { return image_space; } } - CHECK(GenerateImage(image_file_name)) << "Failed to generate image: " << image_file_name; - return space::ImageSpace::Init(image_file_name, true); + CHECK(GenerateImage(image_file_name, &error_msg)) + << "Failed to generate image '" << image_file_name << "': " << error_msg; + ImageSpace* space = ImageSpace::Init(image_file_name.c_str(), true, &error_msg); + if (space == nullptr) { + LOG(FATAL) << "Failed to load image '" << original_image_file_name << "': " << error_msg; + } + return space; } void ImageSpace::VerifyImageAllocations() { @@ -160,8 +177,9 @@ void ImageSpace::VerifyImageAllocations() { } } -ImageSpace* ImageSpace::Init(const std::string& image_file_name, bool validate_oat_file) { - CHECK(!image_file_name.empty()); +ImageSpace* ImageSpace::Init(const char* image_file_name, bool validate_oat_file, + std::string* error_msg) { + CHECK(image_file_name != nullptr); uint64_t start_time = 0; if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) { @@ -169,16 +187,16 @@ ImageSpace* ImageSpace::Init(const std::string& image_file_name, bool validate_o LOG(INFO) << "ImageSpace::Init entering image_file_name=" << image_file_name; } - UniquePtr<File> file(OS::OpenFileForReading(image_file_name.c_str())); + UniquePtr<File> file(OS::OpenFileForReading(image_file_name)); if (file.get() == NULL) { - LOG(ERROR) << "Failed to open " << image_file_name; - return NULL; + *error_msg = StringPrintf("Failed to open '%s'", image_file_name); + return nullptr; } ImageHeader image_header; bool success = file->ReadFully(&image_header, sizeof(image_header)); if (!success || !image_header.IsValid()) { - LOG(ERROR) << "Invalid image header " << image_file_name; - return NULL; + *error_msg = StringPrintf("Invalid image header in '%s'", image_file_name); + return nullptr; } // Note: The image header is part of the image due to mmap page alignment required of offset. @@ -188,10 +206,12 @@ ImageSpace* ImageSpace::Init(const std::string& image_file_name, bool validate_o MAP_PRIVATE | MAP_FIXED, file->Fd(), 0, - false)); + false, + image_file_name, + error_msg)); if (map.get() == NULL) { - LOG(ERROR) << "Failed to map " << image_file_name; - return NULL; + DCHECK(!error_msg->empty()); + return nullptr; } CHECK_EQ(image_header.GetImageBegin(), map->Begin()); DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader))); @@ -199,16 +219,24 @@ ImageSpace* ImageSpace::Init(const std::string& image_file_name, bool validate_o UniquePtr<MemMap> image_map(MemMap::MapFileAtAddress(nullptr, image_header.GetImageBitmapSize(), PROT_READ, MAP_PRIVATE, file->Fd(), image_header.GetBitmapOffset(), - false)); - CHECK(image_map.get() != nullptr) << "failed to map image bitmap"; + false, + image_file_name, + error_msg)); + if (image_map.get() == nullptr) { + *error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str()); + return nullptr; + } size_t bitmap_index = bitmap_index_.fetch_add(1); - std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_file_name.c_str(), + std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_file_name, bitmap_index)); UniquePtr<accounting::SpaceBitmap> bitmap( accounting::SpaceBitmap::CreateFromMemMap(bitmap_name, image_map.release(), reinterpret_cast<byte*>(map->Begin()), map->Size())); - CHECK(bitmap.get() != nullptr) << "could not create " << bitmap_name; + if (bitmap.get() == nullptr) { + *error_msg = StringPrintf("Could not create bitmap '%s'", bitmap_name.c_str()); + return nullptr; + } Runtime* runtime = Runtime::Current(); mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod); @@ -226,15 +254,15 @@ ImageSpace* ImageSpace::Init(const std::string& image_file_name, bool validate_o space->VerifyImageAllocations(); } - space->oat_file_.reset(space->OpenOatFile()); - if (space->oat_file_.get() == NULL) { - LOG(ERROR) << "Failed to open oat file for image: " << image_file_name; - return NULL; + space->oat_file_.reset(space->OpenOatFile(error_msg)); + if (space->oat_file_.get() == nullptr) { + DCHECK(!error_msg->empty()); + return nullptr; } - if (validate_oat_file && !space->ValidateOatFile()) { - LOG(WARNING) << "Failed to validate oat file for image: " << image_file_name; - return NULL; + if (validate_oat_file && !space->ValidateOatFile(error_msg)) { + DCHECK(!error_msg->empty()); + return nullptr; } if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) { @@ -244,7 +272,7 @@ ImageSpace* ImageSpace::Init(const std::string& image_file_name, bool validate_o return space.release(); } -OatFile* ImageSpace::OpenOatFile() const { +OatFile* ImageSpace::OpenOatFile(std::string* error_msg) const { const Runtime* runtime = Runtime::Current(); const ImageHeader& image_header = GetImageHeader(); // Grab location but don't use Object::AsString as we haven't yet initialized the roots to @@ -255,45 +283,47 @@ OatFile* ImageSpace::OpenOatFile() const { oat_filename += runtime->GetHostPrefix(); oat_filename += oat_location->ToModifiedUtf8(); OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, image_header.GetOatDataBegin(), - !Runtime::Current()->IsCompiler()); + !Runtime::Current()->IsCompiler(), error_msg); if (oat_file == NULL) { - LOG(ERROR) << "Failed to open oat file " << oat_filename << " referenced from image."; - return NULL; + *error_msg = StringPrintf("Failed to open oat file '%s' referenced from image %s: %s", + oat_filename.c_str(), GetName(), error_msg->c_str()); + return nullptr; } uint32_t oat_checksum = oat_file->GetOatHeader().GetChecksum(); uint32_t image_oat_checksum = image_header.GetOatChecksum(); if (oat_checksum != image_oat_checksum) { - LOG(ERROR) << "Failed to match oat file checksum " << std::hex << oat_checksum - << " to expected oat checksum " << std::hex << image_oat_checksum - << " in image"; - return NULL; + *error_msg = StringPrintf("Failed to match oat file checksum 0x%x to expected oat checksum 0x%x" + " in image %s", oat_checksum, image_oat_checksum, GetName()); + return nullptr; } return oat_file; } -bool ImageSpace::ValidateOatFile() const { +bool ImageSpace::ValidateOatFile(std::string* error_msg) const { CHECK(oat_file_.get() != NULL); for (const OatFile::OatDexFile* oat_dex_file : oat_file_->GetOatDexFiles()) { const std::string& dex_file_location = oat_dex_file->GetDexFileLocation(); uint32_t dex_file_location_checksum; - if (!DexFile::GetChecksum(dex_file_location.c_str(), &dex_file_location_checksum)) { - LOG(WARNING) << "ValidateOatFile could not find checksum for " << dex_file_location; + if (!DexFile::GetChecksum(dex_file_location.c_str(), &dex_file_location_checksum, error_msg)) { + *error_msg = StringPrintf("Failed to get checksum of dex file '%s' referenced by image %s: " + "%s", dex_file_location.c_str(), GetName(), error_msg->c_str()); return false; } if (dex_file_location_checksum != oat_dex_file->GetDexFileLocationChecksum()) { - LOG(WARNING) << "ValidateOatFile found checksum mismatch between oat file " - << oat_file_->GetLocation() << " and dex file " << dex_file_location - << " (" << oat_dex_file->GetDexFileLocationChecksum() << " != " - << dex_file_location_checksum << ")"; + *error_msg = StringPrintf("ValidateOatFile found checksum mismatch between oat file '%s' and " + "dex file '%s' (0x%x != 0x%x)", + oat_file_->GetLocation().c_str(), dex_file_location.c_str(), + oat_dex_file->GetDexFileLocationChecksum(), + dex_file_location_checksum); return false; } } return true; } -OatFile& ImageSpace::ReleaseOatFile() { +OatFile* ImageSpace::ReleaseOatFile() { CHECK(oat_file_.get() != NULL); - return *oat_file_.release(); + return oat_file_.release(); } void ImageSpace::Dump(std::ostream& os) const { diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h index 381a98e..78a83c9 100644 --- a/runtime/gc/space/image_space.h +++ b/runtime/gc/space/image_space.h @@ -45,12 +45,11 @@ class ImageSpace : public MemMapSpace { // creation of the alloc space. The ReleaseOatFile will later be // used to transfer ownership of the OatFile to the ClassLinker when // it is initialized. - static ImageSpace* Create(const std::string& image) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + static ImageSpace* Create(const char* image) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Releases the OatFile from the ImageSpace so it can be transfer to // the caller, presumably the ClassLinker. - OatFile& ReleaseOatFile() + OatFile* ReleaseOatFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void VerifyImageAllocations() @@ -84,13 +83,13 @@ class ImageSpace : public MemMapSpace { // image's OatFile is up-to-date relative to its DexFile // inputs. Otherwise (for /data), validate the inputs and generate // the OatFile in /data/dalvik-cache if necessary. - static ImageSpace* Init(const std::string& image, bool validate_oat_file) + static ImageSpace* Init(const char* image, bool validate_oat_file, std::string* error_msg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - OatFile* OpenOatFile() const + OatFile* OpenOatFile(std::string* error_msg) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool ValidateOatFile() const + bool ValidateOatFile(std::string* error_msg) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); friend class Space; diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc index c6d028e..1321b19 100644 --- a/runtime/gc/space/large_object_space.cc +++ b/runtime/gc/space/large_object_space.cc @@ -56,10 +56,13 @@ LargeObjectMapSpace* LargeObjectMapSpace::Create(const std::string& name) { return new LargeObjectMapSpace(name); } -mirror::Object* LargeObjectMapSpace::Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated) { +mirror::Object* LargeObjectMapSpace::Alloc(Thread* self, size_t num_bytes, + size_t* bytes_allocated) { + std::string error_msg; MemMap* mem_map = MemMap::MapAnonymous("large object space allocation", NULL, num_bytes, - PROT_READ | PROT_WRITE); - if (mem_map == NULL) { + PROT_READ | PROT_WRITE, &error_msg); + if (UNLIKELY(mem_map == NULL)) { + LOG(WARNING) << "Large object allocation failed: " << error_msg; return NULL; } MutexLock mu(self, lock_); @@ -129,9 +132,10 @@ bool LargeObjectMapSpace::Contains(const mirror::Object* obj) const { FreeListSpace* FreeListSpace::Create(const std::string& name, byte* requested_begin, size_t size) { CHECK_EQ(size % kAlignment, 0U); + std::string error_msg; MemMap* mem_map = MemMap::MapAnonymous(name.c_str(), requested_begin, size, - PROT_READ | PROT_WRITE); - CHECK(mem_map != NULL) << "Failed to allocate large object space mem map"; + PROT_READ | PROT_WRITE, &error_msg); + CHECK(mem_map != NULL) << "Failed to allocate large object space mem map: " << error_msg; return new FreeListSpace(name, mem_map, mem_map->Begin(), mem_map->End()); } diff --git a/runtime/gc/space/large_object_space.h b/runtime/gc/space/large_object_space.h index 3f2e848..ef889d4 100644 --- a/runtime/gc/space/large_object_space.h +++ b/runtime/gc/space/large_object_space.h @@ -96,9 +96,9 @@ class LargeObjectMapSpace : public LargeObjectSpace { // Used to ensure mutual exclusion when the allocation spaces data structures are being modified. mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; std::vector<mirror::Object*, - accounting::GCAllocator<mirror::Object*> > large_objects_ GUARDED_BY(lock_); + accounting::GcAllocator<mirror::Object*> > large_objects_ GUARDED_BY(lock_); typedef SafeMap<mirror::Object*, MemMap*, std::less<mirror::Object*>, - accounting::GCAllocator<std::pair<const mirror::Object*, MemMap*> > > MemMaps; + accounting::GcAllocator<std::pair<const mirror::Object*, MemMap*> > > MemMaps; MemMaps mem_maps_ GUARDED_BY(lock_); }; @@ -217,7 +217,7 @@ class FreeListSpace : public LargeObjectSpace { AllocationHeader* GetAllocationHeader(const mirror::Object* obj); typedef std::set<AllocationHeader*, AllocationHeader::SortByPrevFree, - accounting::GCAllocator<AllocationHeader*> > FreeBlocks; + accounting::GcAllocator<AllocationHeader*> > FreeBlocks; byte* const begin_; byte* const end_; diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc index 6451d5c..00316f7 100644 --- a/runtime/mem_map.cc +++ b/runtime/mem_map.cc @@ -67,7 +67,8 @@ static void CheckMapRequest(byte* addr, size_t byte_count) { static void CheckMapRequest(byte*, size_t) { } #endif -MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t byte_count, int prot) { +MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t byte_count, int prot, + std::string* error_msg) { if (byte_count == 0) { return new MemMap(name, NULL, 0, NULL, 0, prot); } @@ -82,8 +83,8 @@ MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t byte_count, in ScopedFd fd(ashmem_create_region(debug_friendly_name.c_str(), page_aligned_byte_count)); int flags = MAP_PRIVATE; if (fd.get() == -1) { - PLOG(ERROR) << "ashmem_create_region failed (" << name << ")"; - return NULL; + *error_msg = StringPrintf("ashmem_create_region failed for '%s': %s", name, strerror(errno)); + return nullptr; } #else ScopedFd fd(-1); @@ -94,16 +95,17 @@ MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t byte_count, in if (actual == MAP_FAILED) { std::string maps; ReadFileToString("/proc/self/maps", &maps); - PLOG(ERROR) << "mmap(" << reinterpret_cast<void*>(addr) << ", " << page_aligned_byte_count - << ", " << prot << ", " << flags << ", " << fd.get() << ", 0) failed for " << name - << "\n" << maps; - return NULL; + *error_msg = StringPrintf("anonymous mmap(%p, %zd, %x, %x, %d, 0) failed\n%s", + addr, page_aligned_byte_count, prot, flags, fd.get(), + maps.c_str()); + return nullptr; } return new MemMap(name, actual, byte_count, actual, page_aligned_byte_count, prot); } -MemMap* MemMap::MapFileAtAddress(byte* addr, size_t byte_count, - int prot, int flags, int fd, off_t start, bool reuse) { +MemMap* MemMap::MapFileAtAddress(byte* addr, size_t byte_count, int prot, int flags, int fd, + off_t start, bool reuse, const char* filename, + std::string* error_msg) { CHECK_NE(0, prot); CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE)); if (byte_count == 0) { @@ -133,10 +135,10 @@ MemMap* MemMap::MapFileAtAddress(byte* addr, size_t byte_count, if (actual == MAP_FAILED) { std::string maps; ReadFileToString("/proc/self/maps", &maps); - PLOG(ERROR) << "mmap(" << reinterpret_cast<void*>(page_aligned_addr) - << ", " << page_aligned_byte_count - << ", " << prot << ", " << flags << ", " << fd << ", " << page_aligned_offset - << ") failed\n" << maps; + *error_msg = StringPrintf("mmap(%p, %zd, %x, %x, %d, %lld) of file '%s' failed\n%s", + page_aligned_addr, page_aligned_byte_count, prot, flags, fd, + static_cast<int64_t>(page_aligned_offset), + filename, maps.c_str()); return NULL; } return new MemMap("file", actual + page_offset, byte_count, actual, page_aligned_byte_count, diff --git a/runtime/mem_map.h b/runtime/mem_map.h index e294824..919463c 100644 --- a/runtime/mem_map.h +++ b/runtime/mem_map.h @@ -38,14 +38,16 @@ class MemMap { // a name. // // On success, returns returns a MemMap instance. On failure, returns a NULL; - static MemMap* MapAnonymous(const char* ashmem_name, byte* addr, size_t byte_count, int prot); + static MemMap* MapAnonymous(const char* ashmem_name, byte* addr, size_t byte_count, int prot, + std::string* error_msg); // Map part of a file, taking care of non-page aligned offsets. The // "start" offset is absolute, not relative. // // On success, returns returns a MemMap instance. On failure, returns a NULL; - static MemMap* MapFile(size_t byte_count, int prot, int flags, int fd, off_t start) { - return MapFileAtAddress(NULL, byte_count, prot, flags, fd, start, false); + static MemMap* MapFile(size_t byte_count, int prot, int flags, int fd, off_t start, + const char* filename, std::string* error_msg) { + return MapFileAtAddress(NULL, byte_count, prot, flags, fd, start, false, filename, error_msg); } // Map part of a file, taking care of non-page aligned offsets. The @@ -53,8 +55,9 @@ class MemMap { // requesting a specific address for the base of the mapping. // // On success, returns returns a MemMap instance. On failure, returns a NULL; - static MemMap* MapFileAtAddress( - byte* addr, size_t byte_count, int prot, int flags, int fd, off_t start, bool reuse); + static MemMap* MapFileAtAddress(byte* addr, size_t byte_count, int prot, int flags, int fd, + off_t start, bool reuse, const char* filename, + std::string* error_msg); // Releases the memory mapping ~MemMap(); diff --git a/runtime/mem_map_test.cc b/runtime/mem_map_test.cc index dade01b..09de320 100644 --- a/runtime/mem_map_test.cc +++ b/runtime/mem_map_test.cc @@ -24,11 +24,14 @@ namespace art { class MemMapTest : public testing::Test {}; TEST_F(MemMapTest, MapAnonymousEmpty) { + std::string error_msg; UniquePtr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty", NULL, 0, - PROT_READ)); - ASSERT_TRUE(map.get() != NULL); + PROT_READ, + &error_msg)); + ASSERT_TRUE(map.get() != NULL) << error_msg; + ASSERT_TRUE(error_msg.empty()); } } // namespace art diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 4e17b79..af09a1c 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -89,34 +89,32 @@ static jint DexFile_openDexFileNative(JNIEnv* env, jclass, jstring javaSourceNam if (sourceName.c_str() == NULL) { return 0; } - std::string dex_location(sourceName.c_str()); NullableScopedUtfChars outputName(env, javaOutputName); if (env->ExceptionCheck()) { return 0; } - ScopedObjectAccess soa(env); + uint32_t dex_location_checksum; - if (!DexFile::GetChecksum(dex_location, &dex_location_checksum)) { - LOG(WARNING) << "Failed to compute checksum: " << dex_location; - ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow(); - soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/io/IOException;", - "Unable to get checksum of dex file: %s", dex_location.c_str()); + std::string error_msg; + if (!DexFile::GetChecksum(sourceName.c_str(), &dex_location_checksum, &error_msg)) { + ScopedObjectAccess soa(env); + DCHECK(!error_msg.empty()); + ThrowIOException("%s", error_msg.c_str()); return 0; } ClassLinker* linker = Runtime::Current()->GetClassLinker(); const DexFile* dex_file; - if (outputName.c_str() == NULL) { - dex_file = linker->FindDexFileInOatFileFromDexLocation(dex_location, dex_location_checksum); + if (outputName.c_str() == nullptr) { + dex_file = linker->FindDexFileInOatFileFromDexLocation(sourceName.c_str(), + dex_location_checksum, &error_msg); } else { - std::string oat_location(outputName.c_str()); - dex_file = linker->FindOrCreateOatFileForDexLocation(dex_location, dex_location_checksum, oat_location); + dex_file = linker->FindOrCreateOatFileForDexLocation(sourceName.c_str(), dex_location_checksum, + outputName.c_str(), &error_msg); } - if (dex_file == NULL) { - LOG(WARNING) << "Failed to open dex file: " << dex_location; - ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow(); - soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/io/IOException;", - "Unable to open dex file: %s", dex_location.c_str()); + if (dex_file == nullptr) { + ScopedObjectAccess soa(env); + ThrowIOException("%s", error_msg.c_str()); return 0; } return static_cast<jint>(reinterpret_cast<uintptr_t>(dex_file)); @@ -188,21 +186,17 @@ static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jint cookie) { } static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename) { - bool debug_logging = false; + const bool kVerboseLogging = false; // Spammy logging. + const bool kDebugLogging = true; // Logging useful for debugging. ScopedUtfChars filename(env, javaFilename); - if (filename.c_str() == NULL) { - LOG(ERROR) << "DexFile_isDexOptNeeded null filename"; - return JNI_TRUE; - } - if (!OS::FileExists(filename.c_str())) { + if ((filename.c_str() == nullptr) || !OS::FileExists(filename.c_str())) { LOG(ERROR) << "DexFile_isDexOptNeeded file '" << filename.c_str() << "' does not exist"; - ScopedObjectAccess soa(env); - ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow(); - soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/io/FileNotFoundException;", - "%s", filename.c_str()); - return JNI_TRUE; + ScopedLocalRef<jclass> fnfe(env, env->FindClass("java/io/FileNotFoundException")); + const char* message = (filename.c_str() == nullptr) ? "<empty file name>" : filename.c_str(); + env->ThrowNew(fnfe.get(), message); + return JNI_FALSE; } // Always treat elements of the bootclasspath as up-to-date. The @@ -212,7 +206,7 @@ static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename const std::vector<const DexFile*>& boot_class_path = class_linker->GetBootClassPath(); for (size_t i = 0; i < boot_class_path.size(); i++) { if (boot_class_path[i]->GetLocation() == filename.c_str()) { - if (debug_logging) { + if (kVerboseLogging) { LOG(INFO) << "DexFile_isDexOptNeeded ignoring boot class path file: " << filename.c_str(); } return JNI_FALSE; @@ -221,26 +215,32 @@ static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename // Check if we have an odex file next to the dex file. std::string odex_filename(OatFile::DexFilenameToOdexFilename(filename.c_str())); - UniquePtr<const OatFile> oat_file(OatFile::Open(odex_filename, odex_filename, NULL, false)); - if (oat_file.get() != NULL) { - ScopedObjectAccess soa(env); - const art::OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename.c_str(), NULL); - if (oat_dex_file == NULL) { - if (debug_logging) { - LOG(INFO) << "DexFile_isDexOptNeeded GetOatDexFile failed"; - } - } else { + std::string error_msg; + UniquePtr<const OatFile> oat_file(OatFile::Open(odex_filename, odex_filename, NULL, false, + &error_msg)); + if (oat_file.get() == nullptr) { + if (kVerboseLogging) { + LOG(INFO) << "DexFile_isDexOptNeeded failed to open oat file '" << filename.c_str() + << "': " << error_msg; + } + error_msg.clear(); + } else { + const art::OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename.c_str(), NULL, + kDebugLogging); + if (oat_dex_file != nullptr) { uint32_t location_checksum; - // If we have no classes.dex checksum such as in a user build, assume up-to-date. - if (!DexFile::GetChecksum(filename.c_str(), &location_checksum)) { - if (debug_logging) { + // If its not possible to read the classes.dex assume up-to-date as we won't be able to + // compile it anyway. + if (!DexFile::GetChecksum(filename.c_str(), &location_checksum, &error_msg)) { + if (kVerboseLogging) { LOG(INFO) << "DexFile_isDexOptNeeded ignoring precompiled stripped file: " - << filename.c_str(); + << filename.c_str() << ": " << error_msg; } return JNI_FALSE; } - if (ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum)) { - if (debug_logging) { + if (ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum, + &error_msg)) { + if (kVerboseLogging) { LOG(INFO) << "DexFile_isDexOptNeeded precompiled file " << odex_filename << " is up-to-date checksum compared to " << filename.c_str(); } @@ -251,10 +251,12 @@ static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename // Check if we have an oat file in the cache std::string cache_location(GetDalvikCacheFilenameOrDie(filename.c_str())); - oat_file.reset(OatFile::Open(cache_location, filename.c_str(), NULL, false)); - if (oat_file.get() == NULL) { - LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location - << " does not exist for " << filename.c_str(); + oat_file.reset(OatFile::Open(cache_location, filename.c_str(), NULL, false, &error_msg)); + if (oat_file.get() == nullptr) { + if (kDebugLogging) { + LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location + << " does not exist for " << filename.c_str() << ": " << error_msg; + } return JNI_TRUE; } @@ -262,41 +264,53 @@ static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename if (space->IsImageSpace()) { // TODO: Ensure this works with multiple image spaces. const ImageHeader& image_header = space->AsImageSpace()->GetImageHeader(); - if (oat_file->GetOatHeader().GetImageFileLocationOatChecksum() != image_header.GetOatChecksum()) { - ScopedObjectAccess soa(env); - LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location - << " has out-of-date oat checksum compared to " - << image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8(); + if (oat_file->GetOatHeader().GetImageFileLocationOatChecksum() != + image_header.GetOatChecksum()) { + if (kDebugLogging) { + ScopedObjectAccess soa(env); + LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location + << " has out-of-date oat checksum compared to " + << image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8(); + } return JNI_TRUE; } if (oat_file->GetOatHeader().GetImageFileLocationOatDataBegin() != reinterpret_cast<uint32_t>(image_header.GetOatDataBegin())) { - ScopedObjectAccess soa(env); - LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location - << " has out-of-date oat begin compared to " - << image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8(); + if (kDebugLogging) { + ScopedObjectAccess soa(env); + LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location + << " has out-of-date oat begin compared to " + << image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8(); + } return JNI_TRUE; } } } - ScopedObjectAccess soa(env); uint32_t location_checksum; - if (!DexFile::GetChecksum(filename.c_str(), &location_checksum)) { - LOG(ERROR) << "DexFile_isDexOptNeeded failed to compute checksum of " << filename.c_str(); + if (!DexFile::GetChecksum(filename.c_str(), &location_checksum, &error_msg)) { + if (kDebugLogging) { + LOG(ERROR) << "DexFile_isDexOptNeeded failed to compute checksum of " << filename.c_str() + << " (error " << error_msg << ")"; + } return JNI_TRUE; } - if (!ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum)) { - LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location - << " has out-of-date checksum compared to " << filename.c_str(); + if (!ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum, + &error_msg)) { + if (kDebugLogging) { + LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location + << " has out-of-date checksum compared to " << filename.c_str() + << " (error " << error_msg << ")"; + } return JNI_TRUE; } - if (debug_logging) { + if (kVerboseLogging) { LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location << " is up-to-date for " << filename.c_str(); } + CHECK(error_msg.empty()) << error_msg; return JNI_FALSE; } diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc index c23b08c..af1b548 100644 --- a/runtime/native/java_lang_VMClassLoader.cc +++ b/runtime/native/java_lang_VMClassLoader.cc @@ -72,8 +72,10 @@ static jstring VMClassLoader_getBootClassPathResource(JNIEnv* env, jclass, jstri } const DexFile* dex_file = path[index]; const std::string& location(dex_file->GetLocation()); - UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(location)); - if (zip_archive.get() == NULL) { + std::string error_msg; + UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(location.c_str(), &error_msg)); + if (zip_archive.get() == nullptr) { + LOG(WARNING) << "Failed to open zip archive '" << location << "': " << error_msg; return NULL; } UniquePtr<ZipEntry> zip_entry(zip_archive->Find(name.c_str())); diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 7ecaf01..7553dcc 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -48,19 +48,21 @@ void OatFile::CheckLocation(const std::string& location) { } OatFile* OatFile::OpenMemory(std::vector<uint8_t>& oat_contents, - const std::string& location) { + const std::string& location, + std::string* error_msg) { CHECK(!oat_contents.empty()) << location; CheckLocation(location); UniquePtr<OatFile> oat_file(new OatFile(location)); oat_file->begin_ = &oat_contents[0]; oat_file->end_ = &oat_contents[oat_contents.size()]; - return oat_file->Setup() ? oat_file.release() : NULL; + return oat_file->Setup(error_msg) ? oat_file.release() : nullptr; } OatFile* OatFile::Open(const std::string& filename, const std::string& location, byte* requested_base, - bool executable) { + bool executable, + std::string* error_msg) { CHECK(!filename.empty()) << location; CheckLocation(filename); #ifdef ART_USE_PORTABLE_COMPILER @@ -70,7 +72,7 @@ OatFile* OatFile::Open(const std::string& filename, // open a generated dex file by name, remove the file, then open // another generated dex file with the same name. http://b/10614658 if (executable) { - return OpenDlopen(filename, location, requested_base); + return OpenDlopen(filename, location, requested_base, error_msg); } #endif // If we aren't trying to execute, we just use our own ElfFile loader for a couple reasons: @@ -83,21 +85,22 @@ OatFile* OatFile::Open(const std::string& filename, if (file.get() == NULL) { return NULL; } - return OpenElfFile(file.get(), location, requested_base, false, executable); + return OpenElfFile(file.get(), location, requested_base, false, executable, error_msg); } -OatFile* OatFile::OpenWritable(File* file, const std::string& location) { +OatFile* OatFile::OpenWritable(File* file, const std::string& location, std::string* error_msg) { CheckLocation(location); - return OpenElfFile(file, location, NULL, true, false); + return OpenElfFile(file, location, NULL, true, false, error_msg); } OatFile* OatFile::OpenDlopen(const std::string& elf_filename, const std::string& location, - byte* requested_base) { + byte* requested_base, + std::string* error_msg) { UniquePtr<OatFile> oat_file(new OatFile(location)); - bool success = oat_file->Dlopen(elf_filename, requested_base); + bool success = oat_file->Dlopen(elf_filename, requested_base, error_msg); if (!success) { - return NULL; + return nullptr; } return oat_file.release(); } @@ -106,11 +109,13 @@ OatFile* OatFile::OpenElfFile(File* file, const std::string& location, byte* requested_base, bool writable, - bool executable) { + bool executable, + std::string* error_msg) { UniquePtr<OatFile> oat_file(new OatFile(location)); - bool success = oat_file->ElfFileOpen(file, requested_base, writable, executable); + bool success = oat_file->ElfFileOpen(file, requested_base, writable, executable, error_msg); if (!success) { - return NULL; + CHECK(!error_msg->empty()); + return nullptr; } return oat_file.release(); } @@ -127,120 +132,117 @@ OatFile::~OatFile() { } } -bool OatFile::Dlopen(const std::string& elf_filename, byte* requested_base) { +bool OatFile::Dlopen(const std::string& elf_filename, byte* requested_base, + std::string* error_msg) { char* absolute_path = realpath(elf_filename.c_str(), NULL); if (absolute_path == NULL) { - VLOG(class_linker) << "Failed to find absolute path for " << elf_filename; + *error_msg = StringPrintf("Failed to find absolute path for '%s'", elf_filename.c_str()); return false; } dlopen_handle_ = dlopen(absolute_path, RTLD_NOW); free(absolute_path); if (dlopen_handle_ == NULL) { - VLOG(class_linker) << "Failed to dlopen " << elf_filename << ": " << dlerror(); + *error_msg = StringPrintf("Failed to dlopen '%s': %s", elf_filename.c_str(), dlerror()); return false; } begin_ = reinterpret_cast<byte*>(dlsym(dlopen_handle_, "oatdata")); if (begin_ == NULL) { - LOG(WARNING) << "Failed to find oatdata symbol in " << elf_filename << ": " << dlerror(); + *error_msg = StringPrintf("Failed to find oatdata symbol in '%s': %s", elf_filename.c_str(), + dlerror()); return false; } if (requested_base != NULL && begin_ != requested_base) { - std::string maps; - ReadFileToString("/proc/self/maps", &maps); - LOG(WARNING) << "Failed to find oatdata symbol at expected address: oatdata=" - << reinterpret_cast<const void*>(begin_) << " != expected=" - << reinterpret_cast<const void*>(requested_base) - << " /proc/self/maps:\n" << maps; + *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: " + "oatdata=%p != expected=%p /proc/self/maps:\n", + begin_, requested_base); + ReadFileToString("/proc/self/maps", error_msg); return false; } end_ = reinterpret_cast<byte*>(dlsym(dlopen_handle_, "oatlastword")); if (end_ == NULL) { - LOG(WARNING) << "Failed to find oatlastword symbol in " << elf_filename << ": " << dlerror(); + *error_msg = StringPrintf("Failed to find oatlastword symbol in '%s': %s", elf_filename.c_str(), + dlerror()); return false; } // Readjust to be non-inclusive upper bound. end_ += sizeof(uint32_t); - return Setup(); + return Setup(error_msg); } -bool OatFile::ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable) { - elf_file_.reset(ElfFile::Open(file, writable, true)); - if (elf_file_.get() == NULL) { - if (writable) { - PLOG(WARNING) << "Failed to open ELF file for " << file->GetPath(); - } +bool OatFile::ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable, + std::string* error_msg) { + elf_file_.reset(ElfFile::Open(file, writable, true, error_msg)); + if (elf_file_.get() == nullptr) { + DCHECK(!error_msg->empty()); return false; } - bool loaded = elf_file_->Load(executable); + bool loaded = elf_file_->Load(executable, error_msg); if (!loaded) { - LOG(WARNING) << "Failed to load ELF file " << file->GetPath(); + DCHECK(!error_msg->empty()); return false; } begin_ = elf_file_->FindDynamicSymbolAddress("oatdata"); if (begin_ == NULL) { - LOG(WARNING) << "Failed to find oatdata symbol in " << file->GetPath(); + *error_msg = StringPrintf("Failed to find oatdata symbol in '%s'", file->GetPath().c_str()); return false; } if (requested_base != NULL && begin_ != requested_base) { - std::string maps; - ReadFileToString("/proc/self/maps", &maps); - LOG(WARNING) << "Failed to find oatdata symbol at expected address: oatdata=" - << reinterpret_cast<const void*>(begin_) << " != expected=" - << reinterpret_cast<const void*>(requested_base) - << " /proc/self/maps:\n" << maps; + *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: " + "oatdata=%p != expected=%p /proc/self/maps:\n", + begin_, requested_base); + ReadFileToString("/proc/self/maps", error_msg); return false; } end_ = elf_file_->FindDynamicSymbolAddress("oatlastword"); if (end_ == NULL) { - LOG(WARNING) << "Failed to find oatlastword symbol in " << file->GetPath(); + *error_msg = StringPrintf("Failed to find oatlastword symbol in '%s'", file->GetPath().c_str()); return false; } // Readjust to be non-inclusive upper bound. end_ += sizeof(uint32_t); - return Setup(); + return Setup(error_msg); } -bool OatFile::Setup() { +bool OatFile::Setup(std::string* error_msg) { if (!GetOatHeader().IsValid()) { - LOG(WARNING) << "Invalid oat magic for " << GetLocation(); + *error_msg = StringPrintf("Invalid oat magic for '%s'", GetLocation().c_str()); return false; } const byte* oat = Begin(); oat += sizeof(OatHeader); if (oat > End()) { - LOG(ERROR) << "In oat file " << GetLocation() << " found truncated OatHeader"; + *error_msg = StringPrintf("In oat file '%s' found truncated OatHeader", GetLocation().c_str()); return false; } oat += GetOatHeader().GetImageFileLocationSize(); if (oat > End()) { - LOG(ERROR) << "In oat file " << GetLocation() << " found truncated image file location: " - << reinterpret_cast<const void*>(Begin()) - << "+" << sizeof(OatHeader) - << "+" << GetOatHeader().GetImageFileLocationSize() - << "<=" << reinterpret_cast<const void*>(End()); + *error_msg = StringPrintf("In oat file '%s' found truncated image file location: " + "%p + %zd + %ud <= %p", GetLocation().c_str(), + Begin(), sizeof(OatHeader), GetOatHeader().GetImageFileLocationSize(), + End()); return false; } for (size_t i = 0; i < GetOatHeader().GetDexFileCount(); i++) { size_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat); - if (dex_file_location_size == 0U) { - LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i - << " with empty location name"; + if (UNLIKELY(dex_file_location_size == 0U)) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with empty location name", + GetLocation().c_str(), i); return false; } oat += sizeof(dex_file_location_size); - if (oat > End()) { - LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i - << " truncated after dex file location size"; + if (UNLIKELY(oat > End())) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd truncated after dex file " + "location size", GetLocation().c_str(), i); return false; } const char* dex_file_location_data = reinterpret_cast<const char*>(oat); oat += dex_file_location_size; - if (oat > End()) { - LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i - << " with truncated dex file location"; + if (UNLIKELY(oat > End())) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with truncated dex file " + "location", GetLocation().c_str(), i); return false; } @@ -248,55 +250,54 @@ bool OatFile::Setup() { uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat); oat += sizeof(dex_file_checksum); - if (oat > End()) { - LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i - << " for "<< dex_file_location - << " truncated after dex file checksum"; + if (UNLIKELY(oat > End())) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated after " + "dex file checksum", GetLocation().c_str(), i, + dex_file_location.c_str()); return false; } uint32_t dex_file_offset = *reinterpret_cast<const uint32_t*>(oat); - if (dex_file_offset == 0U) { - LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i - << " for "<< dex_file_location - << " with zero dex file offset"; + if (UNLIKELY(dex_file_offset == 0U)) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with zero dex " + "file offset", GetLocation().c_str(), i, dex_file_location.c_str()); return false; } - if (dex_file_offset > Size()) { - LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i - << " for "<< dex_file_location - << " with dex file offset" << dex_file_offset << " > " << Size(); + if (UNLIKELY(dex_file_offset > Size())) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with dex file " + "offset %ud > %zd", GetLocation().c_str(), i, + dex_file_location.c_str(), dex_file_offset, Size()); return false; } oat += sizeof(dex_file_offset); - if (oat > End()) { - LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i - << " for "<< dex_file_location - << " truncated after dex file offset"; + if (UNLIKELY(oat > End())) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated " + " after dex file offsets", GetLocation().c_str(), i, + dex_file_location.c_str()); return false; } const uint8_t* dex_file_pointer = Begin() + dex_file_offset; - if (!DexFile::IsMagicValid(dex_file_pointer)) { - LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i - << " for "<< dex_file_location - << " with invalid dex file magic: " << dex_file_pointer; + if (UNLIKELY(!DexFile::IsMagicValid(dex_file_pointer))) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid " + " dex file magic '%s'", GetLocation().c_str(), i, + dex_file_location.c_str(), dex_file_pointer); return false; } - if (!DexFile::IsVersionValid(dex_file_pointer)) { - LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i - << " for "<< dex_file_location - << " with invalid dex file version: " << dex_file_pointer; + if (UNLIKELY(!DexFile::IsVersionValid(dex_file_pointer))) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid " + " dex file version '%s'", GetLocation().c_str(), i, + dex_file_location.c_str(), dex_file_pointer); return false; } const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer); const uint32_t* methods_offsets_pointer = reinterpret_cast<const uint32_t*>(oat); oat += (sizeof(*methods_offsets_pointer) * header->class_defs_size_); - if (oat > End()) { - LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i - << " for "<< dex_file_location - << " with truncated method offsets"; + if (UNLIKELY(oat > End())) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with truncated " + " method offsets", GetLocation().c_str(), i, + dex_file_location.c_str()); return false; } @@ -323,8 +324,8 @@ const byte* OatFile::End() const { return end_; } -const OatFile::OatDexFile* OatFile::GetOatDexFile(const std::string& dex_location, - const uint32_t* const dex_location_checksum, +const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location, + const uint32_t* dex_location_checksum, bool warn_if_not_found) const { Table::const_iterator it = oat_dex_files_.find(dex_location); if (it != oat_dex_files_.end()) { @@ -373,9 +374,9 @@ size_t OatFile::OatDexFile::FileSize() const { return reinterpret_cast<const DexFile::Header*>(dex_file_pointer_)->file_size_; } -const DexFile* OatFile::OatDexFile::OpenDexFile() const { +const DexFile* OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const { return DexFile::Open(dex_file_pointer_, FileSize(), dex_file_location_, - dex_file_location_checksum_); + dex_file_location_checksum_, error_msg); } const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) const { diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 270976f..af14760 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -45,18 +45,20 @@ class OatFile { static OatFile* Open(const std::string& filename, const std::string& location, byte* requested_base, - bool executable); + bool executable, + std::string* error_msg); // Open an oat file from an already opened File. // Does not use dlopen underneath so cannot be used for runtime use // where relocations may be required. Currently used from // ImageWriter which wants to open a writable version from an existing // file descriptor for patching. - static OatFile* OpenWritable(File* file, const std::string& location); + static OatFile* OpenWritable(File* file, const std::string& location, std::string* error_msg); // Open an oat file backed by a std::vector with the given location. static OatFile* OpenMemory(std::vector<uint8_t>& oat_contents, - const std::string& location); + const std::string& location, + std::string* error_msg); ~OatFile(); @@ -167,7 +169,7 @@ class OatFile { class OatDexFile { public: // Opens the DexFile referred to by this OatDexFile from within the containing OatFile. - const DexFile* OpenDexFile() const; + const DexFile* OpenDexFile(std::string* error_msg) const; // Returns the size of the DexFile refered to by this OatDexFile. size_t FileSize() const; @@ -204,10 +206,10 @@ class OatFile { DISALLOW_COPY_AND_ASSIGN(OatDexFile); }; - const OatDexFile* GetOatDexFile(const std::string& dex_location, + const OatDexFile* GetOatDexFile(const char* dex_location, const uint32_t* const dex_location_checksum, - bool exception_if_not_found = true) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool exception_if_not_found = true) const; + std::vector<const OatDexFile*> GetOatDexFiles() const; size_t Size() const { @@ -219,18 +221,21 @@ class OatFile { static OatFile* OpenDlopen(const std::string& elf_filename, const std::string& location, - byte* requested_base); + byte* requested_base, + std::string* error_msg); static OatFile* OpenElfFile(File* file, const std::string& location, byte* requested_base, bool writable, - bool executable); + bool executable, + std::string* error_msg); explicit OatFile(const std::string& filename); - bool Dlopen(const std::string& elf_filename, byte* requested_base); - bool ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable); - bool Setup(); + bool Dlopen(const std::string& elf_filename, byte* requested_base, std::string* error_msg); + bool ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable, + std::string* error_msg); + bool Setup(std::string* error_msg); const byte* Begin() const; const byte* End() const; diff --git a/runtime/utils.cc b/runtime/utils.cc index e2852a6..f9e4ebe 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -718,9 +718,9 @@ bool IsValidPartOfMemberNameUtf8Slow(const char** pUtf8Ptr) { * this function returns false, then the given pointer may only have * been partially advanced. */ -bool IsValidPartOfMemberNameUtf8(const char** pUtf8Ptr) { +static bool IsValidPartOfMemberNameUtf8(const char** pUtf8Ptr) { uint8_t c = (uint8_t) **pUtf8Ptr; - if (c <= 0x7f) { + if (LIKELY(c <= 0x7f)) { // It's low-ascii, so check the table. uint32_t wordIdx = c >> 5; uint32_t bitIdx = c & 0x1f; @@ -761,7 +761,7 @@ bool IsValidMemberName(const char* s) { } enum ClassNameType { kName, kDescriptor }; -bool IsValidClassName(const char* s, ClassNameType type, char separator) { +static bool IsValidClassName(const char* s, ClassNameType type, char separator) { int arrayCount = 0; while (*s == '[') { arrayCount++; @@ -1194,12 +1194,12 @@ std::string GetDalvikCacheOrDie(const char* android_data) { return dalvik_cache; } -std::string GetDalvikCacheFilenameOrDie(const std::string& location) { +std::string GetDalvikCacheFilenameOrDie(const char* location) { std::string dalvik_cache(GetDalvikCacheOrDie(GetAndroidData())); if (location[0] != '/') { LOG(FATAL) << "Expected path in location to be absolute: "<< location; } - std::string cache_file(location, 1); // skip leading slash + std::string cache_file(&location[1]); // skip leading slash if (!EndsWith(location, ".dex") && !EndsWith(location, ".art")) { cache_file += "/"; cache_file += DexFile::kClassesDex; diff --git a/runtime/utils.h b/runtime/utils.h index 975f08b..0174b37 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -351,7 +351,7 @@ const char* GetAndroidData(); std::string GetDalvikCacheOrDie(const char* android_data); // Returns the dalvik-cache location for a DexFile or OatFile, or dies trying. -std::string GetDalvikCacheFilenameOrDie(const std::string& location); +std::string GetDalvikCacheFilenameOrDie(const char* location); // Check whether the given magic matches a known file type. bool IsZipMagic(uint32_t magic); diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc index 8e09e78..db273ec 100644 --- a/runtime/zip_archive.cc +++ b/runtime/zip_archive.cc @@ -19,10 +19,12 @@ #include <vector> #include <fcntl.h> +#include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> +#include "base/stringprintf.h" #include "base/unix_file/fd_file.h" #include "UniquePtr.h" @@ -247,35 +249,38 @@ static bool InflateToMemory(uint8_t* begin, size_t size, return true; } -bool ZipEntry::ExtractToFile(File& file) { +bool ZipEntry::ExtractToFile(File& file, std::string* error_msg) { uint32_t length = GetUncompressedLength(); int result = TEMP_FAILURE_RETRY(ftruncate(file.Fd(), length)); if (result == -1) { - PLOG(WARNING) << "Zip: failed to ftruncate " << file.GetPath() << " to length " << length; + *error_msg = StringPrintf("Zip: failed to ftruncate '%s' to length %ud", file.GetPath().c_str(), + length); return false; } - UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ | PROT_WRITE, MAP_SHARED, file.Fd(), 0)); + UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ | PROT_WRITE, MAP_SHARED, file.Fd(), 0, + file.GetPath().c_str(), error_msg)); if (map.get() == NULL) { - LOG(WARNING) << "Zip: failed to mmap space for " << file.GetPath(); + *error_msg = StringPrintf("Zip: failed to mmap space for '%s': %s", file.GetPath().c_str(), + error_msg->c_str()); return false; } - return ExtractToMemory(map->Begin(), map->Size()); + return ExtractToMemory(map->Begin(), map->Size(), error_msg); } -bool ZipEntry::ExtractToMemory(uint8_t* begin, size_t size) { +bool ZipEntry::ExtractToMemory(uint8_t* begin, size_t size, std::string* error_msg) { // If size is zero, data offset will be meaningless, so bail out early. if (size == 0) { return true; } off64_t data_offset = GetDataOffset(); if (data_offset == -1) { - LOG(WARNING) << "Zip: data_offset=" << data_offset; + *error_msg = StringPrintf("Zip: data_offset=%lld", data_offset); return false; } if (lseek64(zip_archive_->fd_, data_offset, SEEK_SET) != data_offset) { - PLOG(WARNING) << "Zip: lseek to data at " << data_offset << " failed"; + *error_msg = StringPrintf("Zip: lseek to data at %lld failed", data_offset); return false; } @@ -288,25 +293,25 @@ bool ZipEntry::ExtractToMemory(uint8_t* begin, size_t size) { return InflateToMemory(begin, size, zip_archive_->fd_, GetUncompressedLength(), GetCompressedLength()); default: - LOG(WARNING) << "Zip: unknown compression method " << std::hex << GetCompressionMethod(); + *error_msg = StringPrintf("Zip: unknown compression method 0x%x", GetCompressionMethod()); return false; } } -MemMap* ZipEntry::ExtractToMemMap(const char* entry_filename) { +MemMap* ZipEntry::ExtractToMemMap(const char* entry_filename, std::string* error_msg) { std::string name(entry_filename); name += " extracted in memory from "; name += entry_filename; UniquePtr<MemMap> map(MemMap::MapAnonymous(name.c_str(), NULL, GetUncompressedLength(), - PROT_READ | PROT_WRITE)); - if (map.get() == NULL) { - LOG(ERROR) << "Zip: mmap for '" << entry_filename << "' failed"; + PROT_READ | PROT_WRITE, error_msg)); + if (map.get() == nullptr) { + DCHECK(!error_msg->empty()); return NULL; } - bool success = ExtractToMemory(map->Begin(), map->Size()); + bool success = ExtractToMemory(map->Begin(), map->Size(), error_msg); if (!success) { LOG(ERROR) << "Zip: Failed to extract '" << entry_filename << "' to memory"; return NULL; @@ -329,27 +334,25 @@ static void SetCloseOnExec(int fd) { } } -ZipArchive* ZipArchive::Open(const std::string& filename) { - DCHECK(!filename.empty()); - int fd = open(filename.c_str(), O_RDONLY, 0); +ZipArchive* ZipArchive::Open(const char* filename, std::string* error_msg) { + DCHECK(filename != nullptr); + int fd = open(filename, O_RDONLY, 0); if (fd == -1) { - PLOG(WARNING) << "Unable to open '" << filename << "'"; + *error_msg = StringPrintf("Zip: unable to open '%s': %s", filename, strerror(errno)); return NULL; } - return OpenFromFd(fd); + return OpenFromFd(fd, filename, error_msg); } -ZipArchive* ZipArchive::OpenFromFd(int fd) { +ZipArchive* ZipArchive::OpenFromFd(int fd, const char* filename, std::string* error_msg) { SetCloseOnExec(fd); - UniquePtr<ZipArchive> zip_archive(new ZipArchive(fd)); - if (zip_archive.get() == NULL) { - return NULL; - } - if (!zip_archive->MapCentralDirectory()) { + UniquePtr<ZipArchive> zip_archive(new ZipArchive(fd, filename)); + CHECK(zip_archive.get() != nullptr); + if (!zip_archive->MapCentralDirectory(error_msg)) { zip_archive->Close(); return NULL; } - if (!zip_archive->Parse()) { + if (!zip_archive->Parse(error_msg)) { zip_archive->Close(); return NULL; } @@ -374,19 +377,28 @@ void ZipArchive::Close() { dir_offset_ = 0; } +std::string ZipArchive::ErrorStringPrintf(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + std::string result(StringPrintf("Zip '%s' : ", filename_.c_str())); + StringAppendV(&result, fmt, ap); + va_end(ap); + return result; +} + // Find the zip Central Directory and memory-map it. // // On success, returns true after populating fields from the EOCD area: // num_entries_ // dir_offset_ // dir_map_ -bool ZipArchive::MapCentralDirectory() { +bool ZipArchive::MapCentralDirectory(std::string* error_msg) { /* * Get and test file length. */ off64_t file_length = lseek64(fd_, 0, SEEK_END); if (file_length < kEOCDLen) { - LOG(WARNING) << "Zip: length " << file_length << " is too small to be zip"; + *error_msg = ErrorStringPrintf("length %lld is too small to be zip", file_length); return false; } @@ -396,27 +408,26 @@ bool ZipArchive::MapCentralDirectory() { } UniquePtr<uint8_t[]> scan_buf(new uint8_t[read_amount]); - if (scan_buf.get() == NULL) { - return false; - } + CHECK(scan_buf.get() != nullptr); /* * Make sure this is a Zip archive. */ if (lseek64(fd_, 0, SEEK_SET) != 0) { - PLOG(WARNING) << "seek to start failed: "; + *error_msg = ErrorStringPrintf("seek to start failed: %s", strerror(errno)); return false; } ssize_t actual = TEMP_FAILURE_RETRY(read(fd_, scan_buf.get(), sizeof(int32_t))); if (actual != static_cast<ssize_t>(sizeof(int32_t))) { - PLOG(INFO) << "couldn't read first signature from zip archive: "; + *error_msg = ErrorStringPrintf("couldn\'t read first signature from zip archive: %s", + strerror(errno)); return false; } unsigned int header = Le32ToHost(scan_buf.get()); if (header != kLFHSignature) { - LOG(VERBOSE) << "Not a Zip archive (found " << std::hex << header << ")"; + *error_msg = ErrorStringPrintf("not a zip archive (found 0x%x)", header); return false; } @@ -433,12 +444,13 @@ bool ZipArchive::MapCentralDirectory() { off64_t search_start = file_length - read_amount; if (lseek64(fd_, search_start, SEEK_SET) != search_start) { - PLOG(WARNING) << "Zip: seek " << search_start << " failed"; + *error_msg = ErrorStringPrintf("seek %lld failed: %s", search_start, strerror(errno)); return false; } actual = TEMP_FAILURE_RETRY(read(fd_, scan_buf.get(), read_amount)); if (actual != static_cast<ssize_t>(read_amount)) { - PLOG(WARNING) << "Zip: read " << actual << ", expected " << read_amount << ". failed"; + *error_msg = ErrorStringPrintf("read %lld, expected %zd. %s", search_start, read_amount, + strerror(errno)); return false; } @@ -454,14 +466,14 @@ bool ZipArchive::MapCentralDirectory() { } } if (i < 0) { - LOG(WARNING) << "Zip: EOCD not found, not a zip file"; + *error_msg = ErrorStringPrintf("EOCD not found, not a zip file"); return false; } off64_t eocd_offset = search_start + i; const byte* eocd_ptr = scan_buf.get() + i; - DCHECK(eocd_offset < file_length); + CHECK(eocd_offset < file_length); // Grab the CD offset and size, and the number of entries in the // archive. Verify that they look reasonable. @@ -474,29 +486,28 @@ bool ZipArchive::MapCentralDirectory() { uint16_t comment_size = Le16ToHost(eocd_ptr + kEOCDCommentSize); if ((uint64_t) dir_offset + (uint64_t) dir_size > (uint64_t) eocd_offset) { - LOG(WARNING) << "Zip: bad offsets (" - << "dir=" << dir_offset << ", " - << "size=" << dir_size << ", " - << "eocd=" << eocd_offset << ")"; + *error_msg = ErrorStringPrintf("bad offsets (dir=%ud, size=%ud, eocd=%lld)", + dir_offset, dir_size, eocd_offset); return false; } if (num_entries == 0) { - LOG(WARNING) << "Zip: empty archive?"; + *error_msg = ErrorStringPrintf("empty archive?"); return false; } else if (num_entries != total_num_entries || disk_number != 0 || disk_with_central_dir != 0) { - LOG(WARNING) << "spanned archives not supported"; + *error_msg = ErrorStringPrintf("spanned archives not supported"); return false; } // Check to see if comment is a sane size if ((comment_size > (file_length - kEOCDLen)) || (eocd_offset > (file_length - kEOCDLen) - comment_size)) { - LOG(WARNING) << "comment size runs off end of file"; + *error_msg = ErrorStringPrintf("comment size runs off end of file"); return false; } // It all looks good. Create a mapping for the CD. - dir_map_.reset(MemMap::MapFile(dir_size, PROT_READ, MAP_SHARED, fd_, dir_offset)); + dir_map_.reset(MemMap::MapFile(dir_size, PROT_READ, MAP_SHARED, fd_, dir_offset, + filename_.c_str(), error_msg)); if (dir_map_.get() == NULL) { return false; } @@ -506,7 +517,7 @@ bool ZipArchive::MapCentralDirectory() { return true; } -bool ZipArchive::Parse() { +bool ZipArchive::Parse(std::string* error_msg) { const byte* cd_ptr = dir_map_->Begin(); size_t cd_length = dir_map_->Size(); @@ -515,23 +526,23 @@ bool ZipArchive::Parse() { const byte* ptr = cd_ptr; for (int i = 0; i < num_entries_; i++) { if (Le32ToHost(ptr) != kCDESignature) { - LOG(WARNING) << "Zip: missed a central dir sig (at " << i << ")"; + *error_msg = ErrorStringPrintf("missed a central dir sig (at %d)", i); return false; } if (ptr + kCDELen > cd_ptr + cd_length) { - LOG(WARNING) << "Zip: ran off the end (at " << i << ")"; + *error_msg = ErrorStringPrintf("ran off the end (at %d)", i); return false; } int64_t local_hdr_offset = Le32ToHost(ptr + kCDELocalOffset); if (local_hdr_offset >= dir_offset_) { - LOG(WARNING) << "Zip: bad LFH offset " << local_hdr_offset << " at entry " << i; + *error_msg = ErrorStringPrintf("bad LFH offset %lld at entry %d", local_hdr_offset, i); return false; } uint16_t gpbf = Le16ToHost(ptr + kCDEGPBFlags); if ((gpbf & kGPFUnsupportedMask) != 0) { - LOG(WARNING) << "Invalid General Purpose Bit Flag: " << gpbf; + *error_msg = ErrorStringPrintf("invalid general purpose bit flag %x", gpbf); return false; } @@ -544,16 +555,15 @@ bool ZipArchive::Parse() { // Check name for NULL characters if (memchr(name, 0, name_len) != NULL) { - LOG(WARNING) << "Filename contains NUL byte"; + *error_msg = ErrorStringPrintf("filename contains NUL byte"); return false; } dir_entries_.Put(StringPiece(name, name_len), ptr); ptr += kCDELen + name_len + extra_len + comment_len; if (ptr > cd_ptr + cd_length) { - LOG(WARNING) << "Zip: bad CD advance " - << "(" << ptr << " vs " << (cd_ptr + cd_length) << ") " - << "at entry " << i; + *error_msg = ErrorStringPrintf("bad CD advance (%p vs %p) at entry %d", + ptr, cd_ptr + cd_length, i); return false; } } diff --git a/runtime/zip_archive.h b/runtime/zip_archive.h index d9ccba2..8ff952b 100644 --- a/runtime/zip_archive.h +++ b/runtime/zip_archive.h @@ -19,6 +19,7 @@ #include <stdint.h> #include <zlib.h> +#include <string> #include "base/logging.h" #include "base/stringpiece.h" @@ -36,9 +37,9 @@ class MemMap; class ZipEntry { public: - bool ExtractToFile(File& file); - bool ExtractToMemory(uint8_t* begin, size_t size); - MemMap* ExtractToMemMap(const char* entry_filename); + bool ExtractToFile(File& file, std::string* error_msg); + bool ExtractToMemory(uint8_t* begin, size_t size, std::string* error_msg); + MemMap* ExtractToMemMap(const char* entry_filename, std::string* error_msg); uint32_t GetUncompressedLength(); uint32_t GetCrc32(); @@ -109,8 +110,8 @@ class ZipArchive { static const int32_t kGPFUnsupportedMask = (kGPFEncryptedFlag); // return new ZipArchive instance on success, NULL on error. - static ZipArchive* Open(const std::string& filename); - static ZipArchive* OpenFromFd(int fd); + static ZipArchive* Open(const char* filename, std::string* error_msg); + static ZipArchive* OpenFromFd(int fd, const char* filename, std::string* error_msg); ZipEntry* Find(const char* name) const; @@ -119,11 +120,14 @@ class ZipArchive { } private: - explicit ZipArchive(int fd) : fd_(fd), num_entries_(0), dir_offset_(0) {} + explicit ZipArchive(int fd, const char* filename) + : fd_(fd), num_entries_(0), dir_offset_(0), filename_(filename) {} - bool MapCentralDirectory(); - bool Parse(); + bool MapCentralDirectory(std::string* error_msg); + bool Parse(std::string* error_msg); void Close(); + std::string ErrorStringPrintf(const char* fmt, ...) + __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR; int fd_; uint16_t num_entries_; @@ -131,6 +135,8 @@ class ZipArchive { UniquePtr<MemMap> dir_map_; typedef SafeMap<StringPiece, const byte*> DirEntries; DirEntries dir_entries_; + // Containing file for error reporting. + const std::string filename_; friend class ZipEntry; diff --git a/runtime/zip_archive_test.cc b/runtime/zip_archive_test.cc index 9bdc24b..622dc89 100644 --- a/runtime/zip_archive_test.cc +++ b/runtime/zip_archive_test.cc @@ -29,8 +29,10 @@ namespace art { class ZipArchiveTest : public CommonTest {}; TEST_F(ZipArchiveTest, FindAndExtract) { - UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(GetLibCoreDexFileName())); - ASSERT_TRUE(zip_archive.get() != false); + std::string error_msg; + UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(GetLibCoreDexFileName().c_str(), &error_msg)); + ASSERT_TRUE(zip_archive.get() != false) << error_msg; + ASSERT_TRUE(error_msg.empty()); UniquePtr<ZipEntry> zip_entry(zip_archive->Find("classes.dex")); ASSERT_TRUE(zip_entry.get() != false); @@ -38,8 +40,9 @@ TEST_F(ZipArchiveTest, FindAndExtract) { ASSERT_NE(-1, tmp.GetFd()); UniquePtr<File> file(new File(tmp.GetFd(), tmp.GetFilename())); ASSERT_TRUE(file.get() != NULL); - bool success = zip_entry->ExtractToFile(*file); - ASSERT_TRUE(success); + bool success = zip_entry->ExtractToFile(*file, &error_msg); + ASSERT_TRUE(success) << error_msg; + ASSERT_TRUE(error_msg.empty()); file.reset(NULL); uint32_t computed_crc = crc32(0L, Z_NULL, 0); |