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