Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/RTL/Delphi/Other Classes    [ Add a report in this area ]  
Report #:  128041   Status: Open
[Regression in XE6] TFileStream ReadBuffer Fails in XE6 -- Code works fine in XE4
Project:  Delphi Build #:  XE6, XE7
Version:    21.0 Submitted By:   Ken Schafer
Report Type:  Basic functionality failure Date Reported:  10/2/2014 4:05:01 PM
Severity:    Serious / Highly visible problem Last Updated: 10/9/2014 5:25:30 PM
Platform:    All versions Internal Tracking #:   55642
Resolution: None (Resolution Comments) Resolved in Build: : None
Duplicate of:  None
Voting and Rating
Overall Rating: No Ratings Yet
0.00 out of 5
Total Votes: 10
Description
Code that compiles and works perfectly in XE4 completely fails in XE6 when trying to read data from a file stream.

Steps to Reproduce:
Unzip the Attached program which is supposed to take a very large log file and trim out only the last report.

Build it in XE4 and put the quesa.log file in the same directory as the exe.  Run it and it woks fine.

Build it in XE6 with Update 1 and put the quesa.log file in the same directory as the exe.  Run it and it fails to read the TFileStream.
Workarounds
None
Attachment
XE6FailsToWork.zip
Comments

Tomohiro Takahashi at 10/2/2014 6:43:02 PM -
I tested your project with Delphi XE7.
So, is your issue 'if Length(buffer)=0 then' below?

----------
procedure TForm33.Button1Click(Sender: TObject);
var
   TargetFile,fs:TFileStream;
   buffer:AnsiString;
   ReadStartPos,LogStartPos:LongInt;
   StartLogPos,LogPos:PansiChar;
   ...
begin
   fs:=TFileStream.create('quesa.log',fmOpenRead or fmShareDenyNone);
   LogStartPos:=0;
   repeat
      readStartPos:=fs.Position;
      SetLength(Buffer,8192);
      FillChar(Buffer[1],8192,#0);
      SetLength(Buffer,fs.ReadData(@Buffer[1],Min(8192,fs.Size-fs.position)));
      if Length(buffer)=0 then
        raise Exception.Create(LastErrorAsString);  // <<<-----  Length(buffer) is 0
      ...
      ...
----------

Ken Schafer at 10/2/2014 11:53:21 PM -
Really?  

Yes the problem is that while this code works PERFECTLY in XE4, in XE6 (and presumable XE7, though you have to tell me) it doesn't read in any data, instead giving an Invalid Access to Memory Location error.

Tomohiro Takahashi at 10/3/2014 1:27:10 AM -
To reproduce your issue, I need to copy 'quesa.log' into .\Win32\Debug folder?

> ... Run it and it fails to read the TFileStream.
Could you please tell us more detail about the error?

Ken Schafer at 10/3/2014 2:19:55 AM -
Yes, you need to copy the quesa.log into the same directory that your exe is being built to.

I don't know what else I can add to explain -- the line fs.readData works in XE4, it reads the data and fills it into the buffer, and in XE6 it returns 0 bytes read and last error reports an attempt to access an invalid memory location.  It's pretty straight forward.

Ken Schafer at 10/7/2014 2:55:30 PM -
How can code that works in XE4 and NOT in XE6 be "As Designed?"  

What the HECK is the rational for this?  Especially as there is no listed workaround?

Tomohiro Takahashi at 10/7/2014 5:25:07 PM -
This is a comment from internal trakcing system.
<<<<
To address the issue described in this report, find the following statement in the procedure TForm33.Button1Click() that reads as follows.

SetLength(Buffer,fs.ReadData(@Buffer[1],Min(8192,fs.Size-fs.position)));

Edit this statement to read as below, removing the @ operator.

SetLength(Buffer,fs.ReadData(Buffer[1],Min(8192,fs.Size-fs.position)));

Recompiling and running will permit the fs.ReadData() to succeed. With the @ operator in XE6, an inappropriate address is being passed to the WinAPI function actually performing the read operation and is not needed in XE6.

The OS error produced can be seen by calling RaiseLastOSError after the original statement to see an exception error describing the problem.
>>>>

Ken Schafer at 10/8/2014 12:58:53 AM -
Two things.  

1) This does NOT work.

While removing the @sign does cause the fs.ReadData function to RETURN the value 8192, if you actually look at the buffer, it has read in 1 byte and Byte 2 onwards remains #0 as it was initialized to.

To see this, remove the @sign as you suggested and then add the following code

SetLength(Buffer,fs.ReadData(Buffer[1],Min(8192,fs.Size-fs.position)));
if Buffer[2]=#0 then
   raise Exception.Create('Did NOT read in '+IntToStr(Length(Buffer))+' bytes of data!');

2)  The first DEFINITION of TStream.ReadData from System.classes takes a pointer as shown below, so the code that works in XE4 SHOULD work in XE6 as it is still legal.

function TStream.ReadData(Buffer: Pointer; Count: Longint): Longint;

Ken Schafer at 10/8/2014 11:24:47 PM -
Please reopen this bug report as your "workaround" does not work.

Tomohiro Takahashi at 10/9/2014 5:25:47 PM -
I re-opened this report.

Ken Schafer at 10/31/2014 2:06:42 AM -
It appears that the workaround is actually TWO things:

1) Remove the @ sign; and
2) call Read rather than ReadData

Server Response from: ETNACODE01