makeGroup()'s existing-group update path (hit whenever a config-push re-applies a group name that already has members, e.g. a retried config push during controller failover) released xce_g_member_t.u.name via FREEUP() (plain free()). u.name is allocated by makeString(), an rtti-managed, refcounted pointer that is not a malloc()-base address -- freeing it directly corrupts the heap. group_killer() in the same file already releases the identical field correctly via dereference(). Switch both FREEUP(m->u.name) call sites to dereference(m->u.name) to match. Add a regression test that re-applies config for the same group name twice, reproducing the exact ASAN bad-free at group.c:234 pre-fix. This is the root cause of the reproducible xce_scheduler "free(): invalid pointer" SIGABRT crashes seen during 3-attempt controller-failover config-push retries (8 confirmed core dumps). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
316 lines
6.1 KiB
C
316 lines
6.1 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unity.h>
|
|
|
|
#include "group.h"
|
|
#include "utils.h"
|
|
#include "xstring.h"
|
|
|
|
static void test_all(void)
|
|
{
|
|
var mgr;
|
|
xce_group_t* all = NULL;
|
|
int rc = 0;
|
|
|
|
groupmgr_init(&mgr, 16, 16);
|
|
|
|
all = get_group(mgr, "all");
|
|
|
|
TEST_ASSERT_TRUE(all != NULL);
|
|
|
|
rc = is_in_group(all, "rshen");
|
|
|
|
TEST_ASSERT_TRUE(rc > 0);
|
|
|
|
destroy(mgr);
|
|
}
|
|
|
|
static void test_empty(void)
|
|
{
|
|
var mgr;
|
|
xce_group_t* empty = NULL;
|
|
int rc = 0;
|
|
|
|
groupmgr_init(&mgr, 16, 16);
|
|
|
|
empty = get_group(mgr, "empty");
|
|
|
|
TEST_ASSERT_TRUE(empty != NULL);
|
|
|
|
rc = is_in_group(empty, "rshen");
|
|
|
|
TEST_ASSERT_TRUE(rc == 0);
|
|
|
|
destroy(mgr);
|
|
}
|
|
|
|
static void test_all_1(void)
|
|
{
|
|
var mgr;
|
|
xce_group_config_t gdata = {
|
|
.name = "g1",
|
|
.members = { .count = 1, .data = (char*[]) { "all" } }
|
|
};
|
|
|
|
xce_group_t* g = NULL;
|
|
int rc = 0;
|
|
|
|
groupmgr_init(&mgr, 16, 16);
|
|
|
|
g = makeGroup(mgr, &gdata, NULL);
|
|
|
|
TEST_ASSERT_TRUE(g != NULL);
|
|
|
|
rc = is_in_group(g, "rshen");
|
|
|
|
TEST_ASSERT_TRUE(rc > 0);
|
|
|
|
destroy(mgr);
|
|
}
|
|
|
|
static void test_all_2(void)
|
|
{
|
|
var mgr;
|
|
xce_group_config_t gdata = {
|
|
.name = "g1",
|
|
.members = { .count = 2, .data = (char*[]) { "g2", "all" } }
|
|
};
|
|
|
|
xce_group_t* g = NULL;
|
|
int rc = 0;
|
|
|
|
groupmgr_init(&mgr, 16, 16);
|
|
|
|
g = makeGroup(mgr, &gdata, NULL);
|
|
|
|
TEST_ASSERT_TRUE(g != NULL);
|
|
|
|
rc = is_in_group(g, "rshen");
|
|
|
|
TEST_ASSERT_TRUE(rc > 0);
|
|
|
|
destroy(mgr);
|
|
}
|
|
|
|
static void test_empty_1(void)
|
|
{
|
|
var mgr;
|
|
xce_group_config_t gdata = {
|
|
.name = "g1",
|
|
.ex_members = { .count = 1, .data = (char*[]) { "all" } }
|
|
};
|
|
|
|
xce_group_t* g = NULL;
|
|
int rc = 0;
|
|
|
|
groupmgr_init(&mgr, 16, 16);
|
|
|
|
g = makeGroup(mgr, &gdata, NULL);
|
|
|
|
TEST_ASSERT_TRUE(g != NULL);
|
|
|
|
rc = is_in_group(g, "rshen");
|
|
|
|
TEST_ASSERT_TRUE(rc == 0);
|
|
|
|
destroy(mgr);
|
|
}
|
|
|
|
static void test_empty_2(void)
|
|
{
|
|
var mgr;
|
|
xce_group_config_t gdata = {
|
|
.name = "g1",
|
|
.members = { .count = 1, .data = (char*[]) { "empty" } }
|
|
};
|
|
|
|
xce_group_t* g = NULL;
|
|
int rc = 0;
|
|
|
|
groupmgr_init(&mgr, 16, 16);
|
|
|
|
g = makeGroup(mgr, &gdata, NULL);
|
|
|
|
TEST_ASSERT_TRUE(g != NULL);
|
|
|
|
rc = is_in_group(g, "rshen");
|
|
|
|
TEST_ASSERT_TRUE(rc == 0);
|
|
|
|
destroy(mgr);
|
|
}
|
|
|
|
static void test_include(void)
|
|
{
|
|
var mgr;
|
|
xce_group_config_t gdata = {
|
|
.name = "g1",
|
|
.members = { .count = 1, .data = (char*[]) { "rshen" } }
|
|
};
|
|
|
|
xce_group_t* g = NULL;
|
|
int rc = 0;
|
|
|
|
groupmgr_init(&mgr, 16, 16);
|
|
|
|
g = makeGroup(mgr, &gdata, NULL);
|
|
|
|
TEST_ASSERT_TRUE(g != NULL);
|
|
|
|
rc = is_in_group(g, "rshen");
|
|
|
|
TEST_ASSERT_TRUE(rc > 0);
|
|
|
|
destroy(mgr);
|
|
}
|
|
|
|
static void test_exclude(void)
|
|
{
|
|
var mgr;
|
|
xce_group_config_t gdata = {
|
|
.name = "g1",
|
|
.members = { .count = 1, .data = (char*[]) { "all" } },
|
|
.ex_members = { .count = 1, .data = (char*[]) { "rshen" } }
|
|
};
|
|
|
|
xce_group_t* g = NULL;
|
|
int rc = 0;
|
|
|
|
groupmgr_init(&mgr, 16, 16);
|
|
|
|
g = makeGroup(mgr, &gdata, NULL);
|
|
|
|
TEST_ASSERT_TRUE(g != NULL);
|
|
|
|
rc = is_in_group(g, "rshen");
|
|
|
|
TEST_ASSERT_TRUE(rc == 0);
|
|
|
|
destroy(mgr);
|
|
}
|
|
|
|
static void test_nest(void)
|
|
{
|
|
var mgr;
|
|
xce_group_config_t gdata1 = {
|
|
.name = "g1",
|
|
.members = { .count = 1, .data = (char*[]) { "rshen" } }
|
|
};
|
|
xce_group_config_t gdata2 = {
|
|
.name = "g2",
|
|
.members = { .count = 1, .data = (char*[]) { "g1" } }
|
|
};
|
|
|
|
xce_group_t* g = NULL;
|
|
int rc = 0;
|
|
|
|
groupmgr_init(&mgr, 16, 16);
|
|
|
|
g = makeGroup(mgr, &gdata1, NULL);
|
|
|
|
TEST_ASSERT_TRUE(g != NULL);
|
|
|
|
g = makeGroup(mgr, &gdata2, NULL);
|
|
|
|
TEST_ASSERT_TRUE(g != NULL);
|
|
|
|
rc = is_in_group(g, "rshen");
|
|
|
|
TEST_ASSERT_TRUE(rc != 0);
|
|
|
|
destroy(mgr);
|
|
}
|
|
|
|
static void test_nest2(void)
|
|
{
|
|
var mgr;
|
|
xce_group_config_t gdata1 = {
|
|
.name = "g1",
|
|
.members = { .count = 1, .data = (char*[]) { "rshen" } }
|
|
};
|
|
xce_group_config_t gdata2 = {
|
|
.name = "g2",
|
|
.members = { .count = 1, .data = (char*[]) { "all" } },
|
|
.ex_members = { .count = 1, .data = (char*[]) { "g1" } }
|
|
};
|
|
|
|
xce_group_t* g = NULL;
|
|
int rc = 0;
|
|
|
|
groupmgr_init(&mgr, 16, 16);
|
|
|
|
g = makeGroup(mgr, &gdata1, NULL);
|
|
|
|
TEST_ASSERT_TRUE(g != NULL);
|
|
|
|
g = makeGroup(mgr, &gdata2, NULL);
|
|
|
|
TEST_ASSERT_TRUE(g != NULL);
|
|
|
|
rc = is_in_group(g, "rshen");
|
|
|
|
TEST_ASSERT_TRUE(rc == 0);
|
|
|
|
destroy(mgr);
|
|
}
|
|
|
|
static void test_reconfigure_same_group_members(void)
|
|
{
|
|
var mgr;
|
|
xce_group_config_t gdata1 = {
|
|
.name = "g1",
|
|
.members = { .count = 1, .data = (char*[]) { "rshen" } }
|
|
};
|
|
xce_group_config_t gdata2 = {
|
|
.name = "g1",
|
|
.members = { .count = 1, .data = (char*[]) { "alice" } }
|
|
};
|
|
|
|
xce_group_t* g = NULL;
|
|
int rc = 0;
|
|
|
|
groupmgr_init(&mgr, 16, 16);
|
|
|
|
g = makeGroup(mgr, &gdata1, NULL);
|
|
|
|
TEST_ASSERT_TRUE(g != NULL);
|
|
|
|
/* Re-applying config for the SAME group name (e.g. a repeated config
|
|
* push) exercises makeGroup()'s existing-group update path, which must
|
|
* release the old members without corrupting the heap. */
|
|
g = makeGroup(mgr, &gdata2, NULL);
|
|
|
|
TEST_ASSERT_TRUE(g != NULL);
|
|
|
|
rc = is_in_group(g, "alice");
|
|
|
|
TEST_ASSERT_TRUE(rc != 0);
|
|
|
|
rc = is_in_group(g, "rshen");
|
|
|
|
TEST_ASSERT_TRUE(rc == 0);
|
|
|
|
destroy(mgr);
|
|
}
|
|
|
|
void test_group(void)
|
|
{
|
|
printf("\n>> group test\n\n");
|
|
|
|
xstring_table_init(139);
|
|
|
|
RUN_TEST(test_all);
|
|
RUN_TEST(test_empty);
|
|
RUN_TEST(test_all_1);
|
|
RUN_TEST(test_all_2);
|
|
RUN_TEST(test_empty_1);
|
|
RUN_TEST(test_empty_2);
|
|
RUN_TEST(test_include);
|
|
RUN_TEST(test_exclude);
|
|
RUN_TEST(test_nest);
|
|
RUN_TEST(test_nest2);
|
|
RUN_TEST(test_reconfigure_same_group_members);
|
|
|
|
xstring_table_fini();
|
|
}
|