Delphi FMX OSX分段错误11 [英] Delphi FMX OSX Segmentation Fault 11

查看:97
本文介绍了Delphi FMX OSX分段错误11的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Segmentation Fault 11上有很多帖子,但似乎没有一个回答我的问题:

There are a number of Segmentation Fault 11 posts, but none seem to answer my question:

我之前已经发布了简单测试应用程序的代码,但是提供完整性。 Windows 10,带有OSX High Sierra 10.13.6和Xcode 9.4.1的Delphi 10.2.3。

I've posted the code for the simple test application previously, but is provided for completeness. Windows 10, Delphi 10.2.3 with OSX High Sierra 10.13.6 and Xcode 9.4.1.

主机:

unit uDylibTest1;

interface

uses
  System.SysUtils,
  System.Types,
  System.Diagnostics,
  System.UITypes,
  System.Classes,
  System.Variants,

  FMX.Types,
  FMX.Controls,
  FMX.Forms,
  FMX.Graphics,
  FMX.Dialogs,
  FMX.StdCtrls,
  FMX.Platform,
  FMX.Controls.Presentation;


const
  // Windows DLL Names
  {$IFDEF MSWINDOWS}
  TestDLL = 'pTestDLL.dll';
  {$ENDIF MSWINDOWS}

  // macOS DYLIB Names
  {$IFDEF MACOS}
  //TestDLL = 'libpTestDLL.dylib';
    TestDLL = 'libpTestDLL.dylib';
  {$ENDIF MACOS}

type
  TfDylibTest = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TuDylibTest = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

{$IFDEF MSWINDOWS}
function say_Hello(Hello: string; out ReturnString: string): boolean; stdcall; external TestDLL Delayed;
{$ENDIF MSWINDOWS}
{$IFDEF MACOS}
function _say_Hello(Hello: string; out ReturnString: string): boolean; cdecl; external TestDLL;
{$ENDIF MACOS}

function local_say_hello(Hello: string): boolean; forward;

var
  fDylibTest: TfDylibTest;

implementation

function local_say_hello(Hello: string): boolean;
begin
  Result := True;
  showmessage(Hello);
end;

{$R *.fmx}
{$R *.Macintosh.fmx MACOS}
{$R *.Windows.fmx MSWINDOWS}

procedure TfDylibTest.Button1Click(Sender: TObject);
var
 b:boolean;
 sType: string;
 sDLLString: string;

begin
  b := False;
  sType := '';
  // Call the DLL Function
  {$IFDEF MSWINDOWS}
  sDLLString := 'The string passed to the Windows DLL';
  b := say_Hello(sDLLString, sType);
  {$ENDIF MSWINDOWS}
  {$IFDEF MACOS}
  sDLLString := 'The string passed to the macOS DYLIB';
  b :=  _say_Hello(sDLLString, sType);
  {$ENDIF MACOS}

  if b then
    showmessage('Returned From: ' + sType + ': TRUE')
  else
    showmessage('Retur was: FALSE');
end;

procedure TfDylibTest.Button2Click(Sender: TObject);
var
  b: boolean;
 iTime2Auth: integer;
 Opened: boolean;
 i: integer;

begin
  Opened := False;

  // test the Waitnofreeze
  iTime2Auth := 0;

  b := False;
  // Call the local Function
  b := local_say_Hello('The string passed to the LOCAL function');

  if b then
    showmessage('Say Hello OK - LOCAL')
  else
    showmessage('Say Hello Failed - LOCAL');
end;

procedure TfDylibTest.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  showmessage('[Test App] onClose');
end;

procedure TfDylibTest.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  canClose := True;
  showmessage('[Test App] onCloseQuery');
end;

procedure TfDylibTest.FormCreate(Sender: TObject);
begin
  showmessage('[Test App] onCreate');
end;

initialization
  showmessage('[Test App] Initialization');  <<<<-- THIS IS EXECUTED

finalization
  showmessage('[Test App] Finalization');    <<<<-- THIS IS NOT EXECUTED

end.

和DYLIB:

unit uTestDLL;

interface

uses
  System.Diagnostics,
  System.Classes;

// External functions and procedures
{$IFDEF MSWINDOWS}
function say_Hello(Hello: string; out ReturnString: string): boolean; stdcall; forward;
{$ENDIF MSWINDOWS}
{$IFDEF MACOS}
function _say_Hello(Hello: string; out ReturnString: string): boolean; cdecl; forward;
{$ENDIF MACOS}

