Buglet in fseek?

Jeff Johnston jjohnstn@redhat.com
Fri Feb 17 21:35:00 GMT 2006


Jeff Johnston wrote:
> Corinna Vinschen wrote:
> 
>> Hi,
>>
>> while investigating a problem with top(1) on Cygwin, I came across this
>> description of fseek(3) in SUSv3:
>>
>> http://www.opengroup.org/onlinepubs/009695399/functions/fseek.html
>>
>> Quote:
>>
>> "[CX] If the most recent operation, other than ftell(), on a given
>>  stream is fflush(), the file offset in the underlying open file
>>  description shall be adjusted to reflect the location specified by
>>  fseek()."
>>
>> [CX] indicates an extension to the ISO C standard.  However, this is
>> quite interesting behaviour.  Consider a file which contents are
>> constantly changed, for instance by the OS.  In case of top(1), this
>> would be /proc/stat or any other file within /proc which contains a
>> snapshot of the current system state.
>>
>> As for top(1), what it does is this, basically:
>>
>>   if (!fp)
>>     fp = fopen ("/proc/stat", "r");
>>   rewind (fp);
>>   fflush (fp);
>>   fread (fp);
>>
>> This works only for the first time the function is called.  For each
>> later call, rewind does not call the underlying system function lseek,
>> which would refresh the contents of the file, because fseek_r optimizes
>> the call away in case of streams only opened for reading.
>>
>> There's nothing wrong with that.  However, according to the above quote,
>> one would think it should be possible to get the desired behaviour by
>> just reordering the calls, so that fflush is called before rewind:
>>
>>   if (!fp)
>>     fp = fopen ("/proc/stat", "r");
>>   fflush (fp);
>>   rewind (fp);
>>   fread (fp);
>>
>> The above quote indicates that fseek called by rewind should always call
>> lseek if the last action was a call to fflush.  But this is not the case
>> in newlib so just reordering the calls doesn't work here, either.
>>
>> I admit this is not a real bug in newlib, but it's pretty unfortunate
>> behaviour.  In newlib, there's no way to force an lseek in this
>> situation by only using stream functions, except by either opening the
>> file for writing, or by setting the stream buffering to unbuffered
>> (setvbuf).  Of course you can always explicitely call lseek, but that
>> seems somewhat unclean.
>>
>> Would it be a problem to implement the above quoted behaviour in newlib?
>>
>>
> 
> I have no objection to it; it is also mentioned in the POSIX spec.  It 
> will be a little tricky to add to the current logic.
> 
> There are no spots left for flags in the _flags field of a FILE struct, 
> however, there is already a flag in place (_SNPT) which tells fseek not 
> to use the buffer optimization.  At present, the flag never gets reset 
> anywhere.
> 
> One possible solution might be to have fflush set the _SNPT flag as well 
> as saving the offset of the file (including read buffer position, 
> ignoring ungetc).  When a seek occurs, if dealing with a read-only file 
> with _SNPT flag set on and saved position != -1, a check is made 
> regarding the current position.  If the true position differs from the 
> saved position, then a read has occurred and we are not restricted to 
> performing the lseek.  In that case, we simply reset the _SNPT flag and 
> do the regular logic.  Otherwise, we allow the "goto dumb" logic to 
> occur and we reset the _SNPT flag and saved position if appropriate.
> 
> What do you thin?  Have I missed anything?  Typical read-only file usage 
> won't be interfered with.  There won't be any performance penalty added 
> to reads/etc..
> 
> -- Jeff J.
>

I should haved clarified that the new fflush logic is only for read-only 
files; writable files do not have the fflush/fseek problem cited. 
Resetting the saved position is akin to setting it to -1 (an invalid 
value).  The FILE struct would have to be altered to add the new area to 
save the offset.

-- Jeff J.



More information about the Newlib mailing list