2023-08-03 23:05:38

by Rae Moar

[permalink] [raw]
Subject: [PATCH -next v2] kunit: fix uninitialized variables bug in attributes filtering

Fix smatch warnings regarding uninitialized variables in the filtering
patch of the new KUnit Attributes feature.

Fixes: 529534e8cba3 ("kunit: Add ability to filter attributes")

Reported-by: kernel test robot <[email protected]>
Reported-by: Dan Carpenter <[email protected]>
Closes: https://lore.kernel.org/r/[email protected]/

Signed-off-by: Rae Moar <[email protected]>
---

Change since v1:
- Changed initialization of filtered to be {NULL, NULL} at the start and
only updated when ready to return.
- Remove unnecessary +1 in memory allocation for parsed_filters in
executor test.

Note that this is rebased on top of the recent fix:
("kunit: fix possible memory leak in kunit_filter_suites()").

lib/kunit/attributes.c | 40 +++++++++++++++++----------------------
lib/kunit/executor.c | 18 +++++++++++-------
lib/kunit/executor_test.c | 2 +-
3 files changed, 29 insertions(+), 31 deletions(-)

diff --git a/lib/kunit/attributes.c b/lib/kunit/attributes.c
index d37c40c0ce4f..5e3034b6be99 100644
--- a/lib/kunit/attributes.c
+++ b/lib/kunit/attributes.c
@@ -102,7 +102,7 @@ static int int_filter(long val, const char *op, int input, int *err)
static int attr_enum_filter(void *attr, const char *input, int *err,
const char * const str_list[], int max)
{
- int i, j, input_int;
+ int i, j, input_int = -1;
long test_val = (long)attr;
const char *input_val = NULL;

@@ -124,7 +124,7 @@ static int attr_enum_filter(void *attr, const char *input, int *err,
input_int = j;
}

- if (!input_int) {
+ if (input_int < 0) {
*err = -EINVAL;
pr_err("kunit executor: invalid filter input: %s\n", input);
return false;
@@ -186,8 +186,10 @@ static void *attr_module_get(void *test_or_suite, bool is_test)
// Suites get their module attribute from their first test_case
if (test)
return ((void *) test->module_name);
- else
+ else if (kunit_suite_num_test_cases(suite) > 0)
return ((void *) suite->test_cases[0].module_name);
+ else
+ return (void *) "";
}

/* List of all Test Attributes */
@@ -221,7 +223,7 @@ const char *kunit_attr_filter_name(struct kunit_attr_filter filter)
void kunit_print_attr(void *test_or_suite, bool is_test, unsigned int test_level)
{
int i;
- bool to_free;
+ bool to_free = false;
void *attr;
const char *attr_name, *attr_str;
struct kunit_suite *suite = is_test ? NULL : test_or_suite;
@@ -255,7 +257,7 @@ void kunit_print_attr(void *test_or_suite, bool is_test, unsigned int test_level

int kunit_get_filter_count(char *input)
{
- int i, comma_index, count = 0;
+ int i, comma_index = 0, count = 0;

for (i = 0; input[i]; i++) {
if (input[i] == ',') {
@@ -272,7 +274,7 @@ int kunit_get_filter_count(char *input)
struct kunit_attr_filter kunit_next_attr_filter(char **filters, int *err)
{
struct kunit_attr_filter filter = {};
- int i, j, comma_index, new_start_index;
+ int i, j, comma_index = 0, new_start_index = 0;
int op_index = -1, attr_index = -1;
char op;
char *input = *filters;
@@ -316,7 +318,7 @@ struct kunit_attr_filter kunit_next_attr_filter(char **filters, int *err)
filter.attr = &kunit_attr_list[attr_index];
}

- if (comma_index) {
+ if (comma_index > 0) {
input[comma_index] = '\0';
filter.input = input + op_index;
input = input + new_start_index;
@@ -356,31 +358,22 @@ struct kunit_suite *kunit_filter_attr_tests(const struct kunit_suite *const suit

/* Save filtering result on default value */
default_result = filter.attr->filter(filter.attr->attr_default, filter.input, err);
- if (*err) {
- kfree(copy);
- kfree(filtered);
- return NULL;
- }
+ if (*err)
+ goto err;

/* Save suite attribute value and filtering result on that value */
suite_val = filter.attr->get_attr((void *)suite, false);
suite_result = filter.attr->filter(suite_val, filter.input, err);
- if (*err) {
- kfree(copy);
- kfree(filtered);
- return NULL;
- }
+ if (*err)
+ goto err;

/* For each test case, save test case if passes filtering. */
kunit_suite_for_each_test_case(suite, test_case) {
test_val = filter.attr->get_attr((void *) test_case, true);
test_result = filter.attr->filter(filter.attr->get_attr(test_case, true),
filter.input, err);
- if (*err) {
- kfree(copy);
- kfree(filtered);
- return NULL;
- }
+ if (*err)
+ goto err;

/*
* If attribute value of test case is set, filter on that value.
@@ -406,7 +399,8 @@ struct kunit_suite *kunit_filter_attr_tests(const struct kunit_suite *const suit
}
}

- if (n == 0) {
+err:
+ if (n == 0 || *err) {
kfree(copy);
kfree(filtered);
return NULL;
diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
index 481901d245d0..dc295150c4e5 100644
--- a/lib/kunit/executor.c
+++ b/lib/kunit/executor.c
@@ -127,19 +127,18 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
{
int i, j, k;
int filter_count = 0;
- struct kunit_suite **copy, *filtered_suite, *new_filtered_suite;
- struct suite_set filtered;
+ struct kunit_suite **copy, **copy_start, *filtered_suite, *new_filtered_suite;
+ struct suite_set filtered = {NULL, NULL};
struct kunit_glob_filter parsed_glob;
- struct kunit_attr_filter *parsed_filters;
+ struct kunit_attr_filter *parsed_filters = NULL;

const size_t max = suite_set->end - suite_set->start;

copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL);
- filtered.start = copy;
if (!copy) { /* won't be able to run anything, return an empty set */
- filtered.end = copy;
return filtered;
}
+ copy_start = copy;

if (filter_glob)
kunit_parse_glob_filter(&parsed_glob, filter_glob);
@@ -147,7 +146,11 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
/* Parse attribute filters */
if (filters) {
filter_count = kunit_get_filter_count(filters);
- parsed_filters = kcalloc(filter_count + 1, sizeof(*parsed_filters), GFP_KERNEL);
+ parsed_filters = kcalloc(filter_count, sizeof(*parsed_filters), GFP_KERNEL);
+ if (!parsed_filters) {
+ kfree(copy);
+ return filtered;
+ }
for (j = 0; j < filter_count; j++)
parsed_filters[j] = kunit_next_attr_filter(&filters, err);
if (*err)
@@ -166,7 +169,7 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
goto err;
}
}
- if (filter_count) {
+ if (filter_count > 0 && parsed_filters != NULL) {
for (k = 0; k < filter_count; k++) {
new_filtered_suite = kunit_filter_attr_tests(filtered_suite,
parsed_filters[k], filter_action, err);
@@ -195,6 +198,7 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,

*copy++ = filtered_suite;
}
+ filtered.start = copy_start;
filtered.end = copy;

err:
diff --git a/lib/kunit/executor_test.c b/lib/kunit/executor_test.c
index 01280cb8d451..3e0a1c99cb4e 100644
--- a/lib/kunit/executor_test.c
+++ b/lib/kunit/executor_test.c
@@ -119,7 +119,7 @@ static void parse_filter_attr_test(struct kunit *test)
filter_count = kunit_get_filter_count(filters);
KUNIT_EXPECT_EQ(test, filter_count, 2);

- parsed_filters = kunit_kcalloc(test, filter_count + 1, sizeof(*parsed_filters),
+ parsed_filters = kunit_kcalloc(test, filter_count, sizeof(*parsed_filters),
GFP_KERNEL);
for (j = 0; j < filter_count; j++) {
parsed_filters[j] = kunit_next_attr_filter(&filters, &err);

base-commit: 3bffe185ad11e408903d2782727877388d08d94e
--
2.41.0.585.gd2178a4bd4-goog



2023-08-03 23:18:21

by David Gow

[permalink] [raw]
Subject: Re: [PATCH -next v2] kunit: fix uninitialized variables bug in attributes filtering

On Fri, 4 Aug 2023 at 03:37, Rae Moar <[email protected]> wrote:
>
> Fix smatch warnings regarding uninitialized variables in the filtering
> patch of the new KUnit Attributes feature.
>
> Fixes: 529534e8cba3 ("kunit: Add ability to filter attributes")
>
> Reported-by: kernel test robot <[email protected]>
> Reported-by: Dan Carpenter <[email protected]>
> Closes: https://lore.kernel.org/r/[email protected]/
>
> Signed-off-by: Rae Moar <[email protected]>
> ---
>
> Change since v1:
> - Changed initialization of filtered to be {NULL, NULL} at the start and
> only updated when ready to return.
> - Remove unnecessary +1 in memory allocation for parsed_filters in
> executor test.
>
> Note that this is rebased on top of the recent fix:
> ("kunit: fix possible memory leak in kunit_filter_suites()").

Thanks: this looks good to me now!

Reviewed-by: David Gow <[email protected]>

Cheers,
-- David

>
> lib/kunit/attributes.c | 40 +++++++++++++++++----------------------
> lib/kunit/executor.c | 18 +++++++++++-------
> lib/kunit/executor_test.c | 2 +-
> 3 files changed, 29 insertions(+), 31 deletions(-)
>
> diff --git a/lib/kunit/attributes.c b/lib/kunit/attributes.c
> index d37c40c0ce4f..5e3034b6be99 100644
> --- a/lib/kunit/attributes.c
> +++ b/lib/kunit/attributes.c
> @@ -102,7 +102,7 @@ static int int_filter(long val, const char *op, int input, int *err)
> static int attr_enum_filter(void *attr, const char *input, int *err,
> const char * const str_list[], int max)
> {
> - int i, j, input_int;
> + int i, j, input_int = -1;
> long test_val = (long)attr;
> const char *input_val = NULL;
>
> @@ -124,7 +124,7 @@ static int attr_enum_filter(void *attr, const char *input, int *err,
> input_int = j;
> }
>
> - if (!input_int) {
> + if (input_int < 0) {
> *err = -EINVAL;
> pr_err("kunit executor: invalid filter input: %s\n", input);
> return false;
> @@ -186,8 +186,10 @@ static void *attr_module_get(void *test_or_suite, bool is_test)
> // Suites get their module attribute from their first test_case
> if (test)
> return ((void *) test->module_name);
> - else
> + else if (kunit_suite_num_test_cases(suite) > 0)
> return ((void *) suite->test_cases[0].module_name);
> + else
> + return (void *) "";
> }
>
> /* List of all Test Attributes */
> @@ -221,7 +223,7 @@ const char *kunit_attr_filter_name(struct kunit_attr_filter filter)
> void kunit_print_attr(void *test_or_suite, bool is_test, unsigned int test_level)
> {
> int i;
> - bool to_free;
> + bool to_free = false;
> void *attr;
> const char *attr_name, *attr_str;
> struct kunit_suite *suite = is_test ? NULL : test_or_suite;
> @@ -255,7 +257,7 @@ void kunit_print_attr(void *test_or_suite, bool is_test, unsigned int test_level
>
> int kunit_get_filter_count(char *input)
> {
> - int i, comma_index, count = 0;
> + int i, comma_index = 0, count = 0;
>
> for (i = 0; input[i]; i++) {
> if (input[i] == ',') {
> @@ -272,7 +274,7 @@ int kunit_get_filter_count(char *input)
> struct kunit_attr_filter kunit_next_attr_filter(char **filters, int *err)
> {
> struct kunit_attr_filter filter = {};
> - int i, j, comma_index, new_start_index;
> + int i, j, comma_index = 0, new_start_index = 0;
> int op_index = -1, attr_index = -1;
> char op;
> char *input = *filters;
> @@ -316,7 +318,7 @@ struct kunit_attr_filter kunit_next_attr_filter(char **filters, int *err)
> filter.attr = &kunit_attr_list[attr_index];
> }
>
> - if (comma_index) {
> + if (comma_index > 0) {
> input[comma_index] = '\0';
> filter.input = input + op_index;
> input = input + new_start_index;
> @@ -356,31 +358,22 @@ struct kunit_suite *kunit_filter_attr_tests(const struct kunit_suite *const suit
>
> /* Save filtering result on default value */
> default_result = filter.attr->filter(filter.attr->attr_default, filter.input, err);
> - if (*err) {
> - kfree(copy);
> - kfree(filtered);
> - return NULL;
> - }
> + if (*err)
> + goto err;
>
> /* Save suite attribute value and filtering result on that value */
> suite_val = filter.attr->get_attr((void *)suite, false);
> suite_result = filter.attr->filter(suite_val, filter.input, err);
> - if (*err) {
> - kfree(copy);
> - kfree(filtered);
> - return NULL;
> - }
> + if (*err)
> + goto err;
>
> /* For each test case, save test case if passes filtering. */
> kunit_suite_for_each_test_case(suite, test_case) {
> test_val = filter.attr->get_attr((void *) test_case, true);
> test_result = filter.attr->filter(filter.attr->get_attr(test_case, true),
> filter.input, err);
> - if (*err) {
> - kfree(copy);
> - kfree(filtered);
> - return NULL;
> - }
> + if (*err)
> + goto err;
>
> /*
> * If attribute value of test case is set, filter on that value.
> @@ -406,7 +399,8 @@ struct kunit_suite *kunit_filter_attr_tests(const struct kunit_suite *const suit
> }
> }
>
> - if (n == 0) {
> +err:
> + if (n == 0 || *err) {
> kfree(copy);
> kfree(filtered);
> return NULL;
> diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
> index 481901d245d0..dc295150c4e5 100644
> --- a/lib/kunit/executor.c
> +++ b/lib/kunit/executor.c
> @@ -127,19 +127,18 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
> {
> int i, j, k;
> int filter_count = 0;
> - struct kunit_suite **copy, *filtered_suite, *new_filtered_suite;
> - struct suite_set filtered;
> + struct kunit_suite **copy, **copy_start, *filtered_suite, *new_filtered_suite;
> + struct suite_set filtered = {NULL, NULL};
> struct kunit_glob_filter parsed_glob;
> - struct kunit_attr_filter *parsed_filters;
> + struct kunit_attr_filter *parsed_filters = NULL;
>
> const size_t max = suite_set->end - suite_set->start;
>
> copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL);
> - filtered.start = copy;
> if (!copy) { /* won't be able to run anything, return an empty set */
> - filtered.end = copy;
> return filtered;
> }
> + copy_start = copy;
>
> if (filter_glob)
> kunit_parse_glob_filter(&parsed_glob, filter_glob);
> @@ -147,7 +146,11 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
> /* Parse attribute filters */
> if (filters) {
> filter_count = kunit_get_filter_count(filters);
> - parsed_filters = kcalloc(filter_count + 1, sizeof(*parsed_filters), GFP_KERNEL);
> + parsed_filters = kcalloc(filter_count, sizeof(*parsed_filters), GFP_KERNEL);
> + if (!parsed_filters) {
> + kfree(copy);
> + return filtered;
> + }
> for (j = 0; j < filter_count; j++)
> parsed_filters[j] = kunit_next_attr_filter(&filters, err);
> if (*err)
> @@ -166,7 +169,7 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
> goto err;
> }
> }
> - if (filter_count) {
> + if (filter_count > 0 && parsed_filters != NULL) {
> for (k = 0; k < filter_count; k++) {
> new_filtered_suite = kunit_filter_attr_tests(filtered_suite,
> parsed_filters[k], filter_action, err);
> @@ -195,6 +198,7 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
>
> *copy++ = filtered_suite;
> }
> + filtered.start = copy_start;
> filtered.end = copy;
>
> err:
> diff --git a/lib/kunit/executor_test.c b/lib/kunit/executor_test.c
> index 01280cb8d451..3e0a1c99cb4e 100644
> --- a/lib/kunit/executor_test.c
> +++ b/lib/kunit/executor_test.c
> @@ -119,7 +119,7 @@ static void parse_filter_attr_test(struct kunit *test)
> filter_count = kunit_get_filter_count(filters);
> KUNIT_EXPECT_EQ(test, filter_count, 2);
>
> - parsed_filters = kunit_kcalloc(test, filter_count + 1, sizeof(*parsed_filters),
> + parsed_filters = kunit_kcalloc(test, filter_count, sizeof(*parsed_filters),
> GFP_KERNEL);
> for (j = 0; j < filter_count; j++) {
> parsed_filters[j] = kunit_next_attr_filter(&filters, &err);
>
> base-commit: 3bffe185ad11e408903d2782727877388d08d94e
> --
> 2.41.0.585.gd2178a4bd4-goog
>


Attachments:
smime.p7s (3.91 kB)
S/MIME Cryptographic Signature