exports
  {$IFDEF MSWINDOWS}
  say_Hello;
  {$ENDIF MSWINDOWS}
  {$IFDEF MACOS}
  _say_Hello;
  {$ENDIF MACOS}

Implementation

{$IFDEF MSWINDOWS}
function say_Hello(Hello: string; out ReturnString: string): boolean; stdcall; export;
{$ENDIF MSWINDOWS}
{$IFDEF MACOS}
function _say_Hello(Hello: string; out ReturnString: string): boolean; cdecl; export;
{$ENDIF MACOS}
begin
  {$IFDEF MSWINDOWS}
  ReturnString := 'Windows DLL, Received: ' + Hello;
  {$ENDIF MSWINDOWS}
  {$IFDEF MACOS}
  ReturnString := 'macOS DYLIB, Received: ' + Hello;
  {$ENDIF MACOS}
  Result := True;
end;

end.

基本上DYLIB中的一个函数传递了一个字符串参数,它返回TRUE并带有另一个OUT变量字符串,证明数据已进入DYLIB函数并返回。

Basically a function in a DYLIB is passed a string parameter, it returns TRUE with an OUT variable of another string which proves that the data went into the DYLIB function and returned out.

我在调用应用程序中有简单的showmessage()语句,用于诸如onCloseQuery和onClose等之类的东西,这些都显示了一切,一切正常,直到应用程序关闭(onCloseQuery执行) ,执行onClose,并在一切关闭后大约半秒到一秒钟弹出问题报告)。请注意,初始化部分已执行,但终结部分未执行(尽管在Win32模式下运行时已执行)。我已将Google驱动器链接添加到错误日志。 OSX问题报告

I have simple showmessage() statements in the calling application for things like onCloseQuery and onClose etc, these all show, everything WORKS as it should until the application closes(onCloseQuery executed, onClose executed, and about half a second to a second after everything shuts down the problem report pops up). Note that the Initialisation Section IS executed, but the Finalization Section is NOT executed (although it is executed when running in Win32 mode). I've put the google drive link to the error log. OSX Problem Report

当我查看堆栈跟踪时,没有提到我的两个文件(DylibTest和libpTesDLL.DYLIB),它们都是RTL /系统单元。我用Google搜索了Seg Fault 11并搜索了论坛,但似乎没有任何联系。

When I look at the stack trace, there are none of my two files (DylibTest and libpTesDLL.DYLIB) mentioned, it's all RTL/system units. I've googled Seg Fault 11 and searched the forum, but nothing seems related.

我希望获得有关如何进行的任何建议?

I'd appreciate any advice with how I could proceed?

推荐答案

string 并不是跨库边界互操作的可移植数据类型。使用 PChar 代替,然后您需要确定WHO为字符串(库或调用应用程序)分配和释放内存,以及如何分配和释放它们,在一种互操作兼容的方式。您不会以安全的方式在库边界中传递字符串,因此也难怪您会使代码崩溃。

string is NOT a portable data type for interop across library boundaries. Use PChar instead, and then you need to decide WHO allocates and frees memory for strings - the library or the calling app - and HOW they are allocated and freed, and do so in an interop compatible manner. You are not passing strings across the library boundary in a safe manner, so it is no wonder that you are crashing your code.

请尝试以下类似操作:

主机:

// Windows DLL
{$IFDEF MSWINDOWS}
const
  TestDLL = 'pTestDLL.dll';

function say_Hello(Hello: PChar; out ReturnString: PChar): boolean; stdcall; external TestDLL Delayed;
procedure free_String(Mem: PChar); stdcall; external TestDLL Delayed;
{$ENDIF}

// macOS DYLIB
{$IFDEF MACOS}
const
  TestDLL = 'libpTestDLL.dylib';

function say_Hello(Hello: PChar; out ReturnString: PChar): boolean; cdecl; external TestDLL name '_say_Hello';
function free_String(Mem: PChar); cdecl; external TestDLL name '_free_String';
{$ENDIF}

...

procedure TfDylibTest.Button1Click(Sender: TObject);
var
 b: boolean;
 sType: PChar;
 sDLLString: string;
