Question

I'm stucked with a problem with Mono Interop in Linux. I have a native shared library (made in Lazarus) that I need to use in a C# assembly. The shared library is used by a Mono C# assemblie on Windows and on Linux.

The assembly loads the shared library via DllImport at runtime, and calls an exported function that generates a file and returns a string with the new file's name. The function in the shared library works fine, but in Linux the Mono runtime crashes at Object.__icall_wrapper_mono_marshal_free when the function returns. This works fine using Mono on Windows.

I've made several tests and I can tell that the shared library actually works (the new file is generated at the specified path), but in the end the runtime crashes. It seems that the runtime has problems with the marshaling of the resulting string back to the assembly, because it works if I use an exported function that returns an int.

My shared library is something like this:

library fileProcessing;

{$mode objfpc}{$H+}
...

function ProcessFile(File, ResultPath: PChar): PChar; cdecl; // returns a null-terminated string, with a C ABI calling convention
var
  sFile, sPath, sResult: string;
begin
  sFile := StrPas(File);
  sPath := StrPas(ResultPath);
...
  sResult := GenerateNewFile(sFile, sPath); // helper function that generates the file and returns its filename
  Result := stralloc(length(sResult) + 1);
  Result := strpcopy(Result, sResult);
end;
...

exports ProcessFile name 'ProcessFile';

The calling C# assembly goes like this:

namespace SIG
{
  public class TsigKernel
  {
...
    [DllImport("fileProcessing.so", CharSet=CharSet.Ansi,
         EntryPoint="ProcessFile",
         CallingConvention=CallingConvention.Cdecl, SetLastError = true)]
    private static extern string ex_ProcessFile(string File, string ResultPath);

    // managed wrapper for the shared library exported function
    public string ProcessFile(string File, string ResultPath)
    {
     return ex_ProcessFile(File, ResultPath);
    }
...
  }
}

I've tried several alternatives (returning a native string from the exported function, changing the calling convention to stdcall on the assembly and the shared library, changing the charset in the DllImport).

I'm sure that I'm missing something, but I haven't found anything about this problem on Google.

My crash reads:

=================================================================  
Got a SIGABRT while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.  
=================================================================

Stacktrace:
  at (wrapper managed-to-native) object.__icall_wrapper_mono_marshal_free (intptr) <0x00004>
  at (wrapper managed-to-native) object.__icall_wrapper_mono_marshal_free (intptr) <0x00004>
  at (wrapper managed-to-native) SIG.TsigKernel.ex_ProcessFile (string, string) <0x00064>
  at SIG.TsigKernel.ProcessFile (string, string) <0x00010>
  at TEST.Form1.Form1_Load (object,System.EventArgs) <0x00047>
  at System.Windows.Forms.Form.OnLoad (System.EventArgs) <0x00060>
  at System.Windows.Forms.Form.OnLoadInternal (System.EventArgs) <0x00081>
  at System.Windows.Forms.Form.OnCreateControl () <0x00051>
  at System.Windows.Forms.Control.CreateControl () <0x0012e>
  at System.Windows.Forms.Control.WmShowWindow (System.Windows.Forms.Message&) <0x0010f>
  at System.Windows.Forms.Control.WndProc (System.Windows.Forms.Message&) <0x00292>
  at System.Windows.Forms.ScrollableControl.WndProc (System.Windows.Forms.Message&) <0x00013>
  at System.Windows.Forms.ContainerControl.WndProc (System.Windows.Forms.Message&) <0x00051>
  at System.Windows.Forms.Form.WndProc (System.Windows.Forms.Message&) <0x0022a>
  at System.Windows.Forms.Control/ControlWindowTarget.OnMessage (System.Windows.Forms.Message&) <0x0001d>
  at System.Windows.Forms.Control/ControlNativeWindow.WndProc (System.Windows.Forms.Message&) <0x0002d>
  at System.Windows.Forms.NativeWindow.WndProc (intptr,System.Windows.Forms.Msg,intptr,intptr) <0x001eb>
  at System.Windows.Forms.XplatUIX11.SendMessage (intptr,System.Windows.Forms.Msg,intptr,intptr) <0x002ae>
  at System.Windows.Forms.XplatUIX11.MapWindow (System.Windows.Forms.Hwnd,System.Windows.Forms.WindowType) <0x0019a>
  at System.Windows.Forms.XplatUIX11.CreateWindow (System.Windows.Forms.CreateParams) <0x00bb4>
  at System.Windows.Forms.XplatUI.CreateWindow (System.Windows.Forms.CreateParams) <0x0001d>
  at System.Windows.Forms.NativeWindow.CreateHandle (System.Windows.Forms.CreateParams) <0x00030>
  at System.Windows.Forms.Control.CreateHandle () <0x0007f>
  at System.Windows.Forms.Form.CreateHandle () <0x00014>
  at System.Windows.Forms.Control.CreateControl () <0x0008a>
  at System.Windows.Forms.Control.SetVisibleCore (bool) <0x00079>
  at System.Windows.Forms.Form.SetVisibleCore (bool) <0x0021d>
  at System.Windows.Forms.Control.set_Visible (bool) <0x0002c>
  at (wrapper remoting-invoke-with-check) System.Windows.Forms.Control.set_Visible (bool) <0x00057>
  at System.Windows.Forms.Application.RunLoop (bool,System.Windows.Forms.ApplicationContext) <0x001f9>
  at System.Windows.Forms.Application.Run (System.Windows.Forms.ApplicationContext) <0x00052>
  at System.Windows.Forms.Application.Run (System.Windows.Forms.Form) <0x00033>
  at TEST.Program.Main () <0x00044>
  at (wrapper runtime-invoke) object.runtime_invoke_void (object,intptr,intptr,intptr) <0x0003a>

Native stacktrace:
mono [0x80d36a9]
[0xffffe410]
[0xffffe430]
/lib/libc.so.6(gsignal+0x4f) [0xb76430cf]
/lib/libc.so.6(abort+0x187) [0xb76449e7]
/lib/libc.so.6 [0xb767f4ed]
/lib/libc.so.6 [0xb768550b]
/lib/libc.so.6 [0xb7686de4]
/lib/libc.so.6(cfree+0x6d) [0xb7689fdd]
/usr/lib/libglib-2.0.so.0(g_free+0x36) [0xb780d886]
[0xb6561634]
[0xb5786a5d]
[0xb57869d1]
[0xb57866c8]
[0xb5786599]
[0xb578632a]
[0xb5785f7a]
[0xb605dbe7]
[0xb578c7c0]
[0xb578bbfb]
[0xb57820c4]
[0xb578208a]
[0xb5781eeb]
[0xb578b95e]
[0xb578b936]
[0xb578ac74]
[0xb5788acf]
[0xb578c4b3]
[0xb605eca5]
[0xb605e0e6]
[0xb605e069]
[0xb605ddf0]
[0xb57804bd]
[0xb605db43]
[0xb57938a2]
[0xb57800a6]
[0xb57937f5]
[0xb5793798]
[0xb577f062]
[0xb577ee13]
[0xb577eacc]
[0xb71ce1f5]
[0xb71ce26b]
mono [0x8063552]

Any ideas?

Was it helpful?

Solution

It is not generally a good idea to return a string from a native method call. Please refer to the Mono's Interop with Native Libraries (Strings) page to see how to handle your case. If you know the maximum size of the return string, then the StringBuilder approach is the way to go.

OTHER TIPS

What happens is that C# tries to free the memory allocated for returned strings using g_free on Linux or CoTaskMemFree on Windows. While you can use g_alloc or CoTaskMemAlloc in your program to allocate memory, I would recommend to change return type to IntPtr in the C# and use Marshal.PtrToStringAuto to convert it to string. You will also need to free the returned string by passing it to some other function in unmanaged code.

namespace SIG
{
  public class TsigKernel
  {
    ...
    [DllImport("fileProcessing.so", CharSet=CharSet.Ansi,
         EntryPoint="ProcessFile",
         CallingConvention=CallingConvention.Cdecl, SetLastError = true)]
    private static extern IntPtr ex_ProcessFile(string File, string ResultPath);

    [DllImport("fileProcessing.so", CharSet=CharSet.Ansi,
         EntryPoint="FreeText",
         CallingConvertion=CallingConvention.Cdecl, SetLastError = true)]
    private static extern void ex_FreeText(IntPtr str);

    // managed wrapper for the shared library exported function
    public string ProcessFile(string File, string ResultPath)
    {
      IntPtr str_ptr = ex_ProcessFile(File, ResultPath);
      string res = Marshal.PtrToStringAnsi(str_ptr);
      ex_FreeText(str_ptr);
      return res;
    }
    ...
  }
}

Code for FreeText:

function FreeText(Str: PChar); cdecl; // frees previously allocated string, with a C ABI calling convention
begin
  strdispose(Str);
end;

The question is what does stralloc use? In Mono the equivalent code uses g_free on the blob returned, which is mapped to libc free. Chances are that StrAlloc is doing something else.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top