我已经在多平台应用中收到SIGSEGV (11)
个例外代码,看似简单。每次发生这种情况时,调试器似乎都会把我带到一个不同的地方。所以我把一个简单的应用程序拼凑在一起来证明这一点它不会发生在Windows中,但它确实发生在所有其他平台上。 Windows工作正常。我能够每次重新创建并演示如下的唯一示例来自XSuperObject
库。
启动一个新的空白多平台应用程序,只需添加一个按钮。
DFM
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 259
ClientWidth = 310
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
DesignerMasterStyle = 0
object Button1: TButton
Position.X = 136.000000000000000000
Position.Y = 96.000000000000000000
TabOrder = 0
Text = 'Button1'
OnClick = Button1Click
end
end
现在只为此按钮添加OnClick
事件的处理程序。
CODE
unit uMain;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
XSuperObject;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
uses
IOUtils;
procedure TForm1.Button1Click(Sender: TObject);
var
O: ISuperObject;
L: TStringList;
FN: String;
begin
FN:= TPath.Combine(TPath.GetHomePath, 'MyApp');
ForceDirectories(FN);
FN:= TPath.Combine(FN, 'Test.json');
O:= SO;
O.S['foo']:= 'bar';
L:= TStringList.Create;
try
L.Text:= O.AsJSON(True);
L.SaveToFile(FN);
finally
L.Free;
end;
O:= TSuperObject.ParseFile(FN); // <-- SIGSEGV (11) happens here
end;
end.
例如,在使用OSX进行的测试中,按下按钮会产生异常:
Project SIGSEGVTest raised exception class SIGSEGV (11).
当我点击Break
时,它会将我带到System.Character.inc
行的1394
文件中,该文件似乎是一堆二进制文件:
db $59,$40,$00,$00,$00,$00,$00,$40,$8F,$40,$00,$00,$00,$00,$00
在某些情况下,我会反复看到无限的异常。我似乎无法追踪它的来源。我没有运气寻找这个,我发现的一切都是另一种语言,没有答案,或另一个pascal IDE(如拉撒路)。在上述相同的场景中,应用程序只是锁定而不是提供此异常。有时候,当我点击Break
时,调试器也不会把我带到任何地方。
我确实理解异常意味着什么(与访问冲突基本相同),但为什么我在Windows以外的所有平台上都会遇到此异常?
注意
我确实设法通过使用泛型TList<>
而不是传统的已弃用TList
在一个地方修复此问题。但那只是一个,而我正在努力找出我在很多地方得到这个例外的真正原因。几个星期以来一直在争夺它。
我使用的是Delphi XE7 Update 2,我的XSuperObject
副本刚刚更新,但是没有运气。
我还安装了最新的IDE Fix Pack,但仍然没有运气。
更新
例如,在没有调试的情况下从iOS模拟器(iOS 7.1)中运行同一个应用程序时,我得到以下内容:
Access violation at address 0060907D, accessing address 00000000.
更新
这是来自OSX的崩溃报告(太大而不适合这里):
更新
看起来好像指针在某种程度上被破坏了。在目前为止我见过的大多数情况下,当我访问应该初始化的指针时会发生这种情况。例如,当我有一个经典的TList时,它让我使用它就好了,除非我试图读取其中一个指针而且我得到了同样的错误。相同的代码在Windows中完美运行。例如,MyObj:= TMyObj(MyTList[0]);
我可以在那里看到正确的指针,但无论如何都会产生这个异常。不幸的是,由于我试图重现这种特殊情况,我不能。
更新
我终于设法逐步完成了XSuperObject
库(之前我在尝试设置断点时遇到了其他奇怪的问题)。它在第587行中断,该行位于以下构造函数中:
constructor TBaseJSON<T, Typ>.Create(JSON: String; const CheckDate: Boolean);
type PInterface = ^IInterface;
var
JVal: IJSONAncestor;
PIntf: PInterface;
begin
FCheckDate := CheckDate;
if (Self.InheritsFrom(TSuperArray)) and (Trim(JSON) = '{}') then JSON := '[]';
JVal := TJSONObject.ParseJSONValue(JSON, FCheckDate);
if JVal.QueryInterface(GetTypeData(TypeInfo(T)).Guid, FJSONObj) = S_OK then // <-- Happens here
FInterface := TValue.From<T>(FJSONObj).AsInterface
else
FCasted := JVal
end;
答案 0 :(得分:2)
这是XSuperObject中的一个错误。当JSON文件以Unicode BOM开头时,它会崩溃。您需要在没有BOM的情况下保存JSON文件,但是使用Unicode:
L.WriteBOM := False;
L.SaveToFile(FN, TEncoding.UTF8);
但是如果你得到一个带有BOM的JSON文件,你仍然会崩溃。为了避免这种情况,您可以按如下方式修补TSuperObject.ParseStream:
class function TSuperObject.ParseStream(Stream: TStream): TSuperObject;
var
Strm: TStringList;
begin
Strm := TStringList.Create;
try
Strm.LoadFromStream(Stream);
Result := TSuperObject.Create( Strm.Text);
finally
Strm.Free;
end;
end;
这只是一个快速的解决方法。更好的方法应该仔细查看JSON文件的编码。
当您的文件保存在OSX上时,它看起来像这样:
Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 EF BB BF 7B 0D 0A 20 20 22 66 6F 6F 22 3A 22 62 {.. "foo":"b
00000010 61 72 22 0D 0A 7D 0D 0A ar"..}..
前三个字节是BOM,这会导致XSuperObject出现问题。发生崩溃是因为JVal在第二次击中该线时在第587行中为零。
<强>更新强>
RFC 7159表示json实现不能在开头添加字节顺序标记。但如果它存在,他们可能会忽略它。因此,即使能够处理BOM也不是必需的,但在这种情况下不应该崩溃。
应该通过查看文件来检测JSON编码(这在过时的RFC 4327中有解释)