[Mono-dev] managed code wrappers (exceptions & garbage collection across pinvoke barriers)

Zoltan Varga vargaz at gmail.com
Sat Aug 25 16:57:12 EDT 2007


                                    Hi,

  The input parameter is converted by the runtime from ut8 to a managed string
object, which is handled by the GC, so there should be no leak there. The result
is converted from a managed string object to ut8, and the caller should free it
using g_free (). So your example code should work without a leak.

               Zoltan

On 8/25/07, Sebastian Good <sebastian at palladiumconsulting.com> wrote:
> Thanks, I've read (and now-reread!) this fairly carefully, but my case is
> about  C code calling CLI code, not the other way around, so I do not see
> explicit instructions about things like, for instance, how to treat the
> char* returned from the managed delegate. I would have expected the copy of
> the char* I pass to the CLI ("hello", below) to be magically handled by the
> CLI, but the document doesn't make 100% clear how to free the char* copy
> that comes back from the managed delegate. It seems clear to me that the CLI
> can't collect it for me (its lifetime must be managed by C), but it also
> seems that I suffer a memory leak even if I try to g_free it. The equivalent
> explicit marshaling
> (mono_string_to_utf8(reinterpret_cast<MonoString*>(answer))
> works like a charm and leaks nothing.
>
>
>  On 8/25/07, Zoltan Varga <vargaz at gmail.com> wrote:
> > Hi,
> >
> > Try our interop tutorial. It has some answers to your questions.
> >
> > http://www.mono-project.com/Interop_with_Native_Libraries
> >
> >             Zoltan
> >
> > On 8/25/07, Sebastian Good
> <sebastian at palladiumconsulting.com> wrote:
> > >  Thanks to help on this list I've come a long way in embedding mono into
> my
> > > C++ application. During the transition of a very large application (25+
> yrs
> > > of C, Fortran, & C++) towards managed code, we will be adding new code
> in
> > > .NET languages, but needing to access these objects from C++ fairly
> > > intimately. Therefore I'm looking at writing wrappers which expose CLR
> > > classes as C++ classes -- without resorting to (XP)COM or CORBA. I
> figure
> > > most of these can be auto-generated. I believe it will make sense to
> emit
> > > mono-embedding wrappers for Linux and Managed C++ wrappers for Windows.
> If
> > > anyone else is interested (or has already undertaken!) such an effort,
> let
> > > me know. However I'm still looking at some marshalling issues.
> > >
> > >  If I call .NET functions exclusively via the embedding reflection API,
> e.g.
> > > mono_runtime_invoke, and carefully call g_free on returned copies of
> things
> > > like strings, everything works fine, including managed exceptions. It
> seems
> > > that  by caching the reflected objects, e.g. MonoMethod*, performance is
> > > good.
> > >
> > >  However I am having problems with delegates invoked across the barrier.
> > > They execute properly, but appear to leak memory, and I am not sure how
> to
> > > catch exceptions they might throw. For the majority of our interop, we
> can
> > > avoid attempting this scenario, but we'd like to investigate it so that
> we
> > > can provide managed callbacks for unmanaged code to call.
> > >
> > >  In our C++, we define (using MSVC syntax for this prototype)
> > >
> > > // function: string->string
> > >  typedef char* (__stdcall * action_string)(char*);
> > >
> > >  // managed code will stash a delegate here for use by unmanaged code
> > >  action_string _f_string;
> > >  extern "C" _declspec(dllexport) void __stdcall
> init_string(action_string f)
> > >  {  _f_string =f ; }
> > >
> > >  // the unmanged code actually calls this code, e.g. do_string("hello")
> > >  extern "C" _declspec(dllexport) char* __stdcall do_string(char* s);
> > >  {  return _f_string(s); }
> > >  then in C# we write
> > >
> > > // function: string->string, equivalent to action_string above
> > >  public delegate string ActionString(string _);
> > >
> > >  // the managed code we'll be calling from unmanaged code
> > >  public static string Echo(string s) { return s+s; }
> > >
> > >  // and the bootstrapper
> > >  [DllImport("libhost")] public static extern void
> init_string(ActionString
> > > s);
> > >  public static void Boot { init_string(Echo); }
> > >  and again in C++, we can actually call the managed code like so
> > >
> > > // find_method is just a shortcut using debug-helpers
> > >  MonoMethod *bootMethod = find_method("Hello.World:Boot", image);
> > >   mono_runtime_invoke(bootMethod, NULL, NULL, NULL);
> > >  // now we have a function pointer we can call
> > >  char *result = do_string("hello");
> > >  g_free(result);
> > >  Everything works. However, there appears to be a memory leak. I am not
> sure
> > > whether it is the input that is leaking (i.e. a copy of  char*"hello"
> turned
> > > into utf16"hello"), or if I am improperly freeing the output (which I
> must
> > > assume is a copied string) or something else in the internals. What is
> > > encouraging is that all the marshalling is correct, just leaky. Also, if
> the
> > > managed code throws an exception, the program prints an error message
> > > ("uncaught exception") and hangs. I am not sure what I would have
> expected
> > > on the C++ side, perhaps a C++ exception, perhaps silence.
> > >
> > >  >From the fact that the function pointers work at all, I can tell a lot
> of
> > > thought has already gone into this PInvoke stuff. What am I missing on
> the
> > > garbage collection side? (And as soon as the strings work, I need to
> worry
> > > about making sure that managed delegate doesn't move or get garbage
> > > collected!)
> > >
> > >  Thanks
> > >
> > >  Sebastian
> > > _______________________________________________
> > > Mono-devel-list mailing list
> > > Mono-devel-list at lists.ximian.com
> > >
> http://lists.ximian.com/mailman/listinfo/mono-devel-list
> > >
> > >
> >
> >
>
>



More information about the Mono-devel-list mailing list