[metadata] Compute interface offsets of ginst by inflating the GTD instead of doing...
commitaa50145d12112d27745c99f1fb4956cbcf15239d
authorRodrigo Kumpera <kumpera@users.noreply.github.com>
Thu, 15 Nov 2018 12:39:06 +0000 (15 07:39 -0500)
committerAleksey Kliger (λgeek) <akliger@gmail.com>
Thu, 15 Nov 2018 12:39:06 +0000 (15 07:39 -0500)
treeab7ad59a4eb63cd36215f35b47ddd0aac5d9b9a6
parent90c80dd026d6a01896b3d94ad054a9f24c5e3fe9
[metadata] Compute interface offsets of ginst by inflating the GTD instead of doing it from the grounds up. (#10931)

* [metadata] Compute interface offsets of ginst by inflating the GTD instead of doing it from the grounds up. Fixes #10837

Say you have;
```
interface Bar<T> { T Bla(); }
class Foo<A,B>: IBar<A>, IBar<B> {
int IBar<int>.Bla)() { ... }
}
```

The GTD of Foo will have the following interface offsets table:
```
4: IBar<A>
5: IBar<B>
```

With the existing code, if you have Foo<int,int> the interface offsets table will look like this:
```
4: IBar<int>
```

The problem with that is it will produce a hole in the vtable and subclasses of Foo<int,int> will have not on slot 5.

That would be just wasteful, unless you have this:

```
class Sub: Foo<int,int>, IBar<int> {
int IBar<int>.Bla)() { ...  }
}
```

IOW, a subclass that overrides the interface implementation in Foo. The problem is that it's not always reliable to which iface offset
calls to `IBar<int>` will go through and thus it's possible to have calls made against instances of `Sub` to execute the code from its base
class.

The solution is to inflate the interface offsets table from the gtd as that will preserve the number of entries and will cause the
rest of the vtable layout code to fill the duplicated slots correctly.

* Add regression test for #10837.

* [sre] Replace assert with proper error handling.

* [metadata] Don't mono_class_init ifaces, just have offsets setup.

* [metadata] Make setup_interface_offsets not depend on mono_class_init and fix lazy iid computation.

All that interface offset setup needs are iid as the output in interfaces_packed is sorted by it. Remove
the need to use mono_class_init by properly extracting and making iid setup lazy.

Beyond that, make mono_get_unique_iid not return 0 as a valid iid.
Otherwise we don't have a proper sentinel value when lazily computing iid.

* [metadata] Keep interfaces in the same relative order when computing offsets

qsort() is not guaranteed to be a stable sort (one that keeps elements with the
same key in the same order).  For example, the msvc qsort isn't stable.

Add an insertion_order field to ClassAndOffset to keep interfaces with the same
interface_id in the same relative order.

This is all relevant because in setup_interface_offsets we could see the same
interface multiple times (for example, with generics) at different offsets.
mono/metadata/class-init.c
mono/metadata/class.c
mono/metadata/sre.c
mono/tests/Makefile.am
mono/tests/bug-10837.cs [new file with mode: 0644]