[sgen] Fix scanning of invalid entries within arrays
authorVlad Brezae <brezaevlad@gmail.com>
Thu, 27 Aug 2015 23:44:50 +0000 (16:44 -0700)
committerVlad Brezae <brezaevlad@gmail.com>
Sat, 29 Aug 2015 01:00:14 +0000 (18:00 -0700)
mono/metadata/sgen-client-mono.h
mono/metadata/sgen-mono.c

index 2847011dc22d42f47fb168607d3a12ccb77b946b..ede6e48ba408d971d305f1b682051554faea5561 100644 (file)
@@ -103,6 +103,30 @@ enum {
        INTERNAL_MEM_MAX
 };
 
+static inline mword
+sgen_mono_array_size (GCVTable vtable, MonoArray *array, mword *bounds_size, mword descr)
+{
+       mword size, size_without_bounds;
+       int element_size;
+
+       if ((descr & DESC_TYPE_MASK) == DESC_TYPE_VECTOR)
+               element_size = ((descr) >> VECTOR_ELSIZE_SHIFT) & MAX_ELEMENT_SIZE;
+       else
+               element_size = vtable->klass->sizes.element_size;
+
+       size_without_bounds = size = sizeof (MonoArray) + element_size * mono_array_length_fast (array);
+
+       if (G_UNLIKELY (array->bounds)) {
+               size += sizeof (mono_array_size_t) - 1;
+               size &= ~(sizeof (mono_array_size_t) - 1);
+               size += sizeof (MonoArrayBounds) * vtable->klass->rank;
+       }
+
+       if (bounds_size)
+               *bounds_size = size - size_without_bounds;
+       return size;
+}
+
 #define SGEN_CLIENT_OBJECT_HEADER_SIZE         (sizeof (GCObject))
 #define SGEN_CLIENT_MINIMUM_OBJECT_SIZE                SGEN_CLIENT_OBJECT_HEADER_SIZE
 
@@ -118,14 +142,7 @@ sgen_client_slow_object_get_size (GCVTable vtable, GCObject* o)
        if (klass == mono_defaults.string_class) {
                return G_STRUCT_OFFSET (MonoString, chars) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
        } else if (klass->rank) {
-               MonoArray *array = (MonoArray*)o;
-               size_t size = sizeof (MonoArray) + klass->sizes.element_size * mono_array_length_fast (array);
-               if (G_UNLIKELY (array->bounds)) {
-                       size += sizeof (mono_array_size_t) - 1;
-                       size &= ~(sizeof (mono_array_size_t) - 1);
-                       size += sizeof (MonoArrayBounds) * klass->rank;
-               }
-               return size;
+               return sgen_mono_array_size (vtable, (MonoArray*)o, NULL, 0);
        } else {
                /* from a created object: the class must be inited already */
                return klass->instance_size;
@@ -150,20 +167,7 @@ sgen_client_par_object_get_size (GCVTable vtable, GCObject* o)
        } else if (descr == SGEN_DESC_STRING) {
                return G_STRUCT_OFFSET (MonoString, chars) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
        } else if (type == DESC_TYPE_VECTOR) {
-               int element_size = ((descr) >> VECTOR_ELSIZE_SHIFT) & MAX_ELEMENT_SIZE;
-               MonoArray *array = (MonoArray*)o;
-               size_t size = sizeof (MonoArray) + element_size * mono_array_length_fast (array);
-
-               /*
-                * Non-vector arrays with a single dimension whose lower bound is zero are
-                * allocated without bounds.
-                */
-               if ((descr & VECTOR_KIND_ARRAY) && array->bounds) {
-                       size += sizeof (mono_array_size_t) - 1;
-                       size &= ~(sizeof (mono_array_size_t) - 1);
-                       size += sizeof (MonoArrayBounds) * ((MonoVTable*)vtable)->klass->rank;
-               }
-               return size;
+               return sgen_mono_array_size (vtable, (MonoArray*)o, NULL, descr);
        }
 
        return sgen_client_slow_object_get_size (vtable, o);
index bb44f590762d61a3903b3500e8fb4f1d65b8aadf..0a3b810c447d29214064c50076022a2ad1ae57c2 100644 (file)
@@ -1596,15 +1596,17 @@ sgen_client_cardtable_scan_object (GCObject *obj, mword block_obj_size, guint8 *
        SGEN_ASSERT (0, SGEN_VTABLE_HAS_REFERENCES (vt), "Why would we ever call this on reference-free objects?");
 
        if (vt->rank) {
+               MonoArray *arr = (MonoArray*)obj;
                guint8 *card_data, *card_base;
                guint8 *card_data_end;
                char *obj_start = sgen_card_table_align_pointer (obj);
-               mword obj_size = sgen_client_par_object_get_size (vt, obj);
-               char *obj_end = (char*)obj + obj_size;
+               mword bounds_size;
+               mword obj_size = sgen_mono_array_size (vt, arr, &bounds_size, sgen_vtable_get_descriptor (vt));
+               /* We don't want to scan the bounds entries at the end of multidimensional arrays */
+               char *obj_end = (char*)obj + obj_size - bounds_size;
                size_t card_count;
                size_t extra_idx = 0;
 
-               MonoArray *arr = (MonoArray*)obj;
                mword desc = (mword)klass->element_class->gc_descr;
                int elem_size = mono_array_element_size (klass);