Coverage Report

Created: 2026-03-12 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libucl/src/ucl_sexp.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2015, Vsevolod Stakhov
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *   * Redistributions of source code must retain the above copyright
8
 *     notice, this list of conditions and the following disclaimer.
9
 *   * Redistributions in binary form must reproduce the above copyright
10
 *     notice, this list of conditions and the following disclaimer in the
11
 *     documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
17
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
 */
24
25
#ifdef HAVE_CONFIG_H
26
#include "config.h"
27
#endif
28
29
#include <ucl.h>
30
#include "ucl.h"
31
#include "ucl_internal.h"
32
#include "utlist.h"
33
34
#define NEXT_STATE                            \
35
0
  do {                                      \
36
0
    if (p >= end) {                       \
37
0
      if (state != read_ebrace) {       \
38
0
        ucl_create_err(&parser->err,  \
39
0
                 "extra data"); \
40
0
        state = parse_err;            \
41
0
      }                                 \
42
0
    }                                     \
43
0
    else {                                \
44
0
      switch (*p) {                     \
45
0
      case '(':                         \
46
0
        state = read_obrace;          \
47
0
        break;                        \
48
0
      case ')':                         \
49
0
        state = read_ebrace;          \
50
0
        break;                        \
51
0
      default:                          \
52
0
        len = 0;                      \
53
0
        mult = 1;                     \
54
0
        state = read_length;          \
55
0
        break;                        \
56
0
      }                                 \
57
0
    }                                     \
58
0
  } while (0)
59
60
bool ucl_parse_csexp(struct ucl_parser *parser)
61
0
{
62
0
  const unsigned char *p, *end;
63
0
  ucl_object_t *obj;
64
0
  struct ucl_stack *st;
65
0
  uint64_t len = 0, mult = 1;
66
0
  enum {
67
0
    start_parse,
68
0
    read_obrace,
69
0
    read_length,
70
0
    read_value,
71
0
    read_ebrace,
72
0
    parse_err
73
0
  } state = start_parse;
74
75
0
  assert(parser != NULL);
76
0
  assert(parser->chunks != NULL);
77
0
  assert(parser->chunks->begin != NULL);
78
0
  assert(parser->chunks->remain != 0);
79
80
0
  p = parser->chunks->begin;
81
0
  end = p + parser->chunks->remain;
82
83
0
  while (p < end) {
84
0
    switch (state) {
85
0
    case start_parse:
86
      /* At this point we expect open brace */
87
0
      if (*p == '(') {
88
0
        state = read_obrace;
89
0
      }
90
0
      else {
91
0
        ucl_create_err(&parser->err, "bad starting character for "
92
0
                       "sexp block: %x",
93
0
                 (int) *p);
94
0
        state = parse_err;
95
0
      }
96
0
      break;
97
98
0
    case read_obrace:
99
0
      st = calloc(1, sizeof(*st));
100
101
0
      if (st == NULL) {
102
0
        ucl_create_err(&parser->err, "no memory");
103
0
        state = parse_err;
104
0
        continue;
105
0
      }
106
107
0
      st->obj = ucl_object_typed_new(UCL_ARRAY);
108
109
0
      if (st->obj == NULL) {
110
0
        ucl_create_err(&parser->err, "no memory");
111
0
        state = parse_err;
112
0
        free(st);
113
0
        continue;
114
0
      }
115
116
0
      if (parser->stack == NULL) {
117
        /* We have no stack */
118
0
        parser->stack = st;
119
120
0
        if (parser->top_obj == NULL) {
121
0
          parser->top_obj = st->obj;
122
0
        }
123
0
      }
124
0
      else {
125
        /* Prepend new element to the stack */
126
0
        LL_PREPEND(parser->stack, st);
127
0
      }
128
129
0
      p++;
130
0
      NEXT_STATE;
131
132
0
      break;
133
134
0
    case read_length:
135
0
      if (*p == ':') {
136
0
        if (len == 0) {
137
0
          ucl_create_err(&parser->err, "zero length element");
138
0
          state = parse_err;
139
0
          continue;
140
0
        }
141
142
0
        state = read_value;
143
0
      }
144
0
      else if (*p >= '0' && *p <= '9') {
145
0
        len += (*p - '0') * mult;
146
0
        mult *= 10;
147
148
0
        if (len > UINT32_MAX) {
149
0
          ucl_create_err(&parser->err, "too big length of an "
150
0
                         "element");
151
0
          state = parse_err;
152
0
          continue;
153
0
        }
154
0
      }
155
0
      else {
156
0
        ucl_create_err(&parser->err, "bad length character: %x",
157
0
                 (int) *p);
158
0
        state = parse_err;
159
0
        continue;
160
0
      }
161
162
0
      p++;
163
0
      break;
164
165
0
    case read_value:
166
0
      if ((uint64_t) (end - p) > len || len == 0) {
167
0
        ucl_create_err(&parser->err, "invalid length: %llu, %ld "
168
0
                       "remain",
169
0
                 (long long unsigned) len, (long) (end - p));
170
0
        state = parse_err;
171
0
        continue;
172
0
      }
173
0
      obj = ucl_object_typed_new(UCL_STRING);
174
175
0
      obj->value.sv = (const char *) p;
176
0
      obj->len = len;
177
0
      obj->flags |= UCL_OBJECT_BINARY;
178
179
0
      if (!(parser->flags & UCL_PARSER_ZEROCOPY)) {
180
0
        ucl_copy_value_trash(obj);
181
0
      }
182
183
0
      ucl_array_append(parser->stack->obj, obj);
184
0
      p += len;
185
0
      NEXT_STATE;
186
0
      break;
187
188
0
    case read_ebrace:
189
0
      if (parser->stack == NULL) {
190
        /* We have an extra end brace */
191
0
        ucl_create_err(&parser->err, "invalid length: %llu, %ld "
192
0
                       "remain",
193
0
                 (long long unsigned) len, (long) (end - p));
194
0
        state = parse_err;
195
0
        continue;
196
0
      }
197
      /* Pop the container */
198
0
      st = parser->stack;
199
0
      parser->stack = st->next;
200
201
0
      if (parser->stack->obj->type == UCL_ARRAY) {
202
0
        ucl_array_append(parser->stack->obj, st->obj);
203
0
      }
204
0
      else {
205
0
        ucl_create_err(&parser->err, "bad container object, array "
206
0
                       "expected");
207
0
        state = parse_err;
208
0
        continue;
209
0
      }
210
211
0
      free(st);
212
0
      st = NULL;
213
0
      p++;
214
0
      NEXT_STATE;
215
0
      break;
216
217
0
    case parse_err:
218
0
    default:
219
0
      return false;
220
0
    }
221
0
  }
222
223
0
  if (state != read_ebrace) {
224
0
    ucl_create_err(&parser->err, "invalid finishing state: %d", state);
225
0
    return false;
226
0
  }
227
228
0
  return true;
229
0
}