Branch data Line data Source code
1 : : // Copyright 2014 BitPay Inc.
2 : : // Copyright (c) 2015-present The Bitcoin Core developers
3 : : // Distributed under the MIT software license, see the accompanying
4 : : // file COPYING or https://opensource.org/licenses/mit-license.php.
5 : :
6 : : #include <univalue.h>
7 : : #include <univalue_utffilter.h>
8 : :
9 : : #include <cstdint>
10 : : #include <cstring>
11 : : #include <string>
12 : : #include <string_view>
13 : : #include <utility>
14 : : #include <vector>
15 : :
16 : : /*
17 : : * According to stackexchange, the original json test suite wanted
18 : : * to limit depth to 22. Widely-deployed PHP bails at depth 512,
19 : : * so we will follow PHP's lead, which should be more than sufficient
20 : : * (further stackexchange comments indicate depth > 32 rarely occurs).
21 : : */
22 : : static constexpr size_t MAX_JSON_DEPTH = 512;
23 : :
24 : 8357591 : static bool json_isdigit(int ch)
25 : : {
26 : 8357591 : return ((ch >= '0') && (ch <= '9'));
27 : : }
28 : :
29 : : // convert hexadecimal string to unsigned integer
30 : 646 : static const char *hatoui(const char *first, const char *last,
31 : : unsigned int& out)
32 : : {
33 : 646 : unsigned int result = 0;
34 [ + + ]: 3230 : for (; first != last; ++first)
35 : : {
36 : 2584 : int digit;
37 [ + + ]: 2584 : if (json_isdigit(*first))
38 : 1268 : digit = *first - '0';
39 : :
40 [ + + ]: 1316 : else if (*first >= 'a' && *first <= 'f')
41 : 1294 : digit = *first - 'a' + 10;
42 : :
43 [ + - ]: 22 : else if (*first >= 'A' && *first <= 'F')
44 : 22 : digit = *first - 'A' + 10;
45 : :
46 : : else
47 : : break;
48 : :
49 : 2584 : result = 16 * result + digit;
50 : : }
51 : 646 : out = result;
52 : :
53 : 646 : return first;
54 : : }
55 : :
56 : 7129648 : enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed,
57 : : const char *raw, const char *end)
58 : : {
59 : 7129648 : tokenVal.clear();
60 : 7129648 : consumed = 0;
61 : :
62 : 7129648 : const char *rawStart = raw;
63 : :
64 [ + + + + ]: 9134578 : while (raw < end && (json_isspace(*raw))) // skip whitespace
65 : 2004930 : raw++;
66 : :
67 [ + + ]: 7129648 : if (raw >= end)
68 : : return JTOK_NONE;
69 : :
70 [ + + + + : 6911019 : switch (*raw) {
+ + + + +
+ ]
71 : :
72 : 355872 : case '{':
73 : 355872 : raw++;
74 : 355872 : consumed = (raw - rawStart);
75 : 355872 : return JTOK_OBJ_OPEN;
76 : 355855 : case '}':
77 : 355855 : raw++;
78 : 355855 : consumed = (raw - rawStart);
79 : 355855 : return JTOK_OBJ_CLOSE;
80 : 150430 : case '[':
81 : 150430 : raw++;
82 : 150430 : consumed = (raw - rawStart);
83 : 150430 : return JTOK_ARR_OPEN;
84 : 149381 : case ']':
85 : 149381 : raw++;
86 : 149381 : consumed = (raw - rawStart);
87 : 149381 : return JTOK_ARR_CLOSE;
88 : :
89 : 1080632 : case ':':
90 : 1080632 : raw++;
91 : 1080632 : consumed = (raw - rawStart);
92 : 1080632 : return JTOK_COLON;
93 : 878588 : case ',':
94 : 878588 : raw++;
95 : 878588 : consumed = (raw - rawStart);
96 : 878588 : return JTOK_COMMA;
97 : :
98 : 17797 : case 'n':
99 : 17797 : case 't':
100 : 17797 : case 'f':
101 [ + + ]: 17797 : if (!strncmp(raw, "null", 4)) {
102 : 728 : raw += 4;
103 : 728 : consumed = (raw - rawStart);
104 : 728 : return JTOK_KW_NULL;
105 [ + + ]: 17069 : } else if (!strncmp(raw, "true", 4)) {
106 : 14909 : raw += 4;
107 : 14909 : consumed = (raw - rawStart);
108 : 14909 : return JTOK_KW_TRUE;
109 [ + + ]: 2160 : } else if (!strncmp(raw, "false", 5)) {
110 : 2155 : raw += 5;
111 : 2155 : consumed = (raw - rawStart);
112 : 2155 : return JTOK_KW_FALSE;
113 : : } else
114 : : return JTOK_ERR;
115 : :
116 : 2163621 : case '-':
117 : 2163621 : case '0':
118 : 2163621 : case '1':
119 : 2163621 : case '2':
120 : 2163621 : case '3':
121 : 2163621 : case '4':
122 : 2163621 : case '5':
123 : 2163621 : case '6':
124 : 2163621 : case '7':
125 : 2163621 : case '8':
126 : 2163621 : case '9': {
127 : : // part 1: int
128 [ + + ]: 2163621 : std::string numStr;
129 : :
130 : 2163621 : const char *first = raw;
131 : :
132 : 2163621 : const char *firstDigit = first;
133 [ + + ]: 2163621 : if (!json_isdigit(*firstDigit))
134 : 41238 : firstDigit++;
135 [ + + + + ]: 2163621 : if ((*firstDigit == '0') && json_isdigit(firstDigit[1]))
136 : : return JTOK_ERR;
137 : :
138 [ + - ]: 2163620 : numStr += *raw; // copy first char
139 : 2163620 : raw++;
140 : :
141 [ + + + - : 2163620 : if ((*first == '-') && (raw < end) && (!json_isdigit(*raw)))
+ - ]
142 : : return JTOK_ERR;
143 : :
144 [ + + + + ]: 6862336 : while (raw < end && json_isdigit(*raw)) { // copy digits
145 [ + - ]: 4698716 : numStr += *raw;
146 : 4698716 : raw++;
147 : : }
148 : :
149 : : // part 2: frac
150 [ + + + + ]: 2163620 : if (raw < end && *raw == '.') {
151 [ + - ]: 54646 : numStr += *raw; // copy .
152 : 54646 : raw++;
153 : :
154 [ + - + - ]: 54646 : if (raw >= end || !json_isdigit(*raw))
155 : : return JTOK_ERR;
156 [ + + + + ]: 574003 : while (raw < end && json_isdigit(*raw)) { // copy digits
157 [ + - ]: 519357 : numStr += *raw;
158 : 519357 : raw++;
159 : : }
160 : : }
161 : :
162 : : // part 3: exp
163 [ + + + + : 2163620 : if (raw < end && (*raw == 'e' || *raw == 'E')) {
+ + ]
164 [ + - ]: 22918 : numStr += *raw; // copy E
165 : 22918 : raw++;
166 : :
167 [ + - + + : 22918 : if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/-
+ + ]
168 [ + - ]: 22911 : numStr += *raw;
169 : 22911 : raw++;
170 : : }
171 : :
172 [ + - + + ]: 22918 : if (raw >= end || !json_isdigit(*raw))
173 : : return JTOK_ERR;
174 [ + + + + ]: 68735 : while (raw < end && json_isdigit(*raw)) { // copy digits
175 [ + - ]: 45820 : numStr += *raw;
176 : 45820 : raw++;
177 : : }
178 : : }
179 : :
180 [ + - ]: 2163617 : tokenVal = numStr;
181 : 2163617 : consumed = (raw - rawStart);
182 : 2163617 : return JTOK_NUMBER;
183 : 2163621 : }
184 : :
185 : 1758817 : case '"': {
186 : 1758817 : raw++; // skip "
187 : :
188 : 1758817 : std::string valStr;
189 : 1758817 : JSONUTF8StringFilter writer(valStr);
190 : :
191 : 4973480571 : while (true) {
192 [ + + + + ]: 4973480571 : if (raw >= end || (unsigned char)*raw < 0x20)
193 : : return JTOK_ERR;
194 : :
195 [ + + ]: 4973480567 : else if (*raw == '\\') {
196 : 693 : raw++; // skip backslash
197 : :
198 [ + - ]: 693 : if (raw >= end)
199 : : return JTOK_ERR;
200 : :
201 [ + + + + : 693 : switch (*raw) {
+ + + + +
+ ]
202 [ + - ]: 16 : case '"': writer.push_back('\"'); break;
203 [ + - ]: 4 : case '\\': writer.push_back('\\'); break;
204 [ + - ]: 2 : case '/': writer.push_back('/'); break;
205 [ + - ]: 4 : case 'b': writer.push_back('\b'); break;
206 [ + - ]: 4 : case 'f': writer.push_back('\f'); break;
207 [ + - ]: 5 : case 'n': writer.push_back('\n'); break;
208 [ + - ]: 4 : case 'r': writer.push_back('\r'); break;
209 [ + - ]: 4 : case 't': writer.push_back('\t'); break;
210 : :
211 : 646 : case 'u': {
212 : 646 : unsigned int codepoint;
213 [ + - + - ]: 1292 : if (raw + 1 + 4 >= end ||
214 : 646 : hatoui(raw + 1, raw + 1 + 4, codepoint) !=
215 : : raw + 1 + 4)
216 : 0 : return JTOK_ERR;
217 [ + - ]: 646 : writer.push_back_u(codepoint);
218 : 646 : raw += 4;
219 : 646 : break;
220 : : }
221 : : default:
222 : : return JTOK_ERR;
223 : :
224 : : }
225 : :
226 : 689 : raw++; // skip esc'd char
227 : : }
228 : :
229 [ + + ]: 4973479874 : else if (*raw == '"') {
230 : 1758809 : raw++; // skip "
231 : 1758809 : break; // stop scanning
232 : : }
233 : :
234 : : else {
235 [ + - ]: 4971721065 : writer.push_back(static_cast<unsigned char>(*raw));
236 : 4971721065 : raw++;
237 : : }
238 : : }
239 : :
240 [ + + + + ]: 3517618 : if (!writer.finalize())
241 : : return JTOK_ERR;
242 [ + - ]: 1758805 : tokenVal = valStr;
243 : 1758805 : consumed = (raw - rawStart);
244 : 1758805 : return JTOK_STRING;
245 : 1758817 : }
246 : :
247 : : default:
248 : : return JTOK_ERR;
249 : : }
250 : : }
251 : :
252 : : enum expect_bits : unsigned {
253 : : EXP_OBJ_NAME = (1U << 0),
254 : : EXP_COLON = (1U << 1),
255 : : EXP_ARR_VALUE = (1U << 2),
256 : : EXP_VALUE = (1U << 3),
257 : : EXP_NOT_VALUE = (1U << 4),
258 : : };
259 : :
260 : : #define expect(bit) (expectMask & (EXP_##bit))
261 : : #define setExpect(bit) (expectMask |= EXP_##bit)
262 : : #define clearExpect(bit) (expectMask &= ~EXP_##bit)
263 : :
264 : 218701 : bool UniValue::read(std::string_view json)
265 : : {
266 [ + - ]: 218701 : UniValue parsed;
267 [ + - + + ]: 218701 : if (!parsed.read_impl(json)) {
268 [ + - ]: 78 : setNull();
269 : : return false;
270 : : }
271 : 218623 : *this = std::move(parsed);
272 : 218623 : return true;
273 : 218701 : }
274 : :
275 : 218701 : bool UniValue::read_impl(std::string_view str_in)
276 : : {
277 : 218701 : clear();
278 : :
279 : 218701 : uint32_t expectMask = 0;
280 : 218701 : std::vector<UniValue*> stack;
281 : :
282 : 218701 : std::string tokenVal;
283 : 218701 : unsigned int consumed;
284 : 218701 : enum jtokentype tok = JTOK_NONE;
285 : 218701 : enum jtokentype last_tok = JTOK_NONE;
286 : 218701 : const char* raw{str_in.data()};
287 : 218701 : const char* end{raw + str_in.size()};
288 : 5085738 : do {
289 : 5085738 : last_tok = tok;
290 : :
291 [ + - ]: 5085738 : tok = getJsonToken(tokenVal, consumed, raw, end);
292 [ + + ]: 5085738 : if (tok == JTOK_NONE || tok == JTOK_ERR)
293 : : return false;
294 : 5085692 : raw += consumed;
295 : :
296 [ + + ]: 5085692 : bool isValueOpen = jsonTokenIsValue(tok) ||
297 [ + + ]: 2970753 : tok == JTOK_OBJ_OPEN || tok == JTOK_ARR_OPEN;
298 : :
299 [ + + ]: 5085692 : if (expect(VALUE)) {
300 [ + + ]: 1080627 : if (!isValueOpen)
301 : : return false;
302 : 1080625 : clearExpect(VALUE);
303 : :
304 [ + + ]: 4005065 : } else if (expect(ARR_VALUE)) {
305 : 243016 : bool isArrValue = isValueOpen || (tok == JTOK_ARR_CLOSE);
306 [ + + ]: 243016 : if (!isArrValue)
307 : : return false;
308 : :
309 : 243014 : clearExpect(ARR_VALUE);
310 : :
311 [ + + ]: 3762049 : } else if (expect(OBJ_NAME)) {
312 : 1141845 : bool isObjName = (tok == JTOK_OBJ_CLOSE || tok == JTOK_STRING);
313 [ + + ]: 1141845 : if (!isObjName)
314 : : return false;
315 : :
316 [ + + ]: 2620204 : } else if (expect(COLON)) {
317 [ + + ]: 1080633 : if (tok != JTOK_COLON)
318 : : return false;
319 : 1080630 : clearExpect(COLON);
320 : :
321 [ + + ]: 1539571 : } else if (!expect(COLON) && (tok == JTOK_COLON)) {
322 : : return false;
323 : : }
324 : :
325 [ + + ]: 5085680 : if (expect(NOT_VALUE)) {
326 [ + + ]: 2401519 : if (isValueOpen)
327 : : return false;
328 : 2401517 : clearExpect(NOT_VALUE);
329 : : }
330 : :
331 [ + + + + : 5085678 : switch (tok) {
+ + + - ]
332 : :
333 : 506298 : case JTOK_OBJ_OPEN:
334 : 506298 : case JTOK_ARR_OPEN: {
335 [ + + ]: 506298 : VType utyp = (tok == JTOK_OBJ_OPEN ? VOBJ : VARR);
336 [ - + + + ]: 506298 : if (!stack.size()) {
337 [ + + ]: 218580 : if (utyp == VOBJ)
338 [ + - ]: 217878 : setObject();
339 : : else
340 [ + - ]: 702 : setArray();
341 [ + - ]: 218580 : stack.push_back(this);
342 : : } else {
343 : 287718 : UniValue tmpVal(utyp);
344 : 287718 : UniValue *top = stack.back();
345 [ + - ]: 287718 : top->values.push_back(tmpVal);
346 : :
347 : 287718 : UniValue *newTop = &(top->values.back());
348 [ + - ]: 287718 : stack.push_back(newTop);
349 : 287718 : }
350 : :
351 [ - + + + ]: 506298 : if (stack.size() > MAX_JSON_DEPTH)
352 : : return false;
353 : :
354 [ + + ]: 506296 : if (utyp == VOBJ)
355 : 355870 : setExpect(OBJ_NAME);
356 : : else
357 : 150426 : setExpect(ARR_VALUE);
358 : : break;
359 : : }
360 : :
361 : 505232 : case JTOK_OBJ_CLOSE:
362 : 505232 : case JTOK_ARR_CLOSE: {
363 [ - + + - : 505232 : if (!stack.size() || (last_tok == JTOK_COMMA))
+ + ]
364 : : return false;
365 : :
366 [ + + ]: 505230 : VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR);
367 : 505230 : UniValue *top = stack.back();
368 [ + + ]: 505230 : if (utyp != top->getType())
369 : : return false;
370 : :
371 : 505229 : stack.pop_back();
372 : 505229 : clearExpect(OBJ_NAME);
373 : 505229 : setExpect(NOT_VALUE);
374 : 505229 : break;
375 : : }
376 : :
377 : 1080630 : case JTOK_COLON: {
378 [ - + + - ]: 1080630 : if (!stack.size())
379 : : return false;
380 : :
381 : 1080630 : UniValue *top = stack.back();
382 [ + - ]: 1080630 : if (top->getType() != VOBJ)
383 : : return false;
384 : :
385 : 1080630 : setExpect(VALUE);
386 : 1080630 : break;
387 : : }
388 : :
389 : 878584 : case JTOK_COMMA: {
390 [ - + ]: 878584 : if (!stack.size() ||
391 [ + - + - ]: 878584 : (last_tok == JTOK_COMMA) || (last_tok == JTOK_ARR_OPEN))
392 : : return false;
393 : :
394 : 878584 : UniValue *top = stack.back();
395 [ + + ]: 878584 : if (top->getType() == VOBJ)
396 : 785978 : setExpect(OBJ_NAME);
397 : : else
398 : 92606 : setExpect(ARR_VALUE);
399 : : break;
400 : : }
401 : :
402 : 17789 : case JTOK_KW_NULL:
403 : 17789 : case JTOK_KW_TRUE:
404 : 17789 : case JTOK_KW_FALSE: {
405 [ + + + ]: 17789 : UniValue tmpVal;
406 [ + + + ]: 17789 : switch (tok) {
407 : : case JTOK_KW_NULL:
408 : : // do nothing more
409 : : break;
410 : 14907 : case JTOK_KW_TRUE:
411 [ + - ]: 14907 : tmpVal.setBool(true);
412 : : break;
413 : 2155 : case JTOK_KW_FALSE:
414 [ + - ]: 2155 : tmpVal.setBool(false);
415 : : break;
416 : : default: /* impossible */ break;
417 : : }
418 : :
419 [ - + + + ]: 17789 : if (!stack.size()) {
420 [ + - ]: 40 : *this = tmpVal;
421 : : break;
422 : : }
423 : :
424 : 17749 : UniValue *top = stack.back();
425 [ + - ]: 17749 : top->values.push_back(tmpVal);
426 : :
427 : 17749 : setExpect(NOT_VALUE);
428 : 17749 : break;
429 : 17789 : }
430 : :
431 : 338342 : case JTOK_NUMBER: {
432 [ - + ]: 676684 : UniValue tmpVal(VNUM, tokenVal);
433 [ - + + + ]: 338342 : if (!stack.size()) {
434 [ + - ]: 58 : *this = tmpVal;
435 : : break;
436 : : }
437 : :
438 : 338284 : UniValue *top = stack.back();
439 [ + - ]: 338284 : top->values.push_back(tmpVal);
440 : :
441 : 338284 : setExpect(NOT_VALUE);
442 : 338284 : break;
443 : 338342 : }
444 : :
445 : 1758803 : case JTOK_STRING: {
446 [ + + ]: 1758803 : if (expect(OBJ_NAME)) {
447 : 1080633 : UniValue *top = stack.back();
448 [ + - ]: 1080633 : top->keys.push_back(tokenVal);
449 : 1080633 : clearExpect(OBJ_NAME);
450 : 1080633 : setExpect(COLON);
451 : : } else {
452 [ - + ]: 1356340 : UniValue tmpVal(VSTR, tokenVal);
453 [ - + + + ]: 678170 : if (!stack.size()) {
454 [ + - ]: 3 : *this = tmpVal;
455 : 3 : break;
456 : : }
457 : 678167 : UniValue *top = stack.back();
458 [ + - ]: 678167 : top->values.push_back(tmpVal);
459 : 678170 : }
460 : :
461 : 1758800 : setExpect(NOT_VALUE);
462 : 1758800 : break;
463 : : }
464 : :
465 : : default:
466 : : return false;
467 : : }
468 [ + + ]: 5085673 : } while (!stack.empty ());
469 : :
470 : : /* Check that nothing follows the initial construct (parsed above). */
471 [ + - ]: 218636 : tok = getJsonToken(tokenVal, consumed, raw, end);
472 [ + + ]: 218636 : if (tok != JTOK_NONE)
473 : 13 : return false;
474 : :
475 : : return true;
476 : 218701 : }
|