From fda0a14f4744c2851766f395775c7531e7c4f7dd Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Thu, 29 Jun 2017 14:44:17 +0000 Subject: Make stdio deferred cancel-safe. If used with fopen(3)/fdopen(3)-ed FILEs, stdio accurately uses non-cancellable internal versions of the functions, i.e. it seems to be fine with regard to cancellation. But if the funopen(3) and f{r,w}open(3) functions were used to open the FILE, and corresponding user functions create cancellation points (they typically have no other choice), then stdio code at least leaks FILE' lock. The change installs cleanup handler which unlocks FILE. Some minimal restructuring of the code was required to make it use common return place to satisfy hand-rolled pthread_cleanup_pop() requirements. Noted by: eugen Reviewed by: eugen, vangyzen Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D11246 --- lib/libc/stdio/fclose.c | 8 ++++---- lib/libc/stdio/fflush.c | 8 ++++---- lib/libc/stdio/fgetc.c | 4 ++-- lib/libc/stdio/fgetln.c | 22 +++++++++++----------- lib/libc/stdio/fgets.c | 22 ++++++++++++---------- lib/libc/stdio/fgetwc.c | 4 ++-- lib/libc/stdio/fgetwln.c | 13 ++++++++----- lib/libc/stdio/fgetws.c | 12 +++++++----- lib/libc/stdio/fputc.c | 4 ++-- lib/libc/stdio/fputs.c | 4 ++-- lib/libc/stdio/fputwc.c | 4 ++-- lib/libc/stdio/fputws.c | 20 ++++++++++---------- lib/libc/stdio/fread.c | 4 ++-- lib/libc/stdio/freopen.c | 29 +++++++++++++++-------------- lib/libc/stdio/fscanf.c | 8 ++++---- lib/libc/stdio/fseek.c | 8 ++++---- lib/libc/stdio/fwrite.c | 4 ++-- lib/libc/stdio/getc.c | 4 ++-- lib/libc/stdio/getchar.c | 4 ++-- lib/libc/stdio/getdelim.c | 13 +++++++------ lib/libc/stdio/gets.c | 17 ++++++++++------- lib/libc/stdio/local.h | 26 ++++++++++++++++++++++++++ lib/libc/stdio/perror.c | 4 ++-- lib/libc/stdio/putc.c | 4 ++-- lib/libc/stdio/putchar.c | 4 ++-- lib/libc/stdio/puts.c | 4 ++-- lib/libc/stdio/putw.c | 5 +++-- lib/libc/stdio/refill.c | 4 ++-- lib/libc/stdio/scanf.c | 8 ++++---- lib/libc/stdio/setvbuf.c | 8 ++++---- lib/libc/stdio/stdio.c | 8 ++++++++ lib/libc/stdio/ungetc.c | 4 ++-- lib/libc/stdio/ungetwc.c | 4 ++-- lib/libc/stdio/vfprintf.c | 4 ++-- lib/libc/stdio/vfscanf.c | 8 ++++---- lib/libc/stdio/vfwprintf.c | 4 ++-- lib/libc/stdio/vfwscanf.c | 4 ++-- lib/libc/stdio/vscanf.c | 4 ++-- 38 files changed, 185 insertions(+), 138 deletions(-) (limited to 'lib/libc/stdio') diff --git a/lib/libc/stdio/fclose.c b/lib/libc/stdio/fclose.c index 24b9b90af9853..063ef841f72c3 100644 --- a/lib/libc/stdio/fclose.c +++ b/lib/libc/stdio/fclose.c @@ -97,7 +97,7 @@ fdclose(FILE *fp, int *fdp) return (EOF); } - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); r = 0; if (fp->_close != __sclose) { r = EOF; @@ -115,7 +115,7 @@ fdclose(FILE *fp, int *fdp) *fdp = fp->_file; r = cleanfile(fp, false); } - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (r); } @@ -130,9 +130,9 @@ fclose(FILE *fp) return (EOF); } - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); r = cleanfile(fp, true); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (r); } diff --git a/lib/libc/stdio/fflush.c b/lib/libc/stdio/fflush.c index 123167a091298..5ecfc4451f675 100644 --- a/lib/libc/stdio/fflush.c +++ b/lib/libc/stdio/fflush.c @@ -56,7 +56,7 @@ fflush(FILE *fp) if (fp == NULL) return (_fwalk(sflush_locked)); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); /* * There is disagreement about the correct behaviour of fflush() @@ -76,7 +76,7 @@ fflush(FILE *fp) retval = 0; else retval = __sflush(fp); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (retval); } @@ -143,8 +143,8 @@ sflush_locked(FILE *fp) { int ret; - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ret = __sflush(fp); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (ret); } diff --git a/lib/libc/stdio/fgetc.c b/lib/libc/stdio/fgetc.c index 2ee4d7a78cb55..025a0c2df3947 100644 --- a/lib/libc/stdio/fgetc.c +++ b/lib/libc/stdio/fgetc.c @@ -46,10 +46,10 @@ int fgetc(FILE *fp) { int retval; - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); /* Orientation set by __sgetc() when buffer is empty. */ /* ORIENT(fp, -1); */ retval = __sgetc(fp); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (retval); } diff --git a/lib/libc/stdio/fgetln.c b/lib/libc/stdio/fgetln.c index c8e30ee2bf653..1e6b9842bcece 100644 --- a/lib/libc/stdio/fgetln.c +++ b/lib/libc/stdio/fgetln.c @@ -85,22 +85,21 @@ char * fgetln(FILE *fp, size_t *lenp) { unsigned char *p; + char *ret; size_t len; size_t off; - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ORIENT(fp, -1); /* make sure there is input */ if (fp->_r <= 0 && __srefill(fp)) { *lenp = 0; - FUNLOCKFILE(fp); - return (NULL); + ret = NULL; + goto end; } /* look for a newline in the input */ if ((p = memchr((void *)fp->_p, '\n', (size_t)fp->_r)) != NULL) { - char *ret; - /* * Found one. Flag buffer as modified to keep fseek from * `optimising' a backward seek, in case the user stomps on @@ -112,8 +111,7 @@ fgetln(FILE *fp, size_t *lenp) fp->_flags |= __SMOD; fp->_r -= len; fp->_p = p; - FUNLOCKFILE(fp); - return (ret); + goto end; } /* @@ -163,12 +161,14 @@ fgetln(FILE *fp, size_t *lenp) #ifdef notdef fp->_lb._base[len] = '\0'; #endif - FUNLOCKFILE(fp); - return ((char *)fp->_lb._base); + ret = (char *)fp->_lb._base; +end: + FUNLOCKFILE_CANCELSAFE(); + return (ret); error: *lenp = 0; /* ??? */ fp->_flags |= __SERR; - FUNLOCKFILE(fp); - return (NULL); /* ??? */ + ret = NULL; + goto end; } diff --git a/lib/libc/stdio/fgets.c b/lib/libc/stdio/fgets.c index a2e39ed3b3370..95d0ad9971966 100644 --- a/lib/libc/stdio/fgets.c +++ b/lib/libc/stdio/fgets.c @@ -53,17 +53,17 @@ char * fgets(char * __restrict buf, int n, FILE * __restrict fp) { size_t len; - char *s; + char *s, *ret; unsigned char *p, *t; - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ORIENT(fp, -1); if (n <= 0) { /* sanity check */ fp->_flags |= __SERR; errno = EINVAL; - FUNLOCKFILE(fp); - return (NULL); + ret = NULL; + goto end; } s = buf; @@ -76,8 +76,8 @@ fgets(char * __restrict buf, int n, FILE * __restrict fp) if (__srefill(fp)) { /* EOF/error: stop with partial or no line */ if (!__sfeof(fp) || s == buf) { - FUNLOCKFILE(fp); - return (NULL); + ret = NULL; + goto end; } break; } @@ -100,8 +100,8 @@ fgets(char * __restrict buf, int n, FILE * __restrict fp) fp->_p = t; (void)memcpy((void *)s, (void *)p, len); s[len] = 0; - FUNLOCKFILE(fp); - return (buf); + ret = buf; + goto end; } fp->_r -= len; fp->_p += len; @@ -110,6 +110,8 @@ fgets(char * __restrict buf, int n, FILE * __restrict fp) n -= len; } *s = 0; - FUNLOCKFILE(fp); - return (buf); + ret = buf; +end: + FUNLOCKFILE_CANCELSAFE(); + return (ret); } diff --git a/lib/libc/stdio/fgetwc.c b/lib/libc/stdio/fgetwc.c index 3074d441f9f6a..5f13e2dd4b744 100644 --- a/lib/libc/stdio/fgetwc.c +++ b/lib/libc/stdio/fgetwc.c @@ -52,10 +52,10 @@ fgetwc_l(FILE *fp, locale_t locale) wint_t r; FIX_LOCALE(locale); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ORIENT(fp, 1); r = __fgetwc(fp, locale); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (r); } diff --git a/lib/libc/stdio/fgetwln.c b/lib/libc/stdio/fgetwln.c index 037657c224b0e..a29f1f6bfb3b9 100644 --- a/lib/libc/stdio/fgetwln.c +++ b/lib/libc/stdio/fgetwln.c @@ -45,13 +45,14 @@ wchar_t *fgetwln_l(FILE * __restrict, size_t *, locale_t); wchar_t * fgetwln_l(FILE * __restrict fp, size_t *lenp, locale_t locale) { + wchar_t *ret; wint_t wc; size_t len; int savserr; FIX_LOCALE(locale); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ORIENT(fp, 1); savserr = fp->_flags & __SERR; @@ -77,14 +78,16 @@ fgetwln_l(FILE * __restrict fp, size_t *lenp, locale_t locale) if (len == 0) goto error; - FUNLOCKFILE(fp); *lenp = len; - return ((wchar_t *)fp->_lb._base); + ret = (wchar_t *)fp->_lb._base; +end: + FUNLOCKFILE_CANCELSAFE(); + return (ret); error: - FUNLOCKFILE(fp); *lenp = 0; - return (NULL); + ret = NULL; + goto end; } wchar_t * diff --git a/lib/libc/stdio/fgetws.c b/lib/libc/stdio/fgetws.c index 8513a372835bb..83d697ea9581e 100644 --- a/lib/libc/stdio/fgetws.c +++ b/lib/libc/stdio/fgetws.c @@ -46,14 +46,14 @@ wchar_t * fgetws_l(wchar_t * __restrict ws, int n, FILE * __restrict fp, locale_t locale) { int sret; - wchar_t *wsp; + wchar_t *wsp, *ret; size_t nconv; const char *src; unsigned char *nl; FIX_LOCALE(locale); struct xlocale_ctype *l = XLOCALE_CTYPE(locale); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ORIENT(fp, 1); if (n <= 0) { @@ -113,12 +113,14 @@ fgetws_l(wchar_t * __restrict ws, int n, FILE * __restrict fp, locale_t locale) goto error; ok: *wsp = L'\0'; - FUNLOCKFILE(fp); + ret = ws; +end: + FUNLOCKFILE_CANCELSAFE(); return (ws); error: - FUNLOCKFILE(fp); - return (NULL); + ret = NULL; + goto end; } wchar_t * diff --git a/lib/libc/stdio/fputc.c b/lib/libc/stdio/fputc.c index 3b6101f92f4d5..32c261aa36856 100644 --- a/lib/libc/stdio/fputc.c +++ b/lib/libc/stdio/fputc.c @@ -46,10 +46,10 @@ int fputc(int c, FILE *fp) { int retval; - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); /* Orientation set by __sputc() when buffer is full. */ /* ORIENT(fp, -1); */ retval = __sputc(c, fp); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (retval); } diff --git a/lib/libc/stdio/fputs.c b/lib/libc/stdio/fputs.c index 1f9795a493faf..b10ac52f95d34 100644 --- a/lib/libc/stdio/fputs.c +++ b/lib/libc/stdio/fputs.c @@ -59,10 +59,10 @@ fputs(const char * __restrict s, FILE * __restrict fp) uio.uio_resid = iov.iov_len = strlen(s); uio.uio_iov = &iov; uio.uio_iovcnt = 1; - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ORIENT(fp, -1); retval = __sfvwrite(fp, &uio); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); if (retval == 0) return (iov.iov_len > INT_MAX ? INT_MAX : iov.iov_len); return (retval); diff --git a/lib/libc/stdio/fputwc.c b/lib/libc/stdio/fputwc.c index 7f0c9109b087c..d168867343350 100644 --- a/lib/libc/stdio/fputwc.c +++ b/lib/libc/stdio/fputwc.c @@ -74,10 +74,10 @@ fputwc_l(wchar_t wc, FILE *fp, locale_t locale) wint_t r; FIX_LOCALE(locale); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ORIENT(fp, 1); r = __fputwc(wc, fp, locale); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (r); } diff --git a/lib/libc/stdio/fputws.c b/lib/libc/stdio/fputws.c index 41530673c0076..19da946054b70 100644 --- a/lib/libc/stdio/fputws.c +++ b/lib/libc/stdio/fputws.c @@ -53,11 +53,13 @@ fputws_l(const wchar_t * __restrict ws, FILE * __restrict fp, locale_t locale) const wchar_t *wsp; FIX_LOCALE(locale); struct xlocale_ctype *l = XLOCALE_CTYPE(locale); + int ret; - FLOCKFILE(fp); + ret = -1; + FLOCKFILE_CANCELSAFE(fp); ORIENT(fp, 1); if (prepwrite(fp) != 0) - goto error; + goto end; uio.uio_iov = &iov; uio.uio_iovcnt = 1; iov.iov_base = buf; @@ -66,17 +68,15 @@ fputws_l(const wchar_t * __restrict ws, FILE * __restrict fp, locale_t locale) nbytes = l->__wcsnrtombs(buf, &wsp, SIZE_T_MAX, sizeof(buf), &fp->_mbstate); if (nbytes == (size_t)-1) - goto error; + goto end; uio.uio_resid = iov.iov_len = nbytes; if (__sfvwrite(fp, &uio) != 0) - goto error; + goto end; } while (wsp != NULL); - FUNLOCKFILE(fp); - return (0); - -error: - FUNLOCKFILE(fp); - return (-1); + ret = 0; +end: + FUNLOCKFILE_CANCELSAFE(); + return (ret); } int diff --git a/lib/libc/stdio/fread.c b/lib/libc/stdio/fread.c index c24df9914b486..ff1c65b480d8a 100644 --- a/lib/libc/stdio/fread.c +++ b/lib/libc/stdio/fread.c @@ -54,9 +54,9 @@ fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp) { size_t ret; - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ret = __fread(buf, size, count, fp); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (ret); } diff --git a/lib/libc/stdio/freopen.c b/lib/libc/stdio/freopen.c index e0104c88eef6d..3d6cc89b6fa09 100644 --- a/lib/libc/stdio/freopen.c +++ b/lib/libc/stdio/freopen.c @@ -68,7 +68,7 @@ freopen(const char * __restrict file, const char * __restrict mode, return (NULL); } - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); if (!__sdidinit) __sinit(); @@ -81,24 +81,24 @@ freopen(const char * __restrict file, const char * __restrict mode, if (file == NULL) { /* See comment below regarding freopen() of closed files. */ if (fp->_flags == 0) { - FUNLOCKFILE(fp); errno = EINVAL; - return (NULL); + fp = NULL; + goto end; } if ((dflags = _fcntl(fp->_file, F_GETFL)) < 0) { sverrno = errno; fclose(fp); - FUNLOCKFILE(fp); errno = sverrno; - return (NULL); + fp = NULL; + goto end; } /* Work around incorrect O_ACCMODE. */ if ((dflags & O_ACCMODE) != O_RDWR && (dflags & (O_ACCMODE | O_EXEC)) != (oflags & O_ACCMODE)) { fclose(fp); - FUNLOCKFILE(fp); errno = EBADF; - return (NULL); + fp = NULL; + goto end; } if (fp->_flags & __SWR) (void) __sflush(fp); @@ -108,9 +108,9 @@ freopen(const char * __restrict file, const char * __restrict mode, if (_fcntl(fp->_file, F_SETFL, dflags) < 0) { sverrno = errno; fclose(fp); - FUNLOCKFILE(fp); errno = sverrno; - return (NULL); + fp = NULL; + goto end; } } if (oflags & O_TRUNC) @@ -193,9 +193,9 @@ finish: if (isopen) (void) (*fp->_close)(fp->_cookie); fp->_flags = 0; /* set it free */ - FUNLOCKFILE(fp); errno = sverrno; /* restore in case _close clobbered */ - return (NULL); + fp = NULL; + goto end; } /* @@ -221,9 +221,9 @@ finish: */ if (f > SHRT_MAX) { fp->_flags = 0; /* set it free */ - FUNLOCKFILE(fp); errno = EMFILE; - return (NULL); + fp = NULL; + goto end; } fp->_flags = flags; @@ -245,6 +245,7 @@ finish: fp->_flags2 |= __S2OAP; (void) _sseek(fp, (fpos_t)0, SEEK_END); } - FUNLOCKFILE(fp); +end: + FUNLOCKFILE_CANCELSAFE(); return (fp); } diff --git a/lib/libc/stdio/fscanf.c b/lib/libc/stdio/fscanf.c index 014f094150482..d3e093334482e 100644 --- a/lib/libc/stdio/fscanf.c +++ b/lib/libc/stdio/fscanf.c @@ -56,10 +56,10 @@ fscanf(FILE * __restrict fp, char const * __restrict fmt, ...) va_list ap; va_start(ap, fmt); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ret = __svfscanf(fp, __get_locale(), fmt, ap); va_end(ap); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (ret); } int @@ -70,9 +70,9 @@ fscanf_l(FILE * __restrict fp, locale_t locale, char const * __restrict fmt, ... FIX_LOCALE(locale); va_start(ap, fmt); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ret = __svfscanf(fp, locale, fmt, ap); va_end(ap); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (ret); } diff --git a/lib/libc/stdio/fseek.c b/lib/libc/stdio/fseek.c index 2897eebf9c882..e933bdabf4d2b 100644 --- a/lib/libc/stdio/fseek.c +++ b/lib/libc/stdio/fseek.c @@ -60,9 +60,9 @@ fseek(FILE *fp, long offset, int whence) if (!__sdidinit) __sinit(); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ret = _fseeko(fp, (off_t)offset, whence, 1); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); if (ret == 0) errno = serrno; return (ret); @@ -78,9 +78,9 @@ fseeko(FILE *fp, off_t offset, int whence) if (!__sdidinit) __sinit(); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ret = _fseeko(fp, offset, whence, 0); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); if (ret == 0) errno = serrno; return (ret); diff --git a/lib/libc/stdio/fwrite.c b/lib/libc/stdio/fwrite.c index 5b57fab0b9e14..41bb4f6b03843 100644 --- a/lib/libc/stdio/fwrite.c +++ b/lib/libc/stdio/fwrite.c @@ -82,7 +82,7 @@ fwrite(const void * __restrict buf, size_t size, size_t count, FILE * __restrict uio.uio_iov = &iov; uio.uio_iovcnt = 1; - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ORIENT(fp, -1); /* * The usual case is success (__sfvwrite returns 0); @@ -91,6 +91,6 @@ fwrite(const void * __restrict buf, size_t size, size_t count, FILE * __restrict */ if (__sfvwrite(fp, &uio) != 0) count = (n - uio.uio_resid) / size; - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (count); } diff --git a/lib/libc/stdio/getc.c b/lib/libc/stdio/getc.c index 4963c8ce68e77..ad2df8a72f5d3 100644 --- a/lib/libc/stdio/getc.c +++ b/lib/libc/stdio/getc.c @@ -49,11 +49,11 @@ int getc(FILE *fp) { int retval; - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); /* Orientation set by __sgetc() when buffer is empty. */ /* ORIENT(fp, -1); */ retval = __sgetc(fp); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (retval); } diff --git a/lib/libc/stdio/getchar.c b/lib/libc/stdio/getchar.c index 2815072f866ed..320f96791ede6 100644 --- a/lib/libc/stdio/getchar.c +++ b/lib/libc/stdio/getchar.c @@ -52,11 +52,11 @@ int getchar(void) { int retval; - FLOCKFILE(stdin); + FLOCKFILE_CANCELSAFE(stdin); /* Orientation set by __sgetc() when buffer is empty. */ /* ORIENT(stdin, -1); */ retval = __sgetc(stdin); - FUNLOCKFILE(stdin); + FUNLOCKFILE_CANCELSAFE(); return (retval); } diff --git a/lib/libc/stdio/getdelim.c b/lib/libc/stdio/getdelim.c index 7e0b2e2b6edb6..26c608f8d49c5 100644 --- a/lib/libc/stdio/getdelim.c +++ b/lib/libc/stdio/getdelim.c @@ -112,7 +112,7 @@ getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim, u_char *endp; size_t linelen; - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ORIENT(fp, -1); if (linep == NULL || linecapp == NULL) { @@ -127,9 +127,9 @@ getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim, /* If fp is at EOF already, we just need space for the NUL. */ if (!__sfeof(fp) || expandtofit(linep, 1, linecapp)) goto error; - FUNLOCKFILE(fp); (*linep)[0] = '\0'; - return (-1); + linelen = -1; + goto end; } linelen = 0; @@ -150,11 +150,12 @@ getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim, done: /* Invariant: *linep has space for at least linelen+1 bytes. */ (*linep)[linelen] = '\0'; - FUNLOCKFILE(fp); +end: + FUNLOCKFILE_CANCELSAFE(); return (linelen); error: fp->_flags |= __SERR; - FUNLOCKFILE(fp); - return (-1); + linelen = -1; + goto end; } diff --git a/lib/libc/stdio/gets.c b/lib/libc/stdio/gets.c index c9438515323ad..f31221a74c637 100644 --- a/lib/libc/stdio/gets.c +++ b/lib/libc/stdio/gets.c @@ -50,27 +50,30 @@ char * gets(char *buf) { int c; - char *s; + char *s, *ret; static int warned; static const char w[] = "warning: this program uses gets(), which is unsafe.\n"; - FLOCKFILE(stdin); + FLOCKFILE_CANCELSAFE(stdin); ORIENT(stdin, -1); if (!warned) { (void) _write(STDERR_FILENO, w, sizeof(w) - 1); warned = 1; } - for (s = buf; (c = __sgetc(stdin)) != '\n';) + for (s = buf; (c = __sgetc(stdin)) != '\n'; ) { if (c == EOF) if (s == buf) { - FUNLOCKFILE(stdin); - return (NULL); + ret = NULL; + goto end; } else break; else *s++ = c; + } *s = 0; - FUNLOCKFILE(stdin); - return (buf); + ret = buf; +end: + FUNLOCKFILE_CANCELSAFE(); + return (ret); } diff --git a/lib/libc/stdio/local.h b/lib/libc/stdio/local.h index 447391ca0d4ff..5c70b73d72b46 100644 --- a/lib/libc/stdio/local.h +++ b/lib/libc/stdio/local.h @@ -38,6 +38,9 @@ * $FreeBSD$ */ +#ifndef _STDIO_LOCAL_H +#define _STDIO_LOCAL_H + #include /* for off_t */ #include #include @@ -138,3 +141,26 @@ __fgetwc(FILE *fp, locale_t locale) if ((fp)->_orientation == 0) \ (fp)->_orientation = (o); \ } while (0) + +void __stdio_cancel_cleanup(void *); +#define FLOCKFILE_CANCELSAFE(fp) \ + { \ + struct _pthread_cleanup_info __cleanup_info__; \ + if (__isthreaded) { \ + _FLOCKFILE(fp); \ + __pthread_cleanup_push_imp( \ + __stdio_cancel_cleanup, (fp), \ + &__cleanup_info__); \ + } else { \ + __pthread_cleanup_push_imp( \ + __stdio_cancel_cleanup, NULL, \ + &__cleanup_info__); \ + } \ + { +#define FUNLOCKFILE_CANCELSAFE() \ + (void)0; \ + } \ + __pthread_cleanup_pop_imp(1); \ + } + +#endif /* _STDIO_LOCAL_H */ diff --git a/lib/libc/stdio/perror.c b/lib/libc/stdio/perror.c index 89c079818fb73..15007882b79ef 100644 --- a/lib/libc/stdio/perror.c +++ b/lib/libc/stdio/perror.c @@ -67,9 +67,9 @@ perror(const char *s) v++; v->iov_base = "\n"; v->iov_len = 1; - FLOCKFILE(stderr); + FLOCKFILE_CANCELSAFE(stderr); __sflush(stderr); (void)_writev(stderr->_file, iov, (v - iov) + 1); stderr->_flags &= ~__SOFF; - FUNLOCKFILE(stderr); + FUNLOCKFILE_CANCELSAFE(); } diff --git a/lib/libc/stdio/putc.c b/lib/libc/stdio/putc.c index aaffece49d76d..c62d13f5ea4e2 100644 --- a/lib/libc/stdio/putc.c +++ b/lib/libc/stdio/putc.c @@ -49,11 +49,11 @@ int putc(int c, FILE *fp) { int retval; - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); /* Orientation set by __sputc() when buffer is full. */ /* ORIENT(fp, -1); */ retval = __sputc(c, fp); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (retval); } diff --git a/lib/libc/stdio/putchar.c b/lib/libc/stdio/putchar.c index 756155902f299..1721a986f854b 100644 --- a/lib/libc/stdio/putchar.c +++ b/lib/libc/stdio/putchar.c @@ -54,11 +54,11 @@ putchar(int c) int retval; FILE *so = stdout; - FLOCKFILE(so); + FLOCKFILE_CANCELSAFE(so); /* Orientation set by __sputc() when buffer is full. */ /* ORIENT(so, -1); */ retval = __sputc(c, so); - FUNLOCKFILE(so); + FUNLOCKFILE_CANCELSAFE(); return (retval); } diff --git a/lib/libc/stdio/puts.c b/lib/libc/stdio/puts.c index 124afc73d6002..b5fa01a0c41d2 100644 --- a/lib/libc/stdio/puts.c +++ b/lib/libc/stdio/puts.c @@ -62,9 +62,9 @@ puts(char const *s) uio.uio_resid = c + 1; uio.uio_iov = &iov[0]; uio.uio_iovcnt = 2; - FLOCKFILE(stdout); + FLOCKFILE_CANCELSAFE(stdout); ORIENT(stdout, -1); retval = __sfvwrite(stdout, &uio) ? EOF : '\n'; - FUNLOCKFILE(stdout); + FUNLOCKFILE_CANCELSAFE(); return (retval); } diff --git a/lib/libc/stdio/putw.c b/lib/libc/stdio/putw.c index ecd5d095de5ef..fc1d81c7c25cb 100644 --- a/lib/libc/stdio/putw.c +++ b/lib/libc/stdio/putw.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" #include "fvwrite.h" #include "libc_private.h" +#include "local.h" int putw(int w, FILE *fp) @@ -53,8 +54,8 @@ putw(int w, FILE *fp) uio.uio_resid = iov.iov_len = sizeof(w); uio.uio_iov = &iov; uio.uio_iovcnt = 1; - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); retval = __sfvwrite(fp, &uio); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (retval); } diff --git a/lib/libc/stdio/refill.c b/lib/libc/stdio/refill.c index 71eb2e53dab61..b4b4e015c91f2 100644 --- a/lib/libc/stdio/refill.c +++ b/lib/libc/stdio/refill.c @@ -53,9 +53,9 @@ lflush(FILE *fp) int ret = 0; if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR)) { - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ret = __sflush(fp); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); } return (ret); } diff --git a/lib/libc/stdio/scanf.c b/lib/libc/stdio/scanf.c index e377724ac5be1..55aa420fa6f5d 100644 --- a/lib/libc/stdio/scanf.c +++ b/lib/libc/stdio/scanf.c @@ -56,9 +56,9 @@ scanf(char const * __restrict fmt, ...) va_list ap; va_start(ap, fmt); - FLOCKFILE(stdin); + FLOCKFILE_CANCELSAFE(stdin); ret = __svfscanf(stdin, __get_locale(), fmt, ap); - FUNLOCKFILE(stdin); + FUNLOCKFILE_CANCELSAFE(); va_end(ap); return (ret); } @@ -70,9 +70,9 @@ scanf_l(locale_t locale, char const * __restrict fmt, ...) FIX_LOCALE(locale); va_start(ap, fmt); - FLOCKFILE(stdin); + FLOCKFILE_CANCELSAFE(stdin); ret = __svfscanf(stdin, locale, fmt, ap); - FUNLOCKFILE(stdin); + FUNLOCKFILE_CANCELSAFE(); va_end(ap); return (ret); } diff --git a/lib/libc/stdio/setvbuf.c b/lib/libc/stdio/setvbuf.c index d396960586160..01db02ea9b64c 100644 --- a/lib/libc/stdio/setvbuf.c +++ b/lib/libc/stdio/setvbuf.c @@ -63,7 +63,7 @@ setvbuf(FILE * __restrict fp, char * __restrict buf, int mode, size_t size) if ((mode != _IOFBF && mode != _IOLBF) || (int)size < 0) return (EOF); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); /* * Write current buffer, if any. Discard unread input (including * ungetc data), cancel line buffering, and free old buffer if @@ -115,8 +115,7 @@ nbf: fp->_w = 0; fp->_bf._base = fp->_p = fp->_nbuf; fp->_bf._size = 1; - FUNLOCKFILE(fp); - return (ret); + goto end; } flags |= __SMBF; } @@ -156,6 +155,7 @@ nbf: } __cleanup = _cleanup; - FUNLOCKFILE(fp); +end: + FUNLOCKFILE_CANCELSAFE(); return (ret); } diff --git a/lib/libc/stdio/stdio.c b/lib/libc/stdio/stdio.c index 5d6fb9ac56442..c92fb4fb0e833 100644 --- a/lib/libc/stdio/stdio.c +++ b/lib/libc/stdio/stdio.c @@ -166,3 +166,11 @@ _sseek(FILE *fp, fpos_t offset, int whence) } return (ret); } + +void +__stdio_cancel_cleanup(void * arg) +{ + + if (arg != NULL) + _funlockfile((FILE *)arg); +} diff --git a/lib/libc/stdio/ungetc.c b/lib/libc/stdio/ungetc.c index 88c9da5551870..a24a5a26ade42 100644 --- a/lib/libc/stdio/ungetc.c +++ b/lib/libc/stdio/ungetc.c @@ -94,10 +94,10 @@ ungetc(int c, FILE *fp) if (!__sdidinit) __sinit(); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ORIENT(fp, -1); ret = __ungetc(c, fp); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (ret); } diff --git a/lib/libc/stdio/ungetwc.c b/lib/libc/stdio/ungetwc.c index 78bc38d954a01..b47caf4b32484 100644 --- a/lib/libc/stdio/ungetwc.c +++ b/lib/libc/stdio/ungetwc.c @@ -76,10 +76,10 @@ ungetwc_l(wint_t wc, FILE *fp, locale_t locale) wint_t r; FIX_LOCALE(locale); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ORIENT(fp, 1); r = __ungetwc(wc, fp, locale); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (r); } diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c index bf45bfb421ede..4779ad7a99026 100644 --- a/lib/libc/stdio/vfprintf.c +++ b/lib/libc/stdio/vfprintf.c @@ -274,14 +274,14 @@ vfprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt0, int ret; FIX_LOCALE(locale); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); /* optimise fprintf(stderr) (and other unbuffered Unix files) */ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && fp->_file >= 0) ret = __sbprintf(fp, locale, fmt0, ap); else ret = __vfprintf(fp, locale, fmt0, ap); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (ret); } int diff --git a/lib/libc/stdio/vfscanf.c b/lib/libc/stdio/vfscanf.c index e49a9e1ed134e..8f7c1e81638cf 100644 --- a/lib/libc/stdio/vfscanf.c +++ b/lib/libc/stdio/vfscanf.c @@ -443,9 +443,9 @@ __vfscanf(FILE *fp, char const *fmt0, va_list ap) { int ret; - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ret = __svfscanf(fp, __get_locale(), fmt0, ap); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (ret); } int @@ -454,9 +454,9 @@ vfscanf_l(FILE *fp, locale_t locale, char const *fmt0, va_list ap) int ret; FIX_LOCALE(locale); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ret = __svfscanf(fp, locale, fmt0, ap); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (ret); } diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c index 9a5381d54b9bb..f130c14b1a2c7 100644 --- a/lib/libc/stdio/vfwprintf.c +++ b/lib/libc/stdio/vfwprintf.c @@ -356,14 +356,14 @@ vfwprintf_l(FILE * __restrict fp, locale_t locale, { int ret; FIX_LOCALE(locale); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); /* optimise fprintf(stderr) (and other unbuffered Unix files) */ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && fp->_file >= 0) ret = __sbprintf(fp, locale, fmt0, ap); else ret = __vfwprintf(fp, locale, fmt0, ap); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (ret); } int diff --git a/lib/libc/stdio/vfwscanf.c b/lib/libc/stdio/vfwscanf.c index 63b5dd1be28aa..aedc249f8cff0 100644 --- a/lib/libc/stdio/vfwscanf.c +++ b/lib/libc/stdio/vfwscanf.c @@ -428,10 +428,10 @@ vfwscanf_l(FILE * __restrict fp, locale_t locale, int ret; FIX_LOCALE(locale); - FLOCKFILE(fp); + FLOCKFILE_CANCELSAFE(fp); ORIENT(fp, 1); ret = __vfwscanf(fp, locale, fmt, ap); - FUNLOCKFILE(fp); + FUNLOCKFILE_CANCELSAFE(); return (ret); } int diff --git a/lib/libc/stdio/vscanf.c b/lib/libc/stdio/vscanf.c index 8729c9ca6ba82..309d00c460d21 100644 --- a/lib/libc/stdio/vscanf.c +++ b/lib/libc/stdio/vscanf.c @@ -54,9 +54,9 @@ vscanf_l(locale_t locale, const char * __restrict fmt, __va_list ap) int retval; FIX_LOCALE(locale); - FLOCKFILE(stdin); + FLOCKFILE_CANCELSAFE(stdin); retval = __svfscanf(stdin, locale, fmt, ap); - FUNLOCKFILE(stdin); + FUNLOCKFILE_CANCELSAFE(); return (retval); } int -- cgit v1.2.3