v1.1.5 - Fix CRITICAL segfault: Use wrapper nodes for no-kind-filter subscriptions
The kind index optimization in v1.1.4 introduced a critical bug that caused segmentation faults in production. The bug was in add_subscription_to_kind_index() which directly assigned sub->next for no-kind-filter subscriptions, corrupting the main active_subscriptions linked list. Root Cause: - subscription_t has only ONE 'next' pointer used by active_subscriptions list - Code tried to reuse 'next' for no_kind_filter_subs list - This overwrote the active_subscriptions linkage, breaking list traversal - Result: segfaults when iterating subscriptions Fix: - Added no_kind_filter_node_t wrapper structure (like kind_subscription_node_t) - Changed no_kind_filter_subs from subscription_t* to no_kind_filter_node_t* - Updated add/remove functions to use wrapper nodes - Updated broadcast function to iterate through wrapper nodes This follows the same pattern already used for kind_index entries and prevents any corruption of the subscription structure's next pointer.
This commit is contained in:
@@ -100,10 +100,17 @@ void add_subscription_to_kind_index(subscription_t* sub) {
|
||||
filter = filter->next;
|
||||
}
|
||||
|
||||
// If subscription has no kind filter, add to no-kind-filter list
|
||||
// If subscription has no kind filter, add to no-kind-filter list using wrapper node
|
||||
if (!has_kind_filter) {
|
||||
sub->next = g_subscription_manager.no_kind_filter_subs;
|
||||
g_subscription_manager.no_kind_filter_subs = sub;
|
||||
no_kind_filter_node_t* node = malloc(sizeof(no_kind_filter_node_t));
|
||||
if (!node) {
|
||||
DEBUG_ERROR("add_subscription_to_kind_index: failed to allocate no-kind-filter node");
|
||||
return;
|
||||
}
|
||||
|
||||
node->subscription = sub;
|
||||
node->next = g_subscription_manager.no_kind_filter_subs;
|
||||
g_subscription_manager.no_kind_filter_subs = node;
|
||||
DEBUG_TRACE("KIND_INDEX: Added subscription '%s' to no-kind-filter list", sub->id);
|
||||
}
|
||||
}
|
||||
@@ -130,11 +137,13 @@ void remove_subscription_from_kind_index(subscription_t* sub) {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from no-kind-filter list
|
||||
subscription_t** current = &g_subscription_manager.no_kind_filter_subs;
|
||||
// Remove from no-kind-filter list if present
|
||||
no_kind_filter_node_t** current = &g_subscription_manager.no_kind_filter_subs;
|
||||
while (*current) {
|
||||
if (*current == sub) {
|
||||
if ((*current)->subscription == sub) {
|
||||
no_kind_filter_node_t* to_free = *current;
|
||||
*current = (*current)->next;
|
||||
free(to_free);
|
||||
DEBUG_TRACE("KIND_INDEX: Removed subscription '%s' from no-kind-filter list", sub->id);
|
||||
break;
|
||||
}
|
||||
@@ -797,12 +806,12 @@ int broadcast_event_to_subscriptions(cJSON* event) {
|
||||
}
|
||||
|
||||
// Add subscriptions with no kind filter (must check against all events)
|
||||
subscription_t* no_kind_sub = g_subscription_manager.no_kind_filter_subs;
|
||||
while (no_kind_sub && candidate_count < MAX_TOTAL_SUBSCRIPTIONS) {
|
||||
if (no_kind_sub->active) {
|
||||
candidates_to_check[candidate_count++] = no_kind_sub;
|
||||
no_kind_filter_node_t* no_kind_node = g_subscription_manager.no_kind_filter_subs;
|
||||
while (no_kind_node && candidate_count < MAX_TOTAL_SUBSCRIPTIONS) {
|
||||
if (no_kind_node->subscription && no_kind_node->subscription->active) {
|
||||
candidates_to_check[candidate_count++] = no_kind_node->subscription;
|
||||
}
|
||||
no_kind_sub = no_kind_sub->next;
|
||||
no_kind_node = no_kind_node->next;
|
||||
}
|
||||
|
||||
DEBUG_TRACE("BROADCAST: Checking %d candidate subscriptions (kind index optimization)", candidate_count);
|
||||
|
||||
Reference in New Issue
Block a user