{ %target=win64 } program tw34772; {$mode objfpc}{$H+} {$WARN 5058 off : Variable "$1" does not seem to be initialized} uses Classes, SysUtils; procedure Test1(a: array of Integer); begin WriteLn('Test1 - Start ', a[0]); if a[0] = 1 then exit; if a[0] = 2 then raise EAbort.Create('Test'); WriteLn('Test1 - End ', a[0]); end; procedure Test2(a: array of Integer); var Test: Pointer; begin GetMem(Test, 4); try WriteLn('Test2 - Start ', a[0]); if a[0] = 1 then exit; if a[0] = 2 then raise EAbort.Create('Test'); WriteLn('Test2 - End ', a[0]); finally FreeMem(Test); WriteLn('Test2 - Finally ', a[0]); end; end; procedure Test3(a: array of Integer); begin try WriteLn('Test3 - Start ', a[0]); if a[0] = 1 then exit; if a[0] = 2 then raise EAbort.Create('Test'); WriteLn('Test3 - End ', a[0]); except on E: Exception do begin if E.ClassType <> EAbort then raise; { Unexpected exception } WriteLn('Test3 - Except ', a[0]); end; end; end; procedure Test4(a: array of Integer); var Test: Pointer; begin GetMem(Test, 4); try try WriteLn('Test4 - Start ', a[0]); if a[0] = 1 then exit; if a[0] = 2 then raise EAbort.Create('Test'); WriteLn('Test4 - End ', a[0]); except on E: Exception do begin if E.ClassType <> EAbort then raise; { Unexpected exception } WriteLn('Test4 - Except ', a[0]); end; end; finally FreeMem(Test); WriteLn('Test4 - Finally ', a[0]); end; end; procedure Test5(a: array of Integer); safecall; begin WriteLn('Test5 - Start ', a[0]); if a[0] = 1 then exit; if a[0] = 2 then raise EAbort.Create('Test'); WriteLn('Test5 - End ', a[0]); end; procedure Test6(a: array of Integer); safecall; var Test: Pointer; begin GetMem(Test, 4); try WriteLn('Test6 - Start ', a[0]); if a[0] = 1 then exit; if a[0] = 2 then raise EAbort.Create('Test'); WriteLn('Test6 - End ', a[0]); finally FreeMem(Test); WriteLn('Test6 - Finally ', a[0]); end; end; procedure Test7(a: array of Integer); safecall; begin try WriteLn('Test7 - Start ', a[0]); if a[0] = 1 then exit; if a[0] = 2 then raise EAbort.Create('Test'); WriteLn('Test7 - End ', a[0]); except on E: Exception do begin if E.ClassType <> EAbort then raise; { Unexpected exception } WriteLn('Test7 - Except ', a[0]); end; end; end; procedure Test8(a: array of Integer); safecall; var Test: Pointer; begin GetMem(Test, 4); try try WriteLn('Test8 - Start ', a[0]); if a[0] = 1 then exit; if a[0] = 2 then raise EAbort.Create('Test'); WriteLn('Test8 - End ', a[0]); except on E: Exception do begin if E.ClassType <> EAbort then raise; { Unexpected exception } WriteLn('Test8 - Except ', a[0]); end; end; finally FreeMem(Test); WriteLn('Test8 - Finally ', a[0]); end; end; function Test9(a: array of Integer): Boolean; var Test: Pointer; begin Result := True; GetMem(Test, 4); try WriteLn('Test9 - Start ', a[0]); if a[0] = 1 then exit; if a[0] = 2 then raise EAbort.Create('Test'); WriteLn('Test9 - End ', a[0]); finally FreeMem(Test); WriteLn('Test9 - Finally ', a[0]); if a[0] = 0 then Result := False; end; Result := True; end; procedure Test10(a: array of Integer); var Test, Test2: Pointer; begin GetMem(Test, 4); try GetMem(Test2, 4); try WriteLn('Test10 - Start ', a[0]); if a[0] = 1 then exit; if a[0] = 2 then raise EAbort.Create('Test'); WriteLn('Test10 - End ', a[0]); finally FreeMem(Test2); WriteLn('Test10 - Finally A ', a[0]); end; finally FreeMem(Test); WriteLn('Test10 - Finally B ', a[0]); end; end; procedure Test11(a: array of Integer); safecall; var Test, Test2: Pointer; begin GetMem(Test, 4); try GetMem(Test2, 4); try WriteLn('Test11 - Start ', a[0]); if a[0] = 1 then exit; if a[0] = 2 then raise EAbort.Create('Test'); WriteLn('Test11 - End ', a[0]); finally FreeMem(Test2); WriteLn('Test11 - Finally A ', a[0]); end; finally FreeMem(Test); WriteLn('Test11 - Finally B ', a[0]); end; end; procedure Test12(a: Integer); safecall; var Test, Test2: Pointer; begin GetMem(Test, 4); try GetMem(Test2, 4); try WriteLn('Test12 - Start ', a); if a = 1 then exit; if a = 2 then raise EAbort.Create('Test'); WriteLn('Test12 - End ', a); finally FreeMem(Test2); WriteLn('Test12 - Finally A ', a); end; finally FreeMem(Test); WriteLn('Test12 - Finally B ', a); end; end; var X, TestCount: Integer; ReferenceCount: LongInt; MemMgr, NewMemMgr: TMemoryManager; Fail: Boolean; function HookGetMem(Size: PtrUInt): Pointer; begin Inc(ReferenceCount); Result := MemMgr.GetMem(Size); end; function HookReAllocMem(var p: Pointer; Size: PtrUInt): Pointer; begin if p = nil then Inc(ReferenceCount); Result := MemMgr.ReAllocMem(p, Size); { If ReAllocMem(nil, 0) is called, ReferenceCount is incremented then decremented, reflecting the null operation } if Size = 0 then Dec(ReferenceCount); end; function HookFreeMem(ptr: Pointer): PtrUInt; begin Dec(ReferenceCount); Result := MemMgr.FreeMem(ptr); end; function HookFreeMemSize(ptr: Pointer; Size: PtrUInt): PtrUInt; begin Dec(ReferenceCount); Result := MemMgr.FreeMemSize(ptr, Size); end; procedure PostTestAnalysis; begin Inc(TestCount); if ReferenceCount <> 0 then begin WriteLn('FAIL - Reference count = ', ReferenceCount); Fail := True; end; end; procedure CheckTestCount; begin if TestCount <> 3 then begin Fail := True; WriteLn('FAIL - Only ', TestCount, ' sub-tests were run for this test'); end; end; begin { Set up hooks to track memory leaks } GetMemoryManager(MemMgr); NewMemMgr := MemMgr; NewMemMgr.GetMem := @HookGetMem; NewMemMgr.ReAllocMem := @HookReAllocMem; NewMemMgr.FreeMem := @HookFreeMem; NewMemMgr.FreeMemSize := @HookFreeMemSize; SetMemoryManager(NewMemMgr); { Test parameters [0] = Run to end of procedure [1] = Exit prematurely [2] = raise exception } { Test1 - implicit try..finally } TestCount := 0; for X := 0 to 2 do begin ReferenceCount := 0; try Test1([X]); except on E: Exception do if E.ClassType <> EAbort then begin { Unexpected exception } WriteLn('FAIL - Exception ', E.ClassName, ' raised: "', E.Message, '"'); Fail := True; Continue; end; end; PostTestAnalysis; end; CheckTestCount; { Test2 - implicit + explicit try..finally } TestCount := 0; for X := 0 to 2 do begin ReferenceCount := 0; try Test2([X]); except on E: Exception do if E.ClassType <> EAbort then begin { Unexpected exception } WriteLn('FAIL - Exception ', E.ClassName, ' raised: "', E.Message, '"'); Fail := True; Continue; end; end; PostTestAnalysis; end; CheckTestCount; { Test3 - implicit try..finally and explicit try..except } TestCount := 0; for X := 0 to 2 do begin ReferenceCount := 0; try Test3([X]); except { Exceptions should be caught } on E: Exception do begin WriteLn('FAIL - Exception ', E.ClassName, ' raised: "', E.Message, '"'); Fail := True; Continue; end; end; PostTestAnalysis; end; CheckTestCount; { Test4 - implicit + explicit try..finally and explicit try..except } TestCount := 0; for X := 0 to 2 do begin ReferenceCount := 0; try Test4([X]); except { Exceptions should be caught } on E: Exception do begin WriteLn('FAIL - Exception ', E.ClassName, ' raised: "', E.Message, '"'); Fail := True; Continue; end; end; PostTestAnalysis; end; CheckTestCount; { Test5 - implicit try..finally with safecall } TestCount := 0; for X := 0 to 2 do begin ReferenceCount := 0; try Test5([X]); except { Everything gets wrapped into a ESafecallException } end; PostTestAnalysis; end; CheckTestCount; { Test6 - implicit + explicit try..finally with safecall } TestCount := 0; for X := 0 to 2 do begin ReferenceCount := 0; try Test6([X]); except { Everything gets wrapped into a ESafecallException } end; PostTestAnalysis; end; CheckTestCount; { Test7 - implicit try..finally and explicit try..except with safecall } TestCount := 0; for X := 0 to 2 do begin ReferenceCount := 0; try Test7([X]); except { Everything gets wrapped into a ESafecallException } end; PostTestAnalysis; end; CheckTestCount; { Test8 - implicit + explicit try..finally and explicit try..except with safecall } TestCount := 0; for X := 0 to 2 do begin ReferenceCount := 0; try Test8([X]); except { Everything gets wrapped into a ESafecallException } end; PostTestAnalysis; end; CheckTestCount; { Test9 - implicit + explicit try..finally with code following } TestCount := 0; for X := 0 to 2 do begin ReferenceCount := 0; try if not Test9([X]) then begin WriteLn('FAIL - Code following finally block wasn''t executed'); Fail := True; Continue; end; except on E: Exception do if E.ClassType <> EAbort then begin { Unexpected exception } WriteLn('FAIL - Exception ', E.ClassName, ' raised: "', E.Message, '"'); Fail := True; Continue; end; end; PostTestAnalysis; end; CheckTestCount; { Test10 - implicit + 2 * explicit try..finally } TestCount := 0; for X := 0 to 2 do begin ReferenceCount := 0; try Test10([X]); except on E: Exception do if E.ClassType <> EAbort then begin { Unexpected exception } WriteLn('FAIL - Exception ', E.ClassName, ' raised: "', E.Message, '"'); Fail := True; Continue; end; end; PostTestAnalysis; end; CheckTestCount; { Test11 - implicit + 2 * explicit try..finally with safecall } TestCount := 0; for X := 0 to 2 do begin ReferenceCount := 0; try Test11([X]); except { Everything gets wrapped into a ESafecallException } end; PostTestAnalysis; end; CheckTestCount; { Test12 - 2 * explicit try..finally with safecall } TestCount := 0; for X := 0 to 2 do begin ReferenceCount := 0; try Test12(X); except { Everything gets wrapped into a ESafecallException } end; PostTestAnalysis; end; CheckTestCount; if Fail then Halt(1) else WriteLn('ok'); end.