Skip to content

Commit

Permalink
libkmod: Release memory on error paths
Browse files Browse the repository at this point in the history
Do not override pointers to first list nodes if appending failed,
otherwise it's impossible to release already existing nodes of these
lists afterwards.

Remove the now unused function kmod_list_remove_n_latest as well.

Signed-off-by: Tobias Stoeckmann <[email protected]>
  • Loading branch information
stoeckmann committed Nov 6, 2024
1 parent a3cc3fd commit 37b1738
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 53 deletions.
1 change: 0 additions & 1 deletion libkmod/libkmod-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ _must_check_ _nonnull_(2) struct kmod_list *kmod_list_append(struct kmod_list *l
_must_check_ _nonnull_(2) struct kmod_list *kmod_list_prepend(struct kmod_list *list, const void *data);
_must_check_ struct kmod_list *kmod_list_remove(struct kmod_list *list);
_must_check_ _nonnull_(2) struct kmod_list *kmod_list_remove_data(struct kmod_list *list, const void *data);
_must_check_ struct kmod_list *kmod_list_remove_n_latest(struct kmod_list *list, unsigned int n);
_nonnull_(2) struct kmod_list *kmod_list_insert_after(struct kmod_list *list, const void *data);
_nonnull_(2) struct kmod_list *kmod_list_insert_before(struct kmod_list *list, const void *data);
_must_check_ struct kmod_list *kmod_list_append_list(struct kmod_list *list1, struct kmod_list *list2);
Expand Down
17 changes: 0 additions & 17 deletions libkmod/libkmod-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,23 +198,6 @@ struct kmod_list *kmod_list_remove_data(struct kmod_list *list, const void *data
return container_of(node, struct kmod_list, node);
}

/*
* n must be greater to or equal the number of elements (we don't check the
* condition)
*/
struct kmod_list *kmod_list_remove_n_latest(struct kmod_list *list, unsigned int n)
{
struct kmod_list *l = list;
unsigned int i;

for (i = 0; i < n; i++) {
l = kmod_list_last(l);
l = kmod_list_remove(l);
}

return l;
}

KMOD_EXPORT struct kmod_list *kmod_list_prev(const struct kmod_list *list,
const struct kmod_list *curr)
{
Expand Down
54 changes: 46 additions & 8 deletions libkmod/libkmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ static int kmod_lookup_alias_from_alias_bin(struct kmod_ctx *ctx,
const char *name, struct kmod_list **list)
{
int err, nmatch = 0;
struct kmod_list *added, *start;
struct index_file *idx;
struct index_value *realnames, *realname;

Expand All @@ -376,8 +377,10 @@ static int kmod_lookup_alias_from_alias_bin(struct kmod_ctx *ctx,
index_file_close(idx);
}

start = *list;
for (realname = realnames; realname; realname = realname->next) {
struct kmod_module *mod;
struct kmod_list *node;

err = kmod_module_new_from_alias(ctx, name, realname->value, &mod);
if (err < 0) {
Expand All @@ -386,15 +389,23 @@ static int kmod_lookup_alias_from_alias_bin(struct kmod_ctx *ctx,
goto fail;
}

*list = kmod_list_append(*list, mod);
node = kmod_list_append(*list, mod);
if (node == NULL) {
ERR(ctx, "out of memory\n");
kmod_module_unref(mod);
goto fail;
}
*list = node;
nmatch++;
}

index_values_free(realnames);
return nmatch;

fail:
*list = kmod_list_remove_n_latest(*list, nmatch);
added = start == NULL ? *list : kmod_list_next(*list, start);
kmod_list_release(added, kmod_module_unref);
*list = start;
index_values_free(realnames);
return err;
}
Expand Down Expand Up @@ -474,6 +485,7 @@ int kmod_lookup_alias_from_builtin_file(struct kmod_ctx *ctx, const char *name,
line = lookup_builtin_file(ctx, name);
if (line != NULL) {
struct kmod_module *mod;
struct kmod_list *node;

err = kmod_module_new_from_name(ctx, name, &mod);
if (err < 0) {
Expand All @@ -485,9 +497,14 @@ int kmod_lookup_alias_from_builtin_file(struct kmod_ctx *ctx, const char *name,
/* already mark it as builtin since it's being created from
* this index */
kmod_module_set_builtin(mod, true);
*list = kmod_list_append(*list, mod);
if (*list == NULL)
node = kmod_list_append(*list, mod);
if (node == NULL) {
ERR(ctx, "out of memory\n");
kmod_module_unref(mod);
err = -ENOMEM;
} else {
*list = node;
}
}

finish:
Expand Down Expand Up @@ -549,6 +566,7 @@ int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name,
line = kmod_search_moddep(ctx, name);
if (line != NULL) {
struct kmod_module *mod;
struct kmod_list *node;

n = kmod_module_new_from_name(ctx, name, &mod);
if (n < 0) {
Expand All @@ -557,7 +575,14 @@ int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name,
goto finish;
}

*list = kmod_list_append(*list, mod);
node = kmod_list_append(*list, mod);
if (node == NULL) {
ERR(ctx, "out of memory\n");
kmod_module_unref(mod);
n = -ENOMEM;
goto finish;
}
*list = node;
kmod_module_parse_depline(mod, line);
}

Expand All @@ -571,15 +596,17 @@ int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name,
struct kmod_list **list)
{
struct kmod_config *config = ctx->config;
struct kmod_list *l;
struct kmod_list *added, *l, *start;
int err, nmatch = 0;

start = *list;
kmod_list_foreach(l, config->aliases) {
const char *aliasname = kmod_alias_get_name(l);
const char *modname = kmod_alias_get_modname(l);

if (fnmatch(aliasname, name, 0) == 0) {
struct kmod_module *mod;
struct kmod_list *node;

err = kmod_module_new_from_alias(ctx, aliasname, modname, &mod);
if (err < 0) {
Expand All @@ -589,15 +616,24 @@ int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name,
goto fail;
}

*list = kmod_list_append(*list, mod);
node = kmod_list_append(*list, mod);
if (node == NULL) {
ERR(ctx, "out of memory\n");
kmod_module_unref(mod);
err = -ENOMEM;
goto fail;
}
*list = node;
nmatch++;
}
}

return nmatch;

fail:
*list = kmod_list_remove_n_latest(*list, nmatch);
added = start == NULL ? *list : kmod_list_next(*list, start);
kmod_list_release(added, kmod_module_unref);
*list = start;
return err;
}

Expand Down Expand Up @@ -625,6 +661,7 @@ int kmod_lookup_alias_from_commands(struct kmod_ctx *ctx, const char *name,
node = kmod_list_append(*list, mod);
if (node == NULL) {
ERR(ctx, "out of memory\n");
kmod_module_unref(mod);
return -ENOMEM;
}

Expand Down Expand Up @@ -661,6 +698,7 @@ int kmod_lookup_alias_from_commands(struct kmod_ctx *ctx, const char *name,
node = kmod_list_append(*list, mod);
if (node == NULL) {
ERR(ctx, "out of memory\n");
kmod_module_unref(mod);
return -ENOMEM;
}

Expand Down
27 changes: 0 additions & 27 deletions testsuite/test-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,33 +76,6 @@ static int test_list_prev(const struct test *t)
}
DEFINE_TEST(test_list_prev, .description = "test list prev");

static int test_list_remove_n_latest(const struct test *t)
{
struct kmod_list *list = NULL, *l;
int i;
const char *v[] = { "v1", "v2", "v3", "v4", "v5" };
const int N = ARRAY_SIZE(v), M = N / 2;

for (i = 0; i < N; i++)
list = kmod_list_append(list, v[i]);
assert_return(len(list) == N, EXIT_FAILURE);

list = kmod_list_remove_n_latest(list, M);
assert_return(len(list) == N - M, EXIT_FAILURE);

i = 0;
kmod_list_foreach(l, list) {
assert_return(l->data == v[i], EXIT_FAILURE);
i++;
}

kmod_list_remove_all(list);

return 0;
}
DEFINE_TEST(test_list_remove_n_latest,
.description = "test list function to remove n latest elements");

static int test_list_remove_data(const struct test *t)
{
struct kmod_list *list = NULL, *l;
Expand Down

0 comments on commit 37b1738

Please sign in to comment.