@cryptotaxi247 / netdata-1 / commits / cff3aaef9

Remove VLA (variable-length arrays) from collectors (#22066)

thiagoftsm committed Mar 30, 2026 at 22:04 UTC cff3aaef92e644bdf94b132064471f0f9a5336ea
12 files changed +83 -45
src/collectors/apps.plugin/apps_os_windows.c
+7 -4
@@ -565,8 +565,7 @@ STRING *GetProcessFriendlyNameFromPathSanitized(WCHAR *path) {
565 static STRING *GetNameFromCmdlineSanitized(struct pid_stat *p) {
566 if(!p->cmdline) return NULL;
567
568 - char buf[string_strlen(p->cmdline) + 1];
569 - memcpy(buf, string2str(p->cmdline), sizeof(buf));
568 + char *buf = strdupz(string2str(p->cmdline));
569 char *words[100];
570 size_t num_words = quoted_strings_splitter(buf, words, 100, isspace_map_pluginsd);
571
@@ -574,15 +573,19 @@ static STRING *GetNameFromCmdlineSanitized(struct pid_stat *p) {
573 // find -s SERVICE in the command line
574 for(size_t i = 0; i < num_words ;i++) {
575 if(strcmp(words[i], "-s") == 0 && i + 1 < num_words) {
577 - char service[strlen(words[i + 1]) + sizeof(SERVICE_PREFIX)]; // sizeof() includes a null
576 + char *service = mallocz(strlen(words[i + 1]) + sizeof(SERVICE_PREFIX)); // sizeof() includes a null
577 strcpy(service, SERVICE_PREFIX);
578 strcpy(&service[sizeof(SERVICE_PREFIX) - 1], words[i + 1]);
579 sanitize_apps_plugin_chart_meta(service);
581 - return string_strdupz(service);
580 + STRING *sanitized = string_strdupz(service);
581 + freez(service);
582 + freez(buf);
583 + return sanitized;
584 }
585 }
586 }
587
588 + freez(buf);
589 return NULL;
590 }
591
src/collectors/apps.plugin/apps_pid.c
+15 -8
@@ -405,8 +405,7 @@ static void remove_extension(char *name) {
405 static inline STRING *comm_from_cmdline_param_sanitized(STRING *cmdline) {
406 if(!cmdline) return NULL;
407
408 - char buf[string_strlen(cmdline) + 1];
409 - memcpy(buf, string2str(cmdline), sizeof(buf));
408 + char *buf = strdupz(string2str(cmdline));
409
410 char *words[100];
411 size_t num_words = quoted_strings_splitter_whitespace(buf, words, 100);
@@ -424,19 +423,21 @@ static inline STRING *comm_from_cmdline_param_sanitized(STRING *cmdline) {
423 name++;
424 remove_extension(name);
425 sanitize_apps_plugin_chart_meta(name);
427 - return string_strdupz(name);
426 + STRING *sanitized = string_strdupz(name);
427 + freez(buf);
428 + return sanitized;
429 }
430 }
431 }
432
433 + freez(buf);
434 return NULL;
435 }
436
437 static inline STRING *comm_from_cmdline_sanitized(STRING *comm, STRING *cmdline) {
438 if(!cmdline) return NULL;
439
438 - char buf[string_strlen(cmdline) + 1];
439 - memcpy(buf, string2str(cmdline), sizeof(buf));
440 + char *buf = strdupz(string2str(cmdline));
441
442 size_t comm_len = string_strlen(comm);
443 char *start = strstr(buf, string2str(comm));
@@ -456,9 +457,12 @@ static inline STRING *comm_from_cmdline_sanitized(STRING *comm, STRING *cmdline)
457
458 remove_extension(start);
459 sanitize_apps_plugin_chart_meta(start);
459 - return string_strdupz(start);
460 + STRING *sanitized = string_strdupz(start);
461 + freez(buf);
462 + return sanitized;
463 }
464
465 + freez(buf);
466 return NULL;
467 }
468
@@ -505,16 +509,19 @@ void update_pid_comm(struct pid_stat *p, const char *comm) {
509
510 // some process names have ( and ), remove the parenthesis
511 size_t len = strlen(comm);
508 - char buf[len + 1];
512 + char *buf;
513 if(comm[0] == '(' && comm[len - 1] == ')') {
514 + buf = mallocz(len - 1);
515 memcpy(buf, &comm[1], len - 2);
516 buf[len - 2] = '\0';
517 }
518 else
514 - memcpy(buf, comm, sizeof(buf));
519 + buf = strdupz(comm);
520
521 sanitize_apps_plugin_chart_meta(buf);
522 + string_freez(p->comm);
523 p->comm = string_strdupz(buf);
524 + freez(buf);
525 p->is_manager = is_process_a_manager(p);
526 p->is_aggregator = is_process_an_aggregator(p);
527
src/collectors/apps.plugin/apps_pid_match.c
+4 -5
@@ -102,13 +102,12 @@ APPS_MATCH pid_match_create(const char *comm) {
102 };
103
104 // copy comm to make changes to it
105 - size_t len = strlen(comm);
106 - char buf[len + 1];
107 - memcpy(buf, comm, sizeof(buf));
105 + char *buf = strdupz(comm);
106
107 trim_all(buf);
108 + size_t len = strlen(buf);
109
111 - if(buf[len - 1] == '*') {
110 + if(len && buf[len - 1] == '*') {
111 buf[--len] = '\0';
112 m.starts_with = true;
113 }
@@ -124,6 +123,7 @@ APPS_MATCH pid_match_create(const char *comm) {
123 if(strchr(nid, '*'))
124 m.pattern = simple_pattern_create(comm, SIMPLE_PATTERN_NO_SEPARATORS, SIMPLE_PATTERN_EXACT, false);
125
126 + freez(buf);
127 return m;
128 }
129
@@ -131,4 +131,3 @@ void pid_match_cleanup(APPS_MATCH *m) {
131 string_freez(m->compare);
132 simple_pattern_free(m->pattern);
133 }
134 -
src/collectors/apps.plugin/apps_targets.c
+4 -3
@@ -5,14 +5,15 @@
5 pid_t INIT_PID = OS_INIT_PID;
6
7 static STRING *get_clean_name(STRING *name) {
8 - char buf[string_strlen(name) + 1];
9 - memcpy(buf, string2str(name), string_strlen(name) + 1);
8 + char *buf = strdupz(string2str(name));
9 netdata_fix_chart_name(buf);
10
11 for (char *d = buf; *d ; d++)
12 if (*d == '.') *d = '_';
13
15 - return string_strdupz(buf);
14 + STRING *clean = string_strdupz(buf);
15 + freez(buf);
16 + return clean;
17 }
18
19 static inline STRING *get_numeric_string(uint64_t n) {
src/collectors/ebpf.plugin/libbpf_api/ebpf_library.c
+6 -2
@@ -1432,8 +1432,7 @@ static void ebpf_parse_service_list(void **out, const char *service)
1432 */
1433 static void ebpf_parse_port_list(void **out, const char *range_param)
1434 {
1435 - char range[strlen(range_param) + 1];
1436 - strncpyz(range, range_param, strlen(range_param));
1435 + char *range = strdupz(range_param);
1436
1437 int first, last;
1438 ebpf_network_viewer_port_list_t **list = (ebpf_network_viewer_port_list_t **)out;
@@ -1459,6 +1458,7 @@ static void ebpf_parse_port_list(void **out, const char *range_param)
1458 netdata_log_info(
1459 "The exclusion cannot be in the second part of the range, the range %s will be ignored.", copied);
1460 freez(copied);
1461 + freez(range);
1462 return;
1463 }
1464 last = str2i((const char *)end);
@@ -1470,6 +1470,7 @@ static void ebpf_parse_port_list(void **out, const char *range_param)
1470 if (first < NETDATA_MINIMUM_PORT_VALUE || first > NETDATA_MAXIMUM_PORT_VALUE) {
1471 netdata_log_info("The first port %d of the range \"%s\" is invalid and it will be ignored!", first, copied);
1472 freez(copied);
1473 + freez(range);
1474 return;
1475 }
1476
@@ -1480,6 +1481,7 @@ static void ebpf_parse_port_list(void **out, const char *range_param)
1481 netdata_log_info(
1482 "The second port %d of the range \"%s\" is invalid and the whole range will be ignored!", last, copied);
1483 freez(copied);
1484 + freez(range);
1485 return;
1486 }
1487
@@ -1487,6 +1489,7 @@ static void ebpf_parse_port_list(void **out, const char *range_param)
1489 netdata_log_info(
1490 "The specified order %s is wrong, the smallest value is always the first, it will be ignored!", copied);
1491 freez(copied);
1492 + freez(range);
1493 return;
1494 }
1495
@@ -1501,6 +1504,7 @@ fillenvpl:
1504 w->cmp_last = (uint16_t)last;
1505
1506 fill_port_list(list, w);
1507 + freez(range);
1508 }
1509
1510 /**
src/collectors/freeipmi.plugin/freeipmi_plugin.c
+4 -2
@@ -1488,8 +1488,7 @@ static void freeimi_function_sensors(const char *transaction, char *function __m
1488 buffer_json_member_add_boolean(wb, "has_history", false);
1489 buffer_json_member_add_string(wb, "help", "View IPMI sensor readings and its state");
1490
1491 - char function_copy[strlen(function) + 1];
1492 - memcpy(function_copy, function, sizeof(function_copy));
1491 + char *function_copy = strdupz(function);
1492 char *words[1024];
1493 size_t num_words = quoted_strings_splitter_whitespace(function_copy, words, 1024);
1494 for(size_t i = 1; i < num_words ;i++) {
@@ -1499,10 +1498,13 @@ static void freeimi_function_sensors(const char *transaction, char *function __m
1498 buffer_json_array_close(wb); // accepted_params
1499 buffer_json_member_add_array(wb, "required_params");
1500 buffer_json_array_close(wb); // required_params
1501 + freez(function_copy);
1502 goto close_and_send;
1503 }
1504 }
1505
1506 + freez(function_copy);
1507 +
1508 buffer_json_member_add_array(wb, "data");
1509
1510 struct sensor *sn;
src/collectors/log2journal/log2journal-yaml.c
+3 -2
@@ -217,13 +217,14 @@ static void yaml_print_multiline_value(const char *s, size_t depth) {
217 if(next) next++;
218
219 size_t len = next ? (size_t)(next - s) : strlen(s);
220 - char buf[len + 1];
221 - copy_to_buffer(buf, sizeof(buf), s, len);
220 + char *buf = mallocz(len + 1);
221 + copy_to_buffer(buf, len + 1, s, len);
222
223 fprintf(stderr, "%.*s%s%s",
224 (int)(depth * 2), " ",
225 buf, next ? "" : "\n");
226
227 + freez(buf);
228 s = next;
229 } while(s && *s);
230 }
src/collectors/network-viewer.plugin/network-viewer.c
+4 -2
@@ -470,8 +470,7 @@ void network_viewer_function(const char *transaction, char *function __maybe_unu
470 buffer_json_array_close(wb); // required_params
471 #endif
472
473 - char function_copy[strlen(function) + 1];
474 - memcpy(function_copy, function, sizeof(function_copy));
473 + char *function_copy = strdupz(function);
474 char *words[1024];
475 size_t num_words = quoted_strings_splitter_whitespace(function_copy, words, 1024);
476 for(size_t i = 1; i < num_words ;i++) {
@@ -483,10 +482,13 @@ void network_viewer_function(const char *transaction, char *function __maybe_unu
482 aggregated = false;
483 }
484 else if(strcmp(param, "info") == 0) {
485 + freez(function_copy);
486 goto close_and_send;
487 }
488 }
489
490 + freez(function_copy);
491 +
492 if(aggregated) {
493 buffer_json_member_add_object(wb, "aggregated_view");
494 {
src/collectors/statsd.plugin/statsd.c
+9 -3
@@ -1551,7 +1551,8 @@ static inline void statsd_get_metric_type_and_id(STATSD_METRIC *m, char *type, c
1551 // ${STATSD_CHART_PREFIX} + "_" + the first word of ${METRIC_NAME}
1552
1553 // find the first word of ${METRIC_NAME}
1554 - char firstword[len + 1], *s = "";
1554 + char *firstword = mallocz(len + 1);
1555 + char *s = "";
1556 strncpyz(firstword, m->name, len);
1557 for (s = firstword; *s ; s++) {
1558 if (unlikely(*s == '.' || *s == '_')) {
@@ -1574,6 +1575,8 @@ static inline void statsd_get_metric_type_and_id(STATSD_METRIC *m, char *type, c
1575 else
1576 snprintfz(id, len, "%s", metrictype);
1577
1578 + freez(firstword);
1579 +
1580 // for the context, we want the full of both the above, separated with a dot (type.id):
1581 snprintfz(context, RRD_ID_LENGTH_MAX, "%s.%s", type, id);
1582
@@ -2136,7 +2139,7 @@ static inline void check_if_metric_is_for_app(STATSD_INDEX *index, STATSD_METRIC
2139 if(unlikely(dim->metric_pattern)) {
2140 size_t dim_name_len = strlen(dim->name);
2141 size_t wildcarded_len = dim_name_len + strlen(m->name) + 1;
2139 - char wildcarded[wildcarded_len];
2142 + char *wildcarded = mallocz(wildcarded_len);
2143
2144 strcpy(wildcarded, dim->name);
2145 char *ws = &wildcarded[dim_name_len];
@@ -2175,6 +2178,8 @@ static inline void check_if_metric_is_for_app(STATSD_INDEX *index, STATSD_METRIC
2178 // the new dimension is appended to the list
2179 // so, it will be matched and linked later too
2180 }
2181 +
2182 + freez(wildcarded);
2183 }
2184 else if(!dim->value_ptr && dim->metric_hash == m->hash && !strcmp(dim->metric, m->name)) {
2185 // we have a match - this metric should be linked to this dimension
@@ -2212,7 +2217,7 @@ static inline RRDDIM *statsd_add_dim_to_app_chart(STATSD_APP *app, STATSD_APP_CH
2217 // the same metric is found multiple times
2218
2219 size_t len = strlen(dim->metric) + 100;
2215 - char metric[ len + 1 ];
2220 + char *metric = mallocz(len + 1);
2221
2222 if(count_same_metric_value_type > 1) {
2223 // the same metric, with the same value type, is added multiple times
@@ -2224,6 +2229,7 @@ static inline RRDDIM *statsd_add_dim_to_app_chart(STATSD_APP *app, STATSD_APP_CH
2229 }
2230
2231 dim->rd = rrddim_add(chart->st, metric, dim->name, dim->multiplier, dim->divisor, dim->algorithm);
2232 + freez(metric);
2233 if(dim->flags != RRDDIM_FLAG_NONE) dim->rd->flags |= dim->flags;
2234 if(dim->options != RRDDIM_OPTION_NONE) dim->rd->collector.options |= dim->options;
2235 return dim->rd;
src/collectors/systemd-journal.plugin/systemd-journal-files.c
+17 -9
@@ -313,29 +313,35 @@ void nd_journal_file_update_header(const char *filename, struct nd_journal_file
313
314 static STRING *string_strdupz_source(const char *s, const char *e, size_t max_len, const char *prefix)
315 {
316 - char buf[max_len];
316 + size_t buf_size = max_len;
317 + size_t remaining = max_len;
318 + char *buf = mallocz(buf_size);
319 size_t len;
320 char *dst = buf;
321
322 if (prefix) {
323 len = strlen(prefix);
324 + if (len >= remaining)
325 + len = remaining - 1;
326 memcpy(buf, prefix, len);
327 dst = &buf[len];
324 - max_len -= len;
328 + remaining -= len;
329 }
330
331 len = e - s;
328 - if (len >= max_len)
329 - len = max_len - 1;
332 + if (len >= remaining)
333 + len = remaining - 1;
334 memcpy(dst, s, len);
335 dst[len] = '\0';
332 - buf[max_len - 1] = '\0';
336 + buf[buf_size - 1] = '\0';
337
338 for (size_t i = 0; buf[i]; i++)
339 if (!is_netdata_api_valid_character(buf[i]))
340 buf[i] = '_';
341
338 - return string_strdupz(buf);
342 + STRING *copy = string_strdupz(buf);
343 + freez(buf);
344 + return copy;
345 }
346
347 static void files_registry_insert_cb(const DICTIONARY_ITEM *item, void *value, void *data __maybe_unused)
@@ -365,9 +371,10 @@ static void files_registry_insert_cb(const DICTIONARY_ITEM *item, void *value, v
371 ;
372 if (d == e) {
373 // a valid IP address
368 - char ip[e - s + 1];
369 - memcpy(ip, s, e - s);
370 - ip[e - s] = '\0';
374 + size_t ip_len = (size_t)(e - s);
375 + char *ip = mallocz(ip_len + 1);
376 + memcpy(ip, s, ip_len);
377 + ip[ip_len] = '\0';
378 char buf[ND_SD_JOURNAL_MAX_SOURCE_LEN];
379 if (ip_to_hostname(ip, buf, sizeof(buf)))
380 njf->source =
@@ -376,6 +383,7 @@ static void files_registry_insert_cb(const DICTIONARY_ITEM *item, void *value, v
383 internal_error(true, "Cannot find the hostname for IP '%s'", ip);
384 njf->source = string_strdupz_source(s, e, ND_SD_JOURNAL_MAX_SOURCE_LEN, "remote-");
385 }
386 + freez(ip);
387 } else
388 njf->source = string_strdupz_source(s, e, ND_SD_JOURNAL_MAX_SOURCE_LEN, "remote-");
389 }
src/collectors/windows-events.plugin/windows-events-sources.c
+6 -3
@@ -581,18 +581,21 @@ void wevt_sources_scan(void) {
581 provider = "Netdata";
582
583 if(provider && *provider) {
584 - char buf[sizeof(WEVT_SOURCE_ALL_OF_PROVIDER_PREFIX) + strlen(provider)]; // sizeof() includes terminator
585 - snprintf(buf, sizeof(buf), WEVT_SOURCE_ALL_OF_PROVIDER_PREFIX "%s", provider);
584 + size_t buf_size = sizeof(WEVT_SOURCE_ALL_OF_PROVIDER_PREFIX) + strlen(provider); // sizeof() includes terminator
585 + char *buf = mallocz(buf_size);
586 + snprintf(buf, buf_size, WEVT_SOURCE_ALL_OF_PROVIDER_PREFIX "%s", provider);
587
588 trim_all(buf);
589 if(buf[0]) {
589 - for (size_t i = 0; i < sizeof(buf) - 1 && buf[i]; i++) {
590 + for (size_t i = 0; i < buf_size - 1 && buf[i]; i++) {
591 // remove character that may interfere with our parsing
592 if (isspace((uint8_t) buf[i]) || buf[i] == '%' || buf[i] == '+' || buf[i] == '|' || buf[i] == ':')
593 buf[i] = '_';
594 }
595 src.provider = string_strdupz(buf);
596 }
597 +
598 + freez(buf);
599 }
600
601 dictionary_set(wevt_sources, src.fullname, &src, sizeof(src));
src/collectors/windows-events.plugin/windows-events-xml.c
+4 -2
@@ -233,12 +233,13 @@ bool buffer_extract_and_print_xml_with_cb(BUFFER *buffer, const char *xml, size_
233 if(!*keys[k]) continue;
234
235 size_t klen = strlen(keys[k]);
236 - char tag_open[klen + 2];
236 + char *tag_open = mallocz(klen + 2);
237 tag_open[0] = '<';
238 strcpy(&tag_open[1], keys[k]);
239 tag_open[klen + 1] = '\0';
240
241 const char *new_start = strstr(start, tag_open);
242 + freez(tag_open);
243 if(!new_start)
244 return false;
245
@@ -253,7 +254,7 @@ bool buffer_extract_and_print_xml_with_cb(BUFFER *buffer, const char *xml, size_
254 }
255 start++; // skip the >
256
256 - char tag_close[klen + 4];
257 + char *tag_close = mallocz(klen + 4);
258 tag_close[0] = '<';
259 tag_close[1] = '/';
260 strcpy(&tag_close[2], keys[k]);
@@ -261,6 +262,7 @@ bool buffer_extract_and_print_xml_with_cb(BUFFER *buffer, const char *xml, size_
262 tag_close[klen + 3] = '\0';
263
264 const char *new_end = strstr(start, tag_close);
265 + freez(tag_close);
266 if(!new_end || (end && new_end > end))
267 return false;
268