Skip to content

Instantly share code, notes, and snippets.

@ComingNine
Created August 5, 2018 17:05
Show Gist options
  • Save ComingNine/8327058dbaf583b617d9917d0e79690b to your computer and use it in GitHub Desktop.
Save ComingNine/8327058dbaf583b617d9917d0e79690b to your computer and use it in GitHub Desktop.
If built with FPC for i386-win32, the application gives "External SIGSEGV". Line 120..130 seems to be the cause...
program NestedRecordArray_ExternalSIGSEGV;
{$I Synopse.inc} // define HASINLINE USETYPEINFO CPU32 CPU64 OWNNORMTOUPPER
{$IFOPT D+} {$DEFINE DEBUG} {$ENDIF}
{$ASSERTIONS ON}
{$IFNDEF FPC} {$APPTYPE CONSOLE} {$ENDIF}
uses
{$I SynDprUses.inc} // use FastMM4 on older Delphi, or set FPC threads
SysUtils, RTLConsts, Classes, Contnrs,
SynCommons, SynLog, SynTests, mORMot,
SynSQLite3, SynSQLite3Static, mORMotSQLite3;
type
{$M+}
TNestedRecord = packed record
DummyString: RawUTF8;
end;
TNestedRecordArray = array of TNestedRecord;
const
__TNestedRecord = 'DummyString: RawUTF8';
type
{$M+}
TOuterRecord = packed record
NestedRecordArray: TNestedRecordArray;
end;
TOuterRecordArray = array of TOuterRecord;
const
__TOuterRecord = 'NestedRecordArray: array of TNestedRecord';
type
{$M+}
TSQLMainRecord = class(TSQLRecord)
private
FOuterRecordArray: TOuterRecordArray;
published
property OuterRecordArray: TOuterRecordArray read FOuterRecordArray write FOuterRecordArray;
end;
TTestNestedRecordArray = class(TSynTestCase)
published
procedure Test;
end;
TMyTestSuite = class(TSynTests)
published
procedure RegisterMyTestCases;
end;
{ TTestNestedRecordArray }
procedure TTestNestedRecordArray.Test;
var
ILog: ISynLog;
DateTime: TDateTime;
DateTimeStr: string;
DBFileName: string;
Model: TSQLModel;
Rest: TSQLRest;
Rec: TSQLMainRecord;
RecID: TID;
NestedRecord: TNestedRecord;
OuterRecord: TOuterRecord;
GroupA: TDynArray;
JsonName: TFileName;
JsonRaw: RawByteString;
JsonUTF8: RawUTF8;
JsonUTF8Buf: PUTF8Char;
JsonValid: Boolean;
begin
ILog := TSynLog.Enter;
DateTime := Now;
DateTimeStr := FormatDateTime('yyyy_mm_dd_hh_nn_ss_zzz', DateTime);
DBFileName := ExeVersion.ProgramFileName + '.' + DateTimeStr + '.db3';
JsonName := DBFileName + '.json';
TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TNestedRecord), __TNestedRecord);
TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TOuterRecord), __TOuterRecord);
Model := TSQLModel.Create([TSQLMainRecord]);
try
Rest := TSQLRestClientDB.Create(Model, nil, DBFileName, TSQLRestServerDB, False);
try
TSQLRestClientDB(Rest).Server.CreateMissingTables;
Rec := TSQLMainRecord.Create;
try
RecordClear(OuterRecord, TypeInfo(TOuterRecord));
GroupA.Init(TypeInfo(TNestedRecordArray), OuterRecord.NestedRecordArray);
RecordClear(NestedRecord, TypeInfo(TNestedRecord));
NestedRecord.DummyString := 'NestedRecord 1';
GroupA.Add(NestedRecord);
RecordClear(NestedRecord, TypeInfo(TNestedRecord));
NestedRecord.DummyString := 'NestedRecord 2';
GroupA.Add(NestedRecord);
Rec.DynArray('OuterRecordArray').Add(OuterRecord);
RecID := Rest.Add(Rec, True);
Assert(RecID > 0, 'Error adding the data');
JsonUTF8 := ObjectToJSON(Rec, [woHumanReadable, woStoreClassName]);
// JsonRaw := JsonUTF8;
JsonRaw := CurrentAnsiConvert.UTF8ToAnsi(JsonUTF8);
SynCommons.FileFromString(JsonRaw, JsonName);
finally
Rec.Free;
end;
// External SIGSEGV !
Rec := TSQLMainRecord.Create(Rest, RecID);
try
Check(Rec.DynArray('OuterRecordArray').Count = 1);
Check(Length(Rec.OuterRecordArray[0].NestedRecordArray) = 2);
Check(Rec.OuterRecordArray[0].NestedRecordArray[0].DummyString = 'NestedRecord 1');
Check(Rec.OuterRecordArray[0].NestedRecordArray[1].DummyString = 'NestedRecord 2');
finally
Rec.Free; // No External SIGSEGV if Rec.Free is commented out
end;
JsonRaw := SynCommons.StringFromFile(JsonName);
// JsonUTF8 := JsonRaw;
JsonUTF8 := CurrentAnsiConvert.AnsiToUTF8(JsonRaw);
JsonUTF8Buf := @JsonUTF8[1];
Rec := JsonToNewObject(JsonUTF8Buf, JsonValid) as TSQLMainRecord;
try
Check(Rec.DynArray('OuterRecordArray').Count = 1);
Check(Length(Rec.OuterRecordArray[0].NestedRecordArray) = 2);
Check(Rec.OuterRecordArray[0].NestedRecordArray[0].DummyString = 'NestedRecord 1');
Check(Rec.OuterRecordArray[0].NestedRecordArray[1].DummyString = 'NestedRecord 2');
finally
Rec.Free;
end;
finally
Rest.Free;
end;
finally
Model.Free;
end;
// If there is no exception, delete the temp files.
DeleteFile(DBFileName);
DeleteFile(JsonName);
end;
{ TMyTestSuite }
procedure TMyTestSuite.RegisterMyTestCases;
begin
AddCase([TTestNestedRecordArray]);
end;
begin
with TMyTestSuite.Create do
begin
try
Run;
finally
Free;
end;
end;
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment