[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());
+ }
+}
+
+}