diff options
author | Vsevolod Stakhov <vsevolod@rspamd.com> | 2024-04-20 15:34:11 +0100 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rspamd.com> | 2024-04-20 15:34:11 +0100 |
commit | e06474f8e8a1c0ec80b056a67cf66f6fcc707295 (patch) | |
tree | d44f8cea8f8e7dc190878650bff7e6e22df0a084 /contrib/libucl | |
parent | d24265cb62e8c7b5b0fa83f14af2544b10448c3b (diff) | |
download | rspamd-e06474f8e8a1c0ec80b056a67cf66f6fcc707295.tar.gz rspamd-e06474f8e8a1c0ec80b056a67cf66f6fcc707295.zip |
[Fix] Backport multiple fixes from libucl
Diffstat (limited to 'contrib/libucl')
-rw-r--r-- | contrib/libucl/ucl_parser.c | 60 |
1 files changed, 42 insertions, 18 deletions
diff --git a/contrib/libucl/ucl_parser.c b/contrib/libucl/ucl_parser.c index df534df2f..6be16d121 100644 --- a/contrib/libucl/ucl_parser.c +++ b/contrib/libucl/ucl_parser.c @@ -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); |