tor-browser

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

testEmptyWindowIsOmitted.cpp (5131B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "mozilla/TextUtils.h"
      6 #include "mozilla/Utf8.h"
      7 
      8 #include <cstring>
      9 
     10 #include "js/CharacterEncoding.h"
     11 #include "js/CompilationAndEvaluation.h"  // JS::Compile
     12 #include "js/Exception.h"
     13 #include "js/friend/ErrorMessages.h"  // JSMSG_*
     14 #include "js/SourceText.h"
     15 #include "jsapi-tests/tests.h"
     16 #include "util/Text.h"
     17 #include "vm/ErrorReporting.h"
     18 
     19 using mozilla::IsAsciiHexDigit;
     20 using mozilla::Utf8Unit;
     21 
     22 BEGIN_TEST(testEmptyWindow) { return testUtf8() && testUtf16(); }
     23 
     24 bool testUtf8() {
     25  // Bad unit with nothing before it.
     26  static const char badLeadingUnit[] = "\x80";
     27  CHECK(testOmittedWindow(badLeadingUnit, JSMSG_BAD_LEADING_UTF8_UNIT, "0x80"));
     28 
     29  // Bad unit at start of a fresh line.
     30  static const char badStartingFreshLine[] = "var x = 5;\n\x98";
     31  CHECK(testOmittedWindow(badStartingFreshLine, JSMSG_BAD_LEADING_UTF8_UNIT,
     32                          "0x98"));
     33 
     34  // Bad trailing unit in initial code point.
     35  static const char badTrailingUnit[] = "\xD8\x20";
     36  CHECK(testOmittedWindow(badTrailingUnit, JSMSG_BAD_TRAILING_UTF8_UNIT,
     37                          "0xD8 0x20"));
     38 
     39  // Bad trailing unit at start of a fresh line.
     40  static const char badTrailingUnitFreshLine[] = "var x = 5;\n\xD8\x20";
     41  CHECK(testOmittedWindow(badTrailingUnitFreshLine,
     42                          JSMSG_BAD_TRAILING_UTF8_UNIT, "0xD8 0x20"));
     43 
     44  // Overlong in initial code point.
     45  static const char overlongInitial[] = "\xC0\x80";
     46  CHECK(testOmittedWindow(overlongInitial, JSMSG_FORBIDDEN_UTF8_CODE_POINT,
     47                          "0xC0 0x80"));
     48 
     49  // Overlong at start of a fresh line.
     50  static const char overlongFreshLine[] = "var x = 5;\n\xC0\x81";
     51  CHECK(testOmittedWindow(overlongFreshLine, JSMSG_FORBIDDEN_UTF8_CODE_POINT,
     52                          "0xC0 0x81"));
     53 
     54  // Not-enough in initial code point.
     55  static const char notEnoughInitial[] = "\xF0";
     56  CHECK(
     57      testOmittedWindow(notEnoughInitial, JSMSG_NOT_ENOUGH_CODE_UNITS, "0xF0"));
     58 
     59  // Not-enough at start of a fresh line.
     60  static const char notEnoughFreshLine[] = "var x = 5;\n\xF0";
     61  CHECK(testOmittedWindow(notEnoughFreshLine, JSMSG_NOT_ENOUGH_CODE_UNITS,
     62                          "0xF0"));
     63 
     64  return true;
     65 }
     66 
     67 bool testUtf16() {
     68  // Bad unit with nothing before it.
     69  static const char16_t badLeadingUnit[] = u"\xDFFF";
     70  CHECK(testOmittedWindow(badLeadingUnit, JSMSG_ILLEGAL_CHARACTER));
     71 
     72  // Bad unit at start of a fresh line.
     73  static const char16_t badStartingFreshLine[] = u"var x = 5;\n\xDFFF";
     74  CHECK(testOmittedWindow(badStartingFreshLine, JSMSG_ILLEGAL_CHARACTER));
     75 
     76  return true;
     77 }
     78 
     79 static bool startsWith(const char* str, const char* prefix) {
     80  return std::strncmp(prefix, str, strlen(prefix)) == 0;
     81 }
     82 
     83 static bool equals(const char* str, const char* expected) {
     84  return std::strcmp(str, expected) == 0;
     85 }
     86 
     87 JSScript* compile(const char16_t* chars, size_t len) {
     88  JS::SourceText<char16_t> source;
     89  MOZ_RELEASE_ASSERT(
     90      source.init(cx, chars, len, JS::SourceOwnership::Borrowed));
     91 
     92  JS::CompileOptions options(cx);
     93  return JS::Compile(cx, options, source);
     94 }
     95 
     96 JSScript* compile(const char* chars, size_t len) {
     97  JS::SourceText<Utf8Unit> source;
     98  MOZ_RELEASE_ASSERT(
     99      source.init(cx, chars, len, JS::SourceOwnership::Borrowed));
    100 
    101  JS::CompileOptions options(cx);
    102  return JS::Compile(cx, options, source);
    103 }
    104 
    105 template <typename CharT, size_t N>
    106 bool testOmittedWindow(const CharT (&chars)[N], unsigned expectedErrorNumber,
    107                       const char* badCodeUnits = nullptr) {
    108  JS::Rooted<JSScript*> script(cx, compile(chars, N - 1));
    109  CHECK(!script);
    110 
    111  JS::ExceptionStack exnStack(cx);
    112  CHECK(JS::StealPendingExceptionStack(cx, &exnStack));
    113 
    114  JS::ErrorReportBuilder report(cx);
    115  CHECK(report.init(cx, exnStack, JS::ErrorReportBuilder::WithSideEffects));
    116 
    117  const auto* errorReport = report.report();
    118 
    119  CHECK(errorReport->errorNumber == expectedErrorNumber);
    120 
    121  if (const auto& notes = errorReport->notes) {
    122    CHECK(sizeof(CharT) == 1);
    123    CHECK(badCodeUnits != nullptr);
    124 
    125    auto iter = notes->begin();
    126    CHECK(iter != notes->end());
    127 
    128    const char* noteMessage = (*iter)->message().c_str();
    129 
    130    // The prefix ought always be the same.
    131    static constexpr char expectedPrefix[] =
    132        "the code units comprising this invalid code point were: ";
    133    constexpr size_t expectedPrefixLen = js_strlen(expectedPrefix);
    134 
    135    CHECK(startsWith(noteMessage, expectedPrefix));
    136 
    137    // The end of the prefix is the bad code units.
    138    CHECK(equals(noteMessage + expectedPrefixLen, badCodeUnits));
    139 
    140    ++iter;
    141    CHECK(iter == notes->end());
    142  } else {
    143    CHECK(sizeof(CharT) == 2);
    144 
    145    // UTF-16 encoding "errors" are not categorical errors, so the errors
    146    // are just of the invalid-character sort, without an accompanying note
    147    // spelling out a series of invalid code units.
    148    CHECK(!badCodeUnits);
    149  }
    150 
    151  CHECK(!errorReport->linebuf());
    152 
    153  return true;
    154 }
    155 END_TEST(testEmptyWindow)