Re: [PATCH] kunit: string-stream: Replace strlcat() with strscpy() and seq_buf

From: David Gow

Date: Sat Jul 04 2026 - 04:28:36 EST


Le 03/07/2026 à 8:12 PM, Ian Bridges a écrit :
> In preparation for removing the strlcat() API[1], replace its uses in
> string-stream.
>
> string_stream_vadd() appends at most a single newline into space that
> was explicitly reserved when the fragment was sized, so a bounded copy
> at the end of the string is enough. The return value of strscpy()
> keeps the length accounting unchanged. string_stream_get_string()
> concatenates a variable number of fragments into a buffer sized to
> hold them all, which is what seq_buf is for.
>
> Link: https://github.com/KSPP/linux/issues/370 [1]
> Signed-off-by: Ian Bridges <icb@xxxxxxxxxxxx>
> ---
> Truncation semantics differ between the two APIs. On overflow,
> strlcat() keeps whatever prefix of the fragment fits, while
> seq_buf_puts() drops any fragment that does not fit whole. Neither
> path is reachable here. string_stream_get_string() sizes the buffer
> to hold all fragments exactly. The newline lands in a byte that
> string_stream_vadd() reserved when it sized the fragment.
>
> The patch was tested as follows:
> - The string-stream KUnit suite passes all 12 tests before and after
> the change. The full lib/kunit KUnit config (95 tests) also shows
> identical results before and after.
> - An x86_64 build of lib/kunit/string-stream.o at W=1 produces no
> warnings.
> - A userspace comparison of the old and new construction ran
> with different fragment lengths for the newline append and with
> randomized fragment lists for the concatenation loop. All outputs
> were identical.
>


Thanks very much (and thanks for testing it so thoroughly!)

As much as I find the need for all of the pointer/length arithmetic with
strscpy here a little less clear than strlcat, it's definitely not worth
the extra loop over the string, so I'm happy with the change.

Reviewed-by: David Gow <david@xxxxxxxxxxxx>

Cheers,
-- David

> lib/kunit/string-stream.c | 9 +++++++--
> 1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/lib/kunit/string-stream.c b/lib/kunit/string-stream.c
> index 0d8f1b30559b..51ba40ebf19f 100644
> --- a/lib/kunit/string-stream.c
> +++ b/lib/kunit/string-stream.c
> @@ -9,6 +9,7 @@
> #include <kunit/static_stub.h>
> #include <kunit/test.h>
> #include <linux/list.h>
> +#include <linux/seq_buf.h>
> #include <linux/slab.h>
>
> #include "string-stream.h"
> @@ -74,7 +75,8 @@ int string_stream_vadd(struct string_stream *stream,
>
> /* Append newline if necessary. */
> if (frag_container->fragment[result_len - 1] != '\n')
> - result_len = strlcat(frag_container->fragment, "\n", buf_len);
> + result_len += strscpy(frag_container->fragment + result_len,
> + "\n", buf_len - result_len);
> } else {
> result_len = vsnprintf(frag_container->fragment, buf_len, fmt, args);
> }
> @@ -118,15 +120,18 @@ char *string_stream_get_string(struct string_stream *stream)
> {
> struct string_stream_fragment *frag_container;
> size_t buf_len = stream->length + 1; /* +1 for null byte. */
> + struct seq_buf sb;
> char *buf;
>
> buf = kzalloc(buf_len, stream->gfp);
> if (!buf)
> return NULL;
>
> + seq_buf_init(&sb, buf, buf_len);
> +
> spin_lock(&stream->lock);
> list_for_each_entry(frag_container, &stream->fragments, node)
> - strlcat(buf, frag_container->fragment, buf_len);
> + seq_buf_puts(&sb, frag_container->fragment);
> spin_unlock(&stream->lock);
>
> return buf;