summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler/dex/arena_allocator.cc4
-rw-r--r--compiler/elf_fixup.cc5
-rw-r--r--compiler/elf_stripper.cc11
-rw-r--r--compiler/elf_stripper.h4
-rw-r--r--compiler/elf_writer.cc5
-rw-r--r--compiler/elf_writer_test.cc17
-rw-r--r--compiler/image_test.cc7
-rw-r--r--compiler/image_writer.cc17
-rw-r--r--compiler/oat_test.cc9
-rw-r--r--dex2oat/dex2oat.cc49
-rw-r--r--oatdump/oatdump.cc34
-rw-r--r--runtime/base/macros.h2
-rw-r--r--runtime/base/unix_file/fd_file.cc4
-rw-r--r--runtime/base/unix_file/fd_file.h4
-rw-r--r--runtime/class_linker.cc373
-rw-r--r--runtime/class_linker.h66
-rw-r--r--runtime/common_test.h16
-rw-r--r--runtime/common_throws.cc9
-rw-r--r--runtime/common_throws.h78
-rw-r--r--runtime/dex_file.cc157
-rw-r--r--runtime/dex_file.h30
-rw-r--r--runtime/dex_file_test.cc15
-rw-r--r--runtime/dex_file_verifier.cc546
-rw-r--r--runtime/dex_file_verifier.h42
-rw-r--r--runtime/dex_method_iterator_test.cc23
-rw-r--r--runtime/elf_file.cc63
-rw-r--r--runtime/elf_file.h6
-rw-r--r--runtime/gc/accounting/atomic_stack.h6
-rw-r--r--runtime/gc/accounting/card_table.cc6
-rw-r--r--runtime/gc/accounting/gc_allocator.cc18
-rw-r--r--runtime/gc/accounting/gc_allocator.h83
-rw-r--r--runtime/gc/accounting/heap_bitmap.h4
-rw-r--r--runtime/gc/accounting/mod_union_table.h4
-rw-r--r--runtime/gc/accounting/space_bitmap.cc8
-rw-r--r--runtime/gc/accounting/space_bitmap.h2
-rw-r--r--runtime/gc/heap.cc5
-rw-r--r--runtime/gc/space/dlmalloc_space.cc10
-rw-r--r--runtime/gc/space/image_space.cc130
-rw-r--r--runtime/gc/space/image_space.h11
-rw-r--r--runtime/gc/space/large_object_space.cc14
-rw-r--r--runtime/gc/space/large_object_space.h6
-rw-r--r--runtime/mem_map.cc28
-rw-r--r--runtime/mem_map.h13
-rw-r--r--runtime/mem_map_test.cc7
-rw-r--r--runtime/native/dalvik_system_DexFile.cc140
-rw-r--r--runtime/native/java_lang_VMClassLoader.cc6
-rw-r--r--runtime/oat_file.cc183
-rw-r--r--runtime/oat_file.h29
-rw-r--r--runtime/utils.cc10
-rw-r--r--runtime/utils.h2
-rw-r--r--runtime/zip_archive.cc120
-rw-r--r--runtime/zip_archive.h22
-rw-r--r--runtime/zip_archive_test.cc11
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);