1 #include "test/jemalloc_test.h"
2
3 #include "jemalloc/internal/util.h"
4
5 typedef enum {
6 TOKEN_TYPE_NONE,
7 TOKEN_TYPE_ERROR,
8 TOKEN_TYPE_EOI,
9 TOKEN_TYPE_NULL,
10 TOKEN_TYPE_FALSE,
11 TOKEN_TYPE_TRUE,
12 TOKEN_TYPE_LBRACKET,
13 TOKEN_TYPE_RBRACKET,
14 TOKEN_TYPE_LBRACE,
15 TOKEN_TYPE_RBRACE,
16 TOKEN_TYPE_COLON,
17 TOKEN_TYPE_COMMA,
18 TOKEN_TYPE_STRING,
19 TOKEN_TYPE_NUMBER
20 } token_type_t;
21
22 typedef struct parser_s parser_t;
23 typedef struct {
24 parser_t *parser;
25 token_type_t token_type;
26 size_t pos;
27 size_t len;
28 size_t line;
29 size_t col;
30 } token_t;
31
32 struct parser_s {
33 bool verbose;
34 char *buf; /* '\0'-terminated. */
35 size_t len; /* Number of characters preceding '\0' in buf. */
36 size_t pos;
37 size_t line;
38 size_t col;
39 token_t token;
40 };
41
42 static void
token_init(token_t * token,parser_t * parser,token_type_t token_type,size_t pos,size_t len,size_t line,size_t col)43 token_init(token_t *token, parser_t *parser, token_type_t token_type,
44 size_t pos, size_t len, size_t line, size_t col) {
45 token->parser = parser;
46 token->token_type = token_type;
47 token->pos = pos;
48 token->len = len;
49 token->line = line;
50 token->col = col;
51 }
52
53 static void
token_error(token_t * token)54 token_error(token_t *token) {
55 if (!token->parser->verbose) {
56 return;
57 }
58 switch (token->token_type) {
59 case TOKEN_TYPE_NONE:
60 not_reached();
61 case TOKEN_TYPE_ERROR:
62 malloc_printf("%zu:%zu: Unexpected character in token: ",
63 token->line, token->col);
64 break;
65 default:
66 malloc_printf("%zu:%zu: Unexpected token: ", token->line,
67 token->col);
68 break;
69 }
70 UNUSED ssize_t err = malloc_write_fd(STDERR_FILENO,
71 &token->parser->buf[token->pos], token->len);
72 malloc_printf("\n");
73 }
74
75 static void
parser_init(parser_t * parser,bool verbose)76 parser_init(parser_t *parser, bool verbose) {
77 parser->verbose = verbose;
78 parser->buf = NULL;
79 parser->len = 0;
80 parser->pos = 0;
81 parser->line = 1;
82 parser->col = 0;
83 }
84
85 static void
parser_fini(parser_t * parser)86 parser_fini(parser_t *parser) {
87 if (parser->buf != NULL) {
88 dallocx(parser->buf, MALLOCX_TCACHE_NONE);
89 }
90 }
91
92 static bool
parser_append(parser_t * parser,const char * str)93 parser_append(parser_t *parser, const char *str) {
94 size_t len = strlen(str);
95 char *buf = (parser->buf == NULL) ? mallocx(len + 1,
96 MALLOCX_TCACHE_NONE) : rallocx(parser->buf, parser->len + len + 1,
97 MALLOCX_TCACHE_NONE);
98 if (buf == NULL) {
99 return true;
100 }
101 memcpy(&buf[parser->len], str, len + 1);
102 parser->buf = buf;
103 parser->len += len;
104 return false;
105 }
106
107 static bool
parser_tokenize(parser_t * parser)108 parser_tokenize(parser_t *parser) {
109 enum {
110 STATE_START,
111 STATE_EOI,
112 STATE_N, STATE_NU, STATE_NUL, STATE_NULL,
113 STATE_F, STATE_FA, STATE_FAL, STATE_FALS, STATE_FALSE,
114 STATE_T, STATE_TR, STATE_TRU, STATE_TRUE,
115 STATE_LBRACKET,
116 STATE_RBRACKET,
117 STATE_LBRACE,
118 STATE_RBRACE,
119 STATE_COLON,
120 STATE_COMMA,
121 STATE_CHARS,
122 STATE_CHAR_ESCAPE,
123 STATE_CHAR_U, STATE_CHAR_UD, STATE_CHAR_UDD, STATE_CHAR_UDDD,
124 STATE_STRING,
125 STATE_MINUS,
126 STATE_LEADING_ZERO,
127 STATE_DIGITS,
128 STATE_DECIMAL,
129 STATE_FRAC_DIGITS,
130 STATE_EXP,
131 STATE_EXP_SIGN,
132 STATE_EXP_DIGITS,
133 STATE_ACCEPT
134 } state = STATE_START;
135 size_t token_pos JEMALLOC_CC_SILENCE_INIT(0);
136 size_t token_line JEMALLOC_CC_SILENCE_INIT(1);
137 size_t token_col JEMALLOC_CC_SILENCE_INIT(0);
138
139 assert_zu_le(parser->pos, parser->len,
140 "Position is past end of buffer");
141
142 while (state != STATE_ACCEPT) {
143 char c = parser->buf[parser->pos];
144
145 switch (state) {
146 case STATE_START:
147 token_pos = parser->pos;
148 token_line = parser->line;
149 token_col = parser->col;
150 switch (c) {
151 case ' ': case '\b': case '\n': case '\r': case '\t':
152 break;
153 case '\0':
154 state = STATE_EOI;
155 break;
156 case 'n':
157 state = STATE_N;
158 break;
159 case 'f':
160 state = STATE_F;
161 break;
162 case 't':
163 state = STATE_T;
164 break;
165 case '[':
166 state = STATE_LBRACKET;
167 break;
168 case ']':
169 state = STATE_RBRACKET;
170 break;
171 case '{':
172 state = STATE_LBRACE;
173 break;
174 case '}':
175 state = STATE_RBRACE;
176 break;
177 case ':':
178 state = STATE_COLON;
179 break;
180 case ',':
181 state = STATE_COMMA;
182 break;
183 case '"':
184 state = STATE_CHARS;
185 break;
186 case '-':
187 state = STATE_MINUS;
188 break;
189 case '0':
190 state = STATE_LEADING_ZERO;
191 break;
192 case '1': case '2': case '3': case '4':
193 case '5': case '6': case '7': case '8': case '9':
194 state = STATE_DIGITS;
195 break;
196 default:
197 token_init(&parser->token, parser,
198 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
199 - token_pos, token_line, token_col);
200 return true;
201 }
202 break;
203 case STATE_EOI:
204 token_init(&parser->token, parser,
205 TOKEN_TYPE_EOI, token_pos, parser->pos -
206 token_pos, token_line, token_col);
207 state = STATE_ACCEPT;
208 break;
209 case STATE_N:
210 switch (c) {
211 case 'u':
212 state = STATE_NU;
213 break;
214 default:
215 token_init(&parser->token, parser,
216 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
217 - token_pos, token_line, token_col);
218 return true;
219 }
220 break;
221 case STATE_NU:
222 switch (c) {
223 case 'l':
224 state = STATE_NUL;
225 break;
226 default:
227 token_init(&parser->token, parser,
228 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
229 - token_pos, token_line, token_col);
230 return true;
231 }
232 break;
233 case STATE_NUL:
234 switch (c) {
235 case 'l':
236 state = STATE_NULL;
237 break;
238 default:
239 token_init(&parser->token, parser,
240 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
241 - token_pos, token_line, token_col);
242 return true;
243 }
244 break;
245 case STATE_NULL:
246 switch (c) {
247 case ' ': case '\b': case '\n': case '\r': case '\t':
248 case '\0':
249 case '[': case ']': case '{': case '}': case ':':
250 case ',':
251 break;
252 default:
253 token_init(&parser->token, parser,
254 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
255 - token_pos, token_line, token_col);
256 return true;
257 }
258 token_init(&parser->token, parser, TOKEN_TYPE_NULL,
259 token_pos, parser->pos - token_pos, token_line,
260 token_col);
261 state = STATE_ACCEPT;
262 break;
263 case STATE_F:
264 switch (c) {
265 case 'a':
266 state = STATE_FA;
267 break;
268 default:
269 token_init(&parser->token, parser,
270 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
271 - token_pos, token_line, token_col);
272 return true;
273 }
274 break;
275 case STATE_FA:
276 switch (c) {
277 case 'l':
278 state = STATE_FAL;
279 break;
280 default:
281 token_init(&parser->token, parser,
282 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
283 - token_pos, token_line, token_col);
284 return true;
285 }
286 break;
287 case STATE_FAL:
288 switch (c) {
289 case 's':
290 state = STATE_FALS;
291 break;
292 default:
293 token_init(&parser->token, parser,
294 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
295 - token_pos, token_line, token_col);
296 return true;
297 }
298 break;
299 case STATE_FALS:
300 switch (c) {
301 case 'e':
302 state = STATE_FALSE;
303 break;
304 default:
305 token_init(&parser->token, parser,
306 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
307 - token_pos, token_line, token_col);
308 return true;
309 }
310 break;
311 case STATE_FALSE:
312 switch (c) {
313 case ' ': case '\b': case '\n': case '\r': case '\t':
314 case '\0':
315 case '[': case ']': case '{': case '}': case ':':
316 case ',':
317 break;
318 default:
319 token_init(&parser->token, parser,
320 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
321 - token_pos, token_line, token_col);
322 return true;
323 }
324 token_init(&parser->token, parser,
325 TOKEN_TYPE_FALSE, token_pos, parser->pos -
326 token_pos, token_line, token_col);
327 state = STATE_ACCEPT;
328 break;
329 case STATE_T:
330 switch (c) {
331 case 'r':
332 state = STATE_TR;
333 break;
334 default:
335 token_init(&parser->token, parser,
336 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
337 - token_pos, token_line, token_col);
338 return true;
339 }
340 break;
341 case STATE_TR:
342 switch (c) {
343 case 'u':
344 state = STATE_TRU;
345 break;
346 default:
347 token_init(&parser->token, parser,
348 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
349 - token_pos, token_line, token_col);
350 return true;
351 }
352 break;
353 case STATE_TRU:
354 switch (c) {
355 case 'e':
356 state = STATE_TRUE;
357 break;
358 default:
359 token_init(&parser->token, parser,
360 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
361 - token_pos, token_line, token_col);
362 return true;
363 }
364 break;
365 case STATE_TRUE:
366 switch (c) {
367 case ' ': case '\b': case '\n': case '\r': case '\t':
368 case '\0':
369 case '[': case ']': case '{': case '}': case ':':
370 case ',':
371 break;
372 default:
373 token_init(&parser->token, parser,
374 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
375 - token_pos, token_line, token_col);
376 return true;
377 }
378 token_init(&parser->token, parser, TOKEN_TYPE_TRUE,
379 token_pos, parser->pos - token_pos, token_line,
380 token_col);
381 state = STATE_ACCEPT;
382 break;
383 case STATE_LBRACKET:
384 token_init(&parser->token, parser, TOKEN_TYPE_LBRACKET,
385 token_pos, parser->pos - token_pos, token_line,
386 token_col);
387 state = STATE_ACCEPT;
388 break;
389 case STATE_RBRACKET:
390 token_init(&parser->token, parser, TOKEN_TYPE_RBRACKET,
391 token_pos, parser->pos - token_pos, token_line,
392 token_col);
393 state = STATE_ACCEPT;
394 break;
395 case STATE_LBRACE:
396 token_init(&parser->token, parser, TOKEN_TYPE_LBRACE,
397 token_pos, parser->pos - token_pos, token_line,
398 token_col);
399 state = STATE_ACCEPT;
400 break;
401 case STATE_RBRACE:
402 token_init(&parser->token, parser, TOKEN_TYPE_RBRACE,
403 token_pos, parser->pos - token_pos, token_line,
404 token_col);
405 state = STATE_ACCEPT;
406 break;
407 case STATE_COLON:
408 token_init(&parser->token, parser, TOKEN_TYPE_COLON,
409 token_pos, parser->pos - token_pos, token_line,
410 token_col);
411 state = STATE_ACCEPT;
412 break;
413 case STATE_COMMA:
414 token_init(&parser->token, parser, TOKEN_TYPE_COMMA,
415 token_pos, parser->pos - token_pos, token_line,
416 token_col);
417 state = STATE_ACCEPT;
418 break;
419 case STATE_CHARS:
420 switch (c) {
421 case '\\':
422 state = STATE_CHAR_ESCAPE;
423 break;
424 case '"':
425 state = STATE_STRING;
426 break;
427 case 0x00: case 0x01: case 0x02: case 0x03: case 0x04:
428 case 0x05: case 0x06: case 0x07: case 0x08: case 0x09:
429 case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e:
430 case 0x0f: case 0x10: case 0x11: case 0x12: case 0x13:
431 case 0x14: case 0x15: case 0x16: case 0x17: case 0x18:
432 case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d:
433 case 0x1e: case 0x1f:
434 token_init(&parser->token, parser,
435 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
436 - token_pos, token_line, token_col);
437 return true;
438 default:
439 break;
440 }
441 break;
442 case STATE_CHAR_ESCAPE:
443 switch (c) {
444 case '"': case '\\': case '/': case 'b': case 'n':
445 case 'r': case 't':
446 state = STATE_CHARS;
447 break;
448 case 'u':
449 state = STATE_CHAR_U;
450 break;
451 default:
452 token_init(&parser->token, parser,
453 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
454 - token_pos, token_line, token_col);
455 return true;
456 }
457 break;
458 case STATE_CHAR_U:
459 switch (c) {
460 case '0': case '1': case '2': case '3': case '4':
461 case '5': case '6': case '7': case '8': case '9':
462 case 'a': case 'b': case 'c': case 'd': case 'e':
463 case 'f':
464 case 'A': case 'B': case 'C': case 'D': case 'E':
465 case 'F':
466 state = STATE_CHAR_UD;
467 break;
468 default:
469 token_init(&parser->token, parser,
470 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
471 - token_pos, token_line, token_col);
472 return true;
473 }
474 break;
475 case STATE_CHAR_UD:
476 switch (c) {
477 case '0': case '1': case '2': case '3': case '4':
478 case '5': case '6': case '7': case '8': case '9':
479 case 'a': case 'b': case 'c': case 'd': case 'e':
480 case 'f':
481 case 'A': case 'B': case 'C': case 'D': case 'E':
482 case 'F':
483 state = STATE_CHAR_UDD;
484 break;
485 default:
486 token_init(&parser->token, parser,
487 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
488 - token_pos, token_line, token_col);
489 return true;
490 }
491 break;
492 case STATE_CHAR_UDD:
493 switch (c) {
494 case '0': case '1': case '2': case '3': case '4':
495 case '5': case '6': case '7': case '8': case '9':
496 case 'a': case 'b': case 'c': case 'd': case 'e':
497 case 'f':
498 case 'A': case 'B': case 'C': case 'D': case 'E':
499 case 'F':
500 state = STATE_CHAR_UDDD;
501 break;
502 default:
503 token_init(&parser->token, parser,
504 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
505 - token_pos, token_line, token_col);
506 return true;
507 }
508 break;
509 case STATE_CHAR_UDDD:
510 switch (c) {
511 case '0': case '1': case '2': case '3': case '4':
512 case '5': case '6': case '7': case '8': case '9':
513 case 'a': case 'b': case 'c': case 'd': case 'e':
514 case 'f':
515 case 'A': case 'B': case 'C': case 'D': case 'E':
516 case 'F':
517 state = STATE_CHARS;
518 break;
519 default:
520 token_init(&parser->token, parser,
521 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
522 - token_pos, token_line, token_col);
523 return true;
524 }
525 break;
526 case STATE_STRING:
527 token_init(&parser->token, parser, TOKEN_TYPE_STRING,
528 token_pos, parser->pos - token_pos, token_line,
529 token_col);
530 state = STATE_ACCEPT;
531 break;
532 case STATE_MINUS:
533 switch (c) {
534 case '0':
535 state = STATE_LEADING_ZERO;
536 break;
537 case '1': case '2': case '3': case '4':
538 case '5': case '6': case '7': case '8': case '9':
539 state = STATE_DIGITS;
540 break;
541 default:
542 token_init(&parser->token, parser,
543 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
544 - token_pos, token_line, token_col);
545 return true;
546 }
547 break;
548 case STATE_LEADING_ZERO:
549 switch (c) {
550 case '.':
551 state = STATE_DECIMAL;
552 break;
553 default:
554 token_init(&parser->token, parser,
555 TOKEN_TYPE_NUMBER, token_pos, parser->pos -
556 token_pos, token_line, token_col);
557 state = STATE_ACCEPT;
558 break;
559 }
560 break;
561 case STATE_DIGITS:
562 switch (c) {
563 case '0': case '1': case '2': case '3': case '4':
564 case '5': case '6': case '7': case '8': case '9':
565 break;
566 case '.':
567 state = STATE_DECIMAL;
568 break;
569 default:
570 token_init(&parser->token, parser,
571 TOKEN_TYPE_NUMBER, token_pos, parser->pos -
572 token_pos, token_line, token_col);
573 state = STATE_ACCEPT;
574 break;
575 }
576 break;
577 case STATE_DECIMAL:
578 switch (c) {
579 case '0': case '1': case '2': case '3': case '4':
580 case '5': case '6': case '7': case '8': case '9':
581 state = STATE_FRAC_DIGITS;
582 break;
583 default:
584 token_init(&parser->token, parser,
585 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
586 - token_pos, token_line, token_col);
587 return true;
588 }
589 break;
590 case STATE_FRAC_DIGITS:
591 switch (c) {
592 case '0': case '1': case '2': case '3': case '4':
593 case '5': case '6': case '7': case '8': case '9':
594 break;
595 case 'e': case 'E':
596 state = STATE_EXP;
597 break;
598 default:
599 token_init(&parser->token, parser,
600 TOKEN_TYPE_NUMBER, token_pos, parser->pos -
601 token_pos, token_line, token_col);
602 state = STATE_ACCEPT;
603 break;
604 }
605 break;
606 case STATE_EXP:
607 switch (c) {
608 case '-': case '+':
609 state = STATE_EXP_SIGN;
610 break;
611 case '0': case '1': case '2': case '3': case '4':
612 case '5': case '6': case '7': case '8': case '9':
613 state = STATE_EXP_DIGITS;
614 break;
615 default:
616 token_init(&parser->token, parser,
617 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
618 - token_pos, token_line, token_col);
619 return true;
620 }
621 break;
622 case STATE_EXP_SIGN:
623 switch (c) {
624 case '0': case '1': case '2': case '3': case '4':
625 case '5': case '6': case '7': case '8': case '9':
626 state = STATE_EXP_DIGITS;
627 break;
628 default:
629 token_init(&parser->token, parser,
630 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
631 - token_pos, token_line, token_col);
632 return true;
633 }
634 break;
635 case STATE_EXP_DIGITS:
636 switch (c) {
637 case '0': case '1': case '2': case '3': case '4':
638 case '5': case '6': case '7': case '8': case '9':
639 break;
640 default:
641 token_init(&parser->token, parser,
642 TOKEN_TYPE_NUMBER, token_pos, parser->pos -
643 token_pos, token_line, token_col);
644 state = STATE_ACCEPT;
645 break;
646 }
647 break;
648 default:
649 not_reached();
650 }
651
652 if (state != STATE_ACCEPT) {
653 if (c == '\n') {
654 parser->line++;
655 parser->col = 0;
656 } else {
657 parser->col++;
658 }
659 parser->pos++;
660 }
661 }
662 return false;
663 }
664
665 static bool parser_parse_array(parser_t *parser);
666 static bool parser_parse_object(parser_t *parser);
667
668 static bool
parser_parse_value(parser_t * parser)669 parser_parse_value(parser_t *parser) {
670 switch (parser->token.token_type) {
671 case TOKEN_TYPE_NULL:
672 case TOKEN_TYPE_FALSE:
673 case TOKEN_TYPE_TRUE:
674 case TOKEN_TYPE_STRING:
675 case TOKEN_TYPE_NUMBER:
676 return false;
677 case TOKEN_TYPE_LBRACE:
678 return parser_parse_object(parser);
679 case TOKEN_TYPE_LBRACKET:
680 return parser_parse_array(parser);
681 default:
682 return true;
683 }
684 not_reached();
685 }
686
687 static bool
parser_parse_pair(parser_t * parser)688 parser_parse_pair(parser_t *parser) {
689 assert_d_eq(parser->token.token_type, TOKEN_TYPE_STRING,
690 "Pair should start with string");
691 if (parser_tokenize(parser)) {
692 return true;
693 }
694 switch (parser->token.token_type) {
695 case TOKEN_TYPE_COLON:
696 if (parser_tokenize(parser)) {
697 return true;
698 }
699 return parser_parse_value(parser);
700 default:
701 return true;
702 }
703 }
704
705 static bool
parser_parse_values(parser_t * parser)706 parser_parse_values(parser_t *parser) {
707 if (parser_parse_value(parser)) {
708 return true;
709 }
710
711 while (true) {
712 if (parser_tokenize(parser)) {
713 return true;
714 }
715 switch (parser->token.token_type) {
716 case TOKEN_TYPE_COMMA:
717 if (parser_tokenize(parser)) {
718 return true;
719 }
720 if (parser_parse_value(parser)) {
721 return true;
722 }
723 break;
724 case TOKEN_TYPE_RBRACKET:
725 return false;
726 default:
727 return true;
728 }
729 }
730 }
731
732 static bool
parser_parse_array(parser_t * parser)733 parser_parse_array(parser_t *parser) {
734 assert_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACKET,
735 "Array should start with [");
736 if (parser_tokenize(parser)) {
737 return true;
738 }
739 switch (parser->token.token_type) {
740 case TOKEN_TYPE_RBRACKET:
741 return false;
742 default:
743 return parser_parse_values(parser);
744 }
745 not_reached();
746 }
747
748 static bool
parser_parse_pairs(parser_t * parser)749 parser_parse_pairs(parser_t *parser) {
750 assert_d_eq(parser->token.token_type, TOKEN_TYPE_STRING,
751 "Object should start with string");
752 if (parser_parse_pair(parser)) {
753 return true;
754 }
755
756 while (true) {
757 if (parser_tokenize(parser)) {
758 return true;
759 }
760 switch (parser->token.token_type) {
761 case TOKEN_TYPE_COMMA:
762 if (parser_tokenize(parser)) {
763 return true;
764 }
765 switch (parser->token.token_type) {
766 case TOKEN_TYPE_STRING:
767 if (parser_parse_pair(parser)) {
768 return true;
769 }
770 break;
771 default:
772 return true;
773 }
774 break;
775 case TOKEN_TYPE_RBRACE:
776 return false;
777 default:
778 return true;
779 }
780 }
781 }
782
783 static bool
parser_parse_object(parser_t * parser)784 parser_parse_object(parser_t *parser) {
785 assert_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACE,
786 "Object should start with {");
787 if (parser_tokenize(parser)) {
788 return true;
789 }
790 switch (parser->token.token_type) {
791 case TOKEN_TYPE_STRING:
792 return parser_parse_pairs(parser);
793 case TOKEN_TYPE_RBRACE:
794 return false;
795 default:
796 return true;
797 }
798 not_reached();
799 }
800
801 static bool
parser_parse(parser_t * parser)802 parser_parse(parser_t *parser) {
803 if (parser_tokenize(parser)) {
804 goto label_error;
805 }
806 if (parser_parse_value(parser)) {
807 goto label_error;
808 }
809
810 if (parser_tokenize(parser)) {
811 goto label_error;
812 }
813 switch (parser->token.token_type) {
814 case TOKEN_TYPE_EOI:
815 return false;
816 default:
817 goto label_error;
818 }
819 not_reached();
820
821 label_error:
822 token_error(&parser->token);
823 return true;
824 }
825
TEST_BEGIN(test_json_parser)826 TEST_BEGIN(test_json_parser) {
827 size_t i;
828 const char *invalid_inputs[] = {
829 /* Tokenizer error case tests. */
830 "{ \"string\": X }",
831 "{ \"string\": nXll }",
832 "{ \"string\": nuXl }",
833 "{ \"string\": nulX }",
834 "{ \"string\": nullX }",
835 "{ \"string\": fXlse }",
836 "{ \"string\": faXse }",
837 "{ \"string\": falXe }",
838 "{ \"string\": falsX }",
839 "{ \"string\": falseX }",
840 "{ \"string\": tXue }",
841 "{ \"string\": trXe }",
842 "{ \"string\": truX }",
843 "{ \"string\": trueX }",
844 "{ \"string\": \"\n\" }",
845 "{ \"string\": \"\\z\" }",
846 "{ \"string\": \"\\uX000\" }",
847 "{ \"string\": \"\\u0X00\" }",
848 "{ \"string\": \"\\u00X0\" }",
849 "{ \"string\": \"\\u000X\" }",
850 "{ \"string\": -X }",
851 "{ \"string\": 0.X }",
852 "{ \"string\": 0.0eX }",
853 "{ \"string\": 0.0e+X }",
854
855 /* Parser error test cases. */
856 "{\"string\": }",
857 "{\"string\" }",
858 "{\"string\": [ 0 }",
859 "{\"string\": {\"a\":0, 1 } }",
860 "{\"string\": {\"a\":0: } }",
861 "{",
862 "{}{",
863 };
864 const char *valid_inputs[] = {
865 /* Token tests. */
866 "null",
867 "false",
868 "true",
869 "{}",
870 "{\"a\": 0}",
871 "[]",
872 "[0, 1]",
873 "0",
874 "1",
875 "10",
876 "-10",
877 "10.23",
878 "10.23e4",
879 "10.23e-4",
880 "10.23e+4",
881 "10.23E4",
882 "10.23E-4",
883 "10.23E+4",
884 "-10.23",
885 "-10.23e4",
886 "-10.23e-4",
887 "-10.23e+4",
888 "-10.23E4",
889 "-10.23E-4",
890 "-10.23E+4",
891 "\"value\"",
892 "\" \\\" \\/ \\b \\n \\r \\t \\u0abc \\u1DEF \"",
893
894 /* Parser test with various nesting. */
895 "{\"a\":null, \"b\":[1,[{\"c\":2},3]], \"d\":{\"e\":true}}",
896 };
897
898 for (i = 0; i < sizeof(invalid_inputs)/sizeof(const char *); i++) {
899 const char *input = invalid_inputs[i];
900 parser_t parser;
901 parser_init(&parser, false);
902 assert_false(parser_append(&parser, input),
903 "Unexpected input appending failure");
904 assert_true(parser_parse(&parser),
905 "Unexpected parse success for input: %s", input);
906 parser_fini(&parser);
907 }
908
909 for (i = 0; i < sizeof(valid_inputs)/sizeof(const char *); i++) {
910 const char *input = valid_inputs[i];
911 parser_t parser;
912 parser_init(&parser, true);
913 assert_false(parser_append(&parser, input),
914 "Unexpected input appending failure");
915 assert_false(parser_parse(&parser),
916 "Unexpected parse error for input: %s", input);
917 parser_fini(&parser);
918 }
919 }
920 TEST_END
921
922 void
write_cb(void * opaque,const char * str)923 write_cb(void *opaque, const char *str) {
924 parser_t *parser = (parser_t *)opaque;
925 if (parser_append(parser, str)) {
926 test_fail("Unexpected input appending failure");
927 }
928 }
929
TEST_BEGIN(test_stats_print_json)930 TEST_BEGIN(test_stats_print_json) {
931 const char *opts[] = {
932 "J",
933 "Jg",
934 "Jm",
935 "Jd",
936 "Jmd",
937 "Jgd",
938 "Jgm",
939 "Jgmd",
940 "Ja",
941 "Jb",
942 "Jl",
943 "Jx",
944 "Jbl",
945 "Jal",
946 "Jab",
947 "Jabl",
948 "Jax",
949 "Jbx",
950 "Jlx",
951 "Jablx",
952 "Jgmdablx",
953 };
954 unsigned arena_ind, i;
955
956 for (i = 0; i < 3; i++) {
957 unsigned j;
958
959 switch (i) {
960 case 0:
961 break;
962 case 1: {
963 size_t sz = sizeof(arena_ind);
964 assert_d_eq(mallctl("arenas.create", (void *)&arena_ind,
965 &sz, NULL, 0), 0, "Unexpected mallctl failure");
966 break;
967 } case 2: {
968 size_t mib[3];
969 size_t miblen = sizeof(mib)/sizeof(size_t);
970 assert_d_eq(mallctlnametomib("arena.0.destroy",
971 mib, &miblen), 0,
972 "Unexpected mallctlnametomib failure");
973 mib[1] = arena_ind;
974 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL,
975 0), 0, "Unexpected mallctlbymib failure");
976 break;
977 } default:
978 not_reached();
979 }
980
981 for (j = 0; j < sizeof(opts)/sizeof(const char *); j++) {
982 parser_t parser;
983
984 parser_init(&parser, true);
985 malloc_stats_print(write_cb, (void *)&parser, opts[j]);
986 assert_false(parser_parse(&parser),
987 "Unexpected parse error, opts=\"%s\"", opts[j]);
988 parser_fini(&parser);
989 }
990 }
991 }
992 TEST_END
993
994 int
main(void)995 main(void) {
996 return test(
997 test_json_parser,
998 test_stats_print_json);
999 }
1000