Check stored references in transactional interpreter.
For boot image extension, we need to reject references to
classes that are defined in a dex file belonging to the boot
image we're compiling against but not actually in the boot
image. Allowing such references could yield duplicate class
objects from multiple extensions.
Test: Additional tests in transaction_test.
Test: m test-art-host-gtest
Test: testrunner.py --host --interp-ac
Change-Id: I99eaec331f6d992dba60aeb98a88c268edac11ac
diff --git a/runtime/transaction.cc b/runtime/transaction.cc
index 9a51e0f..47e59a9 100644
--- a/runtime/transaction.cc
+++ b/runtime/transaction.cc
@@ -128,6 +128,42 @@
}
}
+bool Transaction::WriteValueConstraint(Thread* self, ObjPtr<mirror::Object> value) {
+ if (value == nullptr) {
+ return false; // We can always store null values.
+ }
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ MutexLock mu(self, log_lock_);
+ if (IsStrict()) {
+ // TODO: Should we restrict writes the same way as for boot image extension?
+ return false;
+ } else if (heap->GetBootImageSpaces().empty()) {
+ return false; // No constraints for boot image.
+ } else {
+ // Boot image extension.
+ // Do not allow storing references to a class or instances of a class defined in a dex file
+ // belonging to the boot image we're compiling against but not itself in the boot image.
+ // Allowing this could yield duplicate class objects from multiple extensions.
+ if (heap->ObjectIsInBootImageSpace(value)) {
+ return false; // References to boot image objects are OK.
+ }
+ ObjPtr<mirror::Class> klass = value->IsClass() ? value->AsClass() : value->GetClass();
+ if (!value->IsClass() && heap->ObjectIsInBootImageSpace(klass)) {
+ // Instances of boot image classes are OK.
+ DCHECK(klass->IsInitialized());
+ return false;
+ }
+ // For arrays we need to determine the dex file based on the element type.
+ while (klass->IsArrayClass()) {
+ klass = klass->GetComponentType();
+ }
+ if (klass->IsPrimitive() || heap->ObjectIsInBootImageSpace(klass->GetDexCache())) {
+ return true; // Boot image dex file but not boot image `klass`.
+ }
+ return false;
+ }
+}
+
bool Transaction::ReadConstraint(Thread* self, ObjPtr<mirror::Object> obj, ArtField* field) {
DCHECK(field->IsStatic());
DCHECK(obj->IsClass());