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 07/17] tools/nolibc/printf: Move snprintf length check to callback
Date: Thu, 26 Feb 2026 22:11:50 +0000 [thread overview]
Message-ID: <20260226221150.140ec68a@pumpkin> (raw)
In-Reply-To: <dddbec05-2fff-4aa0-89df-2c49144932cf@t-8ch.de>
On Thu, 26 Feb 2026 22:29:07 +0100
Thomas Weißschuh <linux@weissschuh.net> wrote:
> On 2026-02-25 23:12:21+0000, David Laight wrote:
> > On Wed, 25 Feb 2026 23:37:42 +0100
> > Thomas Weißschuh <linux@weissschuh.net> wrote:
> >
> > > On 2026-02-23 10:17:25+0000, david.laight.linux@gmail.com wrote:
> > >
> > > (...)
> > >
> > > > @@ -425,18 +430,25 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
> > > >
> > > > /* literal char, just queue it */
> > > > }
> > > > +
> > > > + /* Request a final '\0' be added to the snprintf() output.
> > > > + * This may be the only call of the cb() function.
> > > > + */
> > > > + if (cb(state, NULL, 0) != 0)
> > > > + return -1;
> > > > +
> > > > return written;
> > > > }
> > >
> > > (...)
> > >
> > > > +static int __nolibc_sprintf_cb(void *v_state, const char *buf, size_t size)
> > > > {
> > > > - char **state = (char **)_state;
> > > > + struct __nolibc_sprintf_cb_state *state = v_state;
> > > > + size_t space = state->space;
> > > > + char *tgt;
> > > > +
> > > > + /* Truncate the request to fit in the output buffer space.
> > > > + * The last byte is reserved for the terminating '\0'.
> > > > + * state->space can only be zero for snprintf(NULL, 0, fmt, args)
> > > > + * so this normally lets through calls with 'size == 0'.
> > > > + */
> > > > + if (size >= space) {
> > > > + if (space <= 1)
> > > > + return 0;
> > > > + size = space - 1;
> > > > + }
> > > > + tgt = state->buf;
> > > > +
> > > > + /* __nolibc_printf() ends with cb(state, NULL, 0) to request the output
> > > > + * buffer be '\0' terminated.
> > > > + * That will be the only cb() call for, eg, snprintf(buf, sz, "").
> > > > + * Zero lengths can occur at other times (eg "%s" for an empty string).
> > > > + * Unconditionally write the '\0' byte to reduce code size, it is
> > > > + * normally overwritten by the data being output.
> > > > + * There is no point adding a '\0' after copied data - there is always
> > > > + * another call.
> > > > + */
> > > > + *tgt = '\0';
> > > > + state->space = space - size;
> > > > + state->buf = tgt + size;
> > > > + memcpy(tgt, buf, size);
> > >
> > > This trips UBSAN for me when 'buf == NULL'.
> > >
> > > if (cb(state, NULL, 0) != 0)
> > > return -1;
> > >
> > > It can be fixed by adding a NULL check around memcpy(),
> > > but I'd rather not do this as a random fixup.
> >
> > Blame Willy, he made me remove the 'if (size)' check to reduce
> > the code size.
>
> Done. But we still can't hard-break our own testsuite.
> If we can detect UBSAN at build-time, that could work.
> But I would prefer to just add the check.
>
> > The '*tgt = 0' line is (only) needed when size is zero, the other lines
> > are clearly pointless.
> > So the 'random fixup' is adding 'if (size)' rather than a NULL
> > pointer check
> > printf("%s", "") will give a zero size with non-NULL buf.
>
> Can you roll this into the next revision?
I'll add the zero check back.
Probably get around to it tomorrow.
At least I don't have to completely re-order the patches again.
I've got about 15 old branches from failed attempts lurking.
David
>
> > IIRC the C standard make memcpy(tgt, NULL, 0) UB because some old system
> > no one has used for 40+ years would trap when NULL was loaded into an
> > 'address register' and they wanted it to be compliant.
>
> Fair enough. But how would this work for functions where NULL is an
> allowed argument value like 'free()'? Anyways, we use UBSAN in the
> testsuite and it actually found a bunch of issues, so I'd like to keep
> it.
>
> > > >
> > > > - memcpy(*state, buf, size);
> > > > - *state += size;
> > > > return 0;
> > > > }
> > >
> > > (...)
next prev parent reply other threads:[~2026-02-26 22:11 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
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 [this message]
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=20260226221150.140ec68a@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