多处收到SIGSEGV(11)错误
Receiving SIGSEGV (11) errors in many places
我在使用看似简单的代码的多平台应用程序中收到 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
事件添加一个处理程序。
代码
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
时,它会将我带到行 1394
上的某个 System.Character.inc
文件,它似乎是一堆某种二进制文件:
db ,,[=13=],[=13=],[=13=],[=13=],[=13=],,F,,[=13=],[=13=],[=13=],[=13=],[=13=]
在某些情况下,我会反复收到此异常,因为它似乎是无限的。我似乎无法追踪它的来源。我没有任何运气来搜索这个,我找到的所有东西都是另一种语言,没有答案,或者是另一种 pascal IDE(例如 Lazarus)。时不时地,在与上述相同的情况下,应用程序只是锁定而不是给出此异常。有时,当我单击 Break
时,调试器不会带我去任何地方。
我确实理解异常的含义(本质上与访问冲突相同),但为什么我在 Windows 以外的所有平台上都会收到此异常?
注意
我过去确实设法通过使用泛型 TList<>
而不是传统的弃用 TList
在一个地方解决了这个问题。但这只是一个,我正在努力找出在这么多地方出现此异常的真正原因。已经与它斗争了几个星期了。
我正在使用 Delphi XE7 Update 2,我的 XSuperObject
副本刚刚更新到最新版本,但运气不好。
我还安装了最新的 IDE 修复包,但仍然没有成功。
更新
例如,当在 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;
这是 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"..}..
前3个字节是BOM,这给XSuperObject带来了麻烦。发生崩溃是因为 JVal 在第 587 行第二次遇到此行时为 nil。
更新:
RFC 7159 说 json 实现不能在开头添加字节顺序标记。但如果它存在,他们可能会忽略它。因此,即使能够处理 BOM 不是必需的,在这种情况下也不应该崩溃。
应该通过查看文件来检测 JSON 编码(这在过时的 RFC 4327 中有解释)
我在使用看似简单的代码的多平台应用程序中收到 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
事件添加一个处理程序。
代码
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
时,它会将我带到行 1394
上的某个 System.Character.inc
文件,它似乎是一堆某种二进制文件:
db ,,[=13=],[=13=],[=13=],[=13=],[=13=],,F,,[=13=],[=13=],[=13=],[=13=],[=13=]
在某些情况下,我会反复收到此异常,因为它似乎是无限的。我似乎无法追踪它的来源。我没有任何运气来搜索这个,我找到的所有东西都是另一种语言,没有答案,或者是另一种 pascal IDE(例如 Lazarus)。时不时地,在与上述相同的情况下,应用程序只是锁定而不是给出此异常。有时,当我单击 Break
时,调试器不会带我去任何地方。
我确实理解异常的含义(本质上与访问冲突相同),但为什么我在 Windows 以外的所有平台上都会收到此异常?
注意
我过去确实设法通过使用泛型 TList<>
而不是传统的弃用 TList
在一个地方解决了这个问题。但这只是一个,我正在努力找出在这么多地方出现此异常的真正原因。已经与它斗争了几个星期了。
我正在使用 Delphi XE7 Update 2,我的 XSuperObject
副本刚刚更新到最新版本,但运气不好。
我还安装了最新的 IDE 修复包,但仍然没有成功。
更新
例如,当在 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;
这是 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"..}..
前3个字节是BOM,这给XSuperObject带来了麻烦。发生崩溃是因为 JVal 在第 587 行第二次遇到此行时为 nil。
更新:
RFC 7159 说 json 实现不能在开头添加字节顺序标记。但如果它存在,他们可能会忽略它。因此,即使能够处理 BOM 不是必需的,在这种情况下也不应该崩溃。
应该通过查看文件来检测 JSON 编码(这在过时的 RFC 4327 中有解释)