2010-01-11 104 views
3

我在Linux中遇到了Mono Interop的問題。我有一個本地共享庫(在Lazarus中製作),我需要在C#程序集中使用它。共享庫由Windows和Linux上的Mono C#組件使用。Mono(linux)中的DLLImport崩潰:icall_wrapper_mono_marshal_free

該程序集在運行時通過DllImport加載共享庫,並調用導出的函數,該函數生成一個文件並返回一個包含新文件名的字符串。共享庫中的函數工作正常,但在Linux中,Mono運行時在函數返回時在Object .__ icall_wrapper_mono_marshal_free處崩潰。這在Windows上使用Mono很好。

我做了幾個測試,我可以告訴共享庫實際上工作(新文件在指定的路徑生成),但最終運行時崩潰。看起來,運行時將結果字符串封送回程序集時出現問題,因爲如果我使用返回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] 

任何想法?

回答

2

從本地方法調用返回string通常不是一個好主意。請參閱單聲道的Interop with Native Libraries (Strings)頁面,瞭解如何處理您的情況。如果你知道返回字符串的最大尺寸,那麼StringBuilder方法就是要走的路。

+0

非常感謝你。我已經看到了這些文檔,但我完全錯過了StringBuilder方法。現在它工作正常。 – Arcturus 2010-01-11 15:37:57

0

問題是什麼stralloc使用?在Mono中,等效代碼在返回的blob上使用g_free,它被映射到libc free。 StrAlloc有可能做其他事情。

+0

stralloc是一個FreePascal RTL函數,它使用FreePascal本機內存管理器在堆中分配一個新字符串。我不知道它是否在Linux上使用libc,但我現在不喜歡玩弄這種模糊的低級細節。 但是,正如Laurent建議的那樣,使用StringBuilder從本地共享庫將字符串值返回Mono,問題得以解決。 – Arcturus 2010-01-14 22:50:06

+0

libc malloc/free/realloc可以在單元「cmem」中找到,您需要將其包含在主程序的用途中。結果:= PChar類型(malloc的(長度(sresult)+1)); – 2010-01-21 12:50:19

2

會發生什麼情況是C#嘗試釋放爲Linux返回的字符串分配的內存,或者在Windows上使用CoTaskMemFree。雖然您可以在程序中使用g_alloc或CoTaskMemAlloc來分配內存,但我建議將返回類型更改爲C#中的IntPtr,並使用Marshal.PtrToStringAuto將其轉換爲字符串。您還需要通過將其傳遞給非託管代碼中的某個其他函數來釋放返回的字符串。

代碼FreeText的:

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