]> source.dussan.org Git - rspamd.git/commitdiff
[Fix] Backport multiple fixes from libucl
authorVsevolod Stakhov <vsevolod@rspamd.com>
Sat, 20 Apr 2024 14:34:11 +0000 (15:34 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Sat, 20 Apr 2024 14:34:11 +0000 (15:34 +0100)
contrib/libucl/ucl_parser.c

index df534df2f838188b7fdb03aebe6d245c18617693..6be16d12169c034baea77afe24aa736208115621 100644 (file)
@@ -348,8 +348,9 @@ ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t rema
                /* Call generic handler */
                if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
                                parser->var_data)) {
-                       *out_len = dstlen;
                        *found = true;
+                       *out_len = dstlen;
+
                        if (need_free) {
                                free (dst);
                        }
@@ -880,6 +881,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,
        }
 
        if (endptr < end && endptr != start) {
+               p = endptr;
                switch (*p) {
                case 'm':
                case 'M':
@@ -1358,24 +1360,20 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj
  */
 static bool
 ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
-               bool *next_key, bool *end_of_object)
+               bool *next_key, bool *end_of_object, bool *got_content)
 {
        const unsigned char *p, *c = NULL, *end, *t;
        const char *key = NULL;
        bool got_quote = false, got_eq = false, got_semicolon = false,
                        need_unescape = false, ucl_escape = false, var_expand = false,
-                       got_content = false, got_sep = false;
+                       got_sep = false;
        ucl_object_t *nobj;
        ssize_t keylen;
 
        p = chunk->pos;
 
-       if (*p == '.') {
-               /* It is macro actually */
-               if (!(parser->flags & UCL_PARSER_DISABLE_MACRO)) {
-                       ucl_chunk_skipc (chunk, p);
-               }
-
+       if (*p == '.' && !(parser->flags & UCL_PARSER_DISABLE_MACRO)) {
+               ucl_chunk_skipc (chunk, p);
                parser->prev_state = parser->state;
                parser->state = UCL_STATE_MACRO_NAME;
                *end_of_object = false;
@@ -1399,13 +1397,13 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
                                /* The first symbol */
                                c = p;
                                ucl_chunk_skipc (chunk, p);
-                               got_content = true;
+                               *got_content = true;
                        }
                        else if (*p == '"') {
                                /* JSON style key */
                                c = p + 1;
                                got_quote = true;
-                               got_content = true;
+                               *got_content = true;
                                ucl_chunk_skipc (chunk, p);
                        }
                        else if (*p == '}') {
@@ -1413,7 +1411,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
                                *end_of_object = true;
                                return true;
                        }
-                       else if (*p == '.') {
+                       else if (*p == '.' && !(parser->flags & UCL_PARSER_DISABLE_MACRO)) {
                                ucl_chunk_skipc (chunk, p);
                                parser->prev_state = parser->state;
                                parser->state = UCL_STATE_MACRO_NAME;
@@ -1430,7 +1428,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
                        /* Parse the body of a key */
                        if (!got_quote) {
                                if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
-                                       got_content = true;
+                                       *got_content = true;
                                        ucl_chunk_skipc (chunk, p);
                                }
                                else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) {
@@ -1456,11 +1454,11 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
                }
        }
 
-       if (p >= chunk->end && got_content) {
+       if (p >= chunk->end && *got_content) {
                ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
                return false;
        }
-       else if (!got_content) {
+       else if (!*got_content) {
                return true;
        }
        *end_of_object = false;
@@ -1821,6 +1819,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
                case '{':
                        obj = ucl_parser_get_container (parser);
                        if (obj == NULL) {
+                               parser->state = UCL_STATE_ERROR;
+                               ucl_set_err(parser, UCL_ESYNTAX, "object value must be a part of an object",
+                                       &parser->err);
                                return false;
                        }
                        /* We have a new object */
@@ -1842,6 +1843,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
                case '[':
                        obj = ucl_parser_get_container (parser);
                        if (obj == NULL) {
+                               parser->state = UCL_STATE_ERROR;
+                               ucl_set_err(parser, UCL_ESYNTAX, "array value must be a part of an object",
+                                       &parser->err);
                                return false;
                        }
                        /* We have a new array */
@@ -1873,6 +1877,12 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
                        break;
                case '<':
                        obj = ucl_parser_get_container (parser);
+                       if (obj == NULL) {
+                               parser->state = UCL_STATE_ERROR;
+                               ucl_set_err(parser, UCL_ESYNTAX, "multiline value must be a part of an object",
+                                               &parser->err);
+                               return false;
+                       }
                        /* We have something like multiline value, which must be <<[A-Z]+\n */
                        if (chunk->end - p > 3) {
                                if (memcmp (p, "<<", 2) == 0) {
@@ -1924,6 +1934,13 @@ parse_string:
                                obj = ucl_parser_get_container (parser);
                        }
 
+                       if (obj == NULL) {
+                               parser->state = UCL_STATE_ERROR;
+                               ucl_set_err(parser, UCL_ESYNTAX, "value must be a part of an object",
+                                       &parser->err);
+                               return false;
+                       }
+
                        /* Parse atom */
                        if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
                                if (!ucl_lex_number (parser, chunk, obj)) {
@@ -2413,7 +2430,7 @@ ucl_state_machine (struct ucl_parser *parser)
        unsigned char *macro_escaped;
        size_t macro_len = 0;
        struct ucl_macro *macro = NULL;
-       bool next_key = false, end_of_object = false, ret;
+       bool next_key = false, end_of_object = false, got_content = false, ret;
 
        if (parser->top_obj == NULL) {
                parser->state = UCL_STATE_INIT;
@@ -2502,7 +2519,10 @@ ucl_state_machine (struct ucl_parser *parser)
                                parser->state = UCL_STATE_ERROR;
                                return false;
                        }
-                       if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) {
+
+                       got_content = false;
+
+                       if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object, &got_content)) {
                                parser->prev_state = parser->state;
                                parser->state = UCL_STATE_ERROR;
                                return false;
@@ -2525,7 +2545,8 @@ ucl_state_machine (struct ucl_parser *parser)
                                                return false;
                                        }
                                }
-                               else {
+                               else if (got_content) {
+                                       /* Do not switch state if we have not read any content */
                                        parser->state = UCL_STATE_VALUE;
                                }
                        }
@@ -2691,6 +2712,9 @@ ucl_state_machine (struct ucl_parser *parser)
                                return false;
                        }
                        break;
+               case UCL_STATE_ERROR:
+                       /* Already in the error state */
+                       return false;
                default:
                        ucl_set_err (parser, UCL_EINTERNAL,
                                        "internal error: parser is in an unknown state", &parser->err);