diff options
| -rw-r--r-- | src/asm_support.h | 6 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/MethodCodegenDriver.cc | 23 | ||||
| -rw-r--r-- | src/object_test.cc | 2 | ||||
| -rw-r--r-- | src/runtime_support.cc | 120 | ||||
| -rw-r--r-- | src/runtime_support.h | 4 | ||||
| -rw-r--r-- | src/runtime_support_arm.S | 35 | ||||
| -rw-r--r-- | src/thread.cc | 2 | ||||
| -rw-r--r-- | src/thread.h | 2 |
8 files changed, 134 insertions, 60 deletions
diff --git a/src/asm_support.h b/src/asm_support.h index 95d4754928..4d3569ed05 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 6f476f930f..bb66451221 100644 --- a/src/compiler/codegen/arm/MethodCodegenDriver.cc +++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc @@ -58,11 +58,8 @@ STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, 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 @@ STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange) 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 ce19b9b17d..82f52de49e 100644 --- a/src/object_test.cc +++ b/src/object_test.cc @@ -182,7 +182,7 @@ TEST_F(ObjectTest, CheckAndAllocArrayFromCode) { 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 f73e621f23..63efbf738c 100644 --- a/src/runtime_support.cc +++ b/src/runtime_support.cc @@ -637,9 +637,10 @@ extern "C" int artSetObjStaticFromCode(uint32_t field_idx, const Method* referre // 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 @@ extern "C" Object* artAllocObjectFromCode(uint32_t type_idx, Method* method, 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 @@ extern "C" Object* artAllocObjectFromCode(uint32_t type_idx, Method* method, 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); } - 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 + 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 + } } - 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 @@ Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t com } 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 096e6ab257..68e9587125 100644 --- a/src/runtime_support.h +++ b/src/runtime_support.h @@ -26,7 +26,7 @@ namespace art { 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_proxy_invoke_handler(); 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 c73588e09a..cee90435d4 100644 --- a/src/runtime_support_arm.S +++ b/src/runtime_support_arm.S @@ -520,10 +520,27 @@ art_alloc_array_from_code: 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 @@ art_check_and_alloc_array_from_code: 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 1a534f1171..014e2f0932 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -99,10 +99,12 @@ void Thread::InitFunctionPointers() { 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 d612f62def..bade52eedf 100644 --- a/src/thread.h +++ b/src/thread.h @@ -124,8 +124,10 @@ class PACKED Thread { 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*); |