Implement the "unreasonable array allocation" OutOfMemoryError.
This doesn't fix test 061 because we still need AllocWithGrowth, but at least
it gets us far enough to need that.
Change-Id: Ia7b4a1f91a31e25d439f36b17280ce21c9ed8933
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index a4e211b..6be9f76 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -48,7 +48,7 @@
{
oatFlushAllRegs(cUnit); /* Everything to home location */
loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pArrayAllocFromCode), rLR);
+ OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
loadConstant(cUnit, r0, mir->dalvikInsn.vC); // arg0 <- type_id
loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
@@ -70,7 +70,7 @@
int typeId = dInsn->vB;
oatFlushAllRegs(cUnit); /* Everything to home location */
loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pCheckAndArrayAllocFromCode), rLR);
+ OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
loadConstant(cUnit, r0, typeId); // arg0 <- type_id
loadConstant(cUnit, r2, elems); // arg2 <- count
diff --git a/src/object.cc b/src/object.cc
index 8fc4108..49d689c 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -1220,12 +1220,30 @@
DCHECK(array_class != NULL);
DCHECK_GE(component_count, 0);
DCHECK(array_class->IsArrayClass());
- size_t size = SizeOf(component_count, component_size);
+
+ size_t header_size = sizeof(Array);
+ size_t data_size = component_count * component_size;
+ size_t size = header_size + data_size;
+
+ // Check for overflow and throw OutOfMemoryError if this was an unreasonable request.
+ size_t component_shift = sizeof(size_t) * 8 - 1 - CLZ(component_size);
+ if (data_size >> component_shift != size_t(component_count) || size < data_size) {
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/OutOfMemoryError;",
+ "%s of length %zd exceeds the VM limit",
+ PrettyDescriptor(array_class->GetDescriptor()).c_str(), component_count);
+ return NULL;
+ }
+
Array* array = down_cast<Array*>(Heap::AllocObject(array_class, size));
if (array != NULL) {
DCHECK(array->IsArrayInstance());
array->SetLength(component_count);
}
+
+ // TODO: throw OutOfMemoryError. (here or in Heap::AllocObject?)
+ CHECK(array != NULL) << PrettyClass(array_class)
+ << " component_count=" << component_count
+ << " component_size=" << component_size;
return array;
}
diff --git a/src/object.h b/src/object.h
index 42235b8..205d7c0 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1107,11 +1107,6 @@
class MANAGED Array : public Object {
public:
- static size_t SizeOf(size_t component_count,
- size_t component_size) {
- return sizeof(Array) + component_count * component_size;
- }
-
// A convenience for code that doesn't know the component size,
// and doesn't want to have to work it out itself.
static Array* Alloc(Class* array_class, int32_t component_count);
@@ -2226,7 +2221,8 @@
}
inline size_t Array::SizeOf() const {
- return SizeOf(GetLength(), GetClass()->GetComponentSize());
+ // This is safe from overflow because the array was already allocated, so we know it's sane.
+ return sizeof(Array) + GetLength() * GetClass()->GetComponentSize();
}
template<class T>
diff --git a/src/object_test.cc b/src/object_test.cc
index 1451929..167c770 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -172,27 +172,27 @@
EXPECT_TRUE(string->IsString());
}
-extern "C" Array* artArrayAllocFromCode(uint32_t type_idx, Method* method, int32_t component_count);
-TEST_F(ObjectTest, ArrayAllocFromCode) {
+extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count);
+TEST_F(ObjectTest, AllocArrayFromCode) {
// pretend we are trying to call 'new char[3]' from String.toCharArray
Class* java_lang_String = class_linker_->FindSystemClass("Ljava/lang/String;");
Method* toCharArray = java_lang_String->FindVirtualMethod("toCharArray", "()[C");
uint32_t type_idx = FindTypeIdxByDescriptor(*java_lang_dex_file_.get(), "[C");
- Object* array = artArrayAllocFromCode(type_idx, toCharArray, 3);
+ Object* array = artAllocArrayFromCode(type_idx, toCharArray, 3);
EXPECT_TRUE(array->IsArrayInstance());
EXPECT_EQ(3, array->AsArray()->GetLength());
EXPECT_TRUE(array->GetClass()->IsArrayClass());
EXPECT_TRUE(array->GetClass()->GetComponentType()->IsPrimitive());
}
-extern "C" Array* artCheckAndArrayAllocFromCode(uint32_t type_idx, Method* method,
+extern "C" Array* artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method,
int32_t component_count);
-TEST_F(ObjectTest, CheckAndArrayAllocFromCode) {
+TEST_F(ObjectTest, CheckAndAllocArrayFromCode) {
// pretend we are trying to call 'new char[3]' from String.toCharArray
Class* java_util_Arrays = class_linker_->FindSystemClass("Ljava/util/Arrays;");
Method* sort = java_util_Arrays->FindDirectMethod("sort", "([I)V");
uint32_t type_idx = FindTypeIdxByDescriptor(*java_lang_dex_file_.get(), "[I");
- Object* array = artCheckAndArrayAllocFromCode(type_idx, sort, 3);
+ Object* array = artCheckAndAllocArrayFromCode(type_idx, sort, 3);
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 89dac70..039a749 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -352,7 +352,7 @@
}
// Helper function to alloc array for OP_FILLED_NEW_ARRAY
-extern "C" Array* artCheckAndArrayAllocFromCode(uint32_t type_idx, Method* method,
+extern "C" Array* artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method,
int32_t component_count) {
if (component_count < 0) {
Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
@@ -386,7 +386,7 @@
// 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* artArrayAllocFromCode(uint32_t type_idx, Method* method, int32_t component_count) {
+extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count) {
if (component_count < 0) {
Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
component_count);
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 3a1ffcf..985074c 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -29,8 +29,8 @@
#if defined(__arm__)
/* Compiler helpers */
extern "C" void* art_alloc_object_from_code(uint32_t type_idx, void* method);
- extern "C" void* art_array_alloc_from_code(uint32_t, void*, int32_t);
- extern "C" void* art_check_and_array_alloc_from_code(uint32_t, void*, int32_t);
+ extern "C" void* art_alloc_array_from_code(uint32_t, void*, int32_t);
+ extern "C" void* art_check_and_alloc_array_from_code(uint32_t, void*, int32_t);
extern "C" void art_can_put_array_element_from_code(void*, void*);
extern "C" void art_check_cast_from_code(void*, void*);
extern "C" void art_handle_fill_data_from_code(void*, void*);
diff --git a/src/runtime_support_asm.S b/src/runtime_support_asm.S
index 25a6872..eb12854 100644
--- a/src/runtime_support_asm.S
+++ b/src/runtime_support_asm.S
@@ -276,17 +276,17 @@
mov r1, sp @ pass SP
b artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
- .global art_array_alloc_from_code
- .extern artArrayAllocFromCode
+ .global art_alloc_array_from_code
+ .extern artAllocArrayFromCode
/*
* Called by managed code to allocate an array
*/
-art_array_alloc_from_code:
+art_alloc_array_from_code:
str sp, [R9, #THREAD_TOP_OF_MANAGED_STACK_OFFSET] @ record top of stack and pc in case of
str lr, [R9, #THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET] @ walking stack
stmdb sp!, {lr} @ Save LR
sub sp, #12 @ Align stack
- bl artArrayAllocFromCode @ (uint32_t type_idx, Method* method, int32_t component_count)
+ bl artAllocArrayFromCode @ (uint32_t type_idx, Method* method, int32_t component_count)
add sp, #12
ldmia sp!, {lr} @ restore LR
cmp r0, #0 @ success if result is non-null
@@ -297,17 +297,17 @@
mov r1, sp @ pass SP
b artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
- .global art_check_and_array_alloc_from_code
- .extern artCheckAndArrayAllocFromCode
+ .global art_check_and_alloc_array_from_code
+ .extern artCheckAndAllocArrayFromCode
/*
* Called by managed code to allocate an array
*/
-art_check_and_array_alloc_from_code:
+art_check_and_alloc_array_from_code:
str sp, [R9, #THREAD_TOP_OF_MANAGED_STACK_OFFSET] @ record top of stack and pc in case of
str lr, [R9, #THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET] @ walking stack
stmdb sp!, {lr} @ Save LR
sub sp, #12 @ Align stack
- bl artCheckAndArrayAllocFromCode @ (uint32_t type_idx, Method* method, int32_t count)
+ bl artCheckAndAllocArrayFromCode @ (uint32_t type_idx, Method* method, int32_t count)
add sp, #12
ldmia sp!, {lr} @ restore LR
cmp r0, #0 @ success if result is non-null
diff --git a/src/thread.cc b/src/thread.cc
index e997723..87a2017 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -86,9 +86,9 @@
pLdivmod = __aeabi_ldivmod;
pLmul = __aeabi_lmul;
pAllocObjectFromCode = art_alloc_object_from_code;
- pArrayAllocFromCode = art_array_alloc_from_code;
+ pAllocArrayFromCode = art_alloc_array_from_code;
pCanPutArrayElementFromCode = art_can_put_array_element_from_code;
- pCheckAndArrayAllocFromCode = art_check_and_array_alloc_from_code;
+ pCheckAndAllocArrayFromCode = art_check_and_alloc_array_from_code;
pCheckCastFromCode = art_check_cast_from_code;
pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
pInitializeStaticStorage = art_initialize_static_storage_from_code;
diff --git a/src/thread.h b/src/thread.h
index 4f85b70..c949339 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -203,8 +203,8 @@
long long (*pLmul)(long long, long long);
long long (*pLdivmod)(long long, long long);
void* (*pAllocObjectFromCode)(uint32_t, void*);
- void* (*pArrayAllocFromCode)(uint32_t, void*, int32_t);
- void* (*pCheckAndArrayAllocFromCode)(uint32_t, void*, int32_t);
+ void* (*pAllocArrayFromCode)(uint32_t, void*, int32_t);
+ void* (*pCheckAndAllocArrayFromCode)(uint32_t, void*, int32_t);
uint32_t (*pGet32Static)(uint32_t, const Method*);
void (*pSet32Static)(uint32_t, const Method*, uint32_t);
uint64_t (*pGet64Static)(uint32_t, const Method*);