begin
  b := False;
  sType := nil;

  // Call the DLL Function
  {$IF DEFINED(MSWINDOWS) OR DEFINED(MACOS)}
  sDLLString := 'The string passed to the ' + {$IFDEF MSWINDOWS}'Windows DLL'{$ELSE}'macOS DYLIB'{$ENDIF};
  b := say_Hello(PChar(sDLLString), sType);
  if b then
  begin
    try
      ShowMessage('Returned From: ' + string(sType) + ': TRUE');
    finally
      free_String(sType);
    end;        
    Exit;
  end;
  {$IFEND}

  ShowMessage('Retur was: FALSE');
end;

DYLIB:

unit uTestDLL;

interface

{$IF DEFINED(MSWINDOWS) OR DEFINED(MACOS)}

// External functions and procedures
function say_Hello(Hello: PChar; out ReturnString: PChar): boolean; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; forward;
procedure free_String(S: PChar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; forward;

exports
  say_Hello{$IFNDEF MSWINDOWS} name '_say_Hello'{$ENDIF},
  free_String{$IFNDEF MSWINDOWS} name '_free_String'{$ENDIF};

{$IFEND}

implementation

uses
  System.Diagnostics,
  System.Classes;

{$IF DEFINED(MSWINDOWS) OR DEFINED(MACOS)}

function say_Hello(Hello: PChar; out ReturnString: PChar): boolean; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; export;
var
  s: string;
begin
  try
    s := 'FROM: ' + {$IFDEF MSWINDOWS}'Windows DLL'{$ELSE}'macOS DYLIB'{$ENDIF} + ', Received: ' + string(Hello);
    ReturnString := StrAlloc(Length(s));
    try
      StrPCopy(ReturnString, s);
    except
      StrDispose(ReturnString);
      throw;
    end;
    Result := True;
  except
    Result := False;
  end;
end;

procedure free_String(S: PChar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; export;
begin
  StrDispose(S);
end;

{$IFEND}

end.

或者:

主机:

// Windows DLL
{$IFDEF MSWINDOWS}
const
  TestDLL = 'pTestDLL.dll';

function say_Hello(Hello: PChar): PChar; stdcall; external TestDLL Delayed;
procedure free_String(Mem: PChar); stdcall; external TestDLL Delayed;
{$ENDIF}

// macOS DYLIB
{$IFDEF MACOS}
const
  TestDLL = 'libpTestDLL.dylib';

function say_Hello(Hello: PChar): PChar; cdecl; external TestDLL name '_say_Hello';
function free_String(Mem: PChar); cdecl; external TestDLL name '_free_String';
{$ENDIF}

...

procedure TfDylibTest.Button1Click(Sender: TObject);
var
 sType: PChar;
 sDLLString: string;
begin
  sType := nil;

  // Call the DLL Function
  {$IF DEFINED(MSWINDOWS) OR DEFINED(MACOS)}
  sDLLString := 'The string passed to the ' + {$IFDEF MSWINDOWS}'Windows DLL'{$ELSE}'macOS DYLIB'{$ENDIF};
  sType := say_Hello(PChar(sDLLString));
  if sType <> nil then
  begin
    try
      ShowMessage('Returned From: ' + string(sType) + ': TRUE');
    finally
      free_String(sType);
    end;        
    Exit;
  end;
  {$IFEND}

  ShowMessage('Retur was: FALSE');
end;

DYLIB:

unit uTestDLL;

interface

{$IF DEFINED(MSWINDOWS) OR DEFINED(MACOS)}

// External functions and procedures
function say_Hello(Hello: PChar): PChar; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; forward;
procedure free_String(S: PChar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; forward;

exports
  say_Hello{$IFNDEF MSWINDOWS} name '_say_Hello'{$ENDIF},
  free_String{$IFNDEF MSWINDOWS} name '_free_String'{$ENDIF};

{$IFEND}

implementation

uses
  System.Diagnostics,
  System.Classes;

{$IF DEFINED(MSWINDOWS) OR DEFINED(MACOS)}

function say_Hello(Hello: PChar): PChar; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; export;
var
  s: string;
begin
  try
    s := 'FROM: ' + {$IFDEF MSWINDOWS}'Windows DLL'{$ELSE}'macOS DYLIB'{$ENDIF} + ', Received: ' + string(Hello);
    Result := StrAlloc(Length(s));
    try
      StrPCopy(Result, s);
    except
      StrDispose(Result);
      throw;
    end;
  except
    Result := nil;
  end;
end;

procedure free_String(S: PChar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; export;
begin
  StrDispose(S);
end;

{$IFEND}

end.

这篇关于Delphi FMX OSX分段错误11的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