Implement array allocation with access checks.
Change-Id: I0b2c0274087f3f7ed5b0b71c441e5d7e5a25f819
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