diff options
| -rw-r--r-- | src/compiler.cc | 20 | ||||
| -rw-r--r-- | src/dex_verifier.cc | 39 | ||||
| -rw-r--r-- | src/dex_verifier.h | 8 |
3 files changed, 54 insertions, 13 deletions
diff --git a/src/compiler.cc b/src/compiler.cc index 9a49cdd6ec..b7583d9f89 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -60,6 +60,14 @@ namespace x86 { ByteArray* CreateJniDlsymLookupStub(); } +namespace verifier { + class DexVerifier { + public: + static const std::vector<uint8_t>* GetGcMap(Compiler::MethodReference ref); + static bool IsClassRejected(Compiler::ClassReference ref); + }; +} + static double Percentage(size_t x, size_t y) { return 100.0 * ((double)x) / ((double)(x + y)); } @@ -920,6 +928,11 @@ void Compiler::CompileClass(Context* context, size_t class_def_index) { if (SkipClass(class_loader, dex_file, class_def)) { return; } + ClassReference ref(&dex_file, class_def_index); + // Skip compiling classes with generic verifier failures since they will still fail at runtime + if (verifier::DexVerifier::IsClassRejected(ref)) { + return; + } const byte* class_data = dex_file.GetClassData(class_def); if (class_data == NULL) { // empty class, probably a marker interface @@ -1114,13 +1127,6 @@ void Compiler::SetGcMapsDexFile(const ClassLoader* class_loader, const DexFile& } } -namespace verifier { - class DexVerifier { - public: - static const std::vector<uint8_t>* GetGcMap(Compiler::MethodReference ref); - }; -} - void Compiler::SetGcMapsMethod(const DexFile& dex_file, Method* method) { if (method == NULL) { Thread::Current()->ClearException(); diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc index 04829bfee0..b68c7d570c 100644 --- a/src/dex_verifier.cc +++ b/src/dex_verifier.cc @@ -1043,12 +1043,12 @@ bool DexVerifier::Verify() { std::ostream& DexVerifier::Fail(VerifyError error) { CHECK_EQ(failure_, VERIFY_ERROR_NONE); - // If we're optimistically running verification at compile time, turn NO_xxx and ACCESS_xxx - // errors into generic errors so that we re-verify at runtime. We may fail to find or to agree - // on access because of not yet available class loaders, or class loaders that will differ at - // runtime. if (Runtime::Current()->IsCompiler()) { - switch(error) { + switch (error) { + // If we're optimistically running verification at compile time, turn NO_xxx and ACCESS_xxx + // errors into generic errors so that we re-verify at runtime. We may fail to find or to agree + // on access because of not yet available class loaders, or class loaders that will differ at + // runtime. case VERIFY_ERROR_NO_CLASS: case VERIFY_ERROR_NO_FIELD: case VERIFY_ERROR_NO_METHOD: @@ -1057,6 +1057,15 @@ std::ostream& DexVerifier::Fail(VerifyError error) { case VERIFY_ERROR_ACCESS_METHOD: error = VERIFY_ERROR_GENERIC; break; + // Generic failures at compile time will still fail at runtime, so the class is marked as + // rejected to prevent it from being compiled. + case VERIFY_ERROR_GENERIC: { + const DexFile::ClassDef* class_def = ClassHelper(method_->GetDeclaringClass()).GetClassDef(); + CHECK(class_def != NULL); + Compiler::ClassReference ref(dex_file_, dex_file_->GetIndexForClassDef(*class_def)); + AddRejectedClass(ref); + break; + } default: break; } @@ -1168,7 +1177,7 @@ bool DexVerifier::VerifyInstructions() { for(uint32_t dex_pc = 0; dex_pc < insns_size;) { if (!VerifyInstruction(inst, dex_pc)) { DCHECK_NE(failure_, VERIFY_ERROR_NONE); - fail_messages_ << "Rejecting opcode " << inst->DumpString(dex_file_) << " at " << dex_pc; + fail_messages_ << "Rejecting opcode " << inst->Name() << " at " << dex_pc; return false; } /* Flag instructions that are garbage collection points */ @@ -3073,6 +3082,10 @@ const RegType& DexVerifier::ResolveClassAndCheckAccess(uint32_t class_idx) { if (klass == NULL && !result.IsUnresolvedTypes()) { method_->GetDexCacheResolvedTypes()->Set(class_idx, result.GetClass()); } + if (result.IsUnknown()) { + Fail(VERIFY_ERROR_GENERIC) << "accessing unknown class in " << PrettyDescriptor(referrer); + return result; + } // Check if access is allowed. Unresolved types use AllocObjectFromCodeWithAccessCheck to // check at runtime if access is allowed and so pass here. if (!result.IsUnresolvedTypes() && !referrer->CanAccess(result.GetClass())) { @@ -3962,6 +3975,20 @@ void DexVerifier::DeleteGcMaps() { STLDeleteValues(&gc_maps_); } +Mutex DexVerifier::rejected_classes_lock_("verifier rejected classes lock"); +std::set<Compiler::ClassReference> DexVerifier::rejected_classes_; + +void DexVerifier::AddRejectedClass(Compiler::ClassReference ref) { + MutexLock mu(rejected_classes_lock_); + rejected_classes_.insert(ref); + CHECK(IsClassRejected(ref)); +} + +bool DexVerifier::IsClassRejected(Compiler::ClassReference ref) { + MutexLock mu(rejected_classes_lock_); + return (rejected_classes_.find(ref) != rejected_classes_.end()); +} + #if defined(ART_USE_LLVM_COMPILER) InferredRegCategoryMap const* DexVerifier::GenerateInferredRegCategoryMap() { uint32_t insns_size = code_item_->insns_size_in_code_units_; diff --git a/src/dex_verifier.h b/src/dex_verifier.h index b898859964..3008793bc0 100644 --- a/src/dex_verifier.h +++ b/src/dex_verifier.h @@ -20,6 +20,7 @@ #include <deque> #include <limits> #include <map> +#include <set> #include <vector> #include "casts.h" @@ -926,6 +927,8 @@ class DexVerifier { static const std::vector<uint8_t>* GetGcMap(Compiler::MethodReference ref); static void DeleteGcMaps(); + static bool IsClassRejected(Compiler::ClassReference ref); + private: explicit DexVerifier(Method* method); @@ -1260,6 +1263,11 @@ class DexVerifier { static GcMapTable gc_maps_; static void SetGcMap(Compiler::MethodReference ref, const std::vector<uint8_t>& gc_map); + // Set of rejected classes that skip compilation + static Mutex rejected_classes_lock_; + static std::set<Compiler::ClassReference> rejected_classes_; + static void AddRejectedClass(Compiler::ClassReference ref); + RegTypeCache reg_types_; PcToRegisterLineTable reg_table_; |