TStream.ReadBuffer and WriteBuffer should try harder to read the requested bytes
Original Reporter info from Mantis: Michalis @michaliskambi
-
Reporter name: Michalis Kamburelis
Original Reporter info from Mantis: Michalis @michaliskambi
- Reporter name: Michalis Kamburelis
Description:
As discussed in "[fpc-pascal] TStream.ReadBuffer doesn't try hard enough to read the requested bytes" thread ( http://lists.freepascal.org/lists/fpc-pascal/2013-June/038474.html ):
Currently, TStream.ReadBuffer (inside rtl/objpas/classes/streams.inc) does a single call to TStream.Read, and raises exception if Read didn't manage to read Count bytes. This causes bugs, because some overridden TStream.Read implementations can return a value less than Count (but > 0) even when the stream has more bytes. So you should call TStream.Read in a loop, and only when it returns 0 you can be sure that the stream really ended.
This for example means that calling ReadBuffer or WriteBuffer on TFileStream (or any THandleStream actually) is usually working by accident. THandleStream.Read and THandleStream.Write translate to simple OS calls underneath (wrapped in FileRead) and they do not guarantee returning all the available data (see e.g. Libc docs:
http://www.gnu.org/software/libc/manual/html_mono/libc.html#I_002fO-Primitives
: "If read returns at least one character, there is no way you can tell
whether end-of-file was reached. But if you did reach the end, the next
read will return zero. ").
Reproducing this is a little random, unfortunately. Usually they return all data they can (and read count < requested Count only when file ended). But I definitely observed in some situations (when requesting large Counts, but it seemed non-deterministic) that they can return read count < requested Count even though there is more data. This is probably even more probable when THandleStream wraps a network socket or a pipe like stdin.
The same applies to WriteBuffer.
Mantis conversion info:
- Mantis ID: 24645
- OS: Debian GNU/Linux
- OS Build: (testing)
- Platform: i386
- Version: 2.7.1
- Fixed in version: 3.0.0
- Fixed in revision: 28661 (#71a16283)
- Target version: 3.0.0