Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776// SPDX-License-Identifier: GPL-2.0/* * KUnit tests for the seq_buf API * * Copyright (C) 2025, Google LLC. */
#include <kunit/test.h>#include <linux/console.h>#include <linux/fs.h>#include <linux/seq_buf.h>#include <linux/shmem_fs.h>#include <linux/string.h>
static void seq_buf_init_test(struct kunit *test){ char buf[32]; struct seq_buf s;
seq_buf_init(&s, buf, sizeof(buf));
KUNIT_EXPECT_EQ(test, s.size, 32); KUNIT_EXPECT_EQ(test, s.len, 0); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_buffer_left(&s), 32); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 0); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), ""); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 0);}
static void seq_buf_init_append_test(struct kunit *test){ char buf[32] = "hello"; struct seq_buf s;
/* Initial string contents match. */ seq_buf_init_append(&s, buf, sizeof(buf)); KUNIT_EXPECT_EQ(test, s.size, 32); KUNIT_EXPECT_EQ(test, s.len, 5); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_buffer_left(&s), 32 - 5); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 5); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello"); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 5);
/* Appending with space works. */ seq_buf_puts(&s, " world"); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 11); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello world"); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 11);
/* No truncation when space for NUL is present. */ seq_buf_init_append(&s, buf, 12); KUNIT_EXPECT_EQ(test, s.size, 12); KUNIT_EXPECT_EQ(test, s.len, 11); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 11); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello world"); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 11);
/* * No NUL within the size: the content is already truncated, as * strlcat() would see it, so @s starts out overflowed. The content * stays, and appending adds nothing. */ seq_buf_init_append(&s, buf, 11); KUNIT_EXPECT_EQ(test, s.size, 11); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_buffer_left(&s), 0); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 11); KUNIT_EXPECT_MEMEQ(test, buf, "hello world", 11); seq_buf_puts(&s, "!"); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_MEMEQ(test, buf, "hello world", 11); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello worl"); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 10);
/* * The size bounds the scan: the string runs past it, so there is * no NUL within the size either. */ seq_buf_init_append(&s, buf, 5); KUNIT_EXPECT_EQ(test, s.size, 5); /* Overflowed at the size; an unbounded scan would find more. */ KUNIT_EXPECT_EQ(test, s.len, 5 + 1); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_buffer_left(&s), 0); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hell");
/* With no room even for a NUL, @s is overflowed and @buf untouched. */ seq_buf_init_append(&s, buf, 0); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 0); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), ""); KUNIT_EXPECT_EQ(test, buf[0], 'h');}
static void seq_buf_declare_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 24);
KUNIT_EXPECT_EQ(test, s.size, 24); KUNIT_EXPECT_EQ(test, s.len, 0); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_buffer_left(&s), 24); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 0); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "");}
static void seq_buf_clear_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 128);
seq_buf_puts(&s, "hello"); KUNIT_EXPECT_EQ(test, s.len, 5); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello");
seq_buf_clear(&s);
KUNIT_EXPECT_EQ(test, s.len, 0); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "");}
static void seq_buf_puts_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 16);
seq_buf_puts(&s, "hello"); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 5); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello");
seq_buf_puts(&s, " world"); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 11); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello world");}
static void seq_buf_puts_overflow_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 10);
seq_buf_puts(&s, "123456789"); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 9);
seq_buf_puts(&s, "0"); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 10); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "123456789");
seq_buf_clear(&s); KUNIT_EXPECT_EQ(test, s.len, 0); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "");}
static void seq_buf_putc_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 4);
seq_buf_putc(&s, 'a'); seq_buf_putc(&s, 'b'); seq_buf_putc(&s, 'c');
KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 3); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "abc");
seq_buf_putc(&s, 'd'); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 4); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "abc");
seq_buf_putc(&s, 'e'); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 4); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "abc");
seq_buf_clear(&s); KUNIT_EXPECT_EQ(test, s.len, 0); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "");}
static void seq_buf_pop_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 8); struct seq_buf t; char *buf;
/* Nothing to pop. */ KUNIT_EXPECT_EQ(test, seq_buf_pop(&s), -1); KUNIT_EXPECT_EQ(test, s.len, 0);
seq_buf_puts(&s, "hello"); KUNIT_EXPECT_EQ(test, seq_buf_pop(&s), 'o'); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 4); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hell");
/* A 0xff byte must not be mistaken for an empty buffer. */ seq_buf_putc(&s, 0xff); KUNIT_EXPECT_EQ(test, seq_buf_pop(&s), 0xff);
/* A full buffer pops its last byte. */ seq_buf_puts(&s, "abc"); seq_buf_putc(&s, 'd'); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 8); KUNIT_EXPECT_EQ(test, seq_buf_pop(&s), 'd'); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 7); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hellabc");
/* * An overflowed buffer has nothing to pop, and stays overflowed. Use * a buffer allocated at its exact size, so that KASAN reports any * read past its end. */ buf = kunit_kmalloc(test, 16, GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, buf); seq_buf_init(&t, buf, 16); KUNIT_EXPECT_EQ(test, seq_buf_printf(&t, "%s", "longer than sixteen"), -1); KUNIT_EXPECT_EQ(test, seq_buf_pop(&t), -1); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&t));}
static void seq_buf_printf_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 32);
seq_buf_printf(&s, "hello %s", "world"); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 11); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello world");
seq_buf_printf(&s, " %d", 123); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 15); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello world 123");}
static void seq_buf_printf_overflow_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 16);
seq_buf_printf(&s, "%lu", 1234567890UL); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 10); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "1234567890");
seq_buf_printf(&s, "%s", "abcdefghij"); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 16); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "1234567890abcde");
seq_buf_clear(&s); KUNIT_EXPECT_EQ(test, s.len, 0); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "");}
static void seq_buf_get_buf_commit_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 16); char *buf; size_t len;
len = seq_buf_get_buf(&s, &buf); KUNIT_EXPECT_EQ(test, len, 16); KUNIT_EXPECT_PTR_NE(test, buf, NULL);
memcpy(buf, "hello", 5); seq_buf_commit(&s, 5);
KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 5); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello");
len = seq_buf_get_buf(&s, &buf); KUNIT_EXPECT_EQ(test, len, 11); KUNIT_EXPECT_PTR_NE(test, buf, NULL);
memcpy(buf, " worlds!", 8); seq_buf_commit(&s, 6);
KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 11); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello world");
len = seq_buf_get_buf(&s, &buf); KUNIT_EXPECT_EQ(test, len, 5); KUNIT_EXPECT_PTR_NE(test, buf, NULL);
seq_buf_commit(&s, -1); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s));}
static void seq_buf_putmem_hex_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 24); const u8 data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };#ifdef __BIG_ENDIAN const char *expected = "0001020304050607 0809 ";#else const char *expected = "0706050403020100 0908 ";#endif
KUNIT_EXPECT_EQ(test, seq_buf_putmem_hex(&s, data, sizeof(data)), 0); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), strlen(expected)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), expected);}
static void seq_buf_putmem_hex_overflow_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 20); const u8 data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };#ifdef __BIG_ENDIAN const char *expected = "0001020304050607 08";#else const char *expected = "0706050403020100 09";#endif
KUNIT_EXPECT_EQ(test, seq_buf_putmem_hex(&s, data, sizeof(data)), -1); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 20); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), expected);}
static void seq_buf_puts_partial_overflow_test(struct kunit *test){ static const char expected[] = "abcdefg"; DECLARE_SEQ_BUF(s, 16); struct seq_buf t; char buf[8];
/* As much of the string as fits is written, like seq_buf_printf(). */ seq_buf_puts(&s, "hello"); KUNIT_EXPECT_EQ(test, seq_buf_puts(&s, " world, again"), -1); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 16); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello world, ag");
/* Stale bytes after the data must not show up in the string. */ memset(buf, 'X', sizeof(buf)); seq_buf_init(&t, buf, sizeof(buf)); seq_buf_putc(&t, 'a'); KUNIT_EXPECT_EQ(test, seq_buf_puts(&t, "bcdefghij"), -1); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&t));
/* * Check the buffer before seq_buf_str() does: it would write the * terminator over the last byte itself, hiding whether the copy * placed one there. The literal's own NUL is the eighth byte. */ KUNIT_EXPECT_MEMEQ(test, buf, expected, sizeof(buf)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&t), "abcdefg");}
static void seq_buf_putmem_partial_overflow_test(struct kunit *test){ const u8 data[] = { 1, 2, 3, 4, 5, 6, 7 }; const char expected[] = { 'a', 'b', 1, 2, 3, 4, 5, 6 }; struct seq_buf s; char buf[8];
memset(buf, 'X', sizeof(buf)); seq_buf_init(&s, buf, sizeof(buf)); seq_buf_putmem(&s, "ab", 2);
/* One byte too many, so the last byte of @data is dropped. */ KUNIT_EXPECT_EQ(test, seq_buf_putmem(&s, data, sizeof(data)), -1); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s));
/* * Check the buffer rather than seq_buf_str(): seq_buf_putmem() writes * no NUL of its own, so a short copy leaves a stale byte at the end, * exactly where seq_buf_str() would then write the terminator and * hide it. */ KUNIT_EXPECT_MEMEQ(test, buf, expected, sizeof(buf));}
static void seq_buf_putmem_hex_partial_overflow_test(struct kunit *test){ const u8 data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };#ifdef __BIG_ENDIAN const char *expected = "0001020304050607 08"; static const char expected_raw[] = "0001020304050607 080";#else const char *expected = "0706050403020100 09"; static const char expected_raw[] = "0706050403020100 090";#endif struct seq_buf s; char buf[20];
/* Stale bytes after the data must not show up in the string. */ memset(buf, 'X', sizeof(buf)); seq_buf_init(&s, buf, sizeof(buf)); KUNIT_EXPECT_EQ(test, seq_buf_putmem_hex(&s, data, sizeof(data)), -1); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s));
/* Before seq_buf_str() writes the terminator over the last byte. */ KUNIT_EXPECT_MEMEQ(test, buf, expected_raw, sizeof(buf)); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), expected);}
/* * Counters for the console that seq_buf_do_printk_test() registers while it * runs. Only records carrying the marker are counted, so unrelated kernel * messages do not disturb them. * * An empty record carries nothing to recognize it by, so count one only * where the flaw puts it: directly after a record of ours, with nothing in * between. That still misreads a bare line feed printed by another CPU in * exactly that gap, but no longer counts one printed at any point while the * console happens to be registered. */#define SEQ_BUF_PRINTK_MARKER "sbdpkx"
static unsigned int seq_buf_printk_marked;static unsigned int seq_buf_printk_empty;static bool seq_buf_printk_last_was_ours;
static void seq_buf_printk_capture(struct console *con, const char *s, unsigned int count){ const char *text = s; const char *prefix;
/* * Skip what printk() puts in front of the message: a timestamp, * and the caller id as well under CONFIG_PRINTK_CALLER, so strip * every bracketed group rather than just the first. */ while (count && text[0] == '[') { prefix = memchr(text, ']', count); if (!prefix) break; count -= prefix + 1 - text; text = prefix + 1; if (count && text[0] == ' ') { text++; count--; } }
if (strnstr(text, SEQ_BUF_PRINTK_MARKER, count)) { seq_buf_printk_marked++; seq_buf_printk_last_was_ours = true; return; }
if (seq_buf_printk_last_was_ours && (count == 0 || (count == 1 && text[0] == '\n'))) seq_buf_printk_empty++;
seq_buf_printk_last_was_ours = false;}
static void seq_buf_printk_run(struct console *capture, struct seq_buf *s){ seq_buf_printk_marked = 0; seq_buf_printk_empty = 0; seq_buf_printk_last_was_ours = false;
/* * register_console() will not take an unmatched console without * CON_ENABLED, and unregister_console() clears it, so set it on * every run to keep the test repeatable. */ capture->flags = CON_ENABLED; register_console(capture); seq_buf_do_printk(s, KERN_INFO); unregister_console(capture);}
static void seq_buf_do_printk_test(struct kunit *test){ /* * A registered console is a global object: printk() reaches it * through the console list from any CPU, and the console code writes * back into it, so keep it out of this function's stack frame the * way every other console in the tree does. */ static struct console capture = { .name = "sbufcap", .write = seq_buf_printk_capture, .index = -1, }; DECLARE_SEQ_BUF(s, 8); DECLARE_SEQ_BUF(t, 16); DECLARE_SEQ_BUF(u, 8);
/* * Fill the buffer exactly, so that the NUL takes the place of the * last byte and the string ends with the line feed before it. */ seq_buf_puts(&s, SEQ_BUF_PRINTK_MARKER); seq_buf_putc(&s, '\n'); seq_buf_putc(&s, '!'); KUNIT_ASSERT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_ASSERT_EQ(test, seq_buf_used(&s), 8); KUNIT_ASSERT_EQ(test, strlen(seq_buf_str(&s)), 7);
seq_buf_printk_run(&capture, &s);
/* The one line that was written, and nothing after it. */ KUNIT_EXPECT_EQ(test, seq_buf_printk_marked, 1); KUNIT_EXPECT_EQ(test, seq_buf_printk_empty, 0);
/* Check that lines without a trailing newline are shown. */ seq_buf_puts(&t, SEQ_BUF_PRINTK_MARKER "\n" SEQ_BUF_PRINTK_MARKER); KUNIT_ASSERT_FALSE(test, seq_buf_has_overflowed(&t));
seq_buf_printk_run(&capture, &t);
KUNIT_EXPECT_EQ(test, seq_buf_printk_marked, 2); KUNIT_EXPECT_EQ(test, seq_buf_printk_empty, 0);
/* * The buffer above was exactly full, where "len" equals the size. A * buffer that actually overflowed reaches the same bug by the other * route the old test had, with "len" one past the size. */ seq_buf_puts(&u, SEQ_BUF_PRINTK_MARKER "\n"); KUNIT_EXPECT_EQ(test, seq_buf_puts(&u, "yy"), -1); KUNIT_ASSERT_TRUE(test, seq_buf_has_overflowed(&u)); KUNIT_ASSERT_EQ(test, u.len, u.size + 1);
seq_buf_printk_run(&capture, &u);
KUNIT_EXPECT_EQ(test, seq_buf_printk_marked, 1); KUNIT_EXPECT_EQ(test, seq_buf_printk_empty, 0);}
/* Long enough that it cannot fit in the room the test leaves for it. */#define SEQ_BUF_TEST_PATH "/seq_buf_kunit_path_name"
static void seq_buf_path_overflow_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 32); const char *expected = "keep:xxxxxxxxxxxxxxxxxxxxxxx"; struct file *file; size_t len; int i;
/* * The tests run before anything writable is mounted, so take the file * whose path gets printed from shmem, which needs no mount of its own. */ file = shmem_file_setup(SEQ_BUF_TEST_PATH, 0, EMPTY_VMA_FLAGS); if (IS_ERR(file)) kunit_skip(test, "cannot create a file to print the path of");
/* Leave less room than the path needs, so d_path() cannot fit it. */ seq_buf_puts(&s, "keep:"); len = seq_buf_used(&s); for (i = len; i < 28; i++) seq_buf_putc(&s, 'x');
KUNIT_EXPECT_EQ(test, seq_buf_path(&s, &file->f_path, "\n"), -1); fput(file);
KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s));
/* * d_path() keeps as much of the path as fits when it does not fit * whole, and seq_buf_str() would hand out that fragment, as it ends * the string at the last byte of an overflowed buffer. */ for (i = 28; i < 32; i++) KUNIT_EXPECT_EQ_MSG(test, s.buffer[i], '\0', "byte %d past the data is not cleared", i); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), expected);}
static void seq_buf_strlen_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 16);
KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 0); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "");
seq_buf_puts(&s, "hello"); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 5); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), strlen(seq_buf_str(&s)));
seq_buf_printf(&s, " %s", "world"); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 11); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), strlen(seq_buf_str(&s)));}
static void seq_buf_strlen_printf_overflow_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 16); DECLARE_SEQ_BUF(t, 8);
seq_buf_printf(&s, "%s", "1234567890abcdefghij"); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 16); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 15); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "1234567890abcde"); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), strlen(seq_buf_str(&s)));
/* Output one byte too long for the NUL. */ seq_buf_printf(&t, "%s", "12345678"); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&t)); KUNIT_EXPECT_EQ(test, seq_buf_used(&t), 8); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&t), 7); KUNIT_EXPECT_STREQ(test, seq_buf_str(&t), "1234567"); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&t), strlen(seq_buf_str(&t)));}
static void seq_buf_strlen_full_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 4); DECLARE_SEQ_BUF(t, 8); char *buf; size_t len;
/* Filled exactly, with no room left for a NUL, but not overflowed. */ seq_buf_putc(&s, 'a'); seq_buf_putc(&s, 'b'); seq_buf_putc(&s, 'c'); seq_buf_putc(&s, 'd'); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 4); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 3); /* seq_buf_strlen() terminates the buffer by itself. */ KUNIT_EXPECT_EQ(test, s.buffer[3], '\0'); KUNIT_EXPECT_EQ(test, strnlen(s.buffer, s.size), 3); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "abc"); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), strlen(seq_buf_str(&s)));
/* A printf into a full buffer writes nothing. */ KUNIT_EXPECT_EQ(test, seq_buf_printf(&s, "%s", "x"), -1); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 3); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "abc"); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), strlen(seq_buf_str(&s)));
len = seq_buf_get_buf(&t, &buf); KUNIT_ASSERT_EQ(test, len, 8); memset(buf, 'z', len); seq_buf_commit(&t, len); KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&t)); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&t), 7); KUNIT_EXPECT_EQ(test, t.buffer[7], '\0'); KUNIT_EXPECT_EQ(test, strnlen(t.buffer, t.size), 7); KUNIT_EXPECT_STREQ(test, seq_buf_str(&t), "zzzzzzz"); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&t), strlen(seq_buf_str(&t)));}
static void seq_buf_strlen_puts_overflow_test(struct kunit *test){ DECLARE_SEQ_BUF(s, 16);
/* A puts that does not fit copies as much as fits. */ seq_buf_puts(&s, "hello"); KUNIT_EXPECT_EQ(test, seq_buf_puts(&s, " this does not fit"), -1); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s)); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 15); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello this does"); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), strlen(seq_buf_str(&s)));}
static void seq_buf_strlen_embedded_nul_test(struct kunit *test){ static const char data[] = "ab\0cd"; DECLARE_SEQ_BUF(s, 16);
/* * seq_buf_strlen() reports where it put the terminator, not where * the first NUL is, so data carrying a NUL of its own makes the two * disagree. That is expected, and is what the documented caveat is * about. */ seq_buf_putmem(&s, data, sizeof(data) - 1); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 5); KUNIT_EXPECT_EQ(test, strlen(seq_buf_str(&s)), 2);}
static void seq_buf_strlen_zero_size_test(struct kunit *test){ char buf[] = "untouched"; struct seq_buf s;
/* * A zero-sized seq_buf has nowhere to put a terminator. Both * accessors report an empty string and leave the buffer alone * rather than writing outside it. */ seq_buf_init(&s, buf, 0); KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 0); KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), ""); KUNIT_EXPECT_STREQ(test, buf, "untouched");}
static void seq_buf_terminate_test(struct kunit *test){ char buf[16]; struct seq_buf s;
/* * seq_buf_putmem() writes no NUL, so only seq_buf_terminate() can * end these strings early. The NUL in the last byte of buf keeps * the comparisons in bounds if it does not. */
/* Terminates directly after the data when there is room. */ memset(buf, 'z', sizeof(buf) - 1); buf[sizeof(buf) - 1] = '\0'; seq_buf_init(&s, buf, sizeof(buf)); seq_buf_putmem(&s, "ab", 2); seq_buf_terminate(&s); KUNIT_EXPECT_STREQ(test, buf, "ab");
/* Terminates in the last byte once the buffer has overflowed. */ memset(buf, 'z', sizeof(buf) - 1); buf[sizeof(buf) - 1] = '\0'; seq_buf_init(&s, buf, 4); seq_buf_putmem(&s, "abcdef", 6); KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s)); seq_buf_terminate(&s); KUNIT_EXPECT_STREQ(test, buf, "abc");
/* A zero-sized seq_buf is left alone. */ strscpy(buf, "untouched", sizeof(buf)); seq_buf_init(&s, buf, 0); seq_buf_terminate(&s); KUNIT_EXPECT_STREQ(test, buf, "untouched");}
static struct kunit_case seq_buf_test_cases[] = { KUNIT_CASE(seq_buf_init_test), KUNIT_CASE(seq_buf_init_append_test), KUNIT_CASE(seq_buf_declare_test), KUNIT_CASE(seq_buf_clear_test), KUNIT_CASE(seq_buf_puts_test), KUNIT_CASE(seq_buf_puts_overflow_test), KUNIT_CASE(seq_buf_putc_test), KUNIT_CASE(seq_buf_pop_test), KUNIT_CASE(seq_buf_printf_test), KUNIT_CASE(seq_buf_printf_overflow_test), KUNIT_CASE(seq_buf_get_buf_commit_test), KUNIT_CASE(seq_buf_putmem_hex_test), KUNIT_CASE(seq_buf_putmem_hex_overflow_test), KUNIT_CASE(seq_buf_puts_partial_overflow_test), KUNIT_CASE(seq_buf_putmem_partial_overflow_test), KUNIT_CASE(seq_buf_putmem_hex_partial_overflow_test), KUNIT_CASE(seq_buf_path_overflow_test), KUNIT_CASE(seq_buf_strlen_test), KUNIT_CASE(seq_buf_strlen_printf_overflow_test), KUNIT_CASE(seq_buf_strlen_full_test), KUNIT_CASE(seq_buf_strlen_puts_overflow_test), KUNIT_CASE(seq_buf_strlen_embedded_nul_test), KUNIT_CASE(seq_buf_strlen_zero_size_test), KUNIT_CASE(seq_buf_terminate_test), KUNIT_CASE(seq_buf_do_printk_test), {}};
static struct kunit_suite seq_buf_test_suite = { .name = "seq_buf", .test_cases = seq_buf_test_cases,};
kunit_test_suite(seq_buf_test_suite);
MODULE_DESCRIPTION("Runtime test cases for seq_buf string API");MODULE_LICENSE("GPL");