Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/fluent-bit/flb_router.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ struct flb_route {

struct flb_input_routes {
flb_sds_t input_name;
flb_sds_t plugin_name;
int has_alias;
struct flb_input_instance *instance;
struct cfl_list processors;
struct cfl_list routes;
struct cfl_list _head;
Expand Down
132 changes: 115 additions & 17 deletions src/flb_router_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,10 @@ static void input_routes_destroy(struct flb_input_routes *input)
flb_sds_destroy(input->input_name);
}

if (input->plugin_name) {
flb_sds_destroy(input->plugin_name);
}

flb_free(input);
}

Expand Down Expand Up @@ -1080,6 +1084,8 @@ static int parse_input_section(struct flb_cf_section *section,
struct cfl_list *input_routes,
struct flb_config *config)
{
uint32_t mask;
size_t before_count;
struct flb_input_routes *input;
struct cfl_kvlist *kvlist;
struct cfl_variant *name_var;
Expand All @@ -1088,8 +1094,7 @@ static int parse_input_section(struct flb_cf_section *section,
struct cfl_kvlist *routes_kvlist;
struct cfl_list *head;
struct cfl_kvpair *pair;
uint32_t mask;
size_t before_count;
struct cfl_variant *alias_var;

if (!section || !input_routes) {
return -1;
Expand Down Expand Up @@ -1130,13 +1135,29 @@ static int parse_input_section(struct flb_cf_section *section,
cfl_list_init(&input->_head);
cfl_list_init(&input->processors);
cfl_list_init(&input->routes);
input->has_alias = FLB_FALSE;
input->instance = NULL;

input->input_name = copy_from_cfl_sds(name_var->data.as_string);
if (!input->input_name) {
input->plugin_name = copy_from_cfl_sds(name_var->data.as_string);
if (!input->plugin_name) {
flb_free(input);
return -1;
}

alias_var = cfl_kvlist_fetch(kvlist, "alias");
if (alias_var && alias_var->type == CFL_VARIANT_STRING &&
cfl_sds_len(alias_var->data.as_string) > 0) {
input->input_name = copy_from_cfl_sds(alias_var->data.as_string);
input->has_alias = FLB_TRUE;
}
else {
input->input_name = copy_from_cfl_sds(name_var->data.as_string);
}
if (!input->input_name) {
input_routes_destroy(input);
return -1;
}

processors_var = cfl_kvlist_fetch(kvlist, "processors");
if (processors_var) {
if (parse_processors(processors_var, &input->processors, config) != 0) {
Expand Down Expand Up @@ -1223,33 +1244,110 @@ int flb_router_config_parse(struct flb_cf *cf,
}

/* Apply parsed router configuration to actual input/output instances */
static int input_instance_already_selected(struct flb_config *config,
struct flb_input_routes *current,
struct flb_input_instance *candidate)
{
struct cfl_list *head;
struct flb_input_routes *routes;

if (!config || !candidate) {
return FLB_FALSE;
}

cfl_list_foreach(head, &config->input_routes) {
routes = cfl_list_entry(head, struct flb_input_routes, _head);

if (routes == current) {
continue;
}

if (routes->instance == candidate) {
return FLB_TRUE;
}
}

return FLB_FALSE;
}

static struct flb_input_instance *find_input_instance(struct flb_config *config,
flb_sds_t name)
struct flb_input_routes *routes)
{
struct mk_list *head;
struct flb_input_instance *ins;
size_t key_len;

if (!config || !name) {
if (!config || !routes) {
return NULL;
}

mk_list_foreach(head, &config->inputs) {
ins = mk_list_entry(head, struct flb_input_instance, _head);
if (routes->instance) {
return routes->instance;
}

if (!ins->p) {
continue;
if (routes->has_alias && routes->input_name) {
mk_list_foreach(head, &config->inputs) {
ins = mk_list_entry(head, struct flb_input_instance, _head);

if (!ins->p || !ins->alias) {
continue;
}

if (strcmp(ins->alias, routes->input_name) == 0 &&
input_instance_already_selected(config, routes, ins) == FLB_FALSE) {
routes->instance = ins;
return ins;
}
}
}

if (ins->alias && strcmp(ins->alias, name) == 0) {
return ins;
if (routes->input_name) {
mk_list_foreach(head, &config->inputs) {
ins = mk_list_entry(head, struct flb_input_instance, _head);

if (!ins->p) {
continue;
}

if (strcmp(ins->name, routes->input_name) == 0 &&
input_instance_already_selected(config, routes, ins) == FLB_FALSE) {
routes->instance = ins;
return ins;
}
}
}

if (strcmp(ins->name, name) == 0) {
return ins;
if (routes->plugin_name) {
mk_list_foreach(head, &config->inputs) {
ins = mk_list_entry(head, struct flb_input_instance, _head);

if (!ins->p || !ins->p->name) {
continue;
}

if (strcmp(ins->p->name, routes->plugin_name) == 0 &&
input_instance_already_selected(config, routes, ins) == FLB_FALSE) {
routes->instance = ins;
return ins;
}
}
}

if (ins->p->name && strcmp(ins->p->name, name) == 0) {
return ins;
if (routes->input_name) {
key_len = flb_sds_len(routes->input_name);

mk_list_foreach(head, &config->inputs) {
ins = mk_list_entry(head, struct flb_input_instance, _head);

if (!ins->p || key_len == 0) {
continue;
}

if (strncmp(ins->name, routes->input_name, key_len) == 0 &&
input_instance_already_selected(config, routes, ins) == FLB_FALSE) {
routes->instance = ins;
return ins;
}
}
}

Expand Down Expand Up @@ -1355,7 +1453,7 @@ int flb_router_apply_config(struct flb_config *config)
cfl_list_foreach(input_head, &config->input_routes) {
input_routes = cfl_list_entry(input_head, struct flb_input_routes, _head);

input_ins = find_input_instance(config, input_routes->input_name);
input_ins = find_input_instance(config, input_routes);
if (!input_ins) {
flb_warn("[router] could not find input instance '%s' for routes",
input_routes->input_name ? input_routes->input_name : "(null)");
Expand Down
3 changes: 3 additions & 0 deletions tests/internal/conditional_routing.c
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,8 @@ static void setup_conditional_routes(struct flb_input_routes *input_routes,
cfl_list_init(&input_routes->_head);
cfl_list_init(&input_routes->routes);
input_routes->input_name = flb_sds_create("tail");
input_routes->plugin_name = flb_sds_create("tail");
input_routes->has_alias = FLB_FALSE;
Comment on lines +886 to +887
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

LGTM! Test setup properly initializes new routing fields.

The initialization correctly sets plugin_name to "tail" and explicitly disables alias usage with has_alias = FLB_FALSE, which aligns with the test scenario.

However, verify that if flb_sds_create("tail") fails (returns NULL), subsequent code handles it gracefully. The test doesn't check for NULL return from flb_sds_create.


🏁 Script executed:

#!/bin/bash
# Check if there's error handling for plugin_name allocation failures in tests
rg -n -A5 -B2 'plugin_name = flb_sds_create' tests/internal/conditional_routing.c

Length of output: 339



---

🏁 Script executed:

```shell
#!/bin/bash
# Get the full setup_conditional_routes function to see error handling pattern
rg -n -B10 'input_routes->plugin_name = flb_sds_create' tests/internal/conditional_routing.c | head -50

Length of output: 672


🏁 Script executed:

#!/bin/bash
# Check the complete function definition and any error handling
rg -n -A30 'setup_conditional_routes' tests/internal/conditional_routing.c | head -80

Length of output: 3586


🏁 Script executed:

#!/bin/bash
# Look for NULL checks on input_routes fields after initialization
rg -n -A15 'input_routes->has_alias = FLB_FALSE' tests/internal/conditional_routing.c

Length of output: 677



---

🏁 Script executed:

```shell
#!/bin/bash
# Find the exact function signature/definition
rg -n -B5 'setup_conditional_routes\(' tests/internal/conditional_routing.c | grep -A5 'setup_conditional_routes'

Length of output: 1144


🏁 Script executed:

#!/bin/bash
# Check if other test setup helpers validate allocations
rg -n -A10 'flb_sds_create' tests/internal/conditional_routing.c | grep -B2 -A3 'NULL'

Length of output: 267


🏁 Script executed:

#!/bin/bash
# Look for the actual setup_conditional_routes function definition (not calls)
ast-grep --pattern 'void setup_conditional_routes($_) { $$$ }'

Length of output: 0



---

🏁 Script executed:

```shell
#!/bin/bash
# Get the complete setup_conditional_routes function body
rg -n -A60 'static void setup_conditional_routes' tests/internal/conditional_routing.c | head -100

Length of output: 2982


Add NULL validation for allocation failures in setup_conditional_routes.

The function makes 7 flb_sds_create calls (lines 885–886, 893, 900, 907, 914, 921, 928) without checking for NULL returns. This is inconsistent with the validation pattern used elsewhere in the test file (line 229: TEST_CHECK(rule->field != NULL && rule->op != NULL && rule->value != NULL);). If any allocation fails, the function will pass NULL pointers to subsequent operations like cfl_list_add, causing undefined behavior. Add TEST_CHECK assertions to validate all allocations before using them.

🤖 Prompt for AI Agents
In tests/internal/conditional_routing.c around lines 885–928, multiple
flb_sds_create calls (lines 885–886, 893, 900, 907, 914, 921, 928) are used
without NULL checks; add TEST_CHECK assertions immediately after each
flb_sds_create to verify the returned pointer is not NULL before it is assigned
or used (e.g., TEST_CHECK(input_routes->plugin_name != NULL)); do this for every
allocation site so subsequent calls like cfl_list_add never receive NULL
pointers.


/* Route 1: info_logs */
memset(route1, 0, sizeof(struct flb_route));
Expand Down Expand Up @@ -971,6 +973,7 @@ static void cleanup_conditional_routing_instances(struct flb_config *config,
flb_sds_destroy(output2->alias);
flb_sds_destroy(output3->alias);
flb_sds_destroy(input_routes->input_name);
flb_sds_destroy(input_routes->plugin_name);
flb_sds_destroy(route1->name);
flb_sds_destroy(route2->name);
flb_sds_destroy(route3->name);
Expand Down
Loading
Loading