[Mono-bugs] [Bug 48026][Min] New - C++ object return-by-value breaks P/Invoke argument passing

bugzilla-daemon@bugzilla.ximian.com bugzilla-daemon@bugzilla.ximian.com
Fri, 29 Aug 2003 11:44:47 -0400 (EDT)


Please do not reply to this email- if you want to comment on the bug, go to the
URL shown below and enter your comments there.

Changed by patrick@vrac.iastate.edu.

http://bugzilla.ximian.com/show_bug.cgi?id=48026

--- shadow/48026	2003-08-29 11:44:47.000000000 -0400
+++ shadow/48026.tmp.22115	2003-08-29 11:44:47.000000000 -0400
@@ -0,0 +1,232 @@
+Bug#: 48026
+Product: Mono/Runtime
+Version: unspecified
+OS: 
+OS Details: Red Hat 8.0
+Status: NEW   
+Resolution: 
+Severity: 
+Priority: Minor
+Component: misc
+AssignedTo: mono-bugs@ximian.com                            
+ReportedBy: patrick@vrac.iastate.edu               
+QAContact: mono-bugs@ximian.com
+TargetMilestone: ---
+URL: 
+Cc: 
+Summary: C++ object return-by-value breaks P/Invoke argument passing
+
+Description of Problem:
+
+Using the included C# and C++ code, the Mono 0.26 runtime fails to handle
+argument passing with P/Invoke when a C++ object is returned by value.  The
+custom marshaler included in the code is intended to provide the mapping
+between the copied C++ object and the resultant C# object reference.  The
+code does work with the .NET Framework 1.1.
+
+It appears that the Mono runtime fails to pass the raw memory pointer into
+the native function Marshal_getCopy() correctly when its return value is a
+C++ object being returned by value.  Using by-reference return works just
+fine.  Changing the C# code so that ReferenceData is declared as a struct
+and the custom marshaler is removed also works fine.
+
+Steps to reproduce the problem:
+1. Compile return_copy.cpp to libreturn_copy.so
+2. Compile return_copy.cs
+3. Run 'mono return_copy.exe'
+
+Actual Results:
+
+Marshal::Marshal()
+new_Marshal() -- m: 0x80f0980
+new_Marshal() -- m->mRef.x: 51
+DataUser.DataUser() -- mRawObject: 0x80f0980
+DataUser.getReferenceCopy() -- mRawObject: 0x80f0980
+Marshal_getCopy() -- self_: 0x80c2d20
+Marshal_getCopy() -- self_->mRef.x: 135534788
+MarshalNativeToManaged() -- obj's value: 135203200
+Reference copy value: 135203200
+
+Expected Results:
+
+Marshal::Marshal()
+new_Marshal() -- m: 0x80f0980
+new_Marshal() -- m->mRef.x: 51
+DataUser.DataUser() -- mRawObject: 0x80f0980
+DataUser.getReferenceCopy() -- mRawObject: 0x80f0980
+Marshal_getCopy() -- self_: 0x80f0980
+Marshal_getCopy() -- self_->mRef.x: 51
+MarshalNativeToManaged() -- obj's value: 51
+Reference copy value: 51
+
+How often does this happen? 
+
+Every time.
+
+Additional Information:
+
+The following is the source used to expose this problem:
+
+// return_copy.cpp
+// To compile:
+//    c++ -o libreturn_copy.so return_copy.cpp
+
+#ifdef _MSC_VER
+#  include <windows.h>
+#  define MY_API __declspec(dllexport)
+#  define MY_CLASS_API __declspec(dllexport)
+#else
+#  define MY_API
+#  define MY_CLASS_API
+#endif
+
+#include <iostream>
+#include <iomanip>
+
+
+class ReferenceData
+{
+public:
+   unsigned int x;
+};
+
+class Marshal
+{
+public:
+   Marshal()
+   {
+      std::cout << "Marshal::Marshal()" << std::endl;
+      mRef.x = 51;
+   }
+
+   ReferenceData getCopy()
+   {
+      return mRef;
+   }
+
+private:
+   ReferenceData mRef;
+};
+
+extern "C"
+{
+
+MY_API Marshal* new_Marshal()
+{
+   Marshal* m = new Marshal;
+   std::cout << "new_Marshal() -- m: " << std::hex << m << std::dec
+             << std::endl;
+   std::cout << "new_Marshal() -- m->mRef.x: " << m->getCopy().x
+             << std::endl;
+   return m;
+}
+
+MY_API ReferenceData Marshal_getCopy(Marshal* self_)
+{
+   std::cout << "Marshal_getCopy() -- self_: " << std::hex << self_ << std::dec
+             << std::endl;
+   std::cout << "Marshal_getCopy() -- self_->mRef.x: " << self_->getCopy().x
+             << std::endl;
+   return self_->getCopy();
+}
+
+}
+
+================
+
+// return_copy.cs
+// To compile:
+//   mcs return_copy.cs
+
+using System;
+using System.Runtime.InteropServices;
+
+
+namespace test
+{
+
+[StructLayout(LayoutKind.Sequential)]
+class ReferenceData
+{
+   public override string ToString()
+   {
+      return x.ToString();
+   }
+
+   public uint x;
+}
+
+class ReferenceDataMarshaler : ICustomMarshaler
+{
+   public void CleanUpManagedData(Object obj)
+   {
+   }
+
+   public void CleanUpNativeData(IntPtr nativeData)
+   {
+   }
+
+   public int GetNativeDataSize()
+   {
+      return -1;
+   }
+
+   public IntPtr MarshalManagedToNative(Object obj)
+   {
+      return new IntPtr((int) ((ReferenceData) obj).x);
+   }
+
+   public Object MarshalNativeToManaged(IntPtr nativeObj)
+   {
+      ReferenceData obj = new ReferenceData();
+      obj.x = (uint) nativeObj;
+      Console.WriteLine("MarshalNativeToManaged() -- obj's value: " + obj);
+      return obj;
+   }
+
+   public static ICustomMarshaler GetInstance(string cookie)
+   {
+      return mInstance;
+   }
+
+   private static ReferenceDataMarshaler mInstance = new
+ReferenceDataMarshaler();
+}
+
+class DataUser
+{
+   protected internal IntPtr mRawObject;
+
+   [DllImport("return_copy", CharSet=CharSet.Ansi)]
+   private static extern IntPtr new_Marshal();
+
+   public DataUser()
+   {
+      mRawObject = new_Marshal();
+      Console.WriteLine("DataUser.DataUser() -- mRawObject: 0x{0:x}",
+                        mRawObject.ToInt32());
+   }
+
+   [DllImport("return_copy")]
+   [return : MarshalAs(UnmanagedType.CustomMarshaler,
+                       MarshalTypeRef = typeof(ReferenceDataMarshaler))]
+   private static extern ReferenceData Marshal_getCopy(IntPtr instPtr);
+
+   public ReferenceData getByCopy()
+   {
+      Console.WriteLine("DataUser.getReferenceCopy() -- mRawObject: 0x{0:x}",
+                        mRawObject.ToInt32());
+      return Marshal_getCopy(mRawObject);
+   }
+}
+
+class Tester
+{
+   public static void Main()
+   {
+      DataUser u = new DataUser();
+      Console.WriteLine("Reference copy value: " + u.getByCopy());
+   }
+}
+
+}