Recent

Author Topic: [SOLVED] TMemoryStream Question with possible bug FPC 3.2.2  (Read 4849 times)

Schmitty2005

  • Jr. Member
  • **
  • Posts: 65
With this simple program :

Code: Pascal  [Select][+][-]
  1. program MemStreamTest;
  2.  
  3. uses
  4.   sysUtils, Classes;
  5.  
  6. var
  7.   a: TMemoryStream;
  8. begin
  9.   a := TMemoryStream.Create();
  10.   a.Size := 456436;
  11.   sleep(4000);
  12.   a.free();
  13. end.

if a.SaveToFile is used, there are a few random bytes in the front of the stream.  I would expect all zero value.

When using Lazarus to view the memory of the pointer that is listed by the FMemory / Memory variable, the pointer also shows a few random bytes of data that are not zero as well.

if a.size was declared as a.size := 256; , there was no issue.  I did not try other values and do not know at what value I start to get non-zero in the first few bytes.

I don't think this is expected behavior.  Any ideas ?

FPC 3.2.2 on Ubuntu 24.04 LTS.



« Last Edit: July 24, 2025, 04:16:29 am by Schmitty2005 »

Nimbus

  • Jr. Member
  • **
  • Posts: 88
Re: TMemoryStream Question with possible bug FPC 3.2.2
« Reply #1 on: July 15, 2025, 07:38:22 am »
Hi,

You didn't write anything to the stream, therefore you cannot make any assumptions on what's in there. Setting the Size does change the stream's capacity by allocating memory on the heap, yet it's never said to initialize that memory in any way - basically you get the "garbage data" left from previous allocations (or anything that happened to be at same address in memory earlier and then released). If you want zeros, write them.

paule32

  • Hero Member
  • *****
  • Posts: 645
  • One in all. But, not all in one.
Re: TMemoryStream Question with possible bug FPC 3.2.2
« Reply #2 on: July 15, 2025, 10:10:19 am »
isn't the Property SIZE not read-only ?
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

Thaddy

  • Hero Member
  • *****
  • Posts: 19169
  • Glad to be alive.
objects are fine constructs. You can even initialize them with constructors.

paule32

  • Hero Member
  • *****
  • Posts: 645
  • One in all. But, not all in one.
Re: TMemoryStream Question with possible bug FPC 3.2.2
« Reply #4 on: July 15, 2025, 10:35:48 am »
I would write: it is a Design Error/Mistake ...

See:
- when I LoadFromFile, and Size is set ti the File Length ...
- then I would make a Copy, and set the Size (or in other circumstance what ever) to a different Value, then the Copy differs from the Original ...

I don't know how to describe my Concern's in English ... but I hope you can understand what I mean ...

I would change the Size by "add" or "remove" Members from the Stream untouched Size directly ...
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

Thaddy

  • Hero Member
  • *****
  • Posts: 19169
  • Glad to be alive.
Re: TMemoryStream Question with possible bug FPC 3.2.2
« Reply #5 on: July 15, 2025, 02:24:58 pm »
Normally you will not use size on a stream, only if you want an initial size, reserve memory.
BTW: You mention LoadFromFile, but that is an implementation of LoadFromStream with a filestream, not a memorystream.
I think you still not grasp OOP and abstractions like TStream.
« Last Edit: July 15, 2025, 02:27:10 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

paule32

  • Hero Member
  • *****
  • Posts: 645
  • One in all. But, not all in one.
Re: TMemoryStream Question with possible bug FPC 3.2.2
« Reply #6 on: July 15, 2025, 03:47:45 pm »
I wrote: I am not a profesionel Programmer...
I learn by doing self made ...

And therefore I have advantages and disadvantages ...
So, you don't must think I know all over OOP or DSL's any kind ...

So, my knowledge can be right or it have gaps in some Ways...

I will do my best to learn all the Days ... but don't strict see me as pro programmer ...
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6395
  • Compiler Developer
Re: TMemoryStream Question with possible bug FPC 3.2.2
« Reply #7 on: July 15, 2025, 09:30:06 pm »
I would write: it is a Design Error/Mistake ...

No, it's not. The idea is that you can control the size of the underlying backing storage if it supports resizing. E.g. files do, but I/O streams do not.

See:
- when I LoadFromFile, and Size is set ti the File Length ...
- then I would make a Copy, and set the Size (or in other circumstance what ever) to a different Value, then the Copy differs from the Original ...

And so what? That might be a valid use case after all.

I would change the Size by "add" or "remove" Members from the Stream untouched Size directly ...

Such a change would break backwards compatibility in a massive way and would reduce what TStream can be used for. TStream is a base class of the Object Pascal RTL, thus there definitely won't be any changes that break the backwards compatibility.

Schmitty2005

  • Jr. Member
  • **
  • Posts: 65
