linux/lib/kunit/assert.c
Rae Moar dd2f0a0a2f kunit: fix bug in KUNIT_EXPECT_MEMEQ
In KUNIT_EXPECT_MEMEQ and KUNIT_EXPECT_MEMNEQ, add check if one of the
inputs is NULL and fail if this is the case.

Currently, the kernel crashes if one of the inputs is NULL. Instead,
fail the test and add an appropriate error message.

Fixes: b8a926bea8 ("kunit: Introduce KUNIT_EXPECT_MEMEQ and KUNIT_EXPECT_MEMNEQ macros")

This was found by the kernel test robot:
https://lore.kernel.org/all/202212191448.D6EDPdOh-lkp@intel.com/

Reported-by: kernel test robot <lkp@intel.com>

Signed-off-by: Rae Moar <rmoar@google.com>
Reviewed-by: David Gow <davidgow@google.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
2023-01-30 14:46:46 -07:00

275 lines
8.2 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Assertion and expectation serialization API.
*
* Copyright (C) 2019, Google LLC.
* Author: Brendan Higgins <brendanhiggins@google.com>
*/
#include <kunit/assert.h>
#include <kunit/test.h>
#include "string-stream.h"
void kunit_assert_prologue(const struct kunit_loc *loc,
enum kunit_assert_type type,
struct string_stream *stream)
{
const char *expect_or_assert = NULL;
switch (type) {
case KUNIT_EXPECTATION:
expect_or_assert = "EXPECTATION";
break;
case KUNIT_ASSERTION:
expect_or_assert = "ASSERTION";
break;
}
string_stream_add(stream, "%s FAILED at %s:%d\n",
expect_or_assert, loc->file, loc->line);
}
EXPORT_SYMBOL_GPL(kunit_assert_prologue);
static void kunit_assert_print_msg(const struct va_format *message,
struct string_stream *stream)
{
if (message->fmt)
string_stream_add(stream, "\n%pV", message);
}
void kunit_fail_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream)
{
string_stream_add(stream, "%pV", message);
}
EXPORT_SYMBOL_GPL(kunit_fail_assert_format);
void kunit_unary_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream)
{
struct kunit_unary_assert *unary_assert;
unary_assert = container_of(assert, struct kunit_unary_assert, assert);
if (unary_assert->expected_true)
string_stream_add(stream,
KUNIT_SUBTEST_INDENT "Expected %s to be true, but is false\n",
unary_assert->condition);
else
string_stream_add(stream,
KUNIT_SUBTEST_INDENT "Expected %s to be false, but is true\n",
unary_assert->condition);
kunit_assert_print_msg(message, stream);
}
EXPORT_SYMBOL_GPL(kunit_unary_assert_format);
void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream)
{
struct kunit_ptr_not_err_assert *ptr_assert;
ptr_assert = container_of(assert, struct kunit_ptr_not_err_assert,
assert);
if (!ptr_assert->value) {
string_stream_add(stream,
KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n",
ptr_assert->text);
} else if (IS_ERR(ptr_assert->value)) {
string_stream_add(stream,
KUNIT_SUBTEST_INDENT "Expected %s is not error, but is: %ld\n",
ptr_assert->text,
PTR_ERR(ptr_assert->value));
}
kunit_assert_print_msg(message, stream);
}
EXPORT_SYMBOL_GPL(kunit_ptr_not_err_assert_format);
/* Checks if `text` is a literal representing `value`, e.g. "5" and 5 */
static bool is_literal(struct kunit *test, const char *text, long long value,
gfp_t gfp)
{
char *buffer;
int len;
bool ret;
len = snprintf(NULL, 0, "%lld", value);
if (strlen(text) != len)
return false;
buffer = kunit_kmalloc(test, len+1, gfp);
if (!buffer)
return false;
snprintf(buffer, len+1, "%lld", value);
ret = strncmp(buffer, text, len) == 0;
kunit_kfree(test, buffer);
return ret;
}
void kunit_binary_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream)
{
struct kunit_binary_assert *binary_assert;
binary_assert = container_of(assert, struct kunit_binary_assert,
assert);
string_stream_add(stream,
KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n",
binary_assert->text->left_text,
binary_assert->text->operation,
binary_assert->text->right_text);
if (!is_literal(stream->test, binary_assert->text->left_text,
binary_assert->left_value, stream->gfp))
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)\n",
binary_assert->text->left_text,
binary_assert->left_value,
binary_assert->left_value);
if (!is_literal(stream->test, binary_assert->text->right_text,
binary_assert->right_value, stream->gfp))
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)",
binary_assert->text->right_text,
binary_assert->right_value,
binary_assert->right_value);
kunit_assert_print_msg(message, stream);
}
EXPORT_SYMBOL_GPL(kunit_binary_assert_format);
void kunit_binary_ptr_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream)
{
struct kunit_binary_ptr_assert *binary_assert;
binary_assert = container_of(assert, struct kunit_binary_ptr_assert,
assert);
string_stream_add(stream,
KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n",
binary_assert->text->left_text,
binary_assert->text->operation,
binary_assert->text->right_text);
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %px\n",
binary_assert->text->left_text,
binary_assert->left_value);
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %px",
binary_assert->text->right_text,
binary_assert->right_value);
kunit_assert_print_msg(message, stream);
}
EXPORT_SYMBOL_GPL(kunit_binary_ptr_assert_format);
/* Checks if KUNIT_EXPECT_STREQ() args were string literals.
* Note: `text` will have ""s where as `value` will not.
*/
static bool is_str_literal(const char *text, const char *value)
{
int len;
len = strlen(text);
if (len < 2)
return false;
if (text[0] != '\"' || text[len - 1] != '\"')
return false;
return strncmp(text + 1, value, len - 2) == 0;
}
void kunit_binary_str_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream)
{
struct kunit_binary_str_assert *binary_assert;
binary_assert = container_of(assert, struct kunit_binary_str_assert,
assert);
string_stream_add(stream,
KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n",
binary_assert->text->left_text,
binary_assert->text->operation,
binary_assert->text->right_text);
if (!is_str_literal(binary_assert->text->left_text, binary_assert->left_value))
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == \"%s\"\n",
binary_assert->text->left_text,
binary_assert->left_value);
if (!is_str_literal(binary_assert->text->right_text, binary_assert->right_value))
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == \"%s\"",
binary_assert->text->right_text,
binary_assert->right_value);
kunit_assert_print_msg(message, stream);
}
EXPORT_SYMBOL_GPL(kunit_binary_str_assert_format);
/* Adds a hexdump of a buffer to a string_stream comparing it with
* a second buffer. The different bytes are marked with <>.
*/
static void kunit_assert_hexdump(struct string_stream *stream,
const void *buf,
const void *compared_buf,
const size_t len)
{
size_t i;
const u8 *buf1 = buf;
const u8 *buf2 = compared_buf;
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT);
for (i = 0; i < len; ++i) {
if (!(i % 16) && i)
string_stream_add(stream, "\n" KUNIT_SUBSUBTEST_INDENT);
if (buf1[i] != buf2[i])
string_stream_add(stream, "<%02x>", buf1[i]);
else
string_stream_add(stream, " %02x ", buf1[i]);
}
}
void kunit_mem_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream)
{
struct kunit_mem_assert *mem_assert;
mem_assert = container_of(assert, struct kunit_mem_assert,
assert);
if (!mem_assert->left_value) {
string_stream_add(stream,
KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n",
mem_assert->text->left_text);
} else if (!mem_assert->right_value) {
string_stream_add(stream,
KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n",
mem_assert->text->right_text);
} else {
string_stream_add(stream,
KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n",
mem_assert->text->left_text,
mem_assert->text->operation,
mem_assert->text->right_text);
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n",
mem_assert->text->left_text);
kunit_assert_hexdump(stream, mem_assert->left_value,
mem_assert->right_value, mem_assert->size);
string_stream_add(stream, "\n");
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n",
mem_assert->text->right_text);
kunit_assert_hexdump(stream, mem_assert->right_value,
mem_assert->left_value, mem_assert->size);
kunit_assert_print_msg(message, stream);
}
}
EXPORT_SYMBOL_GPL(kunit_mem_assert_format);