tor-browser

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

testExternalStrings.cpp (7059B)


      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 "js/CharacterEncoding.h"  // JS::FindSmallestEncoding, JS::SmallestEncoding
      6 #include "js/GCAPI.h"  // JSExternalStringCallbacks, JS_NewExternalUCString, JS_NewExternalStringLatin1, JS_NewMaybeExternalStringUTF8, JS::AutoRequireNoGC
      7 #include "js/String.h"  // JS::IsExternalStringLatin1
      8 #include "jsapi-tests/tests.h"
      9 #include "util/Text.h"
     10 
     11 static const char16_t arr[] = u"hi, don't delete me";
     12 static const size_t arrlen = js_strlen(arr);
     13 
     14 static const char arr2[] = "hi, don't delete me";
     15 static const size_t arrlen2 = js_strlen(arr2);
     16 
     17 static int finalized1 = 0;
     18 static int finalized2 = 0;
     19 static int finalized3 = 0;
     20 static int finalized4 = 0;
     21 
     22 struct ExternalStringCallbacks : public JSExternalStringCallbacks {
     23  int* finalizedCount = nullptr;
     24  bool isTwoBytes = false;
     25 
     26  explicit ExternalStringCallbacks(int* finalizedCount, bool isTwoBytes)
     27      : finalizedCount(finalizedCount), isTwoBytes(isTwoBytes) {}
     28 
     29  void finalize(JS::Latin1Char* chars) const override {
     30    MOZ_ASSERT(!isTwoBytes);
     31    MOZ_ASSERT(chars == (JS::Latin1Char*)arr2);
     32    (*finalizedCount)++;
     33  }
     34 
     35  void finalize(char16_t* chars) const override {
     36    MOZ_ASSERT(isTwoBytes);
     37    MOZ_ASSERT(chars == arr);
     38    (*finalizedCount)++;
     39  }
     40 
     41  size_t sizeOfBuffer(const JS::Latin1Char* chars,
     42                      mozilla::MallocSizeOf mallocSizeOf) const override {
     43    MOZ_CRASH("Unexpected call");
     44  }
     45 
     46  size_t sizeOfBuffer(const char16_t* chars,
     47                      mozilla::MallocSizeOf mallocSizeOf) const override {
     48    MOZ_CRASH("Unexpected call");
     49  }
     50 };
     51 
     52 MOZ_RUNINIT static const ExternalStringCallbacks callbacks1(&finalized1, true);
     53 MOZ_RUNINIT static const ExternalStringCallbacks callbacks2(&finalized2, true);
     54 MOZ_RUNINIT static const ExternalStringCallbacks callbacks3(&finalized3, false);
     55 MOZ_RUNINIT static const ExternalStringCallbacks callbacks4(&finalized4, false);
     56 
     57 BEGIN_TEST(testExternalStrings) {
     58  const unsigned N = 1000;
     59 
     60  for (unsigned i = 0; i < N; ++i) {
     61    CHECK(JS_NewExternalUCString(cx, arr, arrlen, &callbacks1));
     62    CHECK(JS_NewExternalUCString(cx, arr, arrlen, &callbacks2));
     63    CHECK(JS_NewExternalStringLatin1(cx, (JS::Latin1Char*)arr2, arrlen2,
     64                                     &callbacks3));
     65    CHECK(JS_NewExternalStringLatin1(cx, (JS::Latin1Char*)arr2, arrlen2,
     66                                     &callbacks4));
     67  }
     68 
     69  JS_GC(cx);
     70 
     71  CHECK((N - finalized1) == 0);
     72  CHECK((N - finalized2) == 0);
     73  CHECK((N - finalized3) == 0);
     74  CHECK((N - finalized4) == 0);
     75 
     76  return true;
     77 }
     78 END_TEST(testExternalStrings)
     79 
     80 struct SimpleExternalStringCallbacks : public JSExternalStringCallbacks {
     81  SimpleExternalStringCallbacks() = default;
     82 
     83  void finalize(JS::Latin1Char* chars) const override {}
     84 
     85  void finalize(char16_t* chars) const override {
     86    MOZ_CRASH("Unexpected call");
     87  }
     88 
     89  size_t sizeOfBuffer(const JS::Latin1Char* chars,
     90                      mozilla::MallocSizeOf mallocSizeOf) const override {
     91    MOZ_CRASH("Unexpected call");
     92  }
     93 
     94  size_t sizeOfBuffer(const char16_t* chars,
     95                      mozilla::MallocSizeOf mallocSizeOf) const override {
     96    MOZ_CRASH("Unexpected call");
     97  }
     98 };
     99 
    100 static const SimpleExternalStringCallbacks simpleCallback;
    101 
    102 static const char utf8ASCII[] = "hi, I'm UTF-8 string";
    103 static const size_t utf8ASCIILen = js_strlen(utf8ASCII);
    104 
    105 static const char utf8Latin1[] = "hi, I'm \xC3\x9CTF-8 string";
    106 static const size_t utf8Latin1Len = js_strlen(utf8Latin1);
    107 
    108 static const char latin1[] = "hi, I'm \xDCTF-8 string";
    109 static const size_t latin1Len = js_strlen(latin1);
    110 
    111 static const char utf8UTF16[] = "hi, I'm UTF-\xEF\xBC\x98 string";
    112 static const size_t utf8UTF16Len = js_strlen(utf8UTF16);
    113 
    114 static const char16_t utf16[] = u"hi, I'm UTF-8 string";
    115 static const size_t utf16Len = js_strlen(utf16);
    116 
    117 BEGIN_TEST(testExternalStringsUTF8) {
    118  // UTF-8 chars with ASCII range content should be converted into external
    119  // string.
    120  {
    121    JS::UTF8Chars utf8Chars(utf8ASCII, utf8ASCIILen);
    122    CHECK(JS::FindSmallestEncoding(utf8Chars) == JS::SmallestEncoding::ASCII);
    123    bool allocatedExternal = false;
    124    JS::Rooted<JSString*> str(
    125        cx, JS_NewMaybeExternalStringUTF8(cx, utf8Chars, &simpleCallback,
    126                                          &allocatedExternal));
    127    CHECK(str);
    128    CHECK(allocatedExternal);
    129 
    130    const JSExternalStringCallbacks* callbacks = nullptr;
    131    const JS::Latin1Char* chars = nullptr;
    132    CHECK(JS::IsExternalStringLatin1(str, &callbacks, &chars));
    133    CHECK(callbacks == &simpleCallback);
    134    CHECK((void*)chars == (void*)utf8ASCII);
    135 
    136    CHECK(StringHasLatin1Chars(str));
    137 
    138    JS::AutoAssertNoGC nogc(cx);
    139    size_t length;
    140    chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str, &length);
    141    CHECK(length == utf8ASCIILen);
    142    CHECK(memcmp(chars, utf8ASCII, length) == 0);
    143  }
    144 
    145  // UTF-8 chars with latin-1 range content shouldn't be converted into external
    146  // string, but regular latin-1 string.
    147  {
    148    JS::UTF8Chars utf8Chars(utf8Latin1, utf8Latin1Len);
    149    CHECK(JS::FindSmallestEncoding(utf8Chars) == JS::SmallestEncoding::Latin1);
    150    bool allocatedExternal = false;
    151    JS::Rooted<JSString*> str(
    152        cx, JS_NewMaybeExternalStringUTF8(cx, utf8Chars, &simpleCallback,
    153                                          &allocatedExternal));
    154    CHECK(str);
    155    CHECK(!allocatedExternal);
    156 
    157    const JSExternalStringCallbacks* callbacks = nullptr;
    158    const JS::Latin1Char* chars = nullptr;
    159    CHECK(!JS::IsExternalStringLatin1(str, &callbacks, &chars));
    160    CHECK(!callbacks);
    161    CHECK(!chars);
    162 
    163    CHECK(StringHasLatin1Chars(str));
    164 
    165    JS::AutoAssertNoGC nogc(cx);
    166    size_t length;
    167    chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str, &length);
    168    CHECK(length == latin1Len);
    169    CHECK(memcmp(chars, latin1, length) == 0);
    170  }
    171 
    172  // UTF-8 chars with UTF-16 range content shouldn't be converted into external
    173  // string, but regular TwoBytes string.
    174  {
    175    JS::UTF8Chars utf8Chars(utf8UTF16, utf8UTF16Len);
    176    CHECK(JS::FindSmallestEncoding(utf8Chars) == JS::SmallestEncoding::UTF16);
    177    bool allocatedExternal = false;
    178    JS::Rooted<JSString*> str(
    179        cx, JS_NewMaybeExternalStringUTF8(cx, utf8Chars, &simpleCallback,
    180                                          &allocatedExternal));
    181    CHECK(str);
    182    CHECK(!allocatedExternal);
    183 
    184    const JSExternalStringCallbacks* callbacks = nullptr;
    185    const JS::Latin1Char* chars = nullptr;
    186    CHECK(!JS::IsExternalStringLatin1(str, &callbacks, &chars));
    187    CHECK(!callbacks);
    188    CHECK(!chars);
    189 
    190    CHECK(!StringHasLatin1Chars(str));
    191 
    192    JS::AutoAssertNoGC nogc(cx);
    193    size_t length;
    194    const char16_t* chars16 = nullptr;
    195    chars16 = JS_GetTwoByteStringCharsAndLength(cx, nogc, str, &length);
    196    CHECK(length == utf16Len);
    197    CHECK(memcmp(chars16, utf16, length * sizeof(char16_t)) == 0);
    198  }
    199 
    200  return true;
    201 }
    202 END_TEST(testExternalStringsUTF8)