[fpc-pascal] TStream.ReadBuffer doesn't try hard enough to read the requested bytes
michalis.kambi at gmail.com
Sun Jun 16 03:18:13 CEST 2013
> And what with non-blocking pipes pipes? Wait for a *some* period
> until you get all data? It is up to the programmer to do this INHO.
If you want to get partial data (instead of waiting until all requested
data is available) you should just use TStream.Read instead of
TStream.ReadBuffer. Then it's indeed up to the programmer to handle this.
All existing usage of ReadBuffer right now works only if you get all the
data in a single Read call (which translates to a single read syscall on
Linux, as far as I see), otherwise it fails with exception. That's just
wrong behavior for a ReadBuffer IMHO.
> Also, if you would enforce this behaviour on all kinds of streams,
> you might (`will`, actually) get unexpected performance drops...
I don't see why you would get any performance drop. If you're lucky and
a single Read call is all you need, then the speed is the same as
current implementation, since the 1st check "if Read(Buffer,Count)<Count
then" will return false and we will not call Read again.
Besides, we're talking about correctness here. And TStream.ReadBuffer is
non-virtual and must be suitable for all TStream descedants, handling
whatever virtual TStream.Read does.
>> For example: on Linux, TFileStream.Read calls fpRead which is a
>> system call, and it definitely can return less than requested
>> amount of bytes, and it doesn't mean that stream ended. (See e.g.
>> Libc docs:
>> : "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. ") So if you use TFileStream with
>> ReadBuffer, your code is working purely by accident right now...
> But if you work with a blocking fd (which, for example, a TFileStream
> uses IIRC) you will always get your data. If there is more data to be
> read(), but it would take time, it simply takes time. The only case
> where zero is returned, is IIRC (like you quoted) when the end of the
> `fd` (e.g. pipe, socket, file) is reached on *blocking
Yes, zero is returned only if stream ends. But a result that is
non-zero, but still less than requested Count, doesn't tell you if the
stream ends. The whole point is whether ReadBuffer should take this into
> FYI: I've never had the problem of a `partial read` (e.g.
> SomeStream.Read(50) returning 36 or something) on linux, osx and
> windows; so perhaps you have exposed some bug in an obscure TStream
Reproducing this behavior proved to be difficult, but I definitely
observed it with TFileStream on Linux.
And, even if it would accidentally work for some streams, that's not a
solution. Like I mentioned, TStream.ReadBuffer is non-virtual and must
be suitable for every TStream.
More information about the fpc-pascal