Fix computation of primitive array widths.
The code was comparing class pointers, but the class objects for arrays
of primitives are initialized on demand. If the class wasn't yet
instantiated, the array width code was returning a default value of 4.
This meant the "write values to an array of longs through the unsafe
methods" code was actually scribbling on the wrong part of the array,
which went unnoticed until recently. (The new-ish ldrexd/strexd code
requires 64-bit alignment.)
We now use the existing array element width computation function. The
code needed a bit of rearranging since it expected an instance of the
class rather than the class.
Bug 3023981.
Change-Id: I51462978362b6a4fce26e13eda17e1bbc0eac192
diff --git a/vm/oo/Array.c b/vm/oo/Array.c
index a2f21e6..f026161 100644
--- a/vm/oo/Array.c
+++ b/vm/oo/Array.c
@@ -759,14 +759,20 @@
return true;
}
-static size_t arrayElementWidth(const ArrayObject *array)
+/*
+ * Returns the width, in bytes, required by elements in instances of
+ * the array class.
+ */
+size_t dvmArrayClassElementWidth(const ClassObject* arrayClass)
{
const char *descriptor;
- if (dvmIsObjectArray(array)) {
+ assert(dvmIsArrayClass(arrayClass));
+
+ if (dvmIsObjectArrayClass(arrayClass)) {
return sizeof(Object *);
} else {
- descriptor = array->obj.clazz->descriptor;
+ descriptor = arrayClass->descriptor;
switch (descriptor[1]) {
case 'B': return 1; /* byte */
case 'C': return 2; /* char */
@@ -778,7 +784,7 @@
case 'Z': return 1; /* boolean */
}
}
- LOGE("object %p has an unhandled descriptor '%s'", array, descriptor);
+ LOGE("class %p has an unhandled descriptor '%s'", arrayClass, descriptor);
dvmDumpThread(dvmThreadSelf(), false);
dvmAbort();
return 0; /* Quiet the compiler. */
@@ -790,7 +796,7 @@
assert(array != NULL);
size = offsetof(ArrayObject, contents);
- size += array->length * arrayElementWidth(array);
+ size += array->length * dvmArrayClassElementWidth(array->obj.clazz);
return size;
}