libc __sfvwrite(): roll back FILE buffer pointer on fflush error

__sfvwrite() advances the pointer before calling fflush.  If fflush()
fails, it is not enough to roll back inside it, because we cannot know
how much was advanced by the caller.

Reported by:	Peter <pmc@citylink.dinoex.sub.org>
Reviewed by:	markj
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Fixes:	86a16ada1e
This commit is contained in:
Konstantin Belousov 2022-03-06 10:59:39 +02:00 committed by Mark Johnston
parent 1fb00c8f10
commit bafaa70b6f

View File

@ -54,6 +54,7 @@ int
__sfvwrite(FILE *fp, struct __suio *uio)
{
size_t len;
unsigned char *old_p;
char *p;
struct __siov *iov;
int w, s;
@ -137,8 +138,12 @@ __sfvwrite(FILE *fp, struct __suio *uio)
COPY(w);
/* fp->_w -= w; */ /* unneeded */
fp->_p += w;
if (__fflush(fp))
old_p = fp->_p;
if (__fflush(fp) == EOF) {
if (old_p == fp->_p)
fp->_p -= w;
goto err;
}
} else if (len >= (w = fp->_bf._size)) {
/* write directly */
w = _swrite(fp, p, w);
@ -177,8 +182,12 @@ __sfvwrite(FILE *fp, struct __suio *uio)
COPY(w);
/* fp->_w -= w; */
fp->_p += w;
if (__fflush(fp))
old_p = fp->_p;
if (__fflush(fp) == EOF) {
if (old_p == fp->_p)
fp->_p -= w;
goto err;
}
} else if (s >= (w = fp->_bf._size)) {
w = _swrite(fp, p, w);
if (w <= 0)