tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }