2010-01-11 105 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;