Bug 37695 - Delegate references an overridden method in derived class misbehaves when marshalled as a parameter to native C function.
Summary: Delegate references an overridden method in derived class misbehaves when mar...
Status: RESOLVED FIXED
Alias: None
Product: Runtime
Classification: Mono
Component: JIT (show other bugs)
Version: 4.2.0 (C6)
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2016-01-14 15:40 UTC by Assem Radaideh
Modified: 2016-01-18 16:43 UTC (History)
5 users (show)

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


Attachments
C file + C# file + shell script to build Native library and the Client Managed Executable (2.17 KB, application/x-zip-compressed)
2016-01-14 15:40 UTC, Assem Radaideh
Details
This is the correct Sample. Use this attachement not the previous (3.24 KB, application/zip)
2016-01-18 07:09 UTC, Assem Radaideh
Details


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 Assem Radaideh 2016-01-14 15:40:31 UTC
Created attachment 14588 [details]
C file + C# file + shell script to build Native library and the Client Managed Executable

Assume we have a delegate as a member in a base class that references an overridden method in a derived class of this base class.

Also, C function takes a function pointer that is equivalent to the managed Delegate's signature as a parameter.

if we PInvoked this function passing that delegate, and tried to "callback" it from within the C function, it should invoke the overridden method in derived class.

I've written a minimal code in C and C# that shows this issue:

Native C Library:

main.c:
//////////////////////////////////////////////////////////////////////////////////////////////////
typedef int (* Virtual_OnInit) ();


#define EXPORT __attribute__((visibility("default")))
#define	FORCE_INLINE __attribute__((always_inline))


EXPORT void RegisterVirtualCallBack(Virtual_OnInit onInit)
{

	printf("NATIVE: RegisterVirtualCallBack Entered\n");

	onInit(); // invoke the passed from managed code delegate

	printf("NATIVE: RegisterVirtualCallBack Left\n");


}
//////////////////////////////////////////////////////////////////////////////////////////////////


Build the library using the follwoing:
>gcc -MMD ./main.c -fPIC -O3 -arch i386 -shared -o "./libTestCallBacksPInvoke.so"







and the C# file:
Program.cs:

//////////////////////////////////////////////////////////////////////////////////////////////////
using System;
using System.Runtime.InteropServices;

namespace TestDelegatesPInvoke
{


    class Base
    {
        public delegate void Virtual_OnInit();
        private Virtual_OnInit virtual_OnInit;


        [DllImport("TestCallBacksPInvoke")]
        public static extern void RegisterVirtualCallBack(Virtual_OnInit delegateOnInit);


        public Base()
        {
            Console.WriteLine("This is Base's Constructor");

            virtual_OnInit = new Virtual_OnInit(OnInit);

            RegisterVirtualCallBack(virtual_OnInit);
        }
            

        public virtual void OnInit()
        {
            Console.WriteLine("MANAGED: This is Base's Virtual OnInit");
        }
    }


    class Derived : Base
    {

        public Derived()
        {
            Console.WriteLine("This is Derived's Constructor");
        }
            
        public override void OnInit()
        {
            Console.WriteLine("MANAGED: This is Derived's OnInit");
        }
    }
        



    class MainClass
    {
        public static void Main(string[] args)
        {
            
            Base b = new Derived(); // the virtual_OnInit delegate in the base references Derived's OnInit
           
        }
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////////






To build the exe use:
>mcs /noconfig /debug:full /debug+ /optimize- /out:TestCallback.exe Program.cs /target:exe /define:DEBUG /nostdlib /reference:/Library/Frameworks/Mono.framework/Versions/4.2.1/lib/mono/4.5/System.dll /reference:/Library/Frameworks/Mono.framework/Versions/4.2.1/lib/mono/4.5/System.Core.dll /reference:/Library/Frameworks/Mono.framework/Versions/4.2.1/lib/mono/4.5/mscorlib.dll /warn:4



### When the C# code above built and executed with Mono 4.2.1, the console output is ###

This is Base's Constructor
NATIVE: RegisterVirtualCallBack Entered
MANAGED: This is Base's Virtual OnInit
NATIVE: RegisterVirtualCallBack Left
This is Derived's Constructor



### When built and executed with Mono 4.0.5 and below, it produces the following ###

This is Base's Constructor
NATIVE: RegisterVirtualCallBack Entered
MANAGED: This is Derived's OnInit
NATIVE: RegisterVirtualCallBack Left
This is Derived's Constructor


Which is the correct/needed behavior I believe.
Comment 1 Assem Radaideh 2016-01-18 07:09:52 UTC
Created attachment 14614 [details]
This is the correct Sample. Use this attachement not the previous

This zip file contains 3 files:

1- C file exporting a function to be built as an Shared library (.so)
2- C# file having a class that PInvokes the exported function, passing a delegate that referenced an overridden method.

3- simple shell script file that build both the Native library + .Net Console Executable.

to see the difference : build and run that executable using mono 4.0.5 or bellow and then with 4.2.1 or above. and compare the written 3rd line for both outputs.
Comment 2 Zoltan Varga 2016-01-18 16:43:36 UTC
Fixed in mono master 33104f6a78e23fe8cba86c935a254b6e548fc53e.