git: 74f1007fcc83 - main - printf(): Save errno earlier.

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Fri, 20 Sep 2024 16:51:13 UTC
The branch main has been updated by des:

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

commit 74f1007fcc838501c74a633792c3f01833bf65e1
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-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);
 }