|
@@ -0,0 +1,97 @@
|
|
|
+{ %opt=-Sd }
|
|
|
+
|
|
|
+{$IFNDEF FPC}
|
|
|
+{$apptype console}
|
|
|
+{$ENDIF}
|
|
|
+uses SysUtils;
|
|
|
+
|
|
|
+var
|
|
|
+ s1: string;
|
|
|
+
|
|
|
+// To compile in Delphi
|
|
|
+{$IFNDEF FPC}
|
|
|
+type
|
|
|
+ pinteger = ^integer;
|
|
|
+ pbyte = ^byte;
|
|
|
+{$ENDIF}
|
|
|
+
|
|
|
+function GetS1: string;
|
|
|
+begin
|
|
|
+ result := s1;
|
|
|
+end;
|
|
|
+
|
|
|
+function ThrowsException(a: integer): string;
|
|
|
+begin
|
|
|
+ result := '';
|
|
|
+ if (a > 0) then
|
|
|
+ Abort;
|
|
|
+end;
|
|
|
+
|
|
|
+function Test(cmd: integer): integer;
|
|
|
+begin
|
|
|
+ result := 0;
|
|
|
+ if GetS1 <> '' then
|
|
|
+ begin
|
|
|
+ try
|
|
|
+ // GetS1 returns reference to S1, and this reference is stored on a temp variable.
|
|
|
+ // It's Ok, until an exception is raised in ThrowsException.
|
|
|
+ // The problem is the compiler is planning to store the result of ThrowsException on the same temp variable.
|
|
|
+ // As the ThrowsException raises an exception, this temp variable never gets new value, and in fact remains
|
|
|
+ // equal to S1.
|
|
|
+ // So when the temp variables are cleaned on exit from function Test, the S1's ref counter falls to
|
|
|
+ // 0, and S1 is released.
|
|
|
+ ThrowsException(cmd);
|
|
|
+ result := 1;
|
|
|
+ except
|
|
|
+ result := -1;
|
|
|
+ write('(exception occured) ');
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure DumpString(const s: string);
|
|
|
+var
|
|
|
+ i: integer;
|
|
|
+ pi: pinteger;
|
|
|
+ pb: pbyte;
|
|
|
+begin
|
|
|
+ pi := pinteger(s);
|
|
|
+ pb := pbyte(pi);
|
|
|
+
|
|
|
+ // Printing reference counter and string length
|
|
|
+ dec(pi, 2);
|
|
|
+ for i:=1 to 2 do
|
|
|
+ begin
|
|
|
+ { refcount has to be 1, length 2 -> happens to be the same as i }
|
|
|
+ if (pi^ <> i) then
|
|
|
+ halt(1);
|
|
|
+ write(IntToHex(pi^, 8),' ');
|
|
|
+ inc(pi);
|
|
|
+ end;
|
|
|
+
|
|
|
+ // Printing string bytes
|
|
|
+ for i:=1 to length(s) do
|
|
|
+ begin
|
|
|
+ write(IntToHex(pb^, 2), ' ', '''', char(pb^), ''' ');
|
|
|
+ inc(pb);
|
|
|
+ end;
|
|
|
+ writeln;
|
|
|
+end;
|
|
|
+
|
|
|
+begin
|
|
|
+ s1 := '1'; s1 := s1 + '2'; // making a string with variable ref counter
|
|
|
+
|
|
|
+ write('Dump of S1 at start: '); DumpString(s1);
|
|
|
+ writeln;
|
|
|
+
|
|
|
+ // Calling Test(0) - normal flow, string S1 remains in correct state
|
|
|
+ writeln('Test(0) -> ', Test(0));
|
|
|
+ write('Dump of S1 after Test(0): '); DumpString(s1);
|
|
|
+ writeln;
|
|
|
+
|
|
|
+ // Callig Test(1) - exception is raised by ThrowsException function, and this causes incorrect decrement of S1's ref-counter
|
|
|
+ writeln('Test(1) -> ', Test(1));
|
|
|
+ write('Dump of S1 after Test(1): '); DumpString(s1);
|
|
|
+ writeln;
|
|
|
+end.
|
|
|
+
|