Linux XFS filesystem development
 help / color / mirror / Atom feed
* [PATCH] xfs_scrub: fix strerror_r usage yet again
@ 2025-09-18 19:48 Darrick J. Wong
  2025-09-19 14:47 ` Christoph Hellwig
  0 siblings, 1 reply; 3+ messages in thread
From: Darrick J. Wong @ 2025-09-18 19:48 UTC (permalink / raw)
  To: A. Wilcox, Andrey Albershteyn; +Cc: Christoph Hellwig, linux-xfs

From: Darrick J. Wong <djwong@kernel.org>

In commit 75faf2bc907584, someone tried to fix scrub to use the POSIX
version of strerror_r so that the build would work with musl.
Unfortunately, neither the author nor myself remembered that GNU libc
imposes its own version any time _GNU_SOURCE is defined, which
builddefs.in always does.  Regrettably, the POSIX and GNU versions have
different return types and the glibc version can return any random
pointer and ignore the buffer, so now this code is broken on glibc.

"Fix" this standards body own goal by casting the return value to
intptr_t and employing some gross heuristics to guess at the location of
the actual error string.

Fixes: 75faf2bc907584 ("xfs_scrub: Use POSIX-conformant strerror_r")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
 scrub/common.c |   27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/scrub/common.c b/scrub/common.c
index 0a5970f9c066f7..030beadb1767fb 100644
--- a/scrub/common.c
+++ b/scrub/common.c
@@ -126,8 +126,31 @@ __str_out(
 	fprintf(stream, "%s%s: %s: ", stream_start(stream),
 			_(err_levels[level].string), descr);
 	if (error) {
-		strerror_r(error, buf, DESCR_BUFSZ);
-		fprintf(stream, _("%s."), buf);
+		intptr_t res;
+
+		/*
+		 * GNU strerror_r returns a pointer to a string on success, but
+		 * the returned pointer might point to a static buffer and not
+		 * buf.  XSI strerror_r returns 0 on success, -1 on error.
+		 * Magic #defines influence which variant you might get.
+		 *
+		 * The build system #defines _GNU_SOURCE unconditionally, so
+		 * when compiling against glibc we get the GNU version.
+		 * However, when compiling against musl, the _GNU_SOURCE
+		 * definition does nothing and we get the XSI version anyway.
+		 *
+		 * To handle all this, we set buf to an empty string, and if
+		 * the function returns zero but buf now contains a non-empty
+		 * string, we assume the XSI version and print buf.  If the
+		 * function returns a positive value, we assume that's a
+		 * pointer to a string and print whatever the return value is.
+		 */
+		buf[0] = 0;
+		res = (intptr_t)strerror_r(error, buf, DESCR_BUFSZ);
+		if (res == 0 && strlen(buf) > 0)
+			fprintf(stream, _("%s."), buf);
+		else if (res > 0)
+			fprintf(stream, _("%s."), (char *)res);
 	} else {
 		va_start(args, format);
 		vfprintf(stream, format, args);

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-09-19 16:06 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-18 19:48 [PATCH] xfs_scrub: fix strerror_r usage yet again Darrick J. Wong
2025-09-19 14:47 ` Christoph Hellwig
2025-09-19 16:06   ` Darrick J. Wong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox