JSONParser.cpp (47099B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "vm/JSONParser.h" 8 9 #include "mozilla/Assertions.h" // MOZ_ASSERT 10 #include "mozilla/Attributes.h" // MOZ_STACK_CLASS 11 #include "mozilla/Range.h" // mozilla::Range 12 #include "mozilla/RangedPtr.h" // mozilla::RangedPtr 13 14 #include "mozilla/Sprintf.h" // SprintfLiteral 15 #include "mozilla/TextUtils.h" // mozilla::AsciiAlphanumericToNumber, mozilla::IsAsciiDigit, mozilla::IsAsciiHexDigit 16 17 #include <stddef.h> // size_t 18 #include <stdint.h> // uint32_t 19 #include <utility> // std::move 20 21 #include "jsnum.h" // ParseDecimalNumber, GetFullInteger, FullStringToDouble 22 23 #include "builtin/Array.h" // NewDenseCopiedArray 24 #include "builtin/ParseRecordObject.h" // js::ParseRecordObject 25 #include "ds/IdValuePair.h" // IdValuePair 26 #include "gc/GCEnum.h" // CanGC 27 #include "gc/Tracer.h" // JS::TraceRoot 28 #include "js/AllocPolicy.h" // ReportOutOfMemory 29 #include "js/CharacterEncoding.h" // JS::ConstUTF8CharsZ 30 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin 31 #include "js/ErrorReport.h" // JS_ReportErrorNumberASCII 32 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* 33 #include "js/GCVector.h" // JS::GCVector 34 #include "js/Id.h" // jsid 35 #include "js/JSON.h" // JS::IsValidJSON 36 #include "js/PropertyAndElement.h" // JS_SetPropertyById 37 #include "js/RootingAPI.h" // JS::Handle, JS::MutableHandle, MutableWrappedPtrOperations 38 #include "js/TypeDecls.h" // Latin1Char 39 #include "js/Utility.h" // js_delete 40 #include "js/Value.h" // JS::Value, JS::BooleanValue, JS::NullValue, JS::NumberValue, JS::StringValue 41 #include "js/Vector.h" // Vector 42 #include "util/StringBuilder.h" // JSStringBuilder 43 #include "vm/ArrayObject.h" // ArrayObject 44 #include "vm/ErrorReporting.h" // ReportCompileErrorLatin1, ErrorMetadata 45 #include "vm/JSAtomUtils.h" // AtomizeChars 46 #include "vm/JSContext.h" // JSContext 47 #include "vm/PlainObject.h" // NewPlainObjectWithMaybeDuplicateKeys, NewPlainObjectWithProto 48 #include "vm/Realm.h" // JS::Realm 49 #include "vm/StringType.h" // JSString, JSAtom, JSLinearString, NewStringCopyN, NameToId 50 51 #include "vm/JSAtomUtils-inl.h" // AtomToId 52 53 using namespace js; 54 55 using mozilla::AsciiAlphanumericToNumber; 56 using mozilla::IsAsciiDigit; 57 using mozilla::IsAsciiHexDigit; 58 using mozilla::RangedPtr; 59 60 template <typename CharT, typename ParserT> 61 void JSONTokenizer<CharT, ParserT>::getTextPosition(uint32_t* column, 62 uint32_t* line) { 63 CharPtr ptr = begin; 64 uint32_t col = 1; 65 uint32_t row = 1; 66 for (; ptr < current; ptr++) { 67 if (*ptr == '\n' || *ptr == '\r') { 68 ++row; 69 col = 1; 70 // \r\n is treated as a single newline. 71 if (ptr + 1 < current && *ptr == '\r' && *(ptr + 1) == '\n') { 72 ++ptr; 73 } 74 } else { 75 ++col; 76 } 77 } 78 *column = col; 79 *line = row; 80 } 81 82 static inline bool IsJSONWhitespace(char16_t c) { 83 return c == '\t' || c == '\r' || c == '\n' || c == ' '; 84 } 85 86 template <typename CharT, typename ParserT> 87 bool JSONTokenizer<CharT, ParserT>::consumeTrailingWhitespaces() { 88 for (; current < end; current++) { 89 if (!IsJSONWhitespace(*current)) { 90 return false; 91 } 92 } 93 return true; 94 } 95 96 template <typename CharT, typename ParserT> 97 JSONToken JSONTokenizer<CharT, ParserT>::advance() { 98 while (current < end && IsJSONWhitespace(*current)) { 99 current++; 100 } 101 if (current >= end) { 102 error("unexpected end of data"); 103 return token(JSONToken::Error); 104 } 105 106 sourceStart = current; 107 switch (*current) { 108 case '"': 109 return readString<JSONStringType::LiteralValue>(); 110 111 case '-': 112 case '0': 113 case '1': 114 case '2': 115 case '3': 116 case '4': 117 case '5': 118 case '6': 119 case '7': 120 case '8': 121 case '9': 122 return readNumber(); 123 124 case 't': 125 if (end - current < 4 || current[1] != 'r' || current[2] != 'u' || 126 current[3] != 'e') { 127 error("unexpected keyword"); 128 return token(JSONToken::Error); 129 } 130 current += 4; 131 if (!parser->handler.setBooleanValue(true, getSource())) { 132 return token(JSONToken::OOM); 133 } 134 return token(JSONToken::True); 135 136 case 'f': 137 if (end - current < 5 || current[1] != 'a' || current[2] != 'l' || 138 current[3] != 's' || current[4] != 'e') { 139 error("unexpected keyword"); 140 return token(JSONToken::Error); 141 } 142 current += 5; 143 if (!parser->handler.setBooleanValue(false, getSource())) { 144 return token(JSONToken::OOM); 145 } 146 return token(JSONToken::False); 147 148 case 'n': 149 if (end - current < 4 || current[1] != 'u' || current[2] != 'l' || 150 current[3] != 'l') { 151 error("unexpected keyword"); 152 return token(JSONToken::Error); 153 } 154 current += 4; 155 if (!parser->handler.setNullValue(getSource())) { 156 return token(JSONToken::OOM); 157 } 158 return token(JSONToken::Null); 159 160 case '[': 161 current++; 162 return token(JSONToken::ArrayOpen); 163 case ']': 164 current++; 165 return token(JSONToken::ArrayClose); 166 167 case '{': 168 current++; 169 return token(JSONToken::ObjectOpen); 170 case '}': 171 current++; 172 return token(JSONToken::ObjectClose); 173 174 case ',': 175 current++; 176 return token(JSONToken::Comma); 177 178 case ':': 179 current++; 180 return token(JSONToken::Colon); 181 182 default: 183 error("unexpected character"); 184 return token(JSONToken::Error); 185 } 186 } 187 188 template <typename CharT, typename ParserT> 189 JSONToken JSONTokenizer<CharT, ParserT>::advancePropertyName() { 190 MOZ_ASSERT(current[-1] == ','); 191 192 while (current < end && IsJSONWhitespace(*current)) { 193 current++; 194 } 195 if (current >= end) { 196 error("end of data when property name was expected"); 197 return token(JSONToken::Error); 198 } 199 200 if (*current == '"') { 201 return readString<JSONStringType::PropertyName>(); 202 } 203 204 error("expected double-quoted property name"); 205 return token(JSONToken::Error); 206 } 207 208 template <typename CharT, typename ParserT> 209 JSONToken JSONTokenizer<CharT, ParserT>::advancePropertyColon() { 210 MOZ_ASSERT(current[-1] == '"'); 211 212 while (current < end && IsJSONWhitespace(*current)) { 213 current++; 214 } 215 if (current >= end) { 216 error("end of data after property name when ':' was expected"); 217 return token(JSONToken::Error); 218 } 219 220 if (*current == ':') { 221 current++; 222 return token(JSONToken::Colon); 223 } 224 225 error("expected ':' after property name in object"); 226 return token(JSONToken::Error); 227 } 228 229 template <typename CharT> 230 static inline void AssertPastValue(const RangedPtr<const CharT> current) { 231 /* 232 * We're past an arbitrary JSON value, so the previous character is 233 * *somewhat* constrained, even if this assertion is pretty broad. Don't 234 * knock it till you tried it: this assertion *did* catch a bug once. 235 */ 236 MOZ_ASSERT((current[-1] == 'l' && current[-2] == 'l' && current[-3] == 'u' && 237 current[-4] == 'n') || 238 (current[-1] == 'e' && current[-2] == 'u' && current[-3] == 'r' && 239 current[-4] == 't') || 240 (current[-1] == 'e' && current[-2] == 's' && current[-3] == 'l' && 241 current[-4] == 'a' && current[-5] == 'f') || 242 current[-1] == '}' || current[-1] == ']' || current[-1] == '"' || 243 IsAsciiDigit(current[-1])); 244 } 245 246 template <typename CharT, typename ParserT> 247 JSONToken JSONTokenizer<CharT, ParserT>::advanceAfterProperty() { 248 AssertPastValue(current); 249 250 while (current < end && IsJSONWhitespace(*current)) { 251 current++; 252 } 253 if (current >= end) { 254 error("end of data after property value in object"); 255 return token(JSONToken::Error); 256 } 257 258 if (*current == ',') { 259 current++; 260 return token(JSONToken::Comma); 261 } 262 263 if (*current == '}') { 264 current++; 265 return token(JSONToken::ObjectClose); 266 } 267 268 error("expected ',' or '}' after property value in object"); 269 return token(JSONToken::Error); 270 } 271 272 template <typename CharT, typename ParserT> 273 JSONToken JSONTokenizer<CharT, ParserT>::advanceAfterObjectOpen() { 274 MOZ_ASSERT(current[-1] == '{'); 275 276 while (current < end && IsJSONWhitespace(*current)) { 277 current++; 278 } 279 if (current >= end) { 280 error("end of data while reading object contents"); 281 return token(JSONToken::Error); 282 } 283 284 if (*current == '"') { 285 return readString<JSONStringType::PropertyName>(); 286 } 287 288 if (*current == '}') { 289 current++; 290 return token(JSONToken::ObjectClose); 291 } 292 293 error("expected property name or '}'"); 294 return token(JSONToken::Error); 295 } 296 297 template <typename CharT, typename ParserT> 298 JSONToken JSONTokenizer<CharT, ParserT>::advanceAfterArrayElement() { 299 AssertPastValue(current); 300 301 while (current < end && IsJSONWhitespace(*current)) { 302 current++; 303 } 304 if (current >= end) { 305 error("end of data when ',' or ']' was expected"); 306 return token(JSONToken::Error); 307 } 308 309 if (*current == ',') { 310 current++; 311 return token(JSONToken::Comma); 312 } 313 314 if (*current == ']') { 315 current++; 316 return token(JSONToken::ArrayClose); 317 } 318 319 error("expected ',' or ']' after array element"); 320 return token(JSONToken::Error); 321 } 322 323 template <typename CharT, typename ParserT> 324 template <JSONStringType ST> 325 JSONToken JSONTokenizer<CharT, ParserT>::stringToken(const CharPtr start, 326 size_t length) { 327 if (!parser->handler.template setStringValue<ST>(start, length, 328 getSource())) { 329 return JSONToken::OOM; 330 } 331 return JSONToken::String; 332 } 333 334 template <typename CharT, typename ParserT> 335 template <JSONStringType ST> 336 JSONToken JSONTokenizer<CharT, ParserT>::stringToken( 337 JSONStringBuilder& builder) { 338 if (!parser->handler.template setStringValue<ST>(builder, getSource())) { 339 return JSONToken::OOM; 340 } 341 return JSONToken::String; 342 } 343 344 template <typename CharT, typename ParserT> 345 JSONToken JSONTokenizer<CharT, ParserT>::numberToken(double d) { 346 if (!parser->handler.setNumberValue(d, getSource())) { 347 return JSONToken::OOM; 348 } 349 return JSONToken::Number; 350 } 351 352 template <typename CharT, typename ParserT> 353 template <JSONStringType ST> 354 JSONToken JSONTokenizer<CharT, ParserT>::readString() { 355 MOZ_ASSERT(current < end); 356 MOZ_ASSERT(*current == '"'); 357 358 /* 359 * JSONString: 360 * /^"([^\u0000-\u001F"\\]|\\(["/\\bfnrt]|u[0-9a-fA-F]{4}))*"$/ 361 */ 362 363 if (++current == end) { 364 error("unterminated string literal"); 365 return token(JSONToken::Error); 366 } 367 368 /* 369 * Optimization: if the source contains no escaped characters, create the 370 * string directly from the source text. 371 */ 372 CharPtr start = current; 373 for (; current < end; current++) { 374 if (*current == '"') { 375 size_t length = current - start; 376 current++; 377 return stringToken<ST>(start, length); 378 } 379 380 if (*current == '\\') { 381 break; 382 } 383 384 if (*current <= 0x001F) { 385 error("bad control character in string literal"); 386 return token(JSONToken::Error); 387 } 388 } 389 390 /* 391 * Slow case: string contains escaped characters. Copy a maximal sequence 392 * of unescaped characters into a temporary buffer, then an escaped 393 * character, and repeat until the entire string is consumed. 394 */ 395 JSONStringBuilder builder(parser->handler.context()); 396 do { 397 if (start < current && !builder.append(start.get(), current.get())) { 398 return token(JSONToken::OOM); 399 } 400 401 if (current >= end) { 402 break; 403 } 404 405 char16_t c = *current++; 406 if (c == '"') { 407 return stringToken<ST>(builder); 408 } 409 410 if (c != '\\') { 411 --current; 412 error("bad character in string literal"); 413 return token(JSONToken::Error); 414 } 415 416 if (current >= end) { 417 break; 418 } 419 420 switch (*current++) { 421 case '"': 422 c = '"'; 423 break; 424 case '/': 425 c = '/'; 426 break; 427 case '\\': 428 c = '\\'; 429 break; 430 case 'b': 431 c = '\b'; 432 break; 433 case 'f': 434 c = '\f'; 435 break; 436 case 'n': 437 c = '\n'; 438 break; 439 case 'r': 440 c = '\r'; 441 break; 442 case 't': 443 c = '\t'; 444 break; 445 446 case 'u': 447 if (end - current < 4 || 448 !(IsAsciiHexDigit(current[0]) && IsAsciiHexDigit(current[1]) && 449 IsAsciiHexDigit(current[2]) && IsAsciiHexDigit(current[3]))) { 450 // Point to the first non-hexadecimal character (which may be 451 // missing). 452 if (current == end || !IsAsciiHexDigit(current[0])) { 453 ; // already at correct location 454 } else if (current + 1 == end || !IsAsciiHexDigit(current[1])) { 455 current += 1; 456 } else if (current + 2 == end || !IsAsciiHexDigit(current[2])) { 457 current += 2; 458 } else if (current + 3 == end || !IsAsciiHexDigit(current[3])) { 459 current += 3; 460 } else { 461 MOZ_CRASH("logic error determining first erroneous character"); 462 } 463 464 error("bad Unicode escape"); 465 return token(JSONToken::Error); 466 } 467 c = (AsciiAlphanumericToNumber(current[0]) << 12) | 468 (AsciiAlphanumericToNumber(current[1]) << 8) | 469 (AsciiAlphanumericToNumber(current[2]) << 4) | 470 (AsciiAlphanumericToNumber(current[3])); 471 current += 4; 472 break; 473 474 default: 475 current--; 476 error("bad escaped character"); 477 return token(JSONToken::Error); 478 } 479 if (!builder.append(c)) { 480 return token(JSONToken::OOM); 481 } 482 483 start = current; 484 for (; current < end; current++) { 485 if (*current == '"' || *current == '\\' || *current <= 0x001F) { 486 break; 487 } 488 } 489 } while (current < end); 490 491 error("unterminated string"); 492 return token(JSONToken::Error); 493 } 494 495 template <typename CharT, typename ParserT> 496 JSONToken JSONTokenizer<CharT, ParserT>::readNumber() { 497 MOZ_ASSERT(current < end); 498 MOZ_ASSERT(IsAsciiDigit(*current) || *current == '-'); 499 500 /* 501 * JSONNumber: 502 * /^-?(0|[1-9][0-9]+)(\.[0-9]+)?([eE][\+\-]?[0-9]+)?$/ 503 */ 504 505 bool negative = *current == '-'; 506 507 /* -? */ 508 if (negative && ++current == end) { 509 error("no number after minus sign"); 510 return token(JSONToken::Error); 511 } 512 513 const CharPtr digitStart = current; 514 515 /* 0|[1-9][0-9]+ */ 516 if (!IsAsciiDigit(*current)) { 517 error("unexpected non-digit"); 518 return token(JSONToken::Error); 519 } 520 if (*current++ != '0') { 521 for (; current < end; current++) { 522 if (!IsAsciiDigit(*current)) { 523 break; 524 } 525 } 526 } 527 528 /* Fast path: no fractional or exponent part. */ 529 if (current == end || 530 (*current != '.' && *current != 'e' && *current != 'E')) { 531 mozilla::Range<const CharT> chars(digitStart.get(), current - digitStart); 532 if (chars.length() < strlen("9007199254740992")) { 533 // If the decimal number is shorter than the length of 2**53, (the 534 // largest number a double can represent with integral precision), 535 // parse it using a decimal-only parser. This comparison is 536 // conservative but faster than a fully-precise check. 537 double d = ParseDecimalNumber(chars); 538 return numberToken(negative ? -d : d); 539 } 540 541 double d; 542 if (!GetFullInteger(digitStart.get(), current.get(), 10, 543 IntegerSeparatorHandling::None, &d)) { 544 parser->outOfMemory(); 545 return token(JSONToken::OOM); 546 } 547 return numberToken(negative ? -d : d); 548 } 549 550 /* (\.[0-9]+)? */ 551 if (current < end && *current == '.') { 552 if (++current == end) { 553 error("missing digits after decimal point"); 554 return token(JSONToken::Error); 555 } 556 if (!IsAsciiDigit(*current)) { 557 error("unterminated fractional number"); 558 return token(JSONToken::Error); 559 } 560 while (++current < end) { 561 if (!IsAsciiDigit(*current)) { 562 break; 563 } 564 } 565 } 566 567 /* ([eE][\+\-]?[0-9]+)? */ 568 if (current < end && (*current == 'e' || *current == 'E')) { 569 if (++current == end) { 570 error("missing digits after exponent indicator"); 571 return token(JSONToken::Error); 572 } 573 if (*current == '+' || *current == '-') { 574 if (++current == end) { 575 error("missing digits after exponent sign"); 576 return token(JSONToken::Error); 577 } 578 } 579 if (!IsAsciiDigit(*current)) { 580 error("exponent part is missing a number"); 581 return token(JSONToken::Error); 582 } 583 while (++current < end) { 584 if (!IsAsciiDigit(*current)) { 585 break; 586 } 587 } 588 } 589 590 double d = FullStringToDouble(digitStart.get(), current.get()); 591 return numberToken(negative ? -d : d); 592 } 593 594 template <typename CharT, typename ParserT> 595 void JSONTokenizer<CharT, ParserT>::error(const char* msg) { 596 parser->error(msg); 597 } 598 599 static void ReportJSONSyntaxError(FrontendContext* fc, ErrorMetadata&& metadata, 600 unsigned errorNumber, ...) { 601 va_list args; 602 va_start(args, errorNumber); 603 604 js::ReportCompileErrorLatin1VA(fc, std::move(metadata), nullptr, errorNumber, 605 &args); 606 607 va_end(args); 608 } 609 610 // JSONFullParseHandlerAnyChar uses an AutoSelectGCHeap to switch to allocating 611 // in the tenured heap if we trigger more than one nursery collection. 612 // 613 // JSON parsing allocates from the leaves of the tree upwards (unlike 614 // structured clone deserialization which works from the root 615 // downwards). Because of this it doesn't necessarily make sense to stop 616 // nursery allocation after the first collection as this doesn't doom the 617 // whole data structure to being tenured. We don't know ahead of time how 618 // big the resulting data structure will be but after two nursery 619 // collections then at least half of it will end up tenured. 620 621 JSONFullParseHandlerAnyChar::JSONFullParseHandlerAnyChar(JSContext* cx) 622 : cx(cx), gcHeap(cx, 1), freeElements(cx), freeProperties(cx) {} 623 624 JSONFullParseHandlerAnyChar::JSONFullParseHandlerAnyChar( 625 JSONFullParseHandlerAnyChar&& other) noexcept 626 : cx(other.cx), 627 v(other.v), 628 parseType(other.parseType), 629 gcHeap(cx, 1), 630 freeElements(std::move(other.freeElements)), 631 freeProperties(std::move(other.freeProperties)) {} 632 633 JSONFullParseHandlerAnyChar::~JSONFullParseHandlerAnyChar() { 634 for (size_t i = 0; i < freeElements.length(); i++) { 635 js_delete(freeElements[i]); 636 } 637 638 for (size_t i = 0; i < freeProperties.length(); i++) { 639 js_delete(freeProperties[i]); 640 } 641 } 642 643 inline bool JSONFullParseHandlerAnyChar::objectOpen( 644 Vector<StackEntry, 10>& stack, PropertyVector** properties) { 645 if (!freeProperties.empty()) { 646 *properties = freeProperties.popCopy(); 647 (*properties)->clear(); 648 } else { 649 (*properties) = cx->new_<PropertyVector>(cx); 650 if (!*properties) { 651 return false; 652 } 653 } 654 if (!stack.append(StackEntry(cx, *properties))) { 655 js_delete(*properties); 656 return false; 657 } 658 659 return true; 660 } 661 662 inline bool JSONFullParseHandlerAnyChar::objectPropertyName( 663 Vector<StackEntry, 10>& stack, bool* isProtoInEval) { 664 *isProtoInEval = false; 665 jsid id = AtomToId(atomValue()); 666 if (parseType == ParseType::AttemptForEval) { 667 // In |JSON.parse|, "__proto__" is a property like any other and may 668 // appear multiple times. In object literal syntax, "__proto__" is 669 // prototype mutation and can appear at most once. |JSONParser| only 670 // supports the former semantics, so if this parse attempt is for 671 // |eval|, return true (without reporting an error) to indicate the 672 // JSON parse attempt was unsuccessful. 673 if (id == NameToId(cx->names().proto_)) { 674 *isProtoInEval = true; 675 return true; 676 } 677 } 678 PropertyVector& properties = stack.back().properties(); 679 if (!properties.emplaceBack(id)) { 680 return false; 681 } 682 683 return true; 684 } 685 686 inline bool JSONFullParseHandlerAnyChar::finishObjectMember( 687 Vector<StackEntry, 10>& stack, JS::Handle<JS::Value> value, 688 PropertyVector** properties) { 689 *properties = &stack.back().properties(); 690 (*properties)->back().value = value; 691 return true; 692 } 693 694 inline bool JSONFullParseHandlerAnyChar::finishObject( 695 Vector<StackEntry, 10>& stack, JS::MutableHandle<JS::Value> vp, 696 PropertyVector* properties) { 697 MOZ_ASSERT(properties == &stack.back().properties()); 698 699 NewObjectKind newKind = GenericObject; 700 if (gcHeap == gc::Heap::Tenured) { 701 newKind = TenuredObject; 702 } 703 // properties is traced in the parser; see JSONParser<CharT>::trace() 704 JSObject* obj = NewPlainObjectWithMaybeDuplicateKeys( 705 cx, Handle<IdValueVector>::fromMarkedLocation(properties), newKind); 706 if (!obj) { 707 return false; 708 } 709 710 vp.setObject(*obj); 711 if (!freeProperties.append(properties)) { 712 return false; 713 } 714 stack.popBack(); 715 return true; 716 } 717 718 inline bool JSONFullParseHandlerAnyChar::arrayOpen( 719 Vector<StackEntry, 10>& stack, ElementVector** elements) { 720 if (!freeElements.empty()) { 721 *elements = freeElements.popCopy(); 722 (*elements)->clear(); 723 } else { 724 (*elements) = cx->new_<ElementVector>(cx); 725 if (!*elements) { 726 return false; 727 } 728 } 729 if (!stack.append(StackEntry(cx, *elements))) { 730 js_delete(*elements); 731 return false; 732 } 733 734 return true; 735 } 736 737 inline bool JSONFullParseHandlerAnyChar::arrayElement( 738 Vector<StackEntry, 10>& stack, JS::Handle<JS::Value> value, 739 ElementVector** elements) { 740 *elements = &stack.back().elements(); 741 return (*elements)->append(value.get()); 742 } 743 744 inline bool JSONFullParseHandlerAnyChar::finishArray( 745 Vector<StackEntry, 10>& stack, JS::MutableHandle<JS::Value> vp, 746 ElementVector* elements) { 747 MOZ_ASSERT(elements == &stack.back().elements()); 748 749 NewObjectKind newKind = GenericObject; 750 if (gcHeap == gc::Heap::Tenured) { 751 newKind = TenuredObject; 752 } 753 ArrayObject* obj = 754 NewDenseCopiedArray(cx, elements->length(), elements->begin(), newKind); 755 if (!obj) { 756 return false; 757 } 758 759 vp.setObject(*obj); 760 if (!freeElements.append(elements)) { 761 return false; 762 } 763 stack.popBack(); 764 return true; 765 } 766 767 inline void JSONFullParseHandlerAnyChar::freeStackEntry(StackEntry& entry) { 768 if (entry.state == JSONParserState::FinishArrayElement) { 769 js_delete(&entry.elements()); 770 } else { 771 js_delete(&entry.properties()); 772 } 773 } 774 775 void JSONFullParseHandlerAnyChar::trace(JSTracer* trc) { 776 JS::TraceRoot(trc, &v, "JSONFullParseHandlerAnyChar current value"); 777 } 778 779 template <typename CharT> 780 bool JSONFullParseHandler<CharT>::JSONStringBuilder::append(char16_t c) { 781 return buffer.append(c); 782 } 783 784 template <typename CharT> 785 bool JSONFullParseHandler<CharT>::JSONStringBuilder::append(const CharT* begin, 786 const CharT* end) { 787 return buffer.append(begin, end); 788 } 789 790 template <typename CharT> 791 template <JSONStringType ST> 792 inline bool JSONFullParseHandler<CharT>::setStringValue( 793 CharPtr start, size_t length, mozilla::Span<const CharT>&& source) { 794 JSString* str; 795 if constexpr (ST == JSONStringType::PropertyName) { 796 str = AtomizeChars(cx, start.get(), length); 797 } else { 798 str = NewStringCopyN<CanGC>(cx, start.get(), length, gcHeap); 799 } 800 801 if (!str) { 802 return false; 803 } 804 v = JS::StringValue(str); 805 return true; 806 } 807 808 template <typename CharT> 809 template <JSONStringType ST> 810 inline bool JSONFullParseHandler<CharT>::setStringValue( 811 JSONStringBuilder& builder, mozilla::Span<const CharT>&& source) { 812 JSString* str; 813 if constexpr (ST == JSONStringType::PropertyName) { 814 str = builder.buffer.finishAtom(); 815 } else { 816 str = builder.buffer.finishString(gcHeap); 817 } 818 819 if (!str) { 820 return false; 821 } 822 v = JS::StringValue(str); 823 return true; 824 } 825 826 template <typename CharT> 827 inline bool JSONFullParseHandler<CharT>::setNumberValue( 828 double d, mozilla::Span<const CharT>&& source) { 829 v = JS::NumberValue(d); 830 return true; 831 } 832 833 template <typename CharT> 834 inline bool JSONFullParseHandler<CharT>::setBooleanValue( 835 bool value, mozilla::Span<const CharT>&& source) { 836 return true; 837 } 838 839 template <typename CharT> 840 inline bool JSONFullParseHandler<CharT>::setNullValue( 841 mozilla::Span<const CharT>&& source) { 842 return true; 843 } 844 845 template <typename CharT> 846 void JSONFullParseHandler<CharT>::reportError(const char* msg, uint32_t line, 847 uint32_t column) { 848 const size_t MaxWidth = sizeof("4294967295"); 849 char columnString[MaxWidth]; 850 SprintfLiteral(columnString, "%" PRIu32, column); 851 char lineString[MaxWidth]; 852 SprintfLiteral(lineString, "%" PRIu32, line); 853 854 if (reportLineNumbersFromParsedData) { 855 AutoReportFrontendContext fc(cx); 856 857 ErrorMetadata metadata; 858 metadata.isMuted = false; 859 metadata.filename = filename.valueOr(JS::ConstUTF8CharsZ("")); 860 metadata.lineNumber = line; 861 metadata.columnNumber = JS::ColumnNumberOneOrigin(column); 862 863 ReportJSONSyntaxError(&fc, std::move(metadata), JSMSG_JSON_BAD_PARSE, msg, 864 lineString, columnString); 865 } else { 866 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 867 JSMSG_JSON_BAD_PARSE, msg, lineString, 868 columnString); 869 } 870 } 871 872 template <typename CharT, typename HandlerT> 873 JSONPerHandlerParser<CharT, HandlerT>::~JSONPerHandlerParser() { 874 for (size_t i = 0; i < stack.length(); i++) { 875 handler.freeStackEntry(stack[i]); 876 } 877 } 878 879 template <typename CharT, typename HandlerT> 880 template <typename TempValueT, typename ResultSetter> 881 bool JSONPerHandlerParser<CharT, HandlerT>::parseImpl(TempValueT& value, 882 ResultSetter setResult) { 883 MOZ_ASSERT(stack.empty()); 884 885 JSONToken token; 886 JSONParserState state = JSONParserState::JSONValue; 887 while (true) { 888 switch (state) { 889 case JSONParserState::FinishObjectMember: { 890 typename HandlerT::PropertyVector* properties; 891 if (!handler.finishObjectMember(stack, value, &properties)) { 892 return false; 893 } 894 895 token = tokenizer.advanceAfterProperty(); 896 if (token == JSONToken::ObjectClose) { 897 if (!handler.finishObject(stack, &value, properties)) { 898 return false; 899 } 900 break; 901 } 902 if (token != JSONToken::Comma) { 903 if (token == JSONToken::OOM) { 904 return false; 905 } 906 if (token != JSONToken::Error) { 907 error( 908 "expected ',' or '}' after property-value pair in object " 909 "literal"); 910 } 911 return handler.errorReturn(); 912 } 913 token = tokenizer.advancePropertyName(); 914 /* FALL THROUGH */ 915 } 916 917 JSONMember: 918 if (token == JSONToken::String) { 919 bool isProtoInEval; 920 if (!handler.objectPropertyName(stack, &isProtoInEval)) { 921 return false; 922 } 923 if (isProtoInEval) { 924 // See JSONFullParseHandlerAnyChar::objectPropertyName. 925 return true; 926 } 927 token = tokenizer.advancePropertyColon(); 928 if (token != JSONToken::Colon) { 929 MOZ_ASSERT(token == JSONToken::Error); 930 return handler.errorReturn(); 931 } 932 goto JSONValue; 933 } 934 if (token == JSONToken::OOM) { 935 return false; 936 } 937 if (token != JSONToken::Error) { 938 error("property names must be double-quoted strings"); 939 } 940 return handler.errorReturn(); 941 942 case JSONParserState::FinishArrayElement: { 943 typename HandlerT::ElementVector* elements; 944 if (!handler.arrayElement(stack, value, &elements)) { 945 return false; 946 } 947 token = tokenizer.advanceAfterArrayElement(); 948 if (token == JSONToken::Comma) { 949 goto JSONValue; 950 } 951 if (token == JSONToken::ArrayClose) { 952 if (!handler.finishArray(stack, &value, elements)) { 953 return false; 954 } 955 break; 956 } 957 MOZ_ASSERT(token == JSONToken::Error); 958 return handler.errorReturn(); 959 } 960 961 JSONValue: 962 case JSONParserState::JSONValue: 963 token = tokenizer.advance(); 964 JSONValueSwitch: 965 switch (token) { 966 case JSONToken::String: 967 value = handler.stringValue(); 968 break; 969 case JSONToken::Number: 970 value = handler.numberValue(); 971 break; 972 case JSONToken::True: 973 value = handler.booleanValue(true); 974 break; 975 case JSONToken::False: 976 value = handler.booleanValue(false); 977 break; 978 case JSONToken::Null: 979 value = handler.nullValue(); 980 break; 981 982 case JSONToken::ArrayOpen: { 983 typename HandlerT::ElementVector* elements; 984 if (!handler.arrayOpen(stack, &elements)) { 985 return false; 986 } 987 988 token = tokenizer.advance(); 989 if (token == JSONToken::ArrayClose) { 990 if (!handler.finishArray(stack, &value, elements)) { 991 return false; 992 } 993 break; 994 } 995 goto JSONValueSwitch; 996 } 997 998 case JSONToken::ObjectOpen: { 999 typename HandlerT::PropertyVector* properties; 1000 if (!handler.objectOpen(stack, &properties)) { 1001 return false; 1002 } 1003 1004 token = tokenizer.advanceAfterObjectOpen(); 1005 if (token == JSONToken::ObjectClose) { 1006 if (!handler.finishObject(stack, &value, properties)) { 1007 return false; 1008 } 1009 break; 1010 } 1011 goto JSONMember; 1012 } 1013 1014 case JSONToken::ArrayClose: 1015 case JSONToken::ObjectClose: 1016 case JSONToken::Colon: 1017 case JSONToken::Comma: 1018 // Move the current pointer backwards so that the position 1019 // reported in the error message is correct. 1020 tokenizer.unget(); 1021 error("unexpected character"); 1022 return handler.errorReturn(); 1023 1024 case JSONToken::OOM: 1025 return false; 1026 1027 case JSONToken::Error: 1028 return handler.errorReturn(); 1029 } 1030 break; 1031 } 1032 1033 if (stack.empty()) { 1034 break; 1035 } 1036 state = stack.back().state; 1037 } 1038 1039 if (!tokenizer.consumeTrailingWhitespaces()) { 1040 error("unexpected non-whitespace character after JSON data"); 1041 return handler.errorReturn(); 1042 } 1043 1044 MOZ_ASSERT(tokenizer.finished()); 1045 MOZ_ASSERT(stack.empty()); 1046 1047 setResult(value); 1048 return true; 1049 } 1050 1051 template <typename CharT, typename HandlerT> 1052 void JSONPerHandlerParser<CharT, HandlerT>::outOfMemory() { 1053 ReportOutOfMemory(handler.context()); 1054 } 1055 1056 template <typename CharT, typename HandlerT> 1057 void JSONPerHandlerParser<CharT, HandlerT>::error(const char* msg) { 1058 if (handler.ignoreError()) { 1059 return; 1060 } 1061 1062 uint32_t column = 1, line = 1; 1063 tokenizer.getTextPosition(&column, &line); 1064 1065 handler.reportError(msg, line, column); 1066 } 1067 1068 template class js::JSONPerHandlerParser<Latin1Char, 1069 js::JSONFullParseHandler<Latin1Char>>; 1070 template class js::JSONPerHandlerParser<char16_t, 1071 js::JSONFullParseHandler<char16_t>>; 1072 1073 template class js::JSONPerHandlerParser<Latin1Char, 1074 js::JSONReviveHandler<Latin1Char>>; 1075 template class js::JSONPerHandlerParser<char16_t, 1076 js::JSONReviveHandler<char16_t>>; 1077 1078 template class js::JSONPerHandlerParser<Latin1Char, 1079 js::JSONSyntaxParseHandler<Latin1Char>>; 1080 template class js::JSONPerHandlerParser<char16_t, 1081 js::JSONSyntaxParseHandler<char16_t>>; 1082 1083 template <typename CharT> 1084 bool JSONParser<CharT>::parse(JS::MutableHandle<JS::Value> vp) { 1085 JS::Rooted<JS::Value> tempValue(this->handler.cx); 1086 1087 vp.setUndefined(); 1088 1089 return this->parseImpl(tempValue, 1090 [&](JS::Handle<JS::Value> value) { vp.set(value); }); 1091 } 1092 1093 template <typename CharT> 1094 void JSONParser<CharT>::trace(JSTracer* trc) { 1095 this->handler.trace(trc); 1096 1097 for (auto& elem : this->stack) { 1098 if (elem.state == JSONParserState::FinishArrayElement) { 1099 elem.elements().trace(trc); 1100 } else { 1101 elem.properties().trace(trc); 1102 } 1103 } 1104 } 1105 1106 template class js::JSONParser<Latin1Char>; 1107 template class js::JSONParser<char16_t>; 1108 1109 template <typename CharT> 1110 inline bool JSONReviveHandler<CharT>::objectOpen(Vector<StackEntry, 10>& stack, 1111 PropertyVector** properties) { 1112 ParseRecordObject* newParseRecord = 1113 ParseRecordObject::create(context(), JS::Value()); 1114 if (!newParseRecord) { 1115 return false; 1116 } 1117 if (!parseRecordStack.append(newParseRecord)) { 1118 return false; 1119 } 1120 1121 return Base::objectOpen(stack, properties); 1122 } 1123 1124 template <typename CharT> 1125 inline bool JSONReviveHandler<CharT>::finishObjectMember( 1126 Vector<StackEntry, 10>& stack, JS::Handle<JS::Value> value, 1127 PropertyVector** properties) { 1128 if (!Base::finishObjectMember(stack, value, properties)) { 1129 return false; 1130 } 1131 1132 Rooted<ParseRecordObject*> memberRecord(context(), 1133 parseRecordStack.popCopy()); 1134 // Removes the member's key from the stack 1135 parseRecordStack.popBack(); 1136 1137 Rooted<JS::PropertyKey> key(context(), (*properties)->back().id); 1138 1139 return parseRecordStack.back()->addEntries(context(), key, memberRecord); 1140 } 1141 1142 template <typename CharT> 1143 inline bool JSONReviveHandler<CharT>::finishObject( 1144 Vector<StackEntry, 10>& stack, JS::MutableHandle<JS::Value> vp, 1145 PropertyVector* properties) { 1146 if (!Base::finishObject(stack, vp, properties)) { 1147 return false; 1148 } 1149 parseRecordStack.back()->setValue(vp); 1150 return true; 1151 } 1152 1153 template <typename CharT> 1154 inline bool JSONReviveHandler<CharT>::arrayOpen(Vector<StackEntry, 10>& stack, 1155 ElementVector** elements) { 1156 ParseRecordObject* newParseRecord = 1157 ParseRecordObject::create(context(), JS::Value()); 1158 if (!newParseRecord) { 1159 return false; 1160 } 1161 if (!parseRecordStack.append(newParseRecord)) { 1162 return false; 1163 } 1164 1165 return Base::arrayOpen(stack, elements); 1166 } 1167 1168 template <typename CharT> 1169 inline bool JSONReviveHandler<CharT>::arrayElement( 1170 Vector<StackEntry, 10>& stack, JS::Handle<JS::Value> value, 1171 ElementVector** elements) { 1172 if (!Base::arrayElement(stack, value, elements)) { 1173 return false; 1174 } 1175 size_t index = (*elements)->length() - 1; 1176 // The JSON string is limited to JS::MaxStringLength, so there should be no 1177 // way to get more than IntMax elements 1178 MOZ_ASSERT(index <= js::PropertyKey::IntMax); 1179 Rooted<JS::PropertyKey> key(context(), js::PropertyKey::Int(int32_t(index))); 1180 1181 Rooted<ParseRecordObject*> parseRecord(context(), parseRecordStack.popCopy()); 1182 return parseRecordStack.back()->addEntries(context(), key, parseRecord); 1183 } 1184 1185 template <typename CharT> 1186 inline bool JSONReviveHandler<CharT>::finishArray( 1187 Vector<StackEntry, 10>& stack, JS::MutableHandle<JS::Value> vp, 1188 ElementVector* elements) { 1189 if (!Base::finishArray(stack, vp, elements)) { 1190 return false; 1191 } 1192 parseRecordStack.back()->setValue(vp); 1193 return true; 1194 } 1195 1196 template <typename CharT> 1197 inline bool JSONReviveHandler<CharT>::finishPrimitiveParseRecord( 1198 const Value& value, SourceT source) { 1199 MOZ_ASSERT(!source.IsEmpty()); // Empty source is for objects and arrays 1200 Rooted<JSONParseNode*> parseNode( 1201 context(), NewStringCopy<CanGC, CharT>(context(), source)); 1202 if (!parseNode) { 1203 return false; 1204 } 1205 1206 ParseRecordObject* parseRecord = 1207 ParseRecordObject::create(context(), parseNode, value); 1208 if (!parseRecord) { 1209 return false; 1210 } 1211 1212 return !!parseRecordStack.append(parseRecord); 1213 } 1214 1215 template <typename CharT> 1216 void JSONReviveHandler<CharT>::trace(JSTracer* trc) { 1217 Base::trace(trc); 1218 this->parseRecordStack.trace(trc); 1219 } 1220 1221 template <typename CharT> 1222 bool JSONReviveParser<CharT>::parse(JS::MutableHandle<JS::Value> vp, 1223 JS::MutableHandle<ParseRecordObject*> pro) { 1224 JS::Rooted<JS::Value> tempValue(this->handler.cx); 1225 1226 vp.setUndefined(); 1227 1228 if (!this->parseImpl(tempValue, 1229 [&](JS::Handle<JS::Value> value) { vp.set(value); })) { 1230 return false; 1231 } 1232 MOZ_ASSERT(this->handler.getParseRecordObject()); 1233 pro.set(this->handler.getParseRecordObject()); 1234 return true; 1235 } 1236 1237 template <typename CharT> 1238 void JSONReviveParser<CharT>::trace(JSTracer* trc) { 1239 this->handler.trace(trc); 1240 1241 for (auto& elem : this->stack) { 1242 if (elem.state == JSONParserState::FinishArrayElement) { 1243 elem.elements().trace(trc); 1244 } else { 1245 elem.properties().trace(trc); 1246 } 1247 } 1248 } 1249 1250 template class js::JSONReviveParser<Latin1Char>; 1251 template class js::JSONReviveParser<char16_t>; 1252 1253 template <typename CharT> 1254 inline bool JSONSyntaxParseHandler<CharT>::objectOpen( 1255 Vector<StackEntry, 10>& stack, PropertyVector** properties) { 1256 StackEntry entry{JSONParserState::FinishObjectMember}; 1257 if (!stack.append(entry)) { 1258 return false; 1259 } 1260 return true; 1261 } 1262 1263 template <typename CharT> 1264 inline bool JSONSyntaxParseHandler<CharT>::finishObject( 1265 Vector<StackEntry, 10>& stack, DummyValue* vp, PropertyVector* properties) { 1266 stack.popBack(); 1267 return true; 1268 } 1269 1270 template <typename CharT> 1271 inline bool JSONSyntaxParseHandler<CharT>::arrayOpen( 1272 Vector<StackEntry, 10>& stack, ElementVector** elements) { 1273 StackEntry entry{JSONParserState::FinishArrayElement}; 1274 if (!stack.append(entry)) { 1275 return false; 1276 } 1277 return true; 1278 } 1279 1280 template <typename CharT> 1281 inline bool JSONSyntaxParseHandler<CharT>::finishArray( 1282 Vector<StackEntry, 10>& stack, DummyValue* vp, ElementVector* elements) { 1283 stack.popBack(); 1284 return true; 1285 } 1286 1287 template <typename CharT> 1288 void JSONSyntaxParseHandler<CharT>::reportError(const char* msg, uint32_t line, 1289 uint32_t column) { 1290 const size_t MaxWidth = sizeof("4294967295"); 1291 char columnString[MaxWidth]; 1292 SprintfLiteral(columnString, "%" PRIu32, column); 1293 char lineString[MaxWidth]; 1294 SprintfLiteral(lineString, "%" PRIu32, line); 1295 1296 ErrorMetadata metadata; 1297 metadata.isMuted = false; 1298 metadata.filename = JS::ConstUTF8CharsZ(""); 1299 metadata.lineNumber = 0; 1300 metadata.columnNumber = JS::ColumnNumberOneOrigin(); 1301 1302 ReportJSONSyntaxError(fc, std::move(metadata), JSMSG_JSON_BAD_PARSE, msg, 1303 lineString, columnString); 1304 } 1305 1306 template class js::JSONSyntaxParseHandler<Latin1Char>; 1307 template class js::JSONSyntaxParseHandler<char16_t>; 1308 1309 template <typename CharT> 1310 bool JSONSyntaxParser<CharT>::parse() { 1311 typename HandlerT::DummyValue unused; 1312 1313 if (!this->parseImpl(unused, 1314 [&](const typename HandlerT::DummyValue& unused) {})) { 1315 return false; 1316 } 1317 1318 return true; 1319 } 1320 1321 template class js::JSONSyntaxParser<Latin1Char>; 1322 template class js::JSONSyntaxParser<char16_t>; 1323 1324 template <typename CharT> 1325 static bool IsValidJSONImpl(const CharT* chars, uint32_t len) { 1326 FrontendContext fc; 1327 // NOTE: We don't set stack quota here because JSON parser doesn't use it. 1328 1329 JSONSyntaxParser<CharT> parser(&fc, mozilla::Range(chars, len)); 1330 if (!parser.parse()) { 1331 MOZ_ASSERT(fc.hadErrors()); 1332 return false; 1333 } 1334 MOZ_ASSERT(!fc.hadErrors()); 1335 1336 return true; 1337 } 1338 1339 JS_PUBLIC_API bool JS::IsValidJSON(const JS::Latin1Char* chars, uint32_t len) { 1340 return IsValidJSONImpl(chars, len); 1341 } 1342 1343 JS_PUBLIC_API bool JS::IsValidJSON(const char16_t* chars, uint32_t len) { 1344 return IsValidJSONImpl(chars, len); 1345 } 1346 1347 template <typename CharT> 1348 class MOZ_STACK_CLASS DelegateHandler { 1349 private: 1350 using CharPtr = mozilla::RangedPtr<const CharT>; 1351 1352 public: 1353 using ContextT = FrontendContext; 1354 1355 class DummyValue {}; 1356 1357 struct ElementVector {}; 1358 struct PropertyVector {}; 1359 1360 class JSONStringBuilder { 1361 public: 1362 StringBuilder buffer; 1363 1364 explicit JSONStringBuilder(FrontendContext* fc) : buffer(fc) {} 1365 1366 bool append(char16_t c) { return buffer.append(c); } 1367 bool append(const CharT* begin, const CharT* end) { 1368 return buffer.append(begin, end); 1369 } 1370 }; 1371 1372 struct StackEntry { 1373 JSONParserState state; 1374 }; 1375 1376 public: 1377 FrontendContext* fc; 1378 1379 explicit DelegateHandler(FrontendContext* fc) : fc(fc) {} 1380 1381 DelegateHandler(DelegateHandler&& other) noexcept 1382 : fc(other.fc), handler_(other.handler_) {} 1383 1384 DelegateHandler(const DelegateHandler& other) = delete; 1385 void operator=(const DelegateHandler& other) = delete; 1386 1387 FrontendContext* context() { return fc; } 1388 1389 template <JSONStringType ST> 1390 inline bool setStringValue(CharPtr start, size_t length, 1391 mozilla::Span<const CharT>&& source) { 1392 if (hadHandlerError_) { 1393 return false; 1394 } 1395 1396 if constexpr (ST == JSONStringType::PropertyName) { 1397 return handler_->propertyName(start.get(), length); 1398 } 1399 1400 return handler_->stringValue(start.get(), length); 1401 } 1402 1403 template <JSONStringType ST> 1404 inline bool setStringValue(JSONStringBuilder& builder, 1405 mozilla::Span<const CharT>&& source) { 1406 if (hadHandlerError_) { 1407 return false; 1408 } 1409 1410 if constexpr (ST == JSONStringType::PropertyName) { 1411 if (builder.buffer.isUnderlyingBufferLatin1()) { 1412 return handler_->propertyName(builder.buffer.rawLatin1Begin(), 1413 builder.buffer.length()); 1414 } 1415 1416 return handler_->propertyName(builder.buffer.rawTwoByteBegin(), 1417 builder.buffer.length()); 1418 } 1419 1420 if (builder.buffer.isUnderlyingBufferLatin1()) { 1421 return handler_->stringValue(builder.buffer.rawLatin1Begin(), 1422 builder.buffer.length()); 1423 } 1424 1425 return handler_->stringValue(builder.buffer.rawTwoByteBegin(), 1426 builder.buffer.length()); 1427 } 1428 1429 inline bool setNumberValue(double d, mozilla::Span<const CharT>&& source) { 1430 if (hadHandlerError_) { 1431 return false; 1432 } 1433 1434 if (!handler_->numberValue(d)) { 1435 hadHandlerError_ = true; 1436 } 1437 return !hadHandlerError_; 1438 } 1439 1440 inline bool setBooleanValue(bool value, mozilla::Span<const CharT>&& source) { 1441 if (hadHandlerError_) { 1442 return false; 1443 } 1444 1445 if (!handler_->booleanValue(value)) { 1446 hadHandlerError_ = true; 1447 } 1448 return !hadHandlerError_; 1449 } 1450 inline bool setNullValue(mozilla::Span<const CharT>&& source) { 1451 if (hadHandlerError_) { 1452 return false; 1453 } 1454 1455 if (!handler_->nullValue()) { 1456 hadHandlerError_ = true; 1457 } 1458 return !hadHandlerError_; 1459 } 1460 1461 inline DummyValue numberValue() const { return DummyValue(); } 1462 1463 inline DummyValue stringValue() const { return DummyValue(); } 1464 1465 inline DummyValue booleanValue(bool value) { return DummyValue(); } 1466 1467 inline DummyValue nullValue() { return DummyValue(); } 1468 1469 inline bool objectOpen(Vector<StackEntry, 10>& stack, 1470 PropertyVector** properties) { 1471 if (hadHandlerError_) { 1472 return false; 1473 } 1474 1475 StackEntry entry{JSONParserState::FinishObjectMember}; 1476 if (!stack.append(entry)) { 1477 return false; 1478 } 1479 1480 return handler_->startObject(); 1481 } 1482 inline bool objectPropertyName(Vector<StackEntry, 10>& stack, 1483 bool* isProtoInEval) { 1484 *isProtoInEval = false; 1485 return true; 1486 } 1487 inline bool finishObjectMember(Vector<StackEntry, 10>& stack, 1488 DummyValue& value, 1489 PropertyVector** properties) { 1490 return true; 1491 } 1492 inline bool finishObject(Vector<StackEntry, 10>& stack, DummyValue* vp, 1493 PropertyVector* properties) { 1494 if (hadHandlerError_) { 1495 return false; 1496 } 1497 1498 stack.popBack(); 1499 1500 return handler_->endObject(); 1501 } 1502 1503 inline bool arrayOpen(Vector<StackEntry, 10>& stack, 1504 ElementVector** elements) { 1505 if (hadHandlerError_) { 1506 return false; 1507 } 1508 1509 StackEntry entry{JSONParserState::FinishArrayElement}; 1510 if (!stack.append(entry)) { 1511 return false; 1512 } 1513 1514 return handler_->startArray(); 1515 } 1516 inline bool arrayElement(Vector<StackEntry, 10>& stack, DummyValue& value, 1517 ElementVector** elements) { 1518 return true; 1519 } 1520 inline bool finishArray(Vector<StackEntry, 10>& stack, DummyValue* vp, 1521 ElementVector* elements) { 1522 if (hadHandlerError_) { 1523 return false; 1524 } 1525 1526 stack.popBack(); 1527 1528 return handler_->endArray(); 1529 } 1530 1531 inline bool errorReturn() const { return false; } 1532 1533 inline bool ignoreError() const { return false; } 1534 1535 inline void freeStackEntry(StackEntry& entry) {} 1536 1537 void reportError(const char* msg, uint32_t line, uint32_t column) { 1538 handler_->error(msg, line, column); 1539 } 1540 1541 void setDelegateHandler(JS::JSONParseHandler* handler) { handler_ = handler; } 1542 1543 private: 1544 JS::JSONParseHandler* handler_ = nullptr; 1545 bool hadHandlerError_ = false; 1546 }; 1547 1548 template class DelegateHandler<Latin1Char>; 1549 template class DelegateHandler<char16_t>; 1550 1551 template <typename CharT> 1552 class MOZ_STACK_CLASS DelegateParser 1553 : JSONPerHandlerParser<CharT, DelegateHandler<CharT>> { 1554 using HandlerT = DelegateHandler<CharT>; 1555 using Base = JSONPerHandlerParser<CharT, HandlerT>; 1556 1557 public: 1558 DelegateParser(FrontendContext* fc, mozilla::Range<const CharT> data, 1559 JS::JSONParseHandler* handler) 1560 : Base(fc, data) { 1561 this->handler.setDelegateHandler(handler); 1562 } 1563 1564 DelegateParser(DelegateParser<CharT>&& other) noexcept 1565 : Base(std::move(other)) {} 1566 1567 DelegateParser(const DelegateParser& other) = delete; 1568 void operator=(const DelegateParser& other) = delete; 1569 1570 bool parse() { 1571 typename HandlerT::DummyValue unused; 1572 1573 if (!this->parseImpl(unused, 1574 [&](const typename HandlerT::DummyValue& unused) {})) { 1575 return false; 1576 } 1577 1578 return true; 1579 } 1580 }; 1581 1582 template class DelegateParser<Latin1Char>; 1583 template class DelegateParser<char16_t>; 1584 1585 template <typename CharT> 1586 static bool ParseJSONWithHandlerImpl(const CharT* chars, uint32_t len, 1587 JS::JSONParseHandler* handler) { 1588 FrontendContext fc; 1589 // NOTE: We don't set stack quota here because JSON parser doesn't use it. 1590 1591 DelegateParser<CharT> parser(&fc, mozilla::Range(chars, len), handler); 1592 if (!parser.parse()) { 1593 return false; 1594 } 1595 MOZ_ASSERT(!fc.hadErrors()); 1596 1597 return true; 1598 } 1599 1600 JS_PUBLIC_API bool JS::ParseJSONWithHandler(const JS::Latin1Char* chars, 1601 uint32_t len, 1602 JS::JSONParseHandler* handler) { 1603 return ParseJSONWithHandlerImpl(chars, len, handler); 1604 } 1605 1606 JS_PUBLIC_API bool JS::ParseJSONWithHandler(const char16_t* chars, uint32_t len, 1607 JS::JSONParseHandler* handler) { 1608 return ParseJSONWithHandlerImpl(chars, len, handler); 1609 }