[loader] Init MonoClass:sizes.element_size lazily (Fixes #43563) (#5559)
authorAleksey Kliger (λgeek) <akliger@gmail.com>
Fri, 15 Sep 2017 22:32:04 +0000 (18:32 -0400)
committerLudovic Henry <ludovic@xamarin.com>
Fri, 15 Sep 2017 22:32:04 +0000 (18:32 -0400)
commite88f9c11f1c432f82b2fb0ff5c319e247b50e2da
tree8658f5ad8e5d8b332c06369a708d582398bec509
parent99f2c2a103eaa87997ff4971a6b54d7cbf491575
[loader] Init MonoClass:sizes.element_size lazily (Fixes #43563) (#5559)

* [loader] If signaling recursive type initialize, don't double free

If we detect that a recursive type initialization is happening, we should leave
without removing the class from the init_pending_tld_id list.  Otherwise we get
a double-free when the outer recursive call finally finishes and tries to
remove the same element.

Also re-load the init_list from TLS since a recursive call to mono_class_init could
have modified it between the time the current mono_class_init call started and
when it is finishing.

* [loader] Improve error message when a field's type is a failed class

Add the class failure to the field failure error message.

* [tests] Check that runtime can represent recursive structs

Regression tests for https://bugzilla.xamarin.com/show_bug.cgi?id=43563

* [loader] Init MonoClass:sizes.element_size lazily (Fixes #43563)

Originally mono_bounded_array_class_get () would populate
MonoClass:sizes.element_size as soon as the MonoClass for the array was needed.
This is a problem because we cannot call mono_class_array_element_size () on
the element class on a valuetype until mono_class_layout_fields () finishes
initializing it.

That means that structs which contain an array of themselves would hit the
recursive initialization check in mono_class_setup_fields and the MonoClass for
the element class would be marked as failed to load.

Instead we rely on the MonoClass:size_inited bit to tell us whether the array
class has been initialized and if not, we set the array element size in
mono_class_layout_fields.

This is possible because MonoClass:sizes.element_size is only really needed to
know how to allocate space for an array.  When laying out a class that contains
an array we don't need the element size - they array is just a reference type.

Example:
```csharp
struct S {
    static S[][] foo;
}
```

Fixes https://bugzilla.xamarin.com/show_bug.cgi?id=43563
mono/metadata/class.c
mono/metadata/loader.c
mono/metadata/sgen-mono.c
mono/tests/Makefile.am
mono/tests/recursive-struct-arrays.cs [new file with mode: 0644]