fread and ungetc bug fix
Posted: Wed Jun 14, 2006 9:45 pm
While working on lua support we discovered what appears to be a bug in stdio.c. The data that is putback on the stream by ungetc() is not honored by some other functions. Notably, fread() will ignore the putback which breaks lua file loading. We're proposing the below fix. Any input would be appreciated:
Something else I noticed:
fread() will return partial records if your record size is >1. That seems odd to me, but that is the current behavior so I guess we should just leave it alone for the moment.
e.g.
If I ask to read 10 records of size 4, and fread() finds 38 bytes, I would expect it to return 9 records of size 4 (36 bytes), not 38 bytes which is 9 records plus a half record. The return value of fread() will be 9 because it is forced to an int, so it will lie about how much data it read. Then if you fread() again you will have mis-aligned data because you have already read 1/2 of the record, but you didn't know that because the function lied.
I'm not sure what the behavior of fread() is in a standard implementation, though... I haven't used C extensively in a long time. This may be just a caveat.
It should still probably subtract the 1 from (r * n)... Either way it won't fix the above problem.
Code: Select all
size_t fread(void *buf, size_t r, size_t n, FILE *stream)
{
size_t ret;
switch(stream->type) {
case STD_IOBUF_TYPE_NONE:
case STD_IOBUF_TYPE_GS:
case STD_IOBUF_TYPE_SIO:
case STD_IOBUF_TYPE_STDOUTHOST:
/* cannot read from stdout or stderr. */
ret = 0;
break;
default:
/* attempt to read from the stream file. */
if (stream->has_putback) {
buf[0] = stream->putback;
buf++;
stream->has_putback = 0;
/* subtract 1 from r * n to avoid buffer overflow */
ret = (_ps2sdk_read(stream->fd, buf, (int)((r * n) -1 ))) / (int)r);
} else {
ret = (_ps2sdk_read(stream->fd, buf, (int)(r * n)) / (int)r);
}
}
return (ret);
}
fread() will return partial records if your record size is >1. That seems odd to me, but that is the current behavior so I guess we should just leave it alone for the moment.
e.g.
If I ask to read 10 records of size 4, and fread() finds 38 bytes, I would expect it to return 9 records of size 4 (36 bytes), not 38 bytes which is 9 records plus a half record. The return value of fread() will be 9 because it is forced to an int, so it will lie about how much data it read. Then if you fread() again you will have mis-aligned data because you have already read 1/2 of the record, but you didn't know that because the function lied.
I'm not sure what the behavior of fread() is in a standard implementation, though... I haven't used C extensively in a long time. This may be just a caveat.
It should still probably subtract the 1 from (r * n)... Either way it won't fix the above problem.