From: David Laight <david.laight.linux@gmail.com>
To: "Thomas Weißschuh" <linux@weissschuh.net>
Cc: Willy Tarreau <w@1wt.eu>,
linux-kernel@vger.kernel.org, Cheng Li <lechain@gmail.com>
Subject: Re: [PATCH v3 next 05/17] tools/nolibc: Implement strerror() in terms of strerror_r()
Date: Wed, 25 Feb 2026 22:58:12 +0000 [thread overview]
Message-ID: <20260225225812.2e781973@pumpkin> (raw)
In-Reply-To: <1637d7b3-986f-45fe-a253-9b53187bf397@t-8ch.de>
On Wed, 25 Feb 2026 23:09:25 +0100
Thomas Weißschuh <linux@weissschuh.net> wrote:
> On 2026-02-23 10:17:23+0000, david.laight.linux@gmail.com wrote:
> > From: David Laight <david.laight.linux@gmail.com>
> >
> > strerror() can be the only part of a program that has a .data section.
> > This requres 4k in the program file.
> >
> > Add a simple implementation of strerror_r() (ignores the length) and
> > use that in strerror() so that the "errno=" string is copied at run-time.
> > Use __builtin_memcpy() because that optimises away the input string
> > and just writes the required constants to the target buffer.
> >
> > Put the check for NOLIBC_IGNORE_ERRNO into strerror_r().
> > Always call strerror() from __nolibc_printf().
>
> Why?
>
> > Code size change largely depends on whether the inlining decision for
> > strerror() changes.
> >
> > Change the tests to use the normal EXPECT_VFPRINTF() when testing %m.
> > Skip the tests when !is_nolibc.
> >
> > Signed-off-by: David Laight <david.laight.linux@gmail.com>
> > ---
> >
> > New patch for v3.
> >
> > tools/include/nolibc/stdio.h | 29 ++++++++++++++------
> > tools/testing/selftests/nolibc/nolibc-test.c | 20 ++------------
> > 2 files changed, 23 insertions(+), 26 deletions(-)
> >
> > diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h
> > index 233318b0d0f0..2267f50d03b4 100644
> > --- a/tools/include/nolibc/stdio.h
> > +++ b/tools/include/nolibc/stdio.h
> > @@ -373,11 +373,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
> > outstr="(null)";
> > }
> > else if (c == 'm') {
> > -#ifdef NOLIBC_IGNORE_ERRNO
> > - outstr = "unknown error";
> > -#else
> > outstr = strerror(errno);
> > -#endif /* NOLIBC_IGNORE_ERRNO */
> > }
> > else if (c == '%') {
> > /* queue it verbatim */
> > @@ -682,14 +678,31 @@ int setvbuf(FILE *stream __attribute__((unused)),
> > return 0;
> > }
> >
> > +static __attribute__((unused,))
> > +int strerror_r(int errnum, char *buf, size_t buflen __attribute__((unused)))
>
> This is the GNU variant, but the XSI variant would be better.
man strerror gives me:
int strerror_r(int errnum, char buf[.buflen], size_t buflen);
/* XSI-compliant */
char *strerror_r(int errnum, char buf[.buflen], size_t buflen);
/* GNU-specific */
so I implemented the one that returns the length.
>
> Why is the buflen parameter not used?
Because the i64toa_r() code doesn't have a buffer length parameter.
I could add one, but it would be effectively unused everywhere else.
Or I could add extra code that did extra copies (etc), but in practise
the buffer will be long enough (given the short output) and the limited
number of programs that use nolibc.
Not that truncating the output makes any sense.
The best would be "?", "errno=?" or "errno=value" for len > 17.
Using strerror_r() came from a discussion with Willy.
He wanted to avoid the static initialised data and it looks better
to have strerror() implemented using strerror_r().
>
> > +{
> > +#ifdef NOLIBC_IGNORE_ERRNO
>
> Why did this move here?
> The application can have error numbers without errno.
Where would they come from.
ISTR there are a small number of unusual functions that do return an
errno value - but nothing common.
>
> > + __builtin_memcpy(buf, "unknown error", 14);
> > + return 13;
>
> > +#else
> > + __builtin_memcpy(buf, "errno=", 6);
> > + return 6 + i64toa_r(errnum, buf + 6);
> > +#endif
> > +}
> > +
> > static __attribute__((unused))
> > -const char *strerror(int errno)
> > +const char *strerror(int errnum)
>
> Good point. But also a candidate for its own patch.
>
> > {
> > - static char buf[18] = "errno=";
> > + static char buf[18];
> > + char *b = buf;
> > +
> > + /* Force gcc to use 'register offset' to access buf[]. */
> > + _NOLIBC_OPTIMIZER_HIDE_VAR(b);
> >
> > - i64toa_r(errno, &buf[6]);
> > + /* Use strerror_r() to avoid having the only .data in small programs. */
> > + strerror_r(errnum, b, sizeof(buf));
> >
> > - return buf;
> > + return b;
> > }
> >
> > #endif /* _NOLIBC_STDIO_H */
> > diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
> > index 029ed63e1ae4..61968fdfeec0 100644
> > --- a/tools/testing/selftests/nolibc/nolibc-test.c
> > +++ b/tools/testing/selftests/nolibc/nolibc-test.c
> > @@ -1793,23 +1793,6 @@ static int test_scanf(void)
> > return 0;
> > }
> >
> > -int test_strerror(void)
> > -{
> > - char buf[100];
> > - ssize_t ret;
> > -
> > - memset(buf, 'A', sizeof(buf));
> > -
> > - errno = EINVAL;
> > - ret = snprintf(buf, sizeof(buf), "%m");
> > - if (is_nolibc) {
> > - if (ret < 6 || memcmp(buf, "errno=", 6))
> > - return 1;
> > - }
> > -
> > - return 0;
> > -}
> > -
> > static int test_printf_error(void)
> > {
> > int fd, ret, saved_errno;
> > @@ -1859,8 +1842,9 @@ static int run_printf(int min, int max)
> > CASE_TEST(string_width); EXPECT_VFPRINTF(1, " 1", "%10s", "1"); break;
> > CASE_TEST(number_width); EXPECT_VFPRINTF(1, " 1", "%10d", 1); break;
> > CASE_TEST(width_trunc); EXPECT_VFPRINTF(1, " 1", "%30d", 1); break;
> > + CASE_TEST(errno); EXPECT_VFPRINTF(is_nolibc, "22:errno=22", "%d:%m", errno=22); break;
> > + CASE_TEST(errno-neg); EXPECT_VFPRINTF(is_nolibc, "-22: errno=-22", "%d:%12m", errno=-22); break;
>
> Assigning errno from the printf argument is sneaky.
That's not 'sneaky', I can do 'proper sneaky' :-)
> Please avoid sneakyness.
How about:
CASE_TEST(errno); errno = 22; EXPECT_VFPRINTF(is_nolibc, "errno=22", "%m"); break;
David
>
> > CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break;
> > - CASE_TEST(strerror); EXPECT_ZR(1, test_strerror()); break;
> > CASE_TEST(printf_error); EXPECT_ZR(1, test_printf_error()); break;
> > case __LINE__:
> > return ret; /* must be last */
> > --
> > 2.39.5
> >
next prev parent reply other threads:[~2026-02-25 22:58 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-23 10:17 [PATCH v3 next 00/17] Enhance printf() david.laight.linux
2026-02-23 10:17 ` [PATCH v3 next 01/17] tools/nolibc: Add _NOLIBC_OPTIMIZER_HIDE_VAR() to compiler.h david.laight.linux
2026-02-25 21:25 ` Thomas Weißschuh
2026-02-25 22:17 ` David Laight
2026-02-25 22:24 ` Thomas Weißschuh
2026-02-23 10:17 ` [PATCH v3 next 02/17] tools/nolibc: Optimise and common up the number to ascii functions david.laight.linux
2026-02-25 21:40 ` Thomas Weißschuh
2026-02-25 22:09 ` David Laight
2026-02-23 10:17 ` [PATCH v3 next 03/17] selftests/nolibc: Fix build with host headers and libc david.laight.linux
2026-02-25 21:24 ` Thomas Weißschuh
2026-02-23 10:17 ` [PATCH v3 next 04/17] selftests/nolibc: Improve reporting of vfprintf() errors david.laight.linux
2026-02-25 21:56 ` Thomas Weißschuh
2026-02-26 10:12 ` David Laight
2026-02-26 21:39 ` Thomas Weißschuh
2026-02-23 10:17 ` [PATCH v3 next 05/17] tools/nolibc: Implement strerror() in terms of strerror_r() david.laight.linux
2026-02-25 22:09 ` Thomas Weißschuh
2026-02-25 22:58 ` David Laight [this message]
2026-02-23 10:17 ` [PATCH v3 next 06/17] tools/nolibc/printf: Change variables 'c' to 'ch' and 'tmpbuf[]' to 'outbuf[]' david.laight.linux
2026-02-25 22:23 ` Thomas Weißschuh
2026-02-23 10:17 ` [PATCH v3 next 07/17] tools/nolibc/printf: Move snprintf length check to callback david.laight.linux
2026-02-25 22:37 ` Thomas Weißschuh
2026-02-25 23:12 ` David Laight
2026-02-26 21:29 ` Thomas Weißschuh
2026-02-26 22:11 ` David Laight
2026-02-23 10:17 ` [PATCH v3 next 08/17] tools/nolibc/printf: Output pad characters in 16 byte chunks david.laight.linux
2026-02-23 10:17 ` [PATCH v3 next 09/17] tools/nolibc/printf: Simplify __nolibc_printf() david.laight.linux
2026-02-23 10:17 ` [PATCH v3 next 10/17] tools/nolibc/printf: Use goto and reduce indentation david.laight.linux
2026-02-23 10:17 ` [PATCH v3 next 11/17] tools/nolibc/printf: Use bit-masks to hold requested flag, length and conversion chars david.laight.linux
2026-02-23 10:17 ` [PATCH v3 next 12/17] tools/nolibc/printf: Handle "%s" with the numeric formats david.laight.linux
2026-02-23 10:17 ` [PATCH v3 next 13/17] tools/nolibc/printf: Add support for conversion flags david.laight.linux
2026-02-23 10:17 ` [PATCH v3 next 14/17] tools/nolibc/printf: Add support for left aligning fields david.laight.linux
2026-02-23 10:17 ` [PATCH v3 next 15/17] tools/nolibc/printf: Add support for zero padding and field precision david.laight.linux
2026-02-23 10:17 ` [PATCH v3 next 16/17] tools/nolibc/printf: Add support for octal output david.laight.linux
2026-02-23 10:17 ` [PATCH v3 next 17/17] selftests/nolibc: Use printf variable field widths and precisions david.laight.linux
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260225225812.2e781973@pumpkin \
--to=david.laight.linux@gmail.com \
--cc=lechain@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@weissschuh.net \
--cc=w@1wt.eu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox