Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/Compiler/Delphi/Code Generation/Optimization    [ Add a report in this area ]  
Report #:  51215   Status: Closed
FPU stack leak
Project:  Delphi Build #:  10.0.2288.42451
Version:    10.0 Submitted By:   Joe White
Report Type:  Crash / Data loss / Total failure Date Reported:  8/28/2007 6:25:14 PM
Severity:    Infrequently encountered problem Last Updated: 3/20/2012 2:24:39 AM
Platform:    All platforms Internal Tracking #:   254938
Resolution: Fixed (Resolution Comments) Resolved in Build: : 12.0.3170.16989
Duplicate of:  None
Voting and Rating
Overall Rating: (2 Total Ratings)
5.00 out of 5
Total Votes: 2
Description
In an expression involving two floating-point values (e.g., addition, multiplication), if the second argument throws an exception, the compiler leaves the first argument on the FPU stack, effectively leaking an FPU stack slot.

This confuses the memory manager. See Steps for code that generates bizarre errors as a result of this leak.

Example:

Result := X[Index] - X[Index - 1];

Assume that range-checking is enabled and Index is the lower bound of the array. The code first pushes X[Index] onto the FPU stack. Then the code throws an ERangeError (since Index - 1 is outside the array bounds). The first value should be cleaned up from the FPU stack, but it never is.

More discussion:
http://excastle.com/blog/archive/2007/08/28/48099.aspx
Steps to Reproduce:
The following code shows how confused the RTL gets when there's a leak on the FPU stack. It demonstrates an EInvalidOp (invalid floating-point operation) being thrown during simple string concatenation (!).

This is because the FastMM4 memory manager uses the FPU stack as scratch space during ReallocMem. Like many stack-based architectures, it assumes that each statement will begin and end with an empty stack. In the case of this leak, that assumption is violated, and Bad Things happen.

Steps:
Run the following console app.
Expected behavior: the app should run and exit.
Actual behavior: the "S := S + '*';" line throws an EInvalidOp (invalid floating-point operation) error, due to the FPU stack slot leaked by the LeakFpuStack routine.

----

program Project3;

{$APPTYPE CONSOLE}
{$RANGECHECKS ON}

uses
  Classes,
  SysUtils;

procedure LeakFpuStack;
var
  X: array [1..2] of Double;
  Y: Integer;
begin
  try
    Y := 1;
    X[Y] := X[Y] - X[Y - 1];
  except
  end;
end;

var
  S: string;
  S2: string;

begin
  LeakFpuStack;
  S := StringOfChar('*', 51);
  S2 := 'Allocate something after S, so that S cannot reallocate in place';
  try
    S := S + '*';
  except
    on E: Exception do
    begin
      WriteLn(E.ClassName);
      WriteLn(E.Message);
      Write('(press ENTER)');
      ReadLn;
    end;
  end;
end.
Workarounds
None
Attachment
None
Comments

None

Server Response from: ETNACODE01