summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler.cc20
-rw-r--r--src/dex_verifier.cc39
-rw-r--r--src/dex_verifier.h8
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_;