summaryrefslogtreecommitdiff
path: root/src/stdio/vfprintf.c
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2014-12-17 03:08:53 -0500
committerRich Felker <dalias@aerifal.cx>2015-03-30 01:41:33 -0400
commit0d418ce688da6bc80073539f372be84faf7139d1 (patch)
tree668a137d340d17b7ac790b26778e12720bbcab0a /src/stdio/vfprintf.c
parent051a8fdda8a08bcbea8d5a148fe26fa73adc58b8 (diff)
downloadmusl-0d418ce688da6bc80073539f372be84faf7139d1.tar.gz
correctly handle write errors encountered by printf-family functions
previously, write errors neither stopped further output attempts nor caused the function to return an error to the caller. this could result in silent loss of output, possibly in the middle of output in the event of a non-permanent error. the simplest solution is temporarily clearing the error flag for the target stream, then suppressing further output when the error flag is set and checking/restoring it at the end of the operation to determine the correct return value. since the wide version of the code internally calls the narrow fprintf to perform some of its underlying operations, initial clearing of the error flag is suppressed when performing a narrow vfprintf on a wide-oriented stream. this is not a problem since the behavior of narrow operations on wide-oriented streams is undefined. (cherry picked from commit d42269d7c85308abdbf8cee38b1a1097249eb38b)
Diffstat (limited to 'src/stdio/vfprintf.c')
-rw-r--r--src/stdio/vfprintf.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c
index 9f02f743..c60919bd 100644
--- a/src/stdio/vfprintf.c
+++ b/src/stdio/vfprintf.c
@@ -160,7 +160,7 @@ static void pop_arg(union arg *arg, int type, va_list *ap)
static void out(FILE *f, const char *s, size_t l)
{
- __fwritex((void *)s, l, f);
+ if (!(f->flags & F_ERR)) __fwritex((void *)s, l, f);
}
static void pad(FILE *f, char c, int w, int l, int fl)
@@ -658,6 +658,7 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
int nl_type[NL_ARGMAX+1] = {0};
union arg nl_arg[NL_ARGMAX+1];
unsigned char internal_buf[80], *saved_buf = 0;
+ int olderr;
int ret;
/* the copy allows passing va_list* even if va_list is an array */
@@ -668,6 +669,8 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
}
FLOCK(f);
+ olderr = f->flags & F_ERR;
+ if (f->mode < 1) f->flags &= ~F_ERR;
if (!f->buf_size) {
saved_buf = f->buf;
f->wpos = f->wbase = f->buf = internal_buf;
@@ -682,6 +685,8 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
f->buf_size = 0;
f->wpos = f->wbase = f->wend = 0;
}
+ if (f->flags & F_ERR) ret = -1;
+ f->flags |= olderr;
FUNLOCK(f);
va_end(ap2);
return ret;