Re: TMemoryStream Question with possible bug FPC 3.2.2
« Reply #8 on: July 16, 2025, 01:12:10 am »
Hi,

You didn't write anything to the stream, therefore you cannot make any assumptions on what's in there. Setting the Size does change the stream's capacity by allocating memory on the heap, yet it's never said to initialize that memory in any way - basically you get the "garbage data" left from previous allocations (or anything that happened to be at same address in memory earlier and then released). If you want zeros, write them.

Thank you Nimbus!  Writing zeros fixed the issue.


Schmitty2005

  • Jr. Member
  • **
  • Posts: 65
Re: TMemoryStream Question with possible bug FPC 3.2.2
« Reply #9 on: July 16, 2025, 01:22:29 am »
Is using a loop  the fastest way to fill a TMemoryStream with zeros ?  Or is there another built-in method ? I checked the TMemoryStream docs and did not see a fill method.  I am wondering if there is a better procedure that what I created.  What I created works fine. Yes, I know  I could just write bytes as well.   I am just curious.

I would think writing WORD at a time versus BYTE at a time would be quicker.  I could do QWORD as well. And yes, I should probably check for an even length TmemoryStream as well.

My own zero fill stream method :

Code: Pascal  [Select][+][-]
  1.   procedure zeroStreamFill(var ms: TMemoryStream);
  2.   var
  3.     lms: int64;
  4.     x: word;
  5.   begin
  6.     lms := ms.size div sizeOf(word);
  7.     x := 0;
  8.     ms.position := 0;
  9.     repeat
  10.       begin
  11.         ms.writeWord(0);
  12.         Inc(x);
  13.       end;
  14.     until x > lms;
  15.   end;
  16.  

The streams are used for 16-bit audio creation.
 

Khrys

  • Sr. Member
  • ****
  • Posts: 440
Re: TMemoryStream Question with possible bug FPC 3.2.2
« Reply #10 on: July 16, 2025, 07:25:32 am »
TMemoryStream  is backed only by a single block of memory (accessible via the aptly named  Memory  property), meaning that you can just call  FillChar / FillQWord / ZeroMemory  et al. on that block. You don't even need to reset the position since  Memory  always refers to the start of the block:

Code: Pascal  [Select][+][-]
  1. procedure ZeroStream(Stream: TMemoryStream);
  2. begin
  3.   FillChar(Stream.Memory^, Stream.Size, 0);
  4. end;



P.S.: You don't need to pass class instances as  var  in most cases; even with  const  class members may still be modified.
Class instances are essentially pointers, and class types don't get special treatment for  var / out / const / constref;  these specifiers still refer to the pointer value of a class instance and not the instance data.
Just FYI  :)

Nimbus

  • Jr. Member
  • **
  • Posts: 88
Re: TMemoryStream Question with possible bug FPC 3.2.2
« Reply #11 on: July 16, 2025, 07:31:59 am »
In such a case I'd probably just use a TBytesStream (one of TMemoryStream descendants), built from a dynamic array. Dynamic arrays (as far as I remember), are guaranteed to be zero-initialized from the compiler. Like this:

Code: Pascal  [Select][+][-]
  1. function CreateStream: TBytesStream;
  2. var
  3.   Buffer: array of Byte;
  4. const
  5.   Samples = 44100 * 2 * 10; { 10 secs at 44khz 16-bit stereo }
  6.   SizeInBytes = Samples * 2;
  7. begin
  8.   SetLength(Buffer, SizeInBytes);
  9.   Result := TBytesStream.Create(Buffer);
  10. end;

Thaddy

  • Hero Member
  • *****
  • Posts: 19169
  • Glad to be alive.
Re: TMemoryStream Question with possible bug FPC 3.2.2
« Reply #12 on: July 16, 2025, 09:41:28 am »
Note there is not only fillchar, but also fillword, filldword,fillqword, which may indeed be more efficient if size is a multiple of resp. word, dword or qword. Filldword is most efficient on 32 bits and fillqword most efficient on 64 bits because of register size.
« Last Edit: July 16, 2025, 09:45:13 am by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

creaothceann

  • Sr. Member
  • ****
  • Posts: 361
Re: TMemoryStream Question with possible bug FPC 3.2.2
« Reply #13 on: July 16, 2025, 12:13:19 pm »
FillByte / FillChar already use QWord transfers, see Lazarus\fpc\3.2.2\source\rtl\x86_64\x86_64.inc

Thaddy

  • Hero Member
  • *****
  • Posts: 19169
  • Glad to be alive.
Re: TMemoryStream Question with possible bug FPC 3.2.2
« Reply #14 on: July 16, 2025, 03:57:33 pm »
Hasn't always been the case, though.
objects are fine constructs. You can even initialize them with constructors.

 

TinyPortal © 2005-2018