// SPDX-License-Identifier: GPL-2.0 /* * KUnit tests for the seq_buf API * * Copyright (C) 2025, Google LLC. */ #include #include #include #include #include #include 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");