Skip to content

Commit 035ddac

Browse files
authored
Merge pull request #1414 from Unity-Technologies/unity-master-fix-1188422
[mini] Fix delegate trampoline virtual call via delgate Invoke (mono#18073)
2 parents da4c6e2 + ac78c1e commit 035ddac

File tree

4 files changed

+95
-1
lines changed

4 files changed

+95
-1
lines changed

mono/mini/mini-trampolines.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1203,7 +1203,15 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
12031203
}
12041204
}
12051205

1206-
if (delegate->target &&
1206+
if (tramp_info->method == NULL && delegate->target != NULL && method->flags & METHOD_ATTRIBUTE_VIRTUAL) {
1207+
/* tramp_info->method == NULL happens when someone asks us to JIT some delegate's
1208+
* Invoke method (see compile_special). In that case if method is virtual, the target
1209+
* could be some derived class, so we need to find the correct override.
1210+
*/
1211+
/* FIXME: does it make sense that we get called with tramp_info for the Invoke? */
1212+
method = mono_object_get_virtual_method (delegate->target, method);
1213+
enable_caching = FALSE;
1214+
} else if (delegate->target &&
12071215
method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
12081216
method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
12091217
mono_class_is_abstract (method->klass)) {

mono/tests/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ TESTS_CS_SRC= \
252252
delegate13.cs \
253253
delegate14.cs \
254254
delegate15.cs \
255+
delegate17.cs \
256+
delegate18.cs \
255257
largeexp.cs \
256258
largeexp2.cs \
257259
marshalbyref1.cs \

mono/tests/delegate17.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Reflection;
3+
4+
internal class Program
5+
{
6+
public static int Main (string[] args)
7+
{
8+
// newobj Derived
9+
Derived d = new Derived ();
10+
// ldvirtftn Base::Foo
11+
// newobj Del1::.ctor
12+
Del1 b = new Del1 (d.Foo);
13+
// ldftn Del1::Invoke
14+
// newobj Del2::.ctor
15+
Del2 f = new Del2 (b.Invoke);
16+
// should call Derived.Foo not Base.Foo
17+
var r = f ("abcd");
18+
return r;
19+
}
20+
}
21+
22+
23+
public delegate int Del1 (string s);
24+
public delegate int Del2 (string s);
25+
26+
public class Base
27+
{
28+
public virtual int Foo (string s)
29+
{
30+
Console.WriteLine ("Base.Foo called. Bad");
31+
return 1;
32+
}
33+
}
34+
35+
public class Derived : Base
36+
{
37+
public override int Foo (string s)
38+
{
39+
Console.WriteLine ("Derived.Foo called. Good");
40+
return 0;
41+
}
42+
}

mono/tests/delegate18.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Reflection;
3+
4+
internal class Program
5+
{
6+
public static int Main (string[] args)
7+
{
8+
// newobj Derived
9+
Derived d = new Derived ();
10+
// ldvirtftn Base::Foo
11+
// newobj Del1::.ctor
12+
Del1 b = new Del1 (d.Foo);
13+
var mi = typeof (Del1).GetMethod ("Invoke");
14+
if (mi is null)
15+
return 2;
16+
// should call Derived.Foo not Base.Foo
17+
var r = (int) mi.Invoke (b, new object[] {"abcd"});
18+
return r;
19+
}
20+
}
21+
22+
23+
public delegate int Del1 (string s);
24+
public delegate int Del2 (string s);
25+
26+
public class Base
27+
{
28+
public virtual int Foo (string s)
29+
{
30+
Console.WriteLine ("Base.Foo called. Bad");
31+
return 1;
32+
}
33+
}
34+
35+
public class Derived : Base
36+
{
37+
public override int Foo (string s)
38+
{
39+
Console.WriteLine ("Derived.Foo called. Good");
40+
return 0;
41+
}
42+
}

0 commit comments

Comments
 (0)