6
7
static inline PARSER_RC pluginsd_set(char **words, size_t num_words, PARSER *parser) {
8
int idx = 1;
9
- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words);
9
+ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_DIMENSION_SLOT_MAX);
10
if(slot >= 0) idx++;
11
12
char *dimension = get_word(words, num_words, idx++);
39
40
static inline PARSER_RC pluginsd_begin(char **words, size_t num_words, PARSER *parser) {
41
int idx = 1;
42
- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words);
42
+ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_CHART_SLOT_MAX);
43
if(slot >= 0) idx++;
44
45
char *id = get_word(words, num_words, idx++);
356
if(!host) return PLUGINSD_DISABLE_PLUGIN(parser, NULL, NULL);
357
358
int idx = 1;
359
- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words);
359
+ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_CHART_SLOT_MAX);
360
if(slot >= 0) idx++;
361
362
char *type = get_word(words, num_words, idx++);
473
474
static inline PARSER_RC pluginsd_dimension(char **words, size_t num_words, PARSER *parser) {
475
int idx = 1;
476
- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words);
476
+ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_DIMENSION_SLOT_MAX);
477
if(slot >= 0) idx++;
478
479
char *id = get_word(words, num_words, idx++);
804
timing_init();
805
806
int idx = 1;
807
- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words);
807
+ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_CHART_SLOT_MAX);
808
if(slot >= 0) idx++;
809
810
char *id = get_word(words, num_words, idx++);
949
timing_init();
950
951
int idx = 1;
952
- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words);
952
+ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_DIMENSION_SLOT_MAX);
953
if(slot >= 0) idx++;
954
955
char *dimension = get_word(words, num_words, idx++);
1513
}
1514
}
1515
1516
+static int pluginsd_parser_unittest_slot_bounds(size_t max_slot) {
1517
+ // The boundary cases below build "max_slot - 1", so a zero cap would underflow.
1518
+ // All real callers pass nonzero compile-time caps; guard against misuse anyway.
1519
+ if(max_slot < 1) {
1520
+ netdata_log_error("PLUGINSD: slot bounds unittest requires max_slot >= 1, got %zu", max_slot);
1521
+ return 1;
1522
+ }
1523
+
1524
+ // Note on initialization: every element below is given an explicit
1525
+ // initializer, so C zero-fills the remainder of each slot_word array. The
1526
+ // trailing three entries start empty and are filled from max_slot at runtime.
1527
+ struct slot_test_case {
1528
+ char slot_word[64];
1529
+ ssize_t expected;
1530
+ } cases[] = {
1531
+ { "", -1 }, // no SLOT word -> -1 (caller must not advance idx)
1532
+ { PLUGINSD_KEYWORD_SLOT ":0", 0 }, // explicit zero -> uncached
1533
+ { PLUGINSD_KEYWORD_SLOT ":1", 1 }, // smallest cached slot
1534
+ { PLUGINSD_KEYWORD_SLOT ":-1", 0 }, // negative parses as unsigned 0 -> uncached
1535
+ { PLUGINSD_KEYWORD_SLOT ":abc", 0 }, // malformed decimal -> 0 -> uncached
1536
+ { PLUGINSD_KEYWORD_SLOT ":0xZZ", 0 }, // malformed hex -> 0 -> uncached
1537
+ { PLUGINSD_KEYWORD_SLOT ":0x0AAAAAAAAAAAAAAB", 0 }, // over cap; cast stays positive, would wrap allocation
1538
+ { PLUGINSD_KEYWORD_SLOT ":0xFFFFFFFFFFFFFFFF", 0 }, // u64 max -> over cap -> uncached
1539
+ { PLUGINSD_KEYWORD_SLOT ":0x40000000", 0 }, // over both caps -> uncached (the reported OOM value)
1540
+ { "", 0 }, // filled below: max_slot - 1 (accepted)
1541
+ { "", 0 }, // filled below: max_slot (accepted, boundary)
1542
+ { "", 0 }, // filled below: max_slot + 1 (rejected, boundary)
1543
+ };
1544
+
1545
+ const size_t n = _countof(cases);
1546
+
1547
+ snprintfz(cases[n - 3].slot_word, sizeof(cases[n - 3].slot_word),
1548
+ PLUGINSD_KEYWORD_SLOT ":%zu", max_slot - 1);
1549
+ cases[n - 3].expected = (ssize_t)(max_slot - 1);
1550
+
1551
+ snprintfz(cases[n - 2].slot_word, sizeof(cases[n - 2].slot_word),
1552
+ PLUGINSD_KEYWORD_SLOT ":%zu", max_slot);
1553
+ cases[n - 2].expected = (ssize_t)max_slot;
1554
+
1555
+ snprintfz(cases[n - 1].slot_word, sizeof(cases[n - 1].slot_word),
1556
+ PLUGINSD_KEYWORD_SLOT ":%zu", max_slot + 1);
1557
+ cases[n - 1].expected = 0;
1558
+
1559
+ for(size_t i = 0; i < _countof(cases); i++) {
1560
+ char command[] = "DIMENSION";
1561
+ char *words[] = { command, cases[i].slot_word[0] ? cases[i].slot_word : NULL };
1562
+ size_t num_words = words[1] ? 2 : 1;
1563
+
1564
+ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, max_slot);
1565
+ if(slot != cases[i].expected) {
1566
+ netdata_log_error("PLUGINSD: slot parser unittest failed for '%s': expected %zd, got %zd",
1567
+ words[1] ? words[1] : "(unset)", cases[i].expected, slot);
1568
+ return 1;
1569
+ }
1570
+ }
1571
+
1572
+ return 0;
1573
+}
1574
+
1575
int pluginsd_parser_unittest(void) {
1576
+ if(pluginsd_parser_unittest_slot_bounds(PLUGINSD_DIMENSION_SLOT_MAX))
1577
+ return 1;
1578
+
1579
+ if(pluginsd_parser_unittest_slot_bounds(PLUGINSD_CHART_SLOT_MAX))
1580
+ return 1;
1581
+
1582
PARSER *p = parser_init(NULL, -1, -1, PARSER_INPUT_SPLIT, NULL);
1583
pluginsd_keywords_init(p, PARSER_INIT_PLUGINSD | PARSER_INIT_STREAMING);
1584