Implement array allocation with access checks.
Change-Id: I0b2c0274087f3f7ed5b0b71c441e5d7e5a25f819
diff --git a/src/asm_support.h b/src/asm_support.h
index 95d4754..4d3569e 100644
--- a/src/asm_support.h
+++ b/src/asm_support.h
@@ -24,13 +24,13 @@
#define rSELF r9
#define rLR r14
// Offset of field Thread::suspend_count_ verified in InitCpu
-#define THREAD_SUSPEND_COUNT_OFFSET 392
+#define THREAD_SUSPEND_COUNT_OFFSET 400
// Offset of field Thread::exception_ verified in InitCpu
-#define THREAD_EXCEPTION_OFFSET 388
+#define THREAD_EXCEPTION_OFFSET 396
#elif defined(__i386__)
// Offset of field Thread::self_ verified in InitCpu
-#define THREAD_SELF_OFFSET 380
+#define THREAD_SELF_OFFSET 388
#endif
#endif // ART_SRC_ASM_SUPPORT_H_
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 6f476f9..bb66451 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -58,11 +58,8 @@
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
} else {
- UNIMPLEMENTED(WARNING) << "Need to check access of '"
- << PrettyMethod(cUnit->method_idx, *cUnit->dex_file)
- << "' to unresolved type " << type_idx;
loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
+ OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck), rLR);
}
loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
loadConstant(cUnit, r0, type_idx); // arg0 <- type_id
@@ -84,15 +81,15 @@
int elems = dInsn->vA;
int typeId = dInsn->vB;
oatFlushAllRegs(cUnit); /* Everything to home location */
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
- if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
- cUnit->dex_cache,
- *cUnit->dex_file,
- typeId)) {
- UNIMPLEMENTED(WARNING) << "Need to check access of '"
- << PrettyMethod(cUnit->method_idx, *cUnit->dex_file)
- << "' to unresolved type " << typeId;
+ if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
+ cUnit->dex_cache,
+ *cUnit->dex_file,
+ typeId)) {
+ loadWordDisp(cUnit, rSELF,
+ OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
+ } else {
+ loadWordDisp(cUnit, rSELF,
+ OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCodeWithAccessCheck), rLR);
}
loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
loadConstant(cUnit, r0, typeId); // arg0 <- type_id
diff --git a/src/object_test.cc b/src/object_test.cc
index ce19b9b..82f52de 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -182,7 +182,7 @@
java_lang_dex_file_->GetIndexForStringId(*string_id));
ASSERT_TRUE(type_id != NULL);
uint32_t type_idx = java_lang_dex_file_->GetIndexForTypeId(*type_id);
- Object* array = CheckAndAllocArrayFromCode(type_idx, sort, 3, Thread::Current());
+ Object* array = CheckAndAllocArrayFromCode(type_idx, sort, 3, Thread::Current(), false);
EXPECT_TRUE(array->IsArrayInstance());
EXPECT_EQ(3, array->AsArray()->GetLength());
EXPECT_TRUE(array->GetClass()->IsArrayClass());
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index f73e621..63efbf7 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -637,9 +637,10 @@
// Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
// cannot be resolved, throw an error. If it can, use it to create an instance.
-extern "C" Object* artAllocObjectFromCode(uint32_t type_idx, Method* method,
- Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+// When verification/compiler hasn't been able to verify access, optionally perform an access
+// check.
+static Object* AllocObjectFromCode(uint32_t type_idx, Method* method, Thread* self,
+ bool access_check) {
Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
Runtime* runtime = Runtime::Current();
if (UNLIKELY(klass == NULL)) {
@@ -649,6 +650,16 @@
return NULL; // Failure
}
}
+ if (access_check) {
+ Class* referrer = method->GetDeclaringClass();
+ if (UNLIKELY(!referrer->CanAccess(klass))) {
+ self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+ "illegal class access: '%s' -> '%s'",
+ PrettyDescriptor(referrer).c_str(),
+ PrettyDescriptor(klass).c_str());
+ return NULL; // Failure
+ }
+ }
if (!runtime->GetClassLinker()->EnsureInitialized(klass, true)) {
DCHECK(self->IsExceptionPending());
return NULL; // Failure
@@ -656,34 +667,67 @@
return klass->AllocObject();
}
+extern "C" Object* artAllocObjectFromCode(uint32_t type_idx, Method* method,
+ Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return AllocObjectFromCode(type_idx, method, self, false);
+}
+
extern "C" Object* artAllocObjectFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
Thread* self, Method** sp) {
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return AllocObjectFromCode(type_idx, method, self, true);
+}
+
+// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
+// it cannot be resolved, throw an error. If it can, use it to create an array.
+// When verification/compiler hasn't been able to verify access, optionally perform an access
+// check.
+static Array* AllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
+ Thread* self, bool access_check) {
+ if (UNLIKELY(component_count < 0)) {
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
+ component_count);
+ return NULL; // Failure
+ }
Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
- Runtime* runtime = Runtime::Current();
- if (UNLIKELY(klass == NULL)) {
- klass = runtime->GetClassLinker()->ResolveType(type_idx, method);
- if (klass == NULL) {
- DCHECK(self->IsExceptionPending());
+ if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
+ klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
+ if (klass == NULL) { // Error
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return NULL; // Failure
+ }
+ CHECK(klass->IsArrayClass()) << PrettyClass(klass);
+ }
+ if (access_check) {
+ Class* referrer = method->GetDeclaringClass();
+ if (UNLIKELY(!referrer->CanAccess(klass))) {
+ self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+ "illegal class access: '%s' -> '%s'",
+ PrettyDescriptor(referrer).c_str(),
+ PrettyDescriptor(klass).c_str());
return NULL; // Failure
}
}
- Class* referrer = method->GetDeclaringClass();
- if (UNLIKELY(!referrer->CanAccess(klass))) {
- self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;", "illegal class access: '%s' -> '%s'",
- PrettyDescriptor(referrer).c_str(),
- PrettyDescriptor(klass).c_str());
- return NULL; // Failure
- }
- if (!runtime->GetClassLinker()->EnsureInitialized(klass, true)) {
- DCHECK(self->IsExceptionPending());
- return NULL; // Failure
- }
- return klass->AllocObject();
+ return Array::Alloc(klass, component_count);
}
+extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
+ Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return AllocArrayFromCode(type_idx, method, component_count, self, false);
+}
+
+extern "C" Array* artAllocArrayFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
+ int32_t component_count,
+ Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return AllocArrayFromCode(type_idx, method, component_count, self, true);
+}
+
+// Helper function to alloc array for OP_FILLED_NEW_ARRAY
Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
- Thread* self) {
+ Thread* self, bool access_check) {
if (UNLIKELY(component_count < 0)) {
self->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", component_count);
return NULL; // Failure
@@ -708,38 +752,32 @@
}
return NULL; // Failure
} else {
+ if (access_check) {
+ Class* referrer = method->GetDeclaringClass();
+ if (UNLIKELY(!referrer->CanAccess(klass))) {
+ self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+ "illegal class access: '%s' -> '%s'",
+ PrettyDescriptor(referrer).c_str(),
+ PrettyDescriptor(klass).c_str());
+ return NULL; // Failure
+ }
+ }
DCHECK(klass->IsArrayClass()) << PrettyClass(klass);
return Array::Alloc(klass, component_count);
}
}
-// Helper function to alloc array for OP_FILLED_NEW_ARRAY
extern "C" Array* artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method,
int32_t component_count, Thread* self, Method** sp) {
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return CheckAndAllocArrayFromCode(type_idx, method, component_count, self);
+ return CheckAndAllocArrayFromCode(type_idx, method, component_count, self, false);
}
-// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
-// it cannot be resolved, throw an error. If it can, use it to create an array.
-extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
- Thread* self, Method** sp) {
+extern "C" Array* artCheckAndAllocArrayFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
+ int32_t component_count,
+ Thread* self, Method** sp) {
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- if (UNLIKELY(component_count < 0)) {
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
- component_count);
- return NULL; // Failure
- }
- Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
- if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
- klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
- if (klass == NULL) { // Error
- DCHECK(Thread::Current()->IsExceptionPending());
- return NULL; // Failure
- }
- CHECK(klass->IsArrayClass()) << PrettyClass(klass);
- }
- return Array::Alloc(klass, component_count);
+ return CheckAndAllocArrayFromCode(type_idx, method, component_count, self, true);
}
// Assignable test for code, won't throw. Null and equality tests already performed
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 096e6ab..68e9587 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -26,7 +26,7 @@
extern void CheckSuspendFromCode(Thread* thread);
extern Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
- Thread* self);
+ Thread* self, bool access_check);
extern void DebugMe(Method* method, uint32_t info);
extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
extern Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, bool is_static);
@@ -73,9 +73,11 @@
extern "C" void art_throw_verification_error_from_code(int32_t src1, int32_t ref);
extern "C" void art_unlock_object_from_code(void*);
extern "C" void* art_alloc_array_from_code(uint32_t, void*, int32_t);
+ extern "C" void* art_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
extern "C" void* art_alloc_object_from_code(uint32_t type_idx, void* method);
extern "C" void* art_alloc_object_from_code_with_access_check(uint32_t type_idx, void* method);
extern "C" void* art_check_and_alloc_array_from_code(uint32_t, void*, int32_t);
+ extern "C" void* art_check_and_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
extern "C" void* art_find_instance_field_from_code(uint32_t, void*);
extern "C" void* art_find_static_field_from_code(uint32_t, void*);
extern "C" void* art_get_obj_static_from_code(uint32_t, void*);
diff --git a/src/runtime_support_arm.S b/src/runtime_support_arm.S
index c73588e..cee9043 100644
--- a/src/runtime_support_arm.S
+++ b/src/runtime_support_arm.S
@@ -520,10 +520,27 @@
bxne lr @ return on success
DELIVER_PENDING_EXCEPTION
+ .global art_alloc_array_from_code_with_access_check
+ .extern artAllocArrayFromCodeWithAccessCheck
+ /*
+ * Called by managed code to allocate an array when the caller doesn't know whether it has
+ * access to the created type
+ */
+art_alloc_array_from_code_with_access_check:
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
+ mov r3, r9 @ pass Thread::Current
+ str sp, [sp, #0] @ pass SP
+ @ artAllocArrayFromCodeWithAccessCheck(type_idx, method, component_count, Thread*, SP)
+ bl artAllocArrayFromCodeWithAccessCheck
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+ cmp r0, #0 @ success if result is non-null
+ bxne lr @ return on success
+ DELIVER_PENDING_EXCEPTION
+
.global art_check_and_alloc_array_from_code
.extern artCheckAndAllocArrayFromCode
/*
- * Called by managed code to allocate an array
+ * Called by managed code to allocate an array in a special case for OP_FILLED_NEW_ARRAY
*/
art_check_and_alloc_array_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
@@ -536,6 +553,22 @@
bxne lr @ return on success
DELIVER_PENDING_EXCEPTION
+ .global art_check_and_alloc_array_from_code_with_access_check
+ .extern artCheckAndAllocArrayFromCodeWithAccessCheck
+ /*
+ * Called by managed code to allocate an array in a special case for OP_FILLED_NEW_ARRAY
+ */
+art_check_and_alloc_array_from_code_with_access_check:
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
+ mov r3, r9 @ pass Thread::Current
+ str sp, [sp, #0] @ pass SP
+ @ artCheckAndAllocArrayFromCodeWithAccessCheck(type_idx, method, count, Thread* , SP)
+ bl artCheckAndAllocArrayFromCodeWithAccessCheck
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+ cmp r0, #0 @ success if result is non-null
+ bxne lr @ return on success
+ DELIVER_PENDING_EXCEPTION
+
.global art_test_suspend
.extern artTestSuspendFromCode
/*
diff --git a/src/thread.cc b/src/thread.cc
index 1a534f1..014e2f0 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -99,10 +99,12 @@
pLdivmod = __aeabi_ldivmod;
pLmul = __aeabi_lmul;
pAllocArrayFromCode = art_alloc_array_from_code;
+ pAllocArrayFromCodeWithAccessCheck = art_alloc_array_from_code_with_access_check;
pAllocObjectFromCode = art_alloc_object_from_code;
pAllocObjectFromCodeWithAccessCheck = art_alloc_object_from_code_with_access_check;
pCanPutArrayElementFromCode = art_can_put_array_element_from_code;
pCheckAndAllocArrayFromCode = art_check_and_alloc_array_from_code;
+ pCheckAndAllocArrayFromCodeWithAccessCheck = art_check_and_alloc_array_from_code_with_access_check;
pCheckCastFromCode = art_check_cast_from_code;
pFindInstanceFieldFromCode = art_find_instance_field_from_code;
pGet32Static = art_get32_static_from_code;
diff --git a/src/thread.h b/src/thread.h
index d612f62..bade52e 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -124,8 +124,10 @@
void* (*pAllocObjectFromCode)(uint32_t, void*);
void* (*pAllocObjectFromCodeWithAccessCheck)(uint32_t, void*);
void* (*pAllocArrayFromCode)(uint32_t, void*, int32_t);
+ void* (*pAllocArrayFromCodeWithAccessCheck)(uint32_t, void*, int32_t);
void (*pCanPutArrayElementFromCode)(void*, void*);
void* (*pCheckAndAllocArrayFromCode)(uint32_t, void*, int32_t);
+ void* (*pCheckAndAllocArrayFromCodeWithAccessCheck)(uint32_t, void*, int32_t);
void (*pCheckCastFromCode)(void*, void*);
Object* (*pDecodeJObjectInThread)(Thread* thread, jobject obj);
void (*pDeliverException)(void*);