Сбой DLLImport в Mono (Linux): icall_wrapper_mono_marshal_free - PullRequest
3 голосов
/ 11 января 2010

У меня проблема с Mono Interop в Linux. У меня есть собственная разделяемая библиотека (сделанная в Lazarus), которую мне нужно использовать в сборке C #. Совместно используемая библиотека используется сборкой Mono C # в Windows и Linux.

Сборка загружает общую библиотеку через DllImport во время выполнения и вызывает экспортированную функцию, которая генерирует файл и возвращает строку с именем нового файла. Функция в разделяемой библиотеке работает нормально, но в Linux среда выполнения Mono падает на Object .__ icall_wrapper_mono_marshal_free, когда функция возвращается. Это прекрасно работает, используя Mono на Windows.

Я провел несколько тестов и могу сказать, что разделяемая библиотека действительно работает (новый файл создается по указанному пути), но в итоге среда выполнения вылетает. Кажется, что во время выполнения возникают проблемы с маршалингом полученной строки обратно в сборку, потому что она работает, если я использую экспортированную функцию, которая возвращает int.

Моя общая библиотека выглядит примерно так:

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';

Вызывающая сборка C # выглядит так:

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);
    }
...
  }
}

Я пробовал несколько альтернатив (возвращение нативной строки из экспортированной функции, изменение соглашения о вызовах на stdcall для сборки и разделяемой библиотеки, изменение кодировки в DllImport).

Я уверен, что что-то упустил, но я ничего не нашел об этой проблеме в Google.

Мой сбой гласит:

=================================================================  
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]

Есть идеи?

Ответы [ 3 ]

2 голосов
/ 23 февраля 2013

В результате C # пытается освободить память, выделенную для возвращаемых строк, используя g_free в Linux или CoTaskMemFree в Windows. Хотя вы можете использовать g_alloc или CoTaskMemAlloc в своей программе для выделения памяти, я бы рекомендовал изменить тип возвращаемого значения на IntPtr в C # и использовать Marshal.PtrToStringAuto для преобразования его в строку. Вам также потребуется освободить возвращенную строку, передав ее какой-либо другой функции в неуправляемом коде.

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;
    }
    ...
  }
}

Код для свободного текста:

function FreeText(Str: PChar); cdecl; // frees previously allocated string, with a C ABI calling convention
begin
  strdispose(Str);
end;
2 голосов
/ 11 января 2010

Обычно не рекомендуется возвращать string из вызова нативного метода. Пожалуйста, обратитесь к странице Mono Взаимодействие с нативными библиотеками (строки) , чтобы узнать, как обращаться с вашим делом. Если вы знаете максимальный размер возвращаемой строки, то подход StringBuilder - это то, что вам нужно.

0 голосов
/ 14 января 2010

Вопрос в том, что использует stralloc? В Mono эквивалентный код использует g_free в возвращенном BLOB-объекте, который сопоставлен с libc free. Скорее всего, StrAlloc делает что-то еще.

...