Bug 17325 - RealProxy returns MarshalByRefObject for an Interface instead of the real interface type
Summary: RealProxy returns MarshalByRefObject for an Interface instead of the real int...
Status: RESOLVED FIXED
Alias: None
Product: Runtime
Classification: Mono
Component: Remoting (show other bugs)
Version: 3.2.x
Hardware: All All
: --- normal
Target Milestone: ---
Assignee: Aleksey Kliger
URL:
Depends on:
Blocks:
 
Reported: 2014-01-20 07:55 UTC by Rogier
Modified: 2017-08-14 21:47 UTC (History)
7 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Rogier 2014-01-20 07:55:15 UTC
RealProxy returns System.MarshalByRefObject for an Interface instead of the real interface type.

Possibly because in RealProxy.cs the following code is present:

	
		public Type GetProxiedType() 
		{
			if (_objTP == null) {
				if (class_to_proxy.IsInterface) return typeof(MarshalByRefObject);
				else return class_to_proxy;
			}
			return InternalGetProxyType (_objTP);
		}

For an interface the real proxied type should be returned however (using an Invoke on the proxied type).


To reproduce this try:


using System;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;

namespace TestRmiProxy
{
    class Program
    {
        static void Main(string[] args)
        {
            IComparable transparentProxy = (IComparable)new ProxyTest().GetTransparentProxy();
			Console.Out.WriteLine (transparentProxy.GetType ());
            Console.Out.WriteLine("transparentProxy = {0}", transparentProxy.GetType().IsAssignableFrom(typeof(IComparable)));
        }
    }

    public class ProxyTest : RealProxy
    {
        public ProxyTest() : base(typeof(IComparable))
        {
        }

        public override IMessage Invoke(IMessage msg)
        {
            // Should be called!
            return new ReturnMessage(typeof(IComparable), null, 0, null, null);
        }
    }
}


Should output (.NET):

System.IComparable
transparentProxy = True


But outputs (Mono):

System.MarshalByRefObjext
transparentProxy = False
Comment 1 Rogier 2014-01-29 10:27:51 UTC
Seems to be a runtime issue.
InternalGetTransparentProxy /
Comment 2 Rogier Hofboer 2014-02-26 16:29:52 UTC
Closely related to bug 1013
Comment 3 Rogier Hofboer 2017-03-01 10:02:51 UTC
This is still a problem in mono 4.8.x and in master (5.x.x) with reference sources, because it is caused by the runtime.
Comment 4 Rogier Hofboer 2017-08-07 07:52:13 UTC
Example on how this fails with SimpleInjector:


using SimpleInjector;
using System;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;

namespace Bug17325
{
    public class MainClass
    {
        public static void Main(string[] args) {
            Container container = new Container();
			IComparable transparentProxy = (IComparable)new ProxyTest().GetTransparentProxy();
			container.RegisterSingleton<IComparable>(transparentProxy);
			container.Verify();

            var comparable = container.GetInstance<IComparable>();
            Console.Out.WriteLine(comparable.GetType());
			Console.Out.WriteLine("comparable = {0}", comparable.GetType().IsAssignableFrom(typeof(IComparable)));
        }
    }

	public class ProxyTest : RealProxy
	{
		public ProxyTest() : base(typeof(IComparable))
		{
		}

		public override IMessage Invoke(IMessage msg)
		{
			// Should be called!
			return new ReturnMessage(typeof(IComparable), null, 0, null, null);
		}
	}
}
Comment 5 Aleksey Kliger 2017-08-10 17:15:01 UTC
Rogier: I took a stab at fixing this (https://github.com/mono/mono/pull/5350).  If you're able to build mono, I'd appreciate it if you could try the fix in a variety of scenarios - it feels a little bit fragile but I don't have many remoting tests.  The example from Comment 4 works.

As it happens System.Object.GetType() is a little bit special in that Mono's JIT tries to replace calls to that method by a direct access to a System.Type that's stored in the vtable.  When we initialize the vtable for a transparent proxy, we just copy the System.Type from the "proxied class".  But when we're proxying an interface, the proxied class is just MonoByRefObject, so we copied the wrong type.
Comment 6 Rogier Hofboer 2017-08-11 14:41:22 UTC
Aleksey: This fix works for our use case. Thanks!