[PATCH/RFA] _fflush_r check seek result fix
Jeff Johnston
jjohnstn@redhat.com
Thu Oct 29 19:59:00 GMT 2009
On 28/10/09 06:47 AM, Corinna Vinschen wrote:
> On Oct 28 11:06, Corinna Vinschen wrote:
>> * libc/stdio/fflush.c (_fflush_r): Store old errno to check for
>> low-level seek error condition. Restore old errno in case of
>> success. Don't use new position after seek as error condition,
>> rather check for return value of -1 and errno. Only seek to
>> positive offsets, explain why. Only set fp->_offset if errno
>> is not ESPIPE.
>
> There's a still a problem with this patch. Assuming the offset returned
> by the first seek on a regular file would result in a negative offset
> after fp->_r and fp->_ur have been subtracted, then the new position
> stored in fp->_offset will be incorrect. Therefore, the code must check
> for this condition before changing curoff. The below patch does this,
> so fp->_offset will not be set to an incorrect value.
>
> Alternatively, I'm wondering if it isn't easier to ignore the EINVAL
> condition in the second invocation of seek just like ESPIPE.
>
I think you need to ignore the EINVAL regardless as it doesn't indicate
the seek had a failure as much as ESPIPE doesn't.
-- Jeff J.
>
> Corinna
>
>
> Index: libc/stdio/fflush.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdio/fflush.c,v
> retrieving revision 1.14
> diff -u -p -r1.14 fflush.c
> --- libc/stdio/fflush.c 22 Jul 2009 02:17:12 -0000 1.14
> +++ libc/stdio/fflush.c 28 Oct 2009 10:44:48 -0000
> @@ -115,13 +115,18 @@ _DEFUN(_fflush_r, (ptr, fp),
> to miss a code scenario. */
> if ((fp->_r> 0 || fp->_ur> 0)&& fp->_seek != NULL)
> {
> - int tmp;
> + int tmp_errno;
> #ifdef __LARGE64_FILES
> _fpos64_t curoff;
> #else
> _fpos_t curoff;
> #endif
>
> + /* Save last errno and set errno to 0, so we can check if a device
> + returns with a valid position -1. We restore the last errno if
> + no other error condition has been encountered. */
> + tmp_errno = ptr->_errno;
> + ptr->_errno = 0;
> /* Get the physical position we are at in the file. */
> if (fp->_flags& __SOFF)
> curoff = fp->_offset;
> @@ -135,11 +140,14 @@ _DEFUN(_fflush_r, (ptr, fp),
> else
> #endif
> curoff = fp->_seek (ptr, fp->_cookie, 0, SEEK_CUR);
> - if (curoff == -1L)
> + if (curoff == -1L&& ptr->_errno != 0)
> {
> int result = EOF;
> if (ptr->_errno == ESPIPE)
> - result = 0;
> + {
> + result = 0;
> + ptr->_errno = tmp_errno;
> + }
> else
> fp->_flags |= __SERR;
> _funlockfile (fp);
> @@ -148,27 +156,44 @@ _DEFUN(_fflush_r, (ptr, fp),
> }
> if (fp->_flags& __SRD)
> {
> +#ifdef __LARGE64_FILES
> + _fpos64_t newoff = curoff;
> +#else
> + _fpos_t newoff = curoff;
> +#endif
> /* Current offset is at end of buffer. Compensate for
> characters not yet read. */
> - curoff -= fp->_r;
> + newoff -= fp->_r;
> if (HASUB (fp))
> - curoff -= fp->_ur;
> + newoff -= fp->_ur;
> + /* Make sure that curoff still reflects the current file
> + position if we don't seek. */
> + if (newoff>= 0)
> + curoff = newoff;
> }
> - /* Now physically seek to after byte last read. */
> + /* Now physically seek to after byte last read.
> + If curoff is< 0, fp is either pointing to a non-seekable device,
> + or the application already called lseek and invalidated the
> + information in fp. Seeking doesn't make sense in this case. */
> + if (curoff>= 0)
> + {
> #ifdef __LARGE64_FILES
> - if (fp->_flags& __SL64)
> - tmp = (fp->_seek64 (ptr, fp->_cookie, curoff, SEEK_SET) == curoff);
> - else
> + if (fp->_flags& __SL64)
> + curoff = fp->_seek64 (ptr, fp->_cookie, curoff, SEEK_SET);
> + else
> #endif
> - tmp = (fp->_seek (ptr, fp->_cookie, curoff, SEEK_SET) == curoff);
> - if (tmp)
> + curoff = fp->_seek (ptr, fp->_cookie, curoff, SEEK_SET);
> + }
> + if (curoff != -1 || ptr->_errno == 0 || ptr->_errno == ESPIPE)
> {
> /* Seek successful. We can clear read buffer now. */
> fp->_flags&= ~__SNPT;
> fp->_r = 0;
> fp->_p = fp->_bf._base;
> - if (fp->_flags& __SOFF)
> + if ((fp->_flags& __SOFF)
> + && (curoff != -1 || ptr->_errno != ESPIPE))
> fp->_offset = curoff;
> + ptr->_errno = tmp_errno;
> if (HASUB (fp))
> FREEUB (ptr, fp);
> }
>
More information about the Newlib
mailing list