git: 2403e6d5aa9e - stable/14 - printf(): Save errno earlier.

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Sun, 06 Oct 2024 11:07:25 UTC
The branch stable/14 has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=2403e6d5aa9e8ad71c472639af7e903f16ce3b27

commit 2403e6d5aa9e8ad71c472639af7e903f16ce3b27
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2024-09-20 16:30:30 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2024-10-06 09:12:49 +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
    
    (cherry picked from commit 74f1007fcc838501c74a633792c3f01833bf65e1)
---
 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 a5c465bcdcba..cbc0d29ff823 100644
--- a/lib/libc/stdio/local.h
+++ b/lib/libc/stdio/local.h
@@ -80,7 +80,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 270219ac61f9..60602efaf5e9 100644
--- a/lib/libc/stdio/snprintf.c
+++ b/lib/libc/stdio/snprintf.c
@@ -51,10 +51,11 @@ static char sccsid[] = "@(#)snprintf.c	8.1 (Berkeley) 6/4/93";
 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)
@@ -68,7 +69,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);
@@ -78,10 +79,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;
@@ -96,7 +98,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 0ce9d6f37569..72178c31aa94 100644
--- a/lib/libc/stdio/vfprintf.c
+++ b/lib/libc/stdio/vfprintf.c
@@ -71,7 +71,8 @@ static char sccsid[] = "@(#)vfprintf.c	8.1 (Berkeley) 6/4/93";
 #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);
 
@@ -172,7 +173,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;
@@ -196,7 +197,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)
@@ -268,8 +269,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);
 
@@ -277,9 +279,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);
 }
@@ -304,7 +306,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 */
@@ -314,7 +316,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) */
@@ -466,7 +467,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;
@@ -834,7 +834,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 c80f70924a2a..d851feb4207e 100644
--- a/lib/libc/stdio/vsnprintf.c
+++ b/lib/libc/stdio/vsnprintf.c
@@ -48,12 +48,13 @@ static char sccsid[] = "@(#)vsnprintf.c	8.1 (Berkeley) 6/4/93";
 
 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;
@@ -74,7 +75,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 f23821360b47..b39865a40e82 100644
--- a/lib/libc/stdio/vsprintf.c
+++ b/lib/libc/stdio/vsprintf.c
@@ -40,23 +40,25 @@
 #if defined(LIBC_SCCS) && !defined(lint)
 static char sccsid[] = "@(#)vsprintf.c	8.1 (Berkeley) 6/4/93";
 #endif /* LIBC_SCCS and not lint */
-#include <stdio.h>
+#include <errno.h>
 #include <limits.h>
+#include <stdio.h>
 #include "local.h"
 #include "xlocale_private.h"
 
 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);
 }