The branch main has been updated by des:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=74f1007fcc838501c74a633792c3f01833bf65e1

commit 74f1007fcc838501c74a633792c3f01833bf65e1
Author:     Dag-Erling Smørgrav <d...@freebsd.org>
AuthorDate: 2024-09-20 16:30:30 +0000
Commit:     Dag-Erling Smørgrav <d...@freebsd.org>
CommitDate: 2024-09-20 16:30:39 +0000

    printf(): Save errno earlier.
    
    The manual page says %m is replaced with “the string representation of
    the error code stored in the errno variable at the beginning of the
    call”.  However, we don't actually save `errno` until fairly late in
    `__vfprintf()`.  Make sure it is saved before we do anything that
    might perturb `errno`.
    
    MFC after:      1 week
    Reviewed by:    kevans
    Differential Revision:  https://reviews.freebsd.org/D46718
---
 lib/libc/stdio/local.h     |  2 +-
 lib/libc/stdio/snprintf.c  | 14 ++++++++------
 lib/libc/stdio/vasprintf.c |  5 +++--
 lib/libc/stdio/vdprintf.c  |  3 ++-
 lib/libc/stdio/vfprintf.c  | 20 ++++++++++----------
 lib/libc/stdio/vsnprintf.c |  7 ++++---
 lib/libc/stdio/vsprintf.c  | 10 ++++++----
 7 files changed, 34 insertions(+), 27 deletions(-)

diff --git a/lib/libc/stdio/local.h b/lib/libc/stdio/local.h
index 4d8212e947d1..da08fa246833 100644
--- a/lib/libc/stdio/local.h
+++ b/lib/libc/stdio/local.h
@@ -78,7 +78,7 @@ extern int    __swsetup(FILE *);
 extern int     __sflags(const char *, int *);
 extern int     __ungetc(int, FILE *);
 extern wint_t  __ungetwc(wint_t, FILE *, locale_t);
-extern int     __vfprintf(FILE *, locale_t, const char *, __va_list);
+extern int     __vfprintf(FILE *, locale_t, int, const char *, __va_list);
 extern int     __vfscanf(FILE *, const char *, __va_list);
 extern int     __vfwprintf(FILE *, locale_t, const wchar_t *, __va_list);
 extern int     __vfwscanf(FILE * __restrict, locale_t, const wchar_t * 
__restrict,
diff --git a/lib/libc/stdio/snprintf.c b/lib/libc/stdio/snprintf.c
index 607bb3770ccd..da5032f10e6a 100644
--- a/lib/libc/stdio/snprintf.c
+++ b/lib/libc/stdio/snprintf.c
@@ -50,10 +50,11 @@
 int
 snprintf(char * __restrict str, size_t n, char const * __restrict fmt, ...)
 {
+       FILE f = FAKE_FILE;
+       va_list ap;
        size_t on;
+       int serrno = errno;
        int ret;
-       va_list ap;
-       FILE f = FAKE_FILE;
 
        on = n;
        if (n != 0)
@@ -67,7 +68,7 @@ snprintf(char * __restrict str, size_t n, char const * 
__restrict fmt, ...)
        f._flags = __SWR | __SSTR;
        f._bf._base = f._p = (unsigned char *)str;
        f._bf._size = f._w = n;
-       ret = __vfprintf(&f, __get_locale(), fmt, ap);
+       ret = __vfprintf(&f, __get_locale(), serrno, fmt, ap);
        if (on > 0)
                *f._p = '\0';
        va_end(ap);
@@ -77,10 +78,11 @@ int
 snprintf_l(char * __restrict str, size_t n, locale_t locale,
                char const * __restrict fmt, ...)
 {
+       FILE f = FAKE_FILE;
+       va_list ap;
        size_t on;
+       int serrno = errno;
        int ret;
-       va_list ap;
-       FILE f = FAKE_FILE;
        FIX_LOCALE(locale);
 
        on = n;
@@ -95,7 +97,7 @@ snprintf_l(char * __restrict str, size_t n, locale_t locale,
        f._flags = __SWR | __SSTR;
        f._bf._base = f._p = (unsigned char *)str;
        f._bf._size = f._w = n;
-       ret = __vfprintf(&f, locale, fmt, ap);
+       ret = __vfprintf(&f, locale, serrno, fmt, ap);
        if (on > 0)
                *f._p = '\0';
        va_end(ap);
diff --git a/lib/libc/stdio/vasprintf.c b/lib/libc/stdio/vasprintf.c
index c2c6170a2382..62d8f09fc954 100644
--- a/lib/libc/stdio/vasprintf.c
+++ b/lib/libc/stdio/vasprintf.c
@@ -34,9 +34,9 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <errno.h>
 #include "xlocale_private.h"
 #include "local.h"
 
@@ -44,6 +44,7 @@ int
 vasprintf_l(char **str, locale_t locale, const char *fmt, __va_list ap)
 {
        FILE f = FAKE_FILE;
+       int serrno = errno;
        int ret;
        FIX_LOCALE(locale);
 
@@ -55,7 +56,7 @@ vasprintf_l(char **str, locale_t locale, const char *fmt, 
__va_list ap)
                return (-1);
        }
        f._bf._size = f._w = 127;               /* Leave room for the NUL */
-       ret = __vfprintf(&f, locale, fmt, ap);
+       ret = __vfprintf(&f, locale, serrno, fmt, ap);
        if (ret < 0) {
                free(f._bf._base);
                *str = NULL;
diff --git a/lib/libc/stdio/vdprintf.c b/lib/libc/stdio/vdprintf.c
index 3cff85aa9dc5..39fb55420953 100644
--- a/lib/libc/stdio/vdprintf.c
+++ b/lib/libc/stdio/vdprintf.c
@@ -46,6 +46,7 @@ vdprintf(int fd, const char * __restrict fmt, va_list ap)
 {
        FILE f = FAKE_FILE;
        unsigned char buf[BUFSIZ];
+       int serrno = errno;
        int ret;
 
        if (fd > SHRT_MAX) {
@@ -62,7 +63,7 @@ vdprintf(int fd, const char * __restrict fmt, va_list ap)
        f._bf._base = buf;
        f._bf._size = sizeof(buf);
 
-       if ((ret = __vfprintf(&f, __get_locale(), fmt, ap)) < 0)
+       if ((ret = __vfprintf(&f, __get_locale(), serrno, fmt, ap)) < 0)
                return (ret);
 
        return (__fflush(&f) ? EOF : ret);
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
index 7048315a8d78..99ed11c6cb1d 100644
--- a/lib/libc/stdio/vfprintf.c
+++ b/lib/libc/stdio/vfprintf.c
@@ -68,7 +68,8 @@
 #include "printflocal.h"
 
 static int     __sprint(FILE *, struct __suio *, locale_t);
-static int     __sbprintf(FILE *, locale_t, const char *, va_list) 
__printflike(3, 0)
+static int     __sbprintf(FILE *, locale_t, int, const char *, va_list)
+       __printflike(4, 0)
        __noinline;
 static char    *__wcsconv(wchar_t *, int);
 
@@ -169,7 +170,7 @@ __sprint(FILE *fp, struct __suio *uio, locale_t locale)
  * worries about ungetc buffers and so forth.
  */
 static int
-__sbprintf(FILE *fp, locale_t locale, const char *fmt, va_list ap)
+__sbprintf(FILE *fp, locale_t locale, int serrno, const char *fmt, va_list ap)
 {
        int ret;
        FILE fake = FAKE_FILE;
@@ -193,7 +194,7 @@ __sbprintf(FILE *fp, locale_t locale, const char *fmt, 
va_list ap)
        fake._lbfsize = 0;      /* not actually used, but Just In Case */
 
        /* do the work, then copy any error status */
-       ret = __vfprintf(&fake, locale, fmt, ap);
+       ret = __vfprintf(&fake, locale, serrno, fmt, ap);
        if (ret >= 0 && __fflush(&fake))
                ret = EOF;
        if (fake._flags & __SERR)
@@ -265,8 +266,9 @@ __wcsconv(wchar_t *wcsarg, int prec)
  */
 int
 vfprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt0,
-               va_list ap)
+    va_list ap)
 {
+       int serrno = errno;
        int ret;
        FIX_LOCALE(locale);
 
@@ -274,9 +276,9 @@ vfprintf_l(FILE * __restrict fp, locale_t locale, const 
char * __restrict fmt0,
        /* 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);
+               ret = __sbprintf(fp, locale, serrno, fmt0, ap);
        else
-               ret = __vfprintf(fp, locale, fmt0, ap);
+               ret = __vfprintf(fp, locale, serrno, fmt0, ap);
        FUNLOCKFILE_CANCELSAFE();
        return (ret);
 }
@@ -301,7 +303,7 @@ vfprintf(FILE * __restrict fp, const char * __restrict 
fmt0, va_list ap)
  * Non-MT-safe version
  */
 int
-__vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap)
+__vfprintf(FILE *fp, locale_t locale, int serrno, const char *fmt0, va_list ap)
 {
        char *fmt;              /* format string */
        int ch;                 /* character from fmt */
@@ -311,7 +313,6 @@ __vfprintf(FILE *fp, locale_t locale, const char *fmt0, 
va_list ap)
        int ret;                /* return value accumulator */
        int width;              /* width from format (%8d), or 0 */
        int prec;               /* precision from format; <0 for N/A */
-       int saved_errno;
        int error;
        char errnomsg[NL_TEXTMAX];
        char sign;              /* sign prefix (' ', '+', '-', or \0) */
@@ -463,7 +464,6 @@ __vfprintf(FILE *fp, locale_t locale, const char *fmt0, 
va_list ap)
        savserr = fp->_flags & __SERR;
        fp->_flags &= ~__SERR;
 
-       saved_errno = errno;
        convbuf = NULL;
        fmt = (char *)fmt0;
        argtable = NULL;
@@ -831,7 +831,7 @@ fp_common:
                        break;
 #endif /* !NO_FLOATING_POINT */
                case 'm':
-                       error = __strerror_rl(saved_errno, errnomsg,
+                       error = __strerror_rl(serrno, errnomsg,
                            sizeof(errnomsg), locale);
                        cp = error == 0 ? errnomsg : "<strerror failure>";
                        size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
diff --git a/lib/libc/stdio/vsnprintf.c b/lib/libc/stdio/vsnprintf.c
index 1e25e6757459..45e4fb529be7 100644
--- a/lib/libc/stdio/vsnprintf.c
+++ b/lib/libc/stdio/vsnprintf.c
@@ -47,12 +47,13 @@
 
 int
 vsnprintf_l(char * __restrict str, size_t n, locale_t locale, 
-               const char * __restrict fmt, __va_list ap)
+    const char * __restrict fmt, __va_list ap)
 {
+       FILE f = FAKE_FILE;
        size_t on;
+       int serrno = errno;
        int ret;
        char dummy[2];
-       FILE f = FAKE_FILE;
        FIX_LOCALE(locale);
 
        on = n;
@@ -73,7 +74,7 @@ vsnprintf_l(char * __restrict str, size_t n, locale_t locale,
        f._flags = __SWR | __SSTR;
        f._bf._base = f._p = (unsigned char *)str;
        f._bf._size = f._w = n;
-       ret = __vfprintf(&f, locale, fmt, ap);
+       ret = __vfprintf(&f, locale, serrno, fmt, ap);
        if (on > 0)
                *f._p = '\0';
        return (ret);
diff --git a/lib/libc/stdio/vsprintf.c b/lib/libc/stdio/vsprintf.c
index 298f969a1318..23c18264fa50 100644
--- a/lib/libc/stdio/vsprintf.c
+++ b/lib/libc/stdio/vsprintf.c
@@ -37,8 +37,9 @@
  * SUCH DAMAGE.
  */
 
-#include <stdio.h>
+#include <errno.h>
 #include <limits.h>
+#include <stdio.h>
 #include "local.h"
 #include "xlocale_private.h"
 
@@ -46,16 +47,17 @@
 
 int
 vsprintf_l(char * __restrict str, locale_t locale,
-               const char * __restrict fmt, __va_list ap)
+    const char * __restrict fmt, __va_list ap)
 {
-       int ret;
        FILE f = FAKE_FILE;
+       int serrno = errno;
+       int ret;
        FIX_LOCALE(locale);
 
        f._flags = __SWR | __SSTR;
        f._bf._base = f._p = (unsigned char *)str;
        f._bf._size = f._w = INT_MAX;
-       ret = __vfprintf(&f, locale, fmt, ap);
+       ret = __vfprintf(&f, locale, serrno, fmt, ap);
        *f._p = 0;
        return (ret);
 }

Reply via email to