summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/class_linker.cc20
-rw-r--r--runtime/class_linker.h5
-rw-r--r--runtime/vdex_file.cc141
-rw-r--r--runtime/vdex_file.h10
-rw-r--r--runtime/verifier/verifier_deps.cc11
-rw-r--r--runtime/verifier/verifier_deps.h4
-rw-r--r--test/692-vdex-inmem-loader/vdex_inmem_loader.cc2
-rw-r--r--test/800-smali/jni.cc7
8 files changed, 183 insertions, 17 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 361749073a..6641f80299 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -145,6 +145,7 @@
#include "thread_list.h"
#include "trace.h"
#include "transaction.h"
+#include "vdex_file.h"
#include "verifier/class_verifier.h"
#include "well_known_classes.h"
@@ -4623,7 +4624,7 @@ verifier::FailureKind ClassLinker::VerifyClass(
// Try to use verification information from the oat file, otherwise do runtime verification.
const DexFile& dex_file = *klass->GetDexCache()->GetDexFile();
ClassStatus oat_file_class_status(ClassStatus::kNotReady);
- bool preverified = VerifyClassUsingOatFile(dex_file, klass.Get(), oat_file_class_status);
+ bool preverified = VerifyClassUsingOatFile(self, dex_file, klass, oat_file_class_status);
VLOG(class_linker) << "Class preverified status for class "
<< klass->PrettyDescriptor()
@@ -4738,8 +4739,9 @@ verifier::FailureKind ClassLinker::PerformClassVerification(Thread* self,
error_msg);
}
-bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file,
- ObjPtr<mirror::Class> klass,
+bool ClassLinker::VerifyClassUsingOatFile(Thread* self,
+ const DexFile& dex_file,
+ Handle<mirror::Class> klass,
ClassStatus& oat_file_class_status) {
// If we're compiling, we can only verify the class using the oat file if
// we are not compiling the image or if the class we're verifying is not part of
@@ -4748,7 +4750,7 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file,
if (Runtime::Current()->IsAotCompiler()) {
CompilerCallbacks* callbacks = Runtime::Current()->GetCompilerCallbacks();
// We are compiling an app (not the image).
- if (!callbacks->CanUseOatStatusForVerification(klass.Ptr())) {
+ if (!callbacks->CanUseOatStatusForVerification(klass.Get())) {
return false;
}
}
@@ -4769,6 +4771,16 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file,
// check the class status to ensure we run with access checks.
return true;
}
+
+ // Check the class status with the vdex file.
+ const OatFile* oat_file = oat_dex_file->GetOatFile();
+ if (oat_file != nullptr) {
+ oat_file_class_status = oat_file->GetVdexFile()->ComputeClassStatus(self, klass);
+ if (oat_file_class_status >= ClassStatus::kVerifiedNeedsAccessChecks) {
+ return true;
+ }
+ }
+
// If we only verified a subset of the classes at compile time, we can end up with classes that
// were resolved by the verifier.
if (oat_file_class_status == ClassStatus::kResolved) {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index f9becf97b2..95dc6cfaff 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -557,8 +557,9 @@ class ClassLinker {
verifier::HardFailLogMode log_level = verifier::HardFailLogMode::kLogNone)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_);
- bool VerifyClassUsingOatFile(const DexFile& dex_file,
- ObjPtr<mirror::Class> klass,
+ bool VerifyClassUsingOatFile(Thread* self,
+ const DexFile& dex_file,
+ Handle<mirror::Class> klass,
ClassStatus& oat_file_class_status)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_);
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index d67a968ae8..70fde27105 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -37,7 +37,9 @@
#include "dex_to_dex_decompiler.h"
#include "gc/heap.h"
#include "gc/space/image_space.h"
+#include "mirror/class-inl.h"
#include "quicken_info.h"
+#include "handle_scope-inl.h"
#include "runtime.h"
#include "verifier/verifier_deps.h"
@@ -506,4 +508,143 @@ bool VdexFile::MatchesClassLoaderContext(const ClassLoaderContext& context) cons
}
}
+static ObjPtr<mirror::Class> FindClassAndClearException(ClassLinker* class_linker,
+ Thread* self,
+ const char* name,
+ Handle<mirror::ClassLoader> class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ObjPtr<mirror::Class> result = class_linker->FindClass(self, name, class_loader);
+ if (result == nullptr) {
+ DCHECK(self->IsExceptionPending());
+ self->ClearException();
+ }
+ return result;
+}
+
+static const char* GetStringFromId(const DexFile& dex_file,
+ dex::StringIndex string_id,
+ uint32_t number_of_extra_strings,
+ const uint32_t* extra_strings_offsets,
+ const uint8_t* verifier_deps) {
+ uint32_t num_ids_in_dex = dex_file.NumStringIds();
+ if (string_id.index_ < num_ids_in_dex) {
+ return dex_file.StringDataByIdx(string_id);
+ } else {
+ CHECK_LT(string_id.index_ - num_ids_in_dex, number_of_extra_strings);
+ uint32_t offset = extra_strings_offsets[string_id.index_ - num_ids_in_dex];
+ return reinterpret_cast<const char*>(verifier_deps) + offset;
+ }
+}
+
+// Returns an array of offsets where the assignability checks for each class
+// definition are stored.
+static const uint32_t* GetDexFileClassDefs(const uint8_t* verifier_deps, uint32_t index) {
+ uint32_t dex_file_offset = reinterpret_cast<const uint32_t*>(verifier_deps)[index];
+ return reinterpret_cast<const uint32_t*>(verifier_deps + dex_file_offset);
+}
+
+// Returns an array of offsets where extra strings are stored.
+static const uint32_t* GetExtraStringsOffsets(const DexFile& dex_file,
+ const uint8_t* verifier_deps,
+ const uint32_t* dex_file_class_defs,
+ /*out*/ uint32_t* number_of_extra_strings) {
+ // The information for strings is right after dex_file_class_defs, 4-byte
+ // aligned
+ uint32_t end_of_assignability_types = dex_file_class_defs[dex_file.NumClassDefs()];
+ const uint8_t* strings_data_start =
+ AlignUp(verifier_deps + end_of_assignability_types, sizeof(uint32_t));
+ // First entry is the number of extra strings for this dex file.
+ *number_of_extra_strings = *reinterpret_cast<const uint32_t*>(strings_data_start);
+ // Then an array of offsets in `verifier_deps` for the extra strings.
+ return reinterpret_cast<const uint32_t*>(strings_data_start + sizeof(uint32_t));
+}
+
+ClassStatus VdexFile::ComputeClassStatus(Thread* self, Handle<mirror::Class> cls) const {
+ const DexFile& dex_file = cls->GetDexFile();
+ uint16_t class_def_index = cls->GetDexClassDefIndex();
+
+ // Find which dex file index from within the vdex file.
+ uint32_t index = 0;
+ for (; index < GetVerifierDepsHeader().GetNumberOfDexFiles(); ++index) {
+ if (dex_file.GetLocationChecksum() == GetLocationChecksum(index)) {
+ break;
+ }
+ }
+ DCHECK_NE(index, GetVerifierDepsHeader().GetNumberOfDexFiles());
+
+ const uint8_t* verifier_deps = GetVerifierDepsStart();
+ const uint32_t* dex_file_class_defs = GetDexFileClassDefs(verifier_deps, index);
+
+ // Fetch type checks offsets.
+ uint32_t class_def_offset = dex_file_class_defs[class_def_index];
+ if (class_def_offset == verifier::VerifierDeps::kNotVerifiedMarker) {
+ // Return a status that needs re-verification.
+ return ClassStatus::kResolved;
+ }
+ // End offset for this class's type checks. We know there is one and the loop
+ // will terminate.
+ uint32_t end_offset = verifier::VerifierDeps::kNotVerifiedMarker;
+ for (uint32_t i = class_def_index + 1; i < dex_file.NumClassDefs() + 1; ++i) {
+ end_offset = dex_file_class_defs[i];
+ if (end_offset != verifier::VerifierDeps::kNotVerifiedMarker) {
+ break;
+ }
+ }
+ DCHECK_NE(end_offset, verifier::VerifierDeps::kNotVerifiedMarker);
+
+ uint32_t number_of_extra_strings = 0;
+ // Offset where extra strings are stored.
+ const uint32_t* extra_strings_offsets = GetExtraStringsOffsets(dex_file,
+ verifier_deps,
+ dex_file_class_defs,
+ &number_of_extra_strings);
+
+ // Loop over and perform each assignability check.
+ StackHandleScope<3> hs(self);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(cls->GetClassLoader()));
+ MutableHandle<mirror::Class> source(hs.NewHandle<mirror::Class>(nullptr));
+ MutableHandle<mirror::Class> destination(hs.NewHandle<mirror::Class>(nullptr));
+
+ const uint8_t* cursor = verifier_deps + class_def_offset;
+ const uint8_t* end = verifier_deps + end_offset;
+ while (cursor < end) {
+ uint32_t destination_index;
+ uint32_t source_index;
+ if (UNLIKELY(!DecodeUnsignedLeb128Checked(&cursor, end, &destination_index) ||
+ !DecodeUnsignedLeb128Checked(&cursor, end, &source_index))) {
+ // Error parsing the data, just return that we are not verified.
+ return ClassStatus::kResolved;
+ }
+ const char* destination_desc = GetStringFromId(dex_file,
+ dex::StringIndex(destination_index),
+ number_of_extra_strings,
+ extra_strings_offsets,
+ verifier_deps);
+ destination.Assign(
+ FindClassAndClearException(class_linker, self, destination_desc, class_loader));
+
+ const char* source_desc = GetStringFromId(dex_file,
+ dex::StringIndex(source_index),
+ number_of_extra_strings,
+ extra_strings_offsets,
+ verifier_deps);
+ source.Assign(FindClassAndClearException(class_linker, self, source_desc, class_loader));
+
+ if (destination == nullptr || source == nullptr) {
+ // The interpreter / compiler can handle a missing class.
+ continue;
+ }
+
+ DCHECK(destination->IsResolved() && source->IsResolved());
+ if (!destination->IsAssignableFrom(source.Get())) {
+ // An implicit assignability check is failing in the code, return that the
+ // class is not verified.
+ return ClassStatus::kResolved;
+ }
+ }
+
+ return ClassStatus::kVerifiedNeedsAccessChecks;
+}
+
} // namespace art
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index c8823ab131..97655f6599 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -24,13 +24,20 @@
#include "base/macros.h"
#include "base/mem_map.h"
#include "base/os.h"
+#include "class_status.h"
#include "dex/compact_offset_table.h"
#include "dex/dex_file.h"
#include "quicken_info.h"
+#include "handle.h"
namespace art {
class ClassLoaderContext;
+class Thread;
+
+namespace mirror {
+class Class;
+}
namespace verifier {
class VerifierDeps;
@@ -374,6 +381,9 @@ class VdexFile {
// dequickening.
void AllowWriting(bool value) const;
+ ClassStatus ComputeClassStatus(Thread* self, Handle<mirror::Class> cls) const
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
private:
uint32_t GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const;
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index 0fdc8c6302..7a27a0152a 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -385,10 +385,6 @@ static inline bool DecodeTuple(const uint8_t** in, const uint8_t* end, std::tupl
return true;
}
-// Marker to know whether a class is verified. A non-verified class will have
-// this marker as its offset entry in the encoded data.
-static uint32_t constexpr kNotVerifiedMarker = std::numeric_limits<uint32_t>::max();
-
static void SetUint32InUint8Array(std::vector<uint8_t>* out,
uint32_t uint8_offset,
uint32_t uint32_offset,
@@ -414,7 +410,7 @@ static void EncodeSetVector(std::vector<uint8_t>* out,
EncodeTuple(out, entry);
}
} else {
- SetUint32InUint8Array(out, offsets_index, class_def_index, kNotVerifiedMarker);
+ SetUint32InUint8Array(out, offsets_index, class_def_index, VerifierDeps::kNotVerifiedMarker);
}
class_def_index++;
}
@@ -435,7 +431,7 @@ static bool DecodeSetVector(const uint8_t** cursor,
*cursor += (num_class_defs + 1) * sizeof(uint32_t);
for (uint32_t i = 0; i < num_class_defs; ++i) {
uint32_t offset = offsets[i];
- if (offset == kNotVerifiedMarker) {
+ if (offset == VerifierDeps::kNotVerifiedMarker) {
(*verified_classes)[i] = false;
continue;
}
@@ -446,7 +442,8 @@ static bool DecodeSetVector(const uint8_t** cursor,
// Find the offset of the next entry. This will tell us where to stop when
// reading the checks. Note that the last entry in the `offsets` array points
// to the end of the assignability types data, so the loop will terminate correctly.
- while (next_valid_offset_index <= i || offsets[next_valid_offset_index] == kNotVerifiedMarker) {
+ while (next_valid_offset_index <= i ||
+ offsets[next_valid_offset_index] == VerifierDeps::kNotVerifiedMarker) {
next_valid_offset_index++;
}
const uint8_t* set_end = start + offsets[next_valid_offset_index];
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index d2a564e941..40ece5fee4 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -62,6 +62,10 @@ class VerifierDeps {
public:
explicit VerifierDeps(const std::vector<const DexFile*>& dex_files, bool output_only = true);
+ // Marker to know whether a class is verified. A non-verified class will have
+ // this marker as its offset entry in the encoded data.
+ static uint32_t constexpr kNotVerifiedMarker = std::numeric_limits<uint32_t>::max();
+
// Fill dependencies from stored data. Returns true on success, false on failure.
bool ParseStoredData(const std::vector<const DexFile*>& dex_files, ArrayRef<const uint8_t> data);
diff --git a/test/692-vdex-inmem-loader/vdex_inmem_loader.cc b/test/692-vdex-inmem-loader/vdex_inmem_loader.cc
index a10e2e7054..1d78f8dc68 100644
--- a/test/692-vdex-inmem-loader/vdex_inmem_loader.cc
+++ b/test/692-vdex-inmem-loader/vdex_inmem_loader.cc
@@ -158,7 +158,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_areClassesPreverified(JNIEnv*,
ClassStatus oat_file_class_status(ClassStatus::kNotReady);
bool is_preverified = class_linker->VerifyClassUsingOatFile(
- *dex_file, h_class.Get(), oat_file_class_status);
+ soa.Self(), *dex_file, h_class, oat_file_class_status);
if (is_first) {
all_preverified = is_preverified;
diff --git a/test/800-smali/jni.cc b/test/800-smali/jni.cc
index bf9e88ab45..15830a3cf2 100644
--- a/test/800-smali/jni.cc
+++ b/test/800-smali/jni.cc
@@ -29,11 +29,12 @@ namespace {
extern "C" JNIEXPORT jboolean JNICALL Java_Main_isAotVerified(JNIEnv* env, jclass, jclass cls) {
ScopedObjectAccess soa(env);
Runtime* rt = Runtime::Current();
-
- ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::Class> klass = hs.NewHandle(soa.Decode<mirror::Class>(cls));
const DexFile& dex_file = *klass->GetDexCache()->GetDexFile();
ClassStatus oat_file_class_status(ClassStatus::kNotReady);
- bool ret = rt->GetClassLinker()->VerifyClassUsingOatFile(dex_file, klass, oat_file_class_status);
+ bool ret = rt->GetClassLinker()->VerifyClassUsingOatFile(
+ soa.Self(), dex_file, klass, oat_file_class_status);
return ret;
}