This is an automated email from the ASF dual-hosted git repository. sjanc pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
commit 6546730041adc0119ef24bfa79c4b92a19fc7518 Author: Szymon Janc <[email protected]> AuthorDate: Tue Oct 6 19:16:40 2026 +0200 mgmt/mcumgr/mgmt: Fix group list corruption on unregister When last group in list was unregistered, mgmt_group_list_end was set to the removed group instead of the previous one. Group registered after that was linked to the removed group and was not reachable from the list. When the only group was unregistered list end was not cleared at all. This also adds unit test for groups registration. Assisted-by: Claude:claude-opus-5-5 --- mgmt/mcumgr/mgmt/selftest/pkg.yml | 31 ++++++++++ mgmt/mcumgr/mgmt/selftest/src/mgmt_test.c | 98 +++++++++++++++++++++++++++++++ mgmt/mcumgr/mgmt/src/mgmt.c | 20 ++++--- 3 files changed, 140 insertions(+), 9 deletions(-) diff --git a/mgmt/mcumgr/mgmt/selftest/pkg.yml b/mgmt/mcumgr/mgmt/selftest/pkg.yml new file mode 100644 index 000000000..323bf45a4 --- /dev/null +++ b/mgmt/mcumgr/mgmt/selftest/pkg.yml @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: mgmt/mcumgr/mgmt/selftest +pkg.type: unittest +pkg.description: "Unit tests for mcumgr management group registration." +pkg.author: "Apache Mynewt <[email protected]>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/sys/log/stub" + - '@apache-mynewt-core/sys/console/stub' + - '@apache-mynewt-core/test/testutil' + - '@apache-mynewt-core/mgmt/mcumgr/mgmt' diff --git a/mgmt/mcumgr/mgmt/selftest/src/mgmt_test.c b/mgmt/mcumgr/mgmt/selftest/src/mgmt_test.c new file mode 100644 index 000000000..5e99c7f77 --- /dev/null +++ b/mgmt/mcumgr/mgmt/selftest/src/mgmt_test.c @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/mynewt.h" +#include "testutil/testutil.h" +#include "mgmt/mgmt.h" + +static int +mgmt_test_handler(struct mgmt_ctxt *ctxt) +{ + return 0; +} + +static const struct mgmt_handler mgmt_test_handlers[] = { + [0] = { mgmt_test_handler, NULL }, +}; + +#define MGMT_TEST_GROUP(id) \ + { \ + .mg_handlers = mgmt_test_handlers, \ + .mg_handlers_count = 1, \ + .mg_group_id = (id), \ + } + +static struct mgmt_group group_a = MGMT_TEST_GROUP(MGMT_GROUP_ID_PERUSER + 0); +static struct mgmt_group group_b = MGMT_TEST_GROUP(MGMT_GROUP_ID_PERUSER + 1); +static struct mgmt_group group_c = MGMT_TEST_GROUP(MGMT_GROUP_ID_PERUSER + 2); +static struct mgmt_group group_d = MGMT_TEST_GROUP(MGMT_GROUP_ID_PERUSER + 3); + +static bool +mgmt_test_registered(const struct mgmt_group *group) +{ + return mgmt_find_handler(group->mg_group_id, 0) != NULL; +} + +TEST_CASE_SELF(mgmt_test_case_register_unregister) +{ + mgmt_register_group(&group_a); + mgmt_register_group(&group_b); + mgmt_register_group(&group_c); + TEST_ASSERT(mgmt_test_registered(&group_a)); + TEST_ASSERT(mgmt_test_registered(&group_b)); + TEST_ASSERT(mgmt_test_registered(&group_c)); + + /* Remove last group and add new one at the end of list. */ + mgmt_unregister_group(&group_c); + TEST_ASSERT(!mgmt_test_registered(&group_c)); + mgmt_register_group(&group_d); + TEST_ASSERT(mgmt_test_registered(&group_a)); + TEST_ASSERT(mgmt_test_registered(&group_b)); + TEST_ASSERT(mgmt_test_registered(&group_d)); + + /* Remove first group. */ + mgmt_unregister_group(&group_a); + TEST_ASSERT(!mgmt_test_registered(&group_a)); + TEST_ASSERT(mgmt_test_registered(&group_b)); + TEST_ASSERT(mgmt_test_registered(&group_d)); + + /* Remove all groups, list must be usable afterwards. */ + mgmt_unregister_group(&group_d); + mgmt_unregister_group(&group_b); + TEST_ASSERT(!mgmt_test_registered(&group_b)); + TEST_ASSERT(!mgmt_test_registered(&group_d)); + mgmt_register_group(&group_c); + TEST_ASSERT(mgmt_test_registered(&group_c)); + + /* Unregistering group that is not registered is no-op. */ + mgmt_unregister_group(&group_a); + TEST_ASSERT(mgmt_test_registered(&group_c)); +} + +TEST_SUITE(mgmt_test_suite) +{ + mgmt_test_case_register_unregister(); +} + +int +main(int argc, char **argv) +{ + mgmt_test_suite(); + return tu_any_failed; +} diff --git a/mgmt/mcumgr/mgmt/src/mgmt.c b/mgmt/mcumgr/mgmt/src/mgmt.c index d652089ac..18d2aa558 100644 --- a/mgmt/mcumgr/mgmt/src/mgmt.c +++ b/mgmt/mcumgr/mgmt/src/mgmt.c @@ -80,24 +80,26 @@ mgmt_unregister_group(struct mgmt_group *group) return; } - if (curr == group) { - mgmt_group_list = curr->mg_next; - return; - } - while (curr && curr != group) { prev = curr; curr = curr->mg_next; } - if (!prev || !curr) { + if (!curr) { return; } - prev->mg_next = curr->mg_next; - if (curr->mg_next == NULL) { - mgmt_group_list_end = curr; + if (prev) { + prev->mg_next = curr->mg_next; + } else { + mgmt_group_list = curr->mg_next; + } + + if (mgmt_group_list_end == curr) { + mgmt_group_list_end = prev; } + + curr->mg_next = NULL; } static struct mgmt_group